diff --git a/src/harness/client.ts b/src/harness/client.ts index f85e0e111317d..537ee3f36a0b3 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -306,7 +306,8 @@ namespace ts.server { fileName: entry.file, textSpan: this.decodeSpan(entry), kind: ScriptElementKind.unknown, - name: "" + name: "", + unverified: entry.unverified, })), textSpan: this.decodeSpan(body.textSpan, request.arguments.file) }; diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index a39e4525fd617..42917467727e4 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -685,10 +685,10 @@ namespace FourSlash { } public verifyGoToDefinitionIs(endMarker: ArrayOrSingle) { - this.verifyGoToXWorker(toArray(endMarker), () => this.getGoToDefinition()); + this.verifyGoToXWorker(/*startMarker*/ undefined, toArray(endMarker), () => this.getGoToDefinition()); } - public verifyGoToDefinition(arg0: any, endMarkerNames?: ArrayOrSingle | { file: string }) { + public verifyGoToDefinition(arg0: any, endMarkerNames?: ArrayOrSingle | { file: string, unverified?: boolean }) { this.verifyGoToX(arg0, endMarkerNames, () => this.getGoToDefinitionAndBoundSpan()); } @@ -705,7 +705,7 @@ namespace FourSlash { this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition)); } - private verifyGoToX(arg0: any, endMarkerNames: ArrayOrSingle | { file: string } | undefined, getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) { + private verifyGoToX(arg0: any, endMarkerNames: ArrayOrSingle | { file: string, unverified?: boolean } | undefined, getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) { if (endMarkerNames) { this.verifyGoToXPlain(arg0, endMarkerNames, getDefs); } @@ -725,7 +725,7 @@ namespace FourSlash { } } - private verifyGoToXPlain(startMarkerNames: ArrayOrSingle, endMarkerNames: ArrayOrSingle | { file: string }, getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) { + private verifyGoToXPlain(startMarkerNames: ArrayOrSingle, endMarkerNames: ArrayOrSingle | { file: string, unverified?: boolean }, getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) { for (const start of toArray(startMarkerNames)) { this.verifyGoToXSingle(start, endMarkerNames, getDefs); } @@ -737,12 +737,12 @@ namespace FourSlash { } } - private verifyGoToXSingle(startMarkerName: string, endMarkerNames: ArrayOrSingle | { file: string }, getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) { + private verifyGoToXSingle(startMarkerName: string, endMarkerNames: ArrayOrSingle | { file: string, unverified?: boolean }, getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) { this.goToMarker(startMarkerName); - this.verifyGoToXWorker(toArray(endMarkerNames), getDefs, startMarkerName); + this.verifyGoToXWorker(startMarkerName, toArray(endMarkerNames), getDefs, startMarkerName); } - private verifyGoToXWorker(endMarkers: readonly (string | { file: string })[], getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined, startMarkerName?: string) { + private verifyGoToXWorker(startMarker: string | undefined, endMarkers: readonly (string | { marker?: string, file?: string, unverified?: boolean })[], getDefs: () => readonly ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined, startMarkerName?: string) { const defs = getDefs(); let definitions: readonly ts.DefinitionInfo[]; let testName: string; @@ -763,8 +763,11 @@ namespace FourSlash { } ts.zipWith(endMarkers, definitions, (endMarkerOrFileResult, definition, i) => { - const expectedFileName = typeof endMarkerOrFileResult === "string" ? this.getMarkerByName(endMarkerOrFileResult).fileName : endMarkerOrFileResult.file; - const expectedPosition = typeof endMarkerOrFileResult === "string" ? this.getMarkerByName(endMarkerOrFileResult).position : 0; + const markerName = typeof endMarkerOrFileResult === "string" ? endMarkerOrFileResult : endMarkerOrFileResult.marker; + const marker = markerName !== undefined ? this.getMarkerByName(markerName) : undefined; + const expectedFileName = marker?.fileName || typeof endMarkerOrFileResult !== "string" && endMarkerOrFileResult.file; + ts.Debug.assert(typeof expectedFileName === "string"); + const expectedPosition = marker?.position || 0; if (ts.comparePaths(expectedFileName, definition.fileName, /*ignoreCase*/ true) !== ts.Comparison.EqualTo || expectedPosition !== definition.textSpan.start) { const filesToDisplay = ts.deduplicate([expectedFileName, definition.fileName], ts.equateValues); const markers = [{ text: "EXPECTED", fileName: expectedFileName, position: expectedPosition }, { text: "ACTUAL", fileName: definition.fileName, position: definition.textSpan.start }]; @@ -777,7 +780,15 @@ namespace FourSlash { return `// @Filename: ${fileName}\n${fileContent}`; }).join("\n\n"); - this.raiseError(`${testName} failed for definition ${endMarkerOrFileResult} (${i}): expected ${expectedFileName} at ${expectedPosition}, got ${definition.fileName} at ${definition.textSpan.start}\n\n${text}\n`); + this.raiseError(`${testName} failed for definition ${markerName || expectedFileName} (${i}): expected ${expectedFileName} at ${expectedPosition}, got ${definition.fileName} at ${definition.textSpan.start}\n\n${text}\n`); + } + if (definition.unverified && (typeof endMarkerOrFileResult === "string" || !endMarkerOrFileResult.unverified)) { + const isFileResult = typeof endMarkerOrFileResult !== "string" && !!endMarkerOrFileResult.file; + this.raiseError( + `${testName} failed for definition ${markerName || expectedFileName} (${i}): The actual definition was an \`unverified\` result. Use:\n\n` + + ` verify.goToDefinition(${startMarker === undefined ? "startMarker" : `"${startMarker}"`}, { ${isFileResult ? `file: "${expectedFileName}"` : `marker: "${markerName}"`}, unverified: true })\n\n` + + `if this is expected.` + ); } }); } diff --git a/src/server/protocol.ts b/src/server/protocol.ts index ffcde781d85c5..4608601f75ab0 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -1013,7 +1013,7 @@ namespace ts.server.protocol { * Definition response message. Gives text range for definition. */ export interface DefinitionResponse extends Response { - body?: FileSpanWithContext[]; + body?: DefinitionInfo[]; } export interface DefinitionInfoAndBoundSpanResponse extends Response { diff --git a/src/server/session.ts b/src/server/session.ts index e1f92187b3d49..c31002b94a626 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1224,6 +1224,7 @@ namespace ts.server { containerName: info.containerName, kind: info.kind, name: info.name, + ...info.unverified && { unverified: info.unverified }, }; }); } @@ -1300,8 +1301,8 @@ namespace ts.server { })); } - private mapDefinitionInfo(definitions: readonly DefinitionInfo[], project: Project): readonly protocol.FileSpanWithContext[] { - return definitions.map(def => this.toFileSpanWithContext(def.fileName, def.textSpan, def.contextSpan, project)); + private mapDefinitionInfo(definitions: readonly DefinitionInfo[], project: Project): readonly protocol.DefinitionInfo[] { + return definitions.map(def => ({ ...this.toFileSpanWithContext(def.fileName, def.textSpan, def.contextSpan, project), ...def.unverified && { unverified: def.unverified } })); } /* diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts index b77b8ed0a4ceb..76006e0d53f95 100644 --- a/src/services/goToDefinition.ts +++ b/src/services/goToDefinition.ts @@ -146,7 +146,7 @@ namespace ts.GoToDefinition { end: node.getEnd(), fileName: node.text }, - unverified: !!verifiedFileName, + unverified: !verifiedFileName, }; } } diff --git a/src/testRunner/unittests/tsserver/partialSemanticServer.ts b/src/testRunner/unittests/tsserver/partialSemanticServer.ts index edede23aee3b0..755570abc3101 100644 --- a/src/testRunner/unittests/tsserver/partialSemanticServer.ts +++ b/src/testRunner/unittests/tsserver/partialSemanticServer.ts @@ -218,7 +218,7 @@ function fooB() { }` assert.deepEqual(response.definitions, [{ file: file2.path, start: { line: 1, offset: 1 }, - end: { line: 1, offset: 1 } + end: { line: 1, offset: 1 }, }]); }); }); diff --git a/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts b/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts index 21c72eec41bd7..d50f879a60dc5 100644 --- a/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts +++ b/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts @@ -4436,4 +4436,4 @@ ${dependencyTs.content}`); }); }); }); -} \ No newline at end of file +} diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index a2ff8fc1ea29a..3388024bff1c8 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -7389,7 +7389,7 @@ declare namespace ts.server.protocol { * Definition response message. Gives text range for definition. */ interface DefinitionResponse extends Response { - body?: FileSpanWithContext[]; + body?: DefinitionInfo[]; } interface DefinitionInfoAndBoundSpanResponse extends Response { body?: DefinitionInfoAndBoundSpan; diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index d1bc7f429c28d..295ba1fd14264 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -286,8 +286,8 @@ declare namespace FourSlashInterface { * `verify.goToDefinition(["a", "aa"], "b");` verifies that markers "a" and "aa" have the same definition "b". * `verify.goToDefinition("a", ["b", "bb"]);` verifies that "a" has multiple definitions available. */ - goToDefinition(startMarkerNames: ArrayOrSingle, fileResult: { file: string }): void; - goToDefinition(startMarkerNames: ArrayOrSingle, endMarkerNames: ArrayOrSingle): void; + goToDefinition(startMarkerNames: ArrayOrSingle, fileResult: { file: string, unverified?: boolean }): void; + goToDefinition(startMarkerNames: ArrayOrSingle, endMarkerNames: ArrayOrSingle): void; goToDefinition(startMarkerNames: ArrayOrSingle, endMarkerNames: ArrayOrSingle, range: Range): void; /** Performs `goToDefinition` for each pair. */ goToDefinition(startsAndEnds: [ArrayOrSingle, ArrayOrSingle][]): void; diff --git a/tests/cases/fourslash/goToDefinitionCSSPatternAmbientModule.ts b/tests/cases/fourslash/goToDefinitionCSSPatternAmbientModule.ts index 9d595e81eb444..16a53b7501ff0 100644 --- a/tests/cases/fourslash/goToDefinitionCSSPatternAmbientModule.ts +++ b/tests/cases/fourslash/goToDefinitionCSSPatternAmbientModule.ts @@ -14,4 +14,4 @@ // @Filename: index.ts //// import styles from [|/*1*/"./index.css"|]; -verify.goToDefinition("1", ["2a", "2b"]); +verify.goToDefinition("1", [{ marker: "2a", unverified: true }, "2b"]); diff --git a/tests/cases/fourslash/goToDefinitionScriptImport.ts b/tests/cases/fourslash/goToDefinitionScriptImport.ts index d576f5454ad30..5cede98c02a99 100644 --- a/tests/cases/fourslash/goToDefinitionScriptImport.ts +++ b/tests/cases/fourslash/goToDefinitionScriptImport.ts @@ -16,5 +16,5 @@ // not JS/TS, but if we can, you should be able to jump to it. //// import [|/*2*/"./stylez.css"|]; -verify.goToDefinition("1", "1d"); -verify.goToDefinition("2", "2d"); +verify.goToDefinition("1", { marker: "1d", unverified: true }); +verify.goToDefinition("2", { marker: "2d", unverified: true }); diff --git a/tests/cases/fourslash/server/goToDefinitionScriptImportServer.ts b/tests/cases/fourslash/server/goToDefinitionScriptImportServer.ts index 82e1e6ef5cea4..4d781c004d34e 100644 --- a/tests/cases/fourslash/server/goToDefinitionScriptImportServer.ts +++ b/tests/cases/fourslash/server/goToDefinitionScriptImportServer.ts @@ -19,6 +19,6 @@ // does not exist, but should return a response to it anyway so an editor can create it. //// import [|/*3*/"./foo.txt"|]; -verify.goToDefinition("1", "1d"); -verify.goToDefinition("2", "2d"); -verify.goToDefinition("3", { file: "/foo.txt" }); +verify.goToDefinition("1", { marker: "1d", unverified: true }); +verify.goToDefinition("2", { marker: "2d", unverified: true }); +verify.goToDefinition("3", { file: "/foo.txt", unverified: true });