diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 16b2091733a..6bb3e7d9706 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -749,12 +749,10 @@ namespace ts { return _jsxNamespace; } - function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken, ignoreDiagnostics?: boolean) { + function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken) { // Ensure we have all the type information in place for this file so that all the // emitter questions of this resolver will return the right information. - if (!ignoreDiagnostics) { - getDiagnostics(sourceFile, cancellationToken); - } + getDiagnostics(sourceFile, cancellationToken); return emitResolver; } @@ -26601,7 +26599,7 @@ namespace ts { switch (name.parent.kind) { case SyntaxKind.ImportSpecifier: case SyntaxKind.ExportSpecifier: - return true; + return isIdentifier(name); default: return isDeclarationName(name); } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 6ea50b30f6f..e334c1ce80f 100755 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1179,7 +1179,7 @@ namespace ts { // This is because in the -out scenario all files need to be emitted, and therefore all // files need to be type checked. And the way to specify that all files need to be type // checked is to not pass the file to getEmitResolver. - const emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver((options.outFile || options.out) ? undefined : sourceFile, cancellationToken, emitOnlyDtsFiles); + const emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver((options.outFile || options.out) ? undefined : sourceFile, cancellationToken); performance.mark("beforeEmit"); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 481b91c9276..ce2c10a8dda 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2892,7 +2892,7 @@ namespace ts { // Should not be called directly. Should only be accessed through the Program instance. /* @internal */ getDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[]; /* @internal */ getGlobalDiagnostics(): Diagnostic[]; - /* @internal */ getEmitResolver(sourceFile?: SourceFile, cancellationToken?: CancellationToken, ignoreDiagnostics?: boolean): EmitResolver; + /* @internal */ getEmitResolver(sourceFile?: SourceFile, cancellationToken?: CancellationToken): EmitResolver; /* @internal */ getNodeCount(): number; /* @internal */ getIdentifierCount(): number; diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index 790295c2254..471a9323a3d 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -31,8 +31,11 @@ namespace ts { }; } - function clearScreenIfNotWatchingForFileChanges(system: System, diagnostic: Diagnostic) { - if (system.clearScreen && diagnostic.code !== Diagnostics.Compilation_complete_Watching_for_file_changes.code) { + function clearScreenIfNotWatchingForFileChanges(system: System, diagnostic: Diagnostic, options: CompilerOptions) { + if (system.clearScreen && + diagnostic.code !== Diagnostics.Compilation_complete_Watching_for_file_changes.code && + !options.extendedDiagnostics && + !options.diagnostics) { system.clearScreen(); } } @@ -42,18 +45,18 @@ namespace ts { */ export function createWatchStatusReporter(system: System, pretty?: boolean): WatchStatusReporter { return pretty ? - (diagnostic: Diagnostic, newLine: string) => { - clearScreenIfNotWatchingForFileChanges(system, diagnostic); - let output = `[${ formatColorAndReset(new Date().toLocaleTimeString(), ForegroundColorEscapeSequences.Grey) }] `; - output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${newLine + newLine + newLine}`; - system.write(output); - } : - (diagnostic: Diagnostic, newLine: string) => { - clearScreenIfNotWatchingForFileChanges(system, diagnostic); - let output = new Date().toLocaleTimeString() + " - "; - output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${newLine + newLine + newLine}`; - system.write(output); - }; + (diagnostic, newLine, options) => { + clearScreenIfNotWatchingForFileChanges(system, diagnostic, options); + let output = `[${formatColorAndReset(new Date().toLocaleTimeString(), ForegroundColorEscapeSequences.Grey)}] `; + output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${newLine + newLine + newLine}`; + system.write(output); + } : + (diagnostic, newLine, options) => { + clearScreenIfNotWatchingForFileChanges(system, diagnostic, options); + let output = new Date().toLocaleTimeString() + " - "; + output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${newLine + newLine + newLine}`; + system.write(output); + }; } /** @@ -254,7 +257,7 @@ namespace ts { namespace ts { export type DiagnosticReporter = (diagnostic: Diagnostic) => void; - export type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string) => void; + export type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void; export type CreateProgram = (rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: T) => T; export interface WatchCompilerHost { /** @@ -264,7 +267,7 @@ namespace ts { /** If provided, callback to invoke after every new program creation */ afterProgramCreate?(program: T): void; /** If provided, called with Diagnostic message that informs about change in watch status */ - onWatchStatusChange?(diagnostic: Diagnostic, newLine: string): void; + onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void; // Only for testing /*@internal*/ @@ -725,7 +728,7 @@ namespace ts { function reportWatchDiagnostic(message: DiagnosticMessage) { if (host.onWatchStatusChange) { - host.onWatchStatusChange(createCompilerDiagnostic(message), newLine); + host.onWatchStatusChange(createCompilerDiagnostic(message), newLine, compilerOptions); } } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 8f0b7fa1023..a2da85e1aa7 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2863,6 +2863,15 @@ Actual: ${stringify(fullActual)}`); } } + public verifyNoDocumentHighlights(startRange: Range) { + this.goToRangeStart(startRange); + const documentHighlights = this.getDocumentHighlightsAtCurrentPosition([this.activeFile.fileName]); + const numHighlights = ts.length(documentHighlights); + if (numHighlights > 0) { + this.raiseError(`verifyNoDocumentHighlights failed - unexpectedly got ${numHighlights} highlights`); + } + } + private verifyDocumentHighlights(expectedRanges: Range[], fileNames: string[] = [this.activeFile.fileName]) { const documentHighlights = this.getDocumentHighlightsAtCurrentPosition(fileNames) || []; @@ -4271,6 +4280,10 @@ namespace FourSlashInterface { this.state.verifyDocumentHighlightsOf(startRange, ranges); } + public noDocumentHighlights(startRange: FourSlash.Range) { + this.state.verifyNoDocumentHighlights(startRange); + } + public completionEntryDetailIs(entryName: string, text: string, documentation?: string, kind?: string, tags?: ts.JSDocTagInfo[]) { this.state.verifyCompletionEntryDetails(entryName, text, documentation, kind, tags); } diff --git a/src/harness/unittests/builder.ts b/src/harness/unittests/builder.ts index 8808a151c04..3a275d39e86 100644 --- a/src/harness/unittests/builder.ts +++ b/src/harness/unittests/builder.ts @@ -70,13 +70,6 @@ namespace ts { // Change e.ts and verify previously b.js as well as a.js get emitted again since previous change was consumed completely but not d.ts program = updateProgramFile(program, "/e.ts", "export function bar3() { }"); assertChanges(["/b.js", "/a.js", "/e.js"]); - - // Cancel in the middle of affected files list after b.js emit - program = updateProgramFile(program, "/b.ts", "export class b { foo2() { c + 1; } }"); - assertChanges(["/b.js", "/a.js"], 1); - // Change e.ts and verify previously b.js as well as a.js get emitted again since previous change was consumed completely but not d.ts - program = updateProgramFile(program, "/e.ts", "export function bar5() { }"); - assertChanges(["/b.js", "/a.js", "/e.js"]); }); }); diff --git a/src/harness/unittests/projectErrors.ts b/src/harness/unittests/projectErrors.ts index 77e94c930c3..b35fde0aab1 100644 --- a/src/harness/unittests/projectErrors.ts +++ b/src/harness/unittests/projectErrors.ts @@ -63,7 +63,6 @@ namespace ts.projectSystem { // both files exist - expect no errors checkNumberOfProjects(projectService, { externalProjects: 1 }); const diags3 = sendCompilerOptionsDiagnosticsRequest(session, { projectFileName }, /*seq*/ 2); - console.log(diags3); checkDiagnosticsWithLinePos(diags3, []); }); diff --git a/src/harness/unittests/tscWatchMode.ts b/src/harness/unittests/tscWatchMode.ts index 94c5877e896..185e0bb139a 100644 --- a/src/harness/unittests/tscWatchMode.ts +++ b/src/harness/unittests/tscWatchMode.ts @@ -766,6 +766,29 @@ namespace ts.tscWatch { // This should be 0 host.checkTimeoutQueueLengthAndRun(0); }); + + it("shouldnt report error about unused function incorrectly when file changes from global to module", () => { + const getFileContent = (asModule: boolean) => ` + function one() {} + ${asModule ? "export " : ""}function two() { + return function three() { + one(); + } + }`; + const host = new fakes.FakeServerHost({ lib: true }, /*files*/ { + "/a/b/file.ts": getFileContent(/*asModule*/ false) + }); + const watch = createWatchOfFilesAndCompilerOptions(["/a/b/file.ts"], host, { + noUnusedLocals: true + }); + checkProgramActualFiles(watch(), ["/a/b/file.ts", fakes.FakeServerHost.libPath]); + checkOutputErrors(host, [], ExpectedOutputErrorsPosition.AfterCompilationStarting); + + host.writeFile("/a/b/file.ts", getFileContent(/*asModule*/ true)); + host.runQueuedTimeoutCallbacks(); + checkProgramActualFiles(watch(), ["/a/b/file.ts", fakes.FakeServerHost.libPath]); + checkOutputErrors(host, [], ExpectedOutputErrorsPosition.AfterFileChangeDetected); + }); }); describe("emit once", () => { @@ -1525,30 +1548,44 @@ namespace ts.tscWatch { .revoke(); }); }); - }); - describe("tsc-watch console clearing", () => { - it("clears the console when it starts", () => { - const host = new fakes.FakeServerHost({ lib: true }, /*files*/ { - "/a/f.ts": "", + describe("console clearing", () => { + function checkConsoleClearing(diagnostics: boolean, extendedDiagnostics: boolean) { + const host = new fakes.FakeServerHost({ lib: true }, /*files*/ { + "/a/f.ts": "" + }); + let clearCount: number | undefined; + checkConsoleClears(); + + createWatchOfFilesAndCompilerOptions(["/a/f.ts"], host, { diagnostics, extendedDiagnostics }); + checkConsoleClears(); + + host.writeFile("/a/f.ts", "//"); + host.runQueuedTimeoutCallbacks(); + + checkConsoleClears(); + + function checkConsoleClears() { + if (clearCount === undefined) { + clearCount = 0; + } + else if (!diagnostics && !extendedDiagnostics) { + clearCount++; + } + host.checkScreenClears(clearCount); + return clearCount; + } + } + + it("without --diagnostics or --extendedDiagnostics", () => { + checkConsoleClearing(/*diagnostics*/ false, /*extendedDiagnostics*/ false); }); - - createWatchOfFilesAndCompilerOptions(["/a/f.ts"], host); - host.runQueuedTimeoutCallbacks(); - - host.checkScreenClears(1); - }); - - it("clears the console on recompile", () => { - const host = new fakes.FakeServerHost({ lib: true }, /*files*/ { - "/a/f.ts": "", + it("with --diagnostics", () => { + checkConsoleClearing(/*diagnostics*/ true, /*extendedDiagnostics*/ false); + }); + it("with --extendedDiagnostics", () => { + checkConsoleClearing(/*diagnostics*/ false, /*extendedDiagnostics*/ true); }); - createWatchOfFilesAndCompilerOptions(["/a/f.ts"], host); - - host.vfs.writeFileSync("/a/f.ts", "//"); - host.runQueuedTimeoutCallbacks(); - - host.checkScreenClears(2); }); }); } diff --git a/src/services/completions.ts b/src/services/completions.ts index bce1eadaf26..60dfa8aaaa2 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -1921,7 +1921,8 @@ namespace ts.Completions { return isDeclarationName(contextToken) && !isJsxAttribute(contextToken.parent) // Don't block completions if we're in `class C /**/`, because we're *past* the end of the identifier and might want to complete `extends`. - && !(isClassLike(contextToken.parent) && position > previousToken.end); + // If `contextToken !== previousToken`, this is `class C ex/**/`. + && !(isClassLike(contextToken.parent) && (contextToken !== previousToken || position > previousToken.end)); } function isFunctionLikeButNotConstructor(kind: SyntaxKind) { diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index bdcc29af76e..6a0a701ca1a 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3978,7 +3978,7 @@ declare namespace ts { } declare namespace ts { type DiagnosticReporter = (diagnostic: Diagnostic) => void; - type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string) => void; + type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void; type CreateProgram = (rootNames: ReadonlyArray, options: CompilerOptions, host?: CompilerHost, oldProgram?: T) => T; interface WatchCompilerHost { /** @@ -3988,7 +3988,7 @@ declare namespace ts { /** If provided, callback to invoke after every new program creation */ afterProgramCreate?(program: T): void; /** If provided, called with Diagnostic message that informs about change in watch status */ - onWatchStatusChange?(diagnostic: Diagnostic, newLine: string): void; + onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void; useCaseSensitiveFileNames(): boolean; getNewLine(): string; getCurrentDirectory(): string; diff --git a/tests/cases/fourslash/completionsKeywordsExtends.ts b/tests/cases/fourslash/completionsKeywordsExtends.ts index 065d30d1286..50c9b741cda 100644 --- a/tests/cases/fourslash/completionsKeywordsExtends.ts +++ b/tests/cases/fourslash/completionsKeywordsExtends.ts @@ -1,6 +1,7 @@ /// ////class C/*a*/ /*b*/ { } +////class C e/*c*/ {} // Tests that `isCompletionListBlocker` is true *at* the class name, but false *after* it. @@ -9,3 +10,6 @@ verify.completionListIsEmpty(); goTo.marker("b"); verify.completionListContains("extends"); + +goTo.marker("c"); +verify.completionListContains("extends"); diff --git a/tests/cases/fourslash/documentHighlightInExport1.ts b/tests/cases/fourslash/documentHighlightInExport1.ts new file mode 100644 index 00000000000..bf5bc7cfa94 --- /dev/null +++ b/tests/cases/fourslash/documentHighlightInExport1.ts @@ -0,0 +1,10 @@ +/// + +//// class [|C|] {} +//// [|export|] { [|C|] [|as|] [|D|] }; + +const [classRange, exportKeywordRange, propertyNameRange, asKeywordRange, nameRange] = test.ranges(); +verify.noDocumentHighlights(exportKeywordRange); +verify.documentHighlightsOf(propertyNameRange, [classRange, propertyNameRange, nameRange]); +verify.noDocumentHighlights(asKeywordRange); +verify.documentHighlightsOf(nameRange, [nameRange]); diff --git a/tests/cases/fourslash/findAllRefsInExport1.ts b/tests/cases/fourslash/findAllRefsInExport1.ts new file mode 100644 index 00000000000..02ec901177f --- /dev/null +++ b/tests/cases/fourslash/findAllRefsInExport1.ts @@ -0,0 +1,10 @@ +/// + +//// class C {} +//// /*1*/export { C /*2*/as D }; + +goTo.marker("1"); +verify.noReferences(); + +goTo.marker("2"); +verify.noReferences(); \ No newline at end of file