From 08165c0b17f18972b774c3fd6d316de39260ba71 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Mon, 1 Dec 2014 23:15:13 -0800 Subject: [PATCH] Ensure getEmitOutput only check the file requested --- src/compiler/checker.ts | 13 ++--- src/compiler/emitter.ts | 35 +++++++++---- src/compiler/types.ts | 3 +- src/harness/fourslash.ts | 7 ++- src/harness/harness.ts | 1 - src/services/services.ts | 52 ++++--------------- ...mitOutputWithEarlySyntacticErrors.baseline | 2 + ...ithSemanticErrorsForMultipleFiles.baseline | 8 +++ ...thSemanticErrorsForMultipleFiles2.baseline | 8 +++ ...thSyntacticErrorsForMultipleFiles.baseline | 6 +++ ...hSyntacticErrorsForMultipleFiles2.baseline | 2 + .../getEmitOutputWithEarlySemanticErrors.ts | 10 ++++ ...utputWithSemanticErrorsForMultipleFiles.ts | 16 ++++++ ...tputWithSemanticErrorsForMultipleFiles2.ts | 17 ++++++ ...tputWithSyntacticErrorsForMultipleFiles.ts | 15 ++++++ ...putWithSyntacticErrorsForMultipleFiles2.ts | 16 ++++++ 16 files changed, 142 insertions(+), 69 deletions(-) create mode 100644 tests/baselines/reference/getEmitOutputWithEarlySyntacticErrors.baseline create mode 100644 tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles.baseline create mode 100644 tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles2.baseline create mode 100644 tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles.baseline create mode 100644 tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles2.baseline create mode 100644 tests/cases/fourslash/getEmitOutputWithEarlySemanticErrors.ts create mode 100644 tests/cases/fourslash/getEmitOutputWithSemanticErrorsForMultipleFiles.ts create mode 100644 tests/cases/fourslash/getEmitOutputWithSemanticErrorsForMultipleFiles2.ts create mode 100644 tests/cases/fourslash/getEmitOutputWithSyntacticErrorsForMultipleFiles.ts create mode 100644 tests/cases/fourslash/getEmitOutputWithSyntacticErrorsForMultipleFiles2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a663b038844..edf966a2fe1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -85,7 +85,6 @@ module ts { getDiagnostics, getDeclarationDiagnostics, getGlobalDiagnostics, - checkProgram, getParentOfSymbol, getNarrowedTypeOfSymbol, getDeclaredTypeOfSymbol, @@ -8634,10 +8633,6 @@ module ts { } } - function checkProgram() { - forEach(program.getSourceFiles(), checkSourceFile); - } - function getSortedDiagnostics(): Diagnostic[]{ Debug.assert(fullTypeCheck, "diagnostics are available only in the full typecheck mode"); @@ -8650,12 +8645,11 @@ module ts { } function getDiagnostics(sourceFile?: SourceFile): Diagnostic[]{ - if (sourceFile) { checkSourceFile(sourceFile); return filter(getSortedDiagnostics(), d => d.file === sourceFile); } - checkProgram(); + forEach(program.getSourceFiles(), checkSourceFile); return getSortedDiagnostics(); } @@ -9173,9 +9167,9 @@ module ts { return isImportResolvedToValue(getSymbolOfNode(node)); } - function hasSemanticErrors() { + function hasSemanticErrors(sourceFile?: SourceFile) { // Return true if there is any semantic error in a file or globally - return getDiagnostics().length > 0 || getGlobalDiagnostics().length > 0; + return getDiagnostics(sourceFile).length > 0 || getGlobalDiagnostics().length > 0; } function isEmitBlocked(sourceFile?: SourceFile): boolean { @@ -9293,7 +9287,6 @@ module ts { function invokeEmitter(targetSourceFile?: SourceFile) { var resolver = createResolver(); - checkProgram(); return emitFiles(resolver, targetSourceFile); } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index fab0433890a..cdb36cc5ac9 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -3791,20 +3791,14 @@ module ts { } } - var hasSemanticErrors = resolver.hasSemanticErrors(); - var isEmitBlocked = resolver.isEmitBlocked(targetSourceFile); - - function emitFile(jsFilePath: string, sourceFile?: SourceFile) { - if (!isEmitBlocked) { - emitJavaScript(jsFilePath, sourceFile); - if (!hasSemanticErrors && compilerOptions.declaration) { - writeDeclarationFile(jsFilePath, sourceFile); - } - } - } + var hasSemanticErrors: boolean = false; + var isEmitBlocked: boolean = false; if (targetSourceFile === undefined) { // No targetSourceFile is specified (e.g. calling emitter from batch compiler) + hasSemanticErrors = resolver.hasSemanticErrors(); + isEmitBlocked = resolver.isEmitBlocked(); + forEach(program.getSourceFiles(), sourceFile => { if (shouldEmitToOwnFile(sourceFile, compilerOptions)) { var jsFilePath = getOwnEmitOutputFilePath(sourceFile, program, ".js"); @@ -3820,16 +3814,35 @@ module ts { // targetSourceFile is specified (e.g calling emitter from language service or calling getSemanticDiagnostic from language service) if (shouldEmitToOwnFile(targetSourceFile, compilerOptions)) { // If shouldEmitToOwnFile returns true or targetSourceFile is an external module file, then emit targetSourceFile in its own output file + hasSemanticErrors = resolver.hasSemanticErrors(targetSourceFile); + isEmitBlocked = resolver.isEmitBlocked(targetSourceFile); + var jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, program, ".js"); emitFile(jsFilePath, targetSourceFile); } else if (!isDeclarationFile(targetSourceFile) && compilerOptions.out) { // Otherwise, if --out is specified and targetSourceFile is not a declaration file, // Emit all, non-external-module file, into one single output file + forEach(program.getSourceFiles(), sourceFile => { + if (!shouldEmitToOwnFile(sourceFile, compilerOptions)) { + hasSemanticErrors = hasSemanticErrors || resolver.hasSemanticErrors(sourceFile); + isEmitBlocked = isEmitBlocked || resolver.isEmitBlocked(sourceFile); + } + }); + emitFile(compilerOptions.out); } } + function emitFile(jsFilePath: string, sourceFile?: SourceFile) { + if (!isEmitBlocked) { + emitJavaScript(jsFilePath, sourceFile); + if (!hasSemanticErrors && compilerOptions.declaration) { + writeDeclarationFile(jsFilePath, sourceFile); + } + } + } + // Sort and make the unique list of diagnostics diagnostics.sort(compareDiagnostics); diagnostics = deduplicateSortedDiagnostics(diagnostics); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 277e2cce5ff..0c3f3d96d98 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -861,7 +861,6 @@ module ts { getIdentifierCount(): number; getSymbolCount(): number; getTypeCount(): number; - checkProgram(): void; emitFiles(targetSourceFile?: SourceFile): EmitResult; getParentOfSymbol(symbol: Symbol): Symbol; getNarrowedTypeOfSymbol(symbol: Symbol, node: Node): Type; @@ -973,7 +972,7 @@ module ts { isTopLevelValueImportWithEntityName(node: ImportDeclaration): boolean; getNodeCheckFlags(node: Node): NodeCheckFlags; getEnumMemberValue(node: EnumMember): number; - hasSemanticErrors(): boolean; + hasSemanticErrors(sourceFile?: SourceFile): boolean; isDeclarationVisible(node: Declaration): boolean; isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableOrParameterDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 05e65f5648f..7e364730ede 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2217,11 +2217,10 @@ module FourSlash { // TODO (drosen): We need to enforce checking on these tests. var program = ts.createProgram([Harness.Compiler.fourslashFilename, fileName], { out: "fourslashTestOutput.js", noResolve: true }, host); var checker = ts.createTypeChecker(program, /*fullTypeCheckMode*/ true); - checker.checkProgram(); - var errs = program.getDiagnostics().concat(checker.getDiagnostics()); - if (errs.length > 0) { - throw new Error('Error compiling ' + fileName + ': ' + errs.map(e => e.messageText).join('\r\n')); + var errors = program.getDiagnostics().concat(checker.getDiagnostics()); + if (errors.length > 0) { + throw new Error('Error compiling ' + fileName + ': ' + errors.map(e => e.messageText).join('\r\n')); } checker.emitFiles(); result = result || ''; // Might have an empty fourslash file diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 640d5f0ae53..c0d3ddedce3 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -801,7 +801,6 @@ module Harness { useCaseSensitiveFileNames)); var checker = program.getTypeChecker(/*fullTypeCheckMode*/ true); - checker.checkProgram(); var isEmitBlocked = checker.isEmitBlocked(); diff --git a/src/services/services.ts b/src/services/services.ts index 8bbc03aad6f..a191e5af83c 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -4665,18 +4665,14 @@ module ts { function getEmitOutput(filename: string): EmitOutput { synchronizeHostData(); + filename = normalizeSlashes(filename); - var compilerOptions = program.getCompilerOptions(); - var targetSourceFile = program.getSourceFile(filename); // Current selected file to be output - // If --out flag is not specified, shouldEmitToOwnFile is true. Otherwise shouldEmitToOwnFile is false. - var shouldEmitToOwnFile = ts.shouldEmitToOwnFile(targetSourceFile, compilerOptions); - var emitOutput: EmitOutput = { - outputFiles: [], - emitOutputStatus: undefined, - }; + var sourceFile = getSourceFile(filename); + + var outputFiles: OutputFile[] = []; function getEmitOutputWriter(filename: string, data: string, writeByteOrderMark: boolean) { - emitOutput.outputFiles.push({ + outputFiles.push({ name: filename, writeByteOrderMark: writeByteOrderMark, text: data @@ -4686,41 +4682,15 @@ module ts { // Initialize writer for CompilerHost.writeFile writer = getEmitOutputWriter; - var containSyntacticErrors = false; - - if (shouldEmitToOwnFile) { - // Check only the file we want to emit - containSyntacticErrors = containErrors(program.getDiagnostics(targetSourceFile)); - } else { - // Check the syntactic of only sourceFiles that will get emitted into single output - // Terminate the process immediately if we encounter a syntax error from one of the sourceFiles - containSyntacticErrors = forEach(program.getSourceFiles(), sourceFile => { - if (!isExternalModuleOrDeclarationFile(sourceFile)) { - // If emit to a single file then we will check all files that do not have external module - return containErrors(program.getDiagnostics(sourceFile)); - } - return false; - }); - } - - if (containSyntacticErrors) { - // If there is a syntax error, terminate the process and report outputStatus - emitOutput.emitOutputStatus = EmitReturnStatus.AllOutputGenerationSkipped; - // Reset writer back to undefined to make sure that we produce an error message - // if CompilerHost.writeFile is called when we are not in getEmitOutput - writer = undefined; - return emitOutput; - } - - // Perform semantic and force a type check before emit to ensure that all symbols are updated - // EmitFiles will report if there is an error from TypeChecker and Emitter - // Depend whether we will have to emit into a single file or not either emit only selected file in the project, emit all files into a single file - var emitFilesResult = getFullTypeCheckChecker().emitFiles(targetSourceFile); - emitOutput.emitOutputStatus = emitFilesResult.emitResultStatus; + var emitOutput = getFullTypeCheckChecker().emitFiles(sourceFile); // Reset writer back to undefined to make sure that we produce an error message if CompilerHost.writeFile method is called when we are not in getEmitOutput writer = undefined; - return emitOutput; + + return { + outputFiles, + emitOutputStatus: emitOutput.emitResultStatus + }; } function getMeaningFromDeclaration(node: Node): SemanticMeaning { diff --git a/tests/baselines/reference/getEmitOutputWithEarlySyntacticErrors.baseline b/tests/baselines/reference/getEmitOutputWithEarlySyntacticErrors.baseline new file mode 100644 index 00000000000..a5d5d2eb9d7 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputWithEarlySyntacticErrors.baseline @@ -0,0 +1,2 @@ +EmitOutputStatus : AllOutputGenerationSkipped + diff --git a/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles.baseline b/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles.baseline new file mode 100644 index 00000000000..c6396314824 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles.baseline @@ -0,0 +1,8 @@ +EmitOutputStatus : Succeeded +Filename : tests/cases/fourslash/inputFile1.js +// File to emit, does not contain semantic errors +// expected to be emitted correctelly regardless of the semantic errors in the other file +var noErrors = true; +Filename : tests/cases/fourslash/inputFile1.d.ts +declare var noErrors: boolean; + diff --git a/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles2.baseline b/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles2.baseline new file mode 100644 index 00000000000..41b16b40e65 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles2.baseline @@ -0,0 +1,8 @@ +EmitOutputStatus : DeclarationGenerationSkipped +Filename : out.js +// File to emit, does not contain semantic errors, but --out is passed +// expected to not generate declarations because of the semantic errors in the other file +var noErrors = true; +// File not emitted, and contains semantic errors +var semanticError = "string"; + diff --git a/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles.baseline b/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles.baseline new file mode 100644 index 00000000000..bf27703890b --- /dev/null +++ b/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles.baseline @@ -0,0 +1,6 @@ +EmitOutputStatus : Succeeded +Filename : tests/cases/fourslash/inputFile1.js +// File to emit, does not contain syntactic errors +// expected to be emitted correctelly regardless of the syntactic errors in the other file +var noErrors = true; + diff --git a/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles2.baseline b/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles2.baseline new file mode 100644 index 00000000000..a5d5d2eb9d7 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputWithSyntacticErrorsForMultipleFiles2.baseline @@ -0,0 +1,2 @@ +EmitOutputStatus : AllOutputGenerationSkipped + diff --git a/tests/cases/fourslash/getEmitOutputWithEarlySemanticErrors.ts b/tests/cases/fourslash/getEmitOutputWithEarlySemanticErrors.ts new file mode 100644 index 00000000000..2946fffb808 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputWithEarlySemanticErrors.ts @@ -0,0 +1,10 @@ +/// + +// @BaselineFile: getEmitOutputWithEarlySyntacticErrors.baseline + +// @Filename: inputFile1.ts +// @emitThisFile: true +//// // File contains early errors. All outputs should be skipped. +//// const uninitialized_const_error; + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputWithSemanticErrorsForMultipleFiles.ts b/tests/cases/fourslash/getEmitOutputWithSemanticErrorsForMultipleFiles.ts new file mode 100644 index 00000000000..5cfacc36715 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputWithSemanticErrorsForMultipleFiles.ts @@ -0,0 +1,16 @@ +/// + +// @BaselineFile: getEmitOutputWithSemanticErrorsForMultipleFiles.baseline +// @declaration: true + +// @Filename: inputFile1.ts +// @emitThisFile: true +//// // File to emit, does not contain semantic errors +//// // expected to be emitted correctelly regardless of the semantic errors in the other file +//// var noErrors = true; + +// @Filename: inputFile2.ts +//// // File not emitted, and contains semantic errors +//// var semanticError: boolean = "string"; + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputWithSemanticErrorsForMultipleFiles2.ts b/tests/cases/fourslash/getEmitOutputWithSemanticErrorsForMultipleFiles2.ts new file mode 100644 index 00000000000..d5cfd1346ca --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputWithSemanticErrorsForMultipleFiles2.ts @@ -0,0 +1,17 @@ +/// + +// @BaselineFile: getEmitOutputWithSemanticErrorsForMultipleFiles2.baseline +// @declaration: true +// @out: out.js + +// @Filename: inputFile1.ts +// @emitThisFile: true +//// // File to emit, does not contain semantic errors, but --out is passed +//// // expected to not generate declarations because of the semantic errors in the other file +//// var noErrors = true; + +// @Filename: inputFile2.ts +//// // File not emitted, and contains semantic errors +//// var semanticError: boolean = "string"; + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputWithSyntacticErrorsForMultipleFiles.ts b/tests/cases/fourslash/getEmitOutputWithSyntacticErrorsForMultipleFiles.ts new file mode 100644 index 00000000000..3b3d01eaac8 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputWithSyntacticErrorsForMultipleFiles.ts @@ -0,0 +1,15 @@ +/// + +// @BaselineFile: getEmitOutputWithSyntacticErrorsForMultipleFiles.baseline + +// @Filename: inputFile1.ts +// @emitThisFile: true +//// // File to emit, does not contain syntactic errors +//// // expected to be emitted correctelly regardless of the syntactic errors in the other file +//// var noErrors = true; + +// @Filename: inputFile2.ts +//// // File not emitted, and contains syntactic errors +//// var syntactic Error; + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputWithSyntacticErrorsForMultipleFiles2.ts b/tests/cases/fourslash/getEmitOutputWithSyntacticErrorsForMultipleFiles2.ts new file mode 100644 index 00000000000..ce82f958b91 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputWithSyntacticErrorsForMultipleFiles2.ts @@ -0,0 +1,16 @@ +/// + +// @BaselineFile: getEmitOutputWithSyntacticErrorsForMultipleFiles2.baseline +// @out: out.js + +// @Filename: inputFile1.ts +// @emitThisFile: true +//// // File to emit, does not contain syntactic errors, but --out is passed +//// // expected to not generate outputs because of the syntactic errors in the other file. +//// var noErrors = true; + +// @Filename: inputFile2.ts +//// // File not emitted, and contains syntactic errors +//// var syntactic Error; + +verify.baselineGetEmitOutput(); \ No newline at end of file