From 96fba4d867ee8d7022442b04448e278a2de0399c Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Mon, 11 Aug 2014 16:01:30 -0700 Subject: [PATCH] TypeWriter logic for identifiers --- src/harness/compilerRunner.ts | 8 ++--- src/harness/harness.ts | 4 +-- src/harness/typeWriter.ts | 62 +++++++++++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index cc1bf1ba96..56e54e2b61 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -52,7 +52,6 @@ class CompilerBaselineRunner extends RunnerBase { var rootDir = lastUnit.originalFilePath.indexOf('conformance') === -1 ? 'tests/cases/compiler/' : lastUnit.originalFilePath.substring(0, lastUnit.originalFilePath.lastIndexOf('/')) + '/'; var result: Harness.Compiler.CompilerResult; - var program: ts.Program; var checker: ts.TypeChecker; var options: ts.CompilerOptions; // equivalent to the files that will be passed on the command line @@ -87,10 +86,9 @@ class CompilerBaselineRunner extends RunnerBase { }); } - options = harnessCompiler.compileFiles(toBeCompiled, otherFiles, function (compileResult, _program, _checker) { + options = harnessCompiler.compileFiles(toBeCompiled, otherFiles, function (compileResult, _checker) { result = compileResult; - // The program and checker will be used by typeWriter - program = _program; + // The checker will be used by typeWriter checker = _checker; }, function (settings) { harnessCompiler.setCompilerSettings(tcSettings); @@ -262,7 +260,7 @@ class CompilerBaselineRunner extends RunnerBase { var allFiles = toBeCompiled.concat(otherFiles); var typeLines: string[] = []; var typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {}; - var walker = new TypeWriterWalker(program, checker); + var walker = new TypeWriterWalker(checker); allFiles.forEach(file => { var codeLines = file.content.split('\n'); walker.getTypes(file.unitName).forEach(result => { diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 153c9f6721..5090312447 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -609,7 +609,7 @@ module Harness { public compileFiles(inputFiles: { unitName: string; content: string }[], otherFiles: { unitName: string; content?: string }[], - onComplete: (result: CompilerResult, program: ts.Program, checker: ts.TypeChecker) => void, + onComplete: (result: CompilerResult, checker: ts.TypeChecker) => void, settingsCallback?: (settings: ts.CompilerOptions) => void, options?: ts.CompilerOptions) { @@ -755,7 +755,7 @@ module Harness { var result = new CompilerResult(fileOutputs, errors, []); // Covert the source Map data into the baseline result.updateSourceMapRecord(program, emitResult ? emitResult.sourceMaps : undefined); - onComplete(result, program, checker); + onComplete(result, checker); // reset what newline means in case the last test changed it sys.newLine = '\r\n'; diff --git a/src/harness/typeWriter.ts b/src/harness/typeWriter.ts index 9702f6b32e..bffc82f007 100644 --- a/src/harness/typeWriter.ts +++ b/src/harness/typeWriter.ts @@ -7,9 +7,67 @@ interface TypeWriterResult { } class TypeWriterWalker { - constructor(public program: ts.Program, public checker: ts.TypeChecker) { + results: TypeWriterResult[]; + currentSourceFile: ts.SourceFile; + + constructor(public checker: ts.TypeChecker) { } + public getTypes(fileName: string): TypeWriterResult[] { - return []; + var sourceFile = this.checker.getProgram().getSourceFile(fileName); + this.currentSourceFile = sourceFile; + this.results = []; + this.visitNode(sourceFile); + return this.results; + } + + private visitNode(node: ts.Node): void { + if (node.kind === ts.SyntaxKind.Identifier) { + var identifier = node; + if (!this.isLabel(identifier)) { + var type = this.getTypeOfIdentifier(identifier); + this.log(node, type); + } + } + else if (node.kind === ts.SyntaxKind.ThisKeyword) { + this.log(node, undefined); + } + else { + ts.forEachChild(node, child => this.visitNode(child)); + } + } + + private isLabel(identifier: ts.Identifier): boolean { + var parent = identifier.parent; + switch (parent.kind) { + case ts.SyntaxKind.ContinueStatement: + case ts.SyntaxKind.BreakStatement: + return (parent).label === identifier; + case ts.SyntaxKind.LabelledStatement: + return (parent).label === identifier; + } + return false; + } + + private log(node: ts.Node, type: ts.Type): void { + var actualPos = ts.skipTrivia(this.currentSourceFile.text, node.pos); + var lineAndCharacter = this.currentSourceFile.getLineAndCharacterFromPosition(actualPos); + var name = ts.getSourceTextOfNodeFromSourceText(this.currentSourceFile.text, node); + + this.results.push({ + line: lineAndCharacter.line - 1, + column: lineAndCharacter.character, + syntaxKind: ts.SyntaxKind[node.kind], + identifierName: name, + type: this.checker.typeToString(type) + }); + } + + private getTypeOfIdentifier(node: ts.Identifier): ts.Type { + var identifierSymbol = this.checker.getSymbolInfo(node); + ts.Debug.assert(identifierSymbol, "symbol doesn't exist"); + var type = this.checker.getTypeOfSymbol(identifierSymbol); + ts.Debug.assert(type, "type doesn't exist"); + return type; } }