diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts
index 8f09e98e3fb..12a97433615 100644
--- a/src/services/findAllReferences.ts
+++ b/src/services/findAllReferences.ts
@@ -5,13 +5,14 @@ namespace ts.FindAllReferences {
readonly references: readonly Entry[];
}
- export const enum DefinitionKind { Symbol, Label, Keyword, This, String }
+ export const enum DefinitionKind { Symbol, Label, Keyword, This, String, TripleSlashReference }
export type Definition =
| { readonly type: DefinitionKind.Symbol; readonly symbol: Symbol }
| { readonly type: DefinitionKind.Label; readonly node: Identifier }
| { readonly type: DefinitionKind.Keyword; readonly node: Node }
| { readonly type: DefinitionKind.This; readonly node: Node }
- | { readonly type: DefinitionKind.String; readonly node: StringLiteralLike };
+ | { readonly type: DefinitionKind.String; readonly node: StringLiteralLike }
+ | { readonly type: DefinitionKind.TripleSlashReference; readonly reference: FileReference, readonly file: SourceFile };
export const enum EntryKind { Span, Node, StringLiteral, SearchedLocalFoundProperty, SearchedPropertyFoundLocal }
export type NodeEntryKind = EntryKind.Node | EntryKind.StringLiteral | EntryKind.SearchedLocalFoundProperty | EntryKind.SearchedPropertyFoundLocal;
@@ -298,17 +299,16 @@ namespace ts.FindAllReferences {
}
function definitionToReferencedSymbolDefinitionInfo(def: Definition, checker: TypeChecker, originalNode: Node): ReferencedSymbolDefinitionInfo {
- const info = (() => {
+ const info = ((): { sourceFile: SourceFile, textSpan: TextSpan, name: string, kind: ScriptElementKind, displayParts: SymbolDisplayPart[], context?: Node | ContextWithStartAndEndNode } => {
switch (def.type) {
case DefinitionKind.Symbol: {
const { symbol } = def;
const { displayParts, kind } = getDefinitionKindAndDisplayParts(symbol, checker, originalNode);
const name = displayParts.map(p => p.text).join("");
const declaration = symbol.declarations && firstOrUndefined(symbol.declarations);
+ const node = declaration ? (getNameOfDeclaration(declaration) || declaration) : originalNode;
return {
- node: declaration ?
- getNameOfDeclaration(declaration) || declaration :
- originalNode,
+ ...getFileAndTextSpanFromNode(node),
name,
kind,
displayParts,
@@ -317,32 +317,44 @@ namespace ts.FindAllReferences {
}
case DefinitionKind.Label: {
const { node } = def;
- return { node, name: node.text, kind: ScriptElementKind.label, displayParts: [displayPart(node.text, SymbolDisplayPartKind.text)] };
+ return { ...getFileAndTextSpanFromNode(node), name: node.text, kind: ScriptElementKind.label, displayParts: [displayPart(node.text, SymbolDisplayPartKind.text)] };
}
case DefinitionKind.Keyword: {
const { node } = def;
const name = tokenToString(node.kind)!;
- return { node, name, kind: ScriptElementKind.keyword, displayParts: [{ text: name, kind: ScriptElementKind.keyword }] };
+ return { ...getFileAndTextSpanFromNode(node), name, kind: ScriptElementKind.keyword, displayParts: [{ text: name, kind: ScriptElementKind.keyword }] };
}
case DefinitionKind.This: {
const { node } = def;
const symbol = checker.getSymbolAtLocation(node);
const displayParts = symbol && SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(
checker, symbol, node.getSourceFile(), getContainerNode(node), node).displayParts || [textPart("this")];
- return { node, name: "this", kind: ScriptElementKind.variableElement, displayParts };
+ return { ...getFileAndTextSpanFromNode(node), name: "this", kind: ScriptElementKind.variableElement, displayParts };
}
case DefinitionKind.String: {
const { node } = def;
- return { node, name: node.text, kind: ScriptElementKind.variableElement, displayParts: [displayPart(getTextOfNode(node), SymbolDisplayPartKind.stringLiteral)] };
+ return {
+ ...getFileAndTextSpanFromNode(node),
+ name: node.text,
+ kind: ScriptElementKind.variableElement,
+ displayParts: [displayPart(getTextOfNode(node), SymbolDisplayPartKind.stringLiteral)]
+ };
+ }
+ case DefinitionKind.TripleSlashReference: {
+ return {
+ textSpan: createTextSpanFromRange(def.reference),
+ sourceFile: def.file,
+ name: def.reference.fileName,
+ kind: ScriptElementKind.string,
+ displayParts: [displayPart(`"${def.reference.fileName}"`, SymbolDisplayPartKind.stringLiteral)]
+ };
}
default:
return Debug.assertNever(def);
}
})();
- const { node, name, kind, displayParts, context } = info;
- const sourceFile = node.getSourceFile();
- const textSpan = getTextSpan(isComputedPropertyName(node) ? node.expression : node, sourceFile);
+ const { sourceFile, textSpan, name, kind, displayParts, context } = info;
return {
containerKind: ScriptElementKind.unknown,
containerName: "",
@@ -355,6 +367,14 @@ namespace ts.FindAllReferences {
};
}
+ function getFileAndTextSpanFromNode(node: Node) {
+ const sourceFile = node.getSourceFile();
+ return {
+ sourceFile,
+ textSpan: getTextSpan(isComputedPropertyName(node) ? node.expression : node, sourceFile)
+ };
+ }
+
function getDefinitionKindAndDisplayParts(symbol: Symbol, checker: TypeChecker, node: Node): { displayParts: SymbolDisplayPart[], kind: ScriptElementKind } {
const meaning = Core.getIntersectingMeaningFromDeclarations(node, symbol);
const enclosingDeclaration = symbol.declarations && firstOrUndefined(symbol.declarations) || node;
@@ -603,9 +623,22 @@ namespace ts.FindAllReferences {
node = getAdjustedRenameLocation(node);
}
if (isSourceFile(node)) {
- const reference = GoToDefinition.getReferenceAtPosition(node, position, program);
- const moduleSymbol = reference && program.getTypeChecker().getMergedSymbol(reference.file.symbol);
- return moduleSymbol && getReferencedSymbolsForModule(program, moduleSymbol, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet);
+ const resolvedRef = GoToDefinition.getReferenceAtPosition(node, position, program);
+ if (!resolvedRef) {
+ return undefined;
+ }
+ const moduleSymbol = program.getTypeChecker().getMergedSymbol(resolvedRef.file.symbol);
+ if (moduleSymbol) {
+ return getReferencedSymbolsForModule(program, moduleSymbol, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet);
+ }
+ const fileIncludeReasons = program.getFileIncludeReasons();
+ if (!fileIncludeReasons) {
+ return undefined;
+ }
+ return [{
+ definition: { type: DefinitionKind.TripleSlashReference, reference: resolvedRef.reference, file: node },
+ references: getReferencesForNonModule(resolvedRef.file, fileIncludeReasons, program) || emptyArray
+ }];
}
if (!options.implementations) {
diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts
index 3567716cb1c..faaf1077354 100644
--- a/src/services/goToDefinition.ts
+++ b/src/services/goToDefinition.ts
@@ -1,9 +1,9 @@
/* @internal */
namespace ts.GoToDefinition {
export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile, position: number): readonly DefinitionInfo[] | undefined {
- const reference = getReferenceAtPosition(sourceFile, position, program);
- if (reference) {
- return [getDefinitionInfoForFileReference(reference.fileName, reference.file.fileName)];
+ const resolvedRef = getReferenceAtPosition(sourceFile, position, program);
+ if (resolvedRef) {
+ return [getDefinitionInfoForFileReference(resolvedRef.reference.fileName, resolvedRef.file.fileName)];
}
const node = getTouchingPropertyName(sourceFile, position);
@@ -108,24 +108,24 @@ namespace ts.GoToDefinition {
|| (!isCallLikeExpression(calledDeclaration.parent) && s === calledDeclaration.parent.symbol);
}
- export function getReferenceAtPosition(sourceFile: SourceFile, position: number, program: Program): { fileName: string, file: SourceFile } | undefined {
+ export function getReferenceAtPosition(sourceFile: SourceFile, position: number, program: Program): { reference: FileReference, file: SourceFile } | undefined {
const referencePath = findReferenceInPosition(sourceFile.referencedFiles, position);
if (referencePath) {
const file = program.getSourceFileFromReference(sourceFile, referencePath);
- return file && { fileName: referencePath.fileName, file };
+ return file && { reference: referencePath, file };
}
const typeReferenceDirective = findReferenceInPosition(sourceFile.typeReferenceDirectives, position);
if (typeReferenceDirective) {
const reference = program.getResolvedTypeReferenceDirectives().get(typeReferenceDirective.fileName);
const file = reference && program.getSourceFile(reference.resolvedFileName!); // TODO:GH#18217
- return file && { fileName: typeReferenceDirective.fileName, file };
+ return file && { reference: typeReferenceDirective, file };
}
const libReferenceDirective = findReferenceInPosition(sourceFile.libReferenceDirectives, position);
if (libReferenceDirective) {
const file = program.getLibFileFromReference(libReferenceDirective);
- return file && { fileName: libReferenceDirective.fileName, file };
+ return file && { reference: libReferenceDirective, file };
}
return undefined;
diff --git a/tests/baselines/reference/findAllReferencesTripleSlash.baseline.jsonc b/tests/baselines/reference/findAllReferencesTripleSlash.baseline.jsonc
new file mode 100644
index 00000000000..d53c912d4fb
--- /dev/null
+++ b/tests/baselines/reference/findAllReferencesTripleSlash.baseline.jsonc
@@ -0,0 +1,99 @@
+// === /c.js ===
+// require([|"./b"|]);
+// require("globals");
+
+// === /a.ts ===
+// ///
+// ///
+
+[
+ {
+ "definition": {
+ "containerKind": "",
+ "containerName": "",
+ "fileName": "/a.ts",
+ "kind": "string",
+ "name": "b.ts",
+ "textSpan": {
+ "start": 21,
+ "length": 4
+ },
+ "displayParts": [
+ {
+ "text": "\"b.ts\"",
+ "kind": "stringLiteral"
+ }
+ ]
+ },
+ "references": [
+ {
+ "textSpan": {
+ "start": 21,
+ "length": 4
+ },
+ "fileName": "/a.ts",
+ "isWriteAccess": false,
+ "isDefinition": false
+ },
+ {
+ "textSpan": {
+ "start": 8,
+ "length": 5
+ },
+ "fileName": "/c.js",
+ "isWriteAccess": false,
+ "isDefinition": false
+ }
+ ]
+ }
+]
+
+// === /c.js ===
+// require("./b");
+// require([|"globals"|]);
+
+// === /a.ts ===
+// ///
+// ///
+
+[
+ {
+ "definition": {
+ "containerKind": "",
+ "containerName": "",
+ "fileName": "/a.ts",
+ "kind": "string",
+ "name": "globals",
+ "textSpan": {
+ "start": 52,
+ "length": 7
+ },
+ "displayParts": [
+ {
+ "text": "\"globals\"",
+ "kind": "stringLiteral"
+ }
+ ]
+ },
+ "references": [
+ {
+ "textSpan": {
+ "start": 52,
+ "length": 7
+ },
+ "fileName": "/a.ts",
+ "isWriteAccess": false,
+ "isDefinition": false
+ },
+ {
+ "textSpan": {
+ "start": 24,
+ "length": 9
+ },
+ "fileName": "/c.js",
+ "isWriteAccess": false,
+ "isDefinition": false
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/tests/cases/fourslash/findAllReferencesTripleSlash.ts b/tests/cases/fourslash/findAllReferencesTripleSlash.ts
new file mode 100644
index 00000000000..956371d0ce8
--- /dev/null
+++ b/tests/cases/fourslash/findAllReferencesTripleSlash.ts
@@ -0,0 +1,19 @@
+///
+
+// @checkJs: true
+
+// @Filename: /node_modules/@types/globals/index.d.ts
+//// declare const someAmbientGlobal: unknown;
+
+// @Filename: /a.ts
+//// ///
+//// ///
+
+// @Filename: /b.ts
+//// console.log("b.ts");
+
+// @Filename: /c.js
+//// require("./b");
+//// require("globals");
+
+verify.baselineFindAllReferences("1", "2");