Skip to content

Commit

Permalink
Include context span as relevant declaration span when defintion or o…
Browse files Browse the repository at this point in the history
…ther places are declaration name

Fixes #30849
  • Loading branch information
sheetalkamat committed May 24, 2019
1 parent a2b4029 commit 5d2653f
Show file tree
Hide file tree
Showing 13 changed files with 657 additions and 236 deletions.
24 changes: 16 additions & 8 deletions src/server/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -872,16 +872,24 @@ namespace ts.server.protocol {
file: string;
}

export interface DefinitionTextSpan extends TextSpan {
definitionStart?: Location;
definitionEnd?: Location;
}

export interface DefinitionFileSpan extends FileSpan, DefinitionTextSpan {
}

export interface DefinitionInfoAndBoundSpan {
definitions: ReadonlyArray<FileSpan>;
definitions: ReadonlyArray<DefinitionFileSpan>;
textSpan: TextSpan;
}

/**
* Definition response message. Gives text range for definition.
*/
export interface DefinitionResponse extends Response {
body?: FileSpan[];
body?: DefinitionFileSpan[];
}

export interface DefinitionInfoAndBoundSpanReponse extends Response {
Expand All @@ -892,14 +900,14 @@ namespace ts.server.protocol {
* Definition response message. Gives text range for definition.
*/
export interface TypeDefinitionResponse extends Response {
body?: FileSpan[];
body?: DefinitionFileSpan[];
}

/**
* Implementation response message. Gives text range for implementations.
*/
export interface ImplementationResponse extends Response {
body?: FileSpan[];
body?: DefinitionFileSpan[];
}

/**
Expand Down Expand Up @@ -942,7 +950,7 @@ namespace ts.server.protocol {
}

/** @deprecated */
export interface OccurrencesResponseItem extends FileSpan {
export interface OccurrencesResponseItem extends DefinitionFileSpan {
/**
* True if the occurrence is a write location, false otherwise.
*/
Expand Down Expand Up @@ -972,7 +980,7 @@ namespace ts.server.protocol {
/**
* Span augmented with extra information that denotes the kind of the highlighting to be used for span.
*/
export interface HighlightSpan extends TextSpan {
export interface HighlightSpan extends DefinitionTextSpan {
kind: HighlightSpanKind;
}

Expand Down Expand Up @@ -1007,7 +1015,7 @@ namespace ts.server.protocol {
command: CommandTypes.References;
}

export interface ReferencesResponseItem extends FileSpan {
export interface ReferencesResponseItem extends DefinitionFileSpan {
/** Text of line containing the reference. Including this
* with the response avoids latency of editor loading files
* to show text of reference line (the server already has
Expand Down Expand Up @@ -1150,7 +1158,7 @@ namespace ts.server.protocol {
locs: RenameTextSpan[];
}

export interface RenameTextSpan extends TextSpan {
export interface RenameTextSpan extends DefinitionTextSpan {
readonly prefixText?: string;
readonly suffixText?: string;
}
Expand Down
237 changes: 131 additions & 106 deletions src/server/session.ts

Large diffs are not rendered by default.

116 changes: 95 additions & 21 deletions src/services/findAllReferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,55 @@ namespace ts.FindAllReferences {
export interface NodeEntry {
readonly kind: NodeEntryKind;
readonly node: Node;
readonly declaration?: Node;
}
export interface SpanEntry {
readonly kind: EntryKind.Span;
readonly fileName: string;
readonly textSpan: TextSpan;
}
export function nodeEntry(node: Node, kind: NodeEntryKind = EntryKind.Node): NodeEntry {
return { kind, node: (node as NamedDeclaration).name || node };
const declaration = getDeclarationForDefinitionSpan(
isDeclaration(node) ?
node :
node.parent && isDeclaration(node.parent) && node.parent.name === node ?
node.parent :
undefined
);
return { kind, node: (node as NamedDeclaration).name || node, declaration };
}

export function getDeclarationForDefinitionSpan(node: NamedDeclaration | undefined): Node | undefined {
if (!node) return undefined;
switch (node.kind) {
case SyntaxKind.VariableDeclaration:
return !isVariableDeclarationList(node.parent) || node.parent.declarations.length !== 1 ?
node :
isVariableStatement(node.parent.parent) ?
node.parent.parent :
node.parent;

case SyntaxKind.BindingElement:
return getDeclarationForDefinitionSpan(node.parent.parent as NamedDeclaration);

case SyntaxKind.ImportSpecifier:
return node.parent.parent.parent;

case SyntaxKind.ExportSpecifier:
case SyntaxKind.NamespaceImport:
return node.parent.parent;

case SyntaxKind.ImportClause:
return node.parent;

// Not really interesting definition
// Should we show whole object literal instead?
case SyntaxKind.ShorthandPropertyAssignment:
return undefined;

default:
return node;
}
}

export interface Options {
Expand Down Expand Up @@ -123,7 +164,16 @@ namespace ts.FindAllReferences {
const { symbol } = def;
const { displayParts, kind } = getDefinitionKindAndDisplayParts(symbol, checker, originalNode);
const name = displayParts.map(p => p.text).join("");
return { node: symbol.declarations ? getNameOfDeclaration(first(symbol.declarations)) || first(symbol.declarations) : originalNode, name, kind, displayParts };
const declaration = symbol.declarations ? first(symbol.declarations) : undefined;
return {
node: declaration ?
getNameOfDeclaration(declaration) || declaration :
originalNode,
name,
kind,
displayParts,
declaration: getDeclarationForDefinitionSpan(declaration)
};
}
case DefinitionKind.Label: {
const { node } = def;
Expand All @@ -150,9 +200,21 @@ namespace ts.FindAllReferences {
}
})();

const { node, name, kind, displayParts } = info;
const { node, name, kind, displayParts, declaration } = info;
const sourceFile = node.getSourceFile();
return { containerKind: ScriptElementKind.unknown, containerName: "", fileName: sourceFile.fileName, kind, name, textSpan: getTextSpan(isComputedPropertyName(node) ? node.expression : node, sourceFile), displayParts };
const result: ReferencedSymbolDefinitionInfo = {
containerKind: ScriptElementKind.unknown,
containerName: "",
fileName: sourceFile.fileName,
kind,
name,
textSpan: getTextSpan(isComputedPropertyName(node) ? node.expression : node, sourceFile),
displayParts
};
if (declaration) {
result.definitionSpan = getTextSpan(declaration, sourceFile);
}
return result;
}

function getDefinitionKindAndDisplayParts(symbol: Symbol, checker: TypeChecker, node: Node): { displayParts: SymbolDisplayPart[], kind: ScriptElementKind } {
Expand All @@ -168,14 +230,13 @@ namespace ts.FindAllReferences {
}

export function toReferenceEntry(entry: Entry): ReferenceEntry {
const { textSpan, fileName } = entryToDocumentSpan(entry);
const documentSpan = entryToDocumentSpan(entry);
if (entry.kind === EntryKind.Span) {
return { textSpan, fileName, isWriteAccess: false, isDefinition: false };
return { ...documentSpan, isWriteAccess: false, isDefinition: false };
}
const { kind, node } = entry;
return {
textSpan,
fileName,
...documentSpan,
isWriteAccess: isWriteAccessForReference(node),
isDefinition: node.kind === SyntaxKind.DefaultKeyword
|| !!getDeclarationFromName(node)
Expand All @@ -190,7 +251,11 @@ namespace ts.FindAllReferences {
}
else {
const sourceFile = entry.node.getSourceFile();
return { textSpan: getTextSpan(entry.node, sourceFile), fileName: sourceFile.fileName };
const result: DocumentSpan = { textSpan: getTextSpan(entry.node, sourceFile), fileName: sourceFile.fileName };
if (entry.declaration) {
result.definitionSpan = getTextSpan(entry.declaration, sourceFile);
}
return result;
}
}

Expand Down Expand Up @@ -223,14 +288,16 @@ namespace ts.FindAllReferences {
}

function toImplementationLocation(entry: Entry, checker: TypeChecker): ImplementationLocation {
const documentSpan = entryToDocumentSpan(entry);
if (entry.kind !== EntryKind.Span) {
const { node } = entry;
const sourceFile = node.getSourceFile();
return { textSpan: getTextSpan(node, sourceFile), fileName: sourceFile.fileName, ...implementationKindDisplayParts(node, checker) };
return {
...documentSpan,
...implementationKindDisplayParts(node, checker)
};
}
else {
const { textSpan, fileName } = entry;
return { textSpan, fileName, kind: ScriptElementKind.unknown, displayParts: [] };
return { ...documentSpan, kind: ScriptElementKind.unknown, displayParts: [] };
}
}

Expand All @@ -257,20 +324,27 @@ namespace ts.FindAllReferences {
}

export function toHighlightSpan(entry: Entry): { fileName: string, span: HighlightSpan } {
const documentSpan = entryToDocumentSpan(entry);
if (entry.kind === EntryKind.Span) {
const { fileName, textSpan } = entry;
return { fileName, span: { textSpan, kind: HighlightSpanKind.reference } };
return {
fileName: documentSpan.fileName,
span: {
textSpan: documentSpan.textSpan,
kind: HighlightSpanKind.reference
}
};
}

const { node, kind } = entry;
const sourceFile = node.getSourceFile();
const writeAccess = isWriteAccessForReference(node);
const writeAccess = isWriteAccessForReference(entry.node);
const span: HighlightSpan = {
textSpan: getTextSpan(node, sourceFile),
textSpan: documentSpan.textSpan,
kind: writeAccess ? HighlightSpanKind.writtenReference : HighlightSpanKind.reference,
isInString: kind === EntryKind.StringLiteral ? true : undefined,
isInString: entry.kind === EntryKind.StringLiteral ? true : undefined,
};
return { fileName: sourceFile.fileName, span };
if (documentSpan.definitionSpan) {
span.definitionSpan = documentSpan.definitionSpan;
}
return { fileName: documentSpan.fileName, span };
}

function getTextSpan(node: Node, sourceFile: SourceFile): TextSpan {
Expand Down
6 changes: 5 additions & 1 deletion src/services/goToDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,11 @@ namespace ts.GoToDefinition {
kind: symbolKind,
name: symbolName,
containerKind: undefined!, // TODO: GH#18217
containerName
containerName,
definitionSpan: createTextSpanFromNode(
FindAllReferences.getDeclarationForDefinitionSpan(declaration)!,
sourceFile
)
};
}

Expand Down
23 changes: 16 additions & 7 deletions src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1544,13 +1544,22 @@ namespace ts {

/// References and Occurrences
function getOccurrencesAtPosition(fileName: string, position: number): ReadonlyArray<ReferenceEntry> | undefined {
return flatMap(getDocumentHighlights(fileName, position, [fileName]), entry => entry.highlightSpans.map<ReferenceEntry>(highlightSpan => ({
fileName: entry.fileName,
textSpan: highlightSpan.textSpan,
isWriteAccess: highlightSpan.kind === HighlightSpanKind.writtenReference,
isDefinition: false,
isInString: highlightSpan.isInString,
})));
return flatMap(
getDocumentHighlights(fileName, position, [fileName]),
entry => entry.highlightSpans.map(highlightSpan => {
const result: ReferenceEntry = {
fileName: entry.fileName,
textSpan: highlightSpan.textSpan,
isWriteAccess: highlightSpan.kind === HighlightSpanKind.writtenReference,
isDefinition: false,
isInString: highlightSpan.isInString,
};
if (highlightSpan.definitionSpan) {
result.definitionSpan = highlightSpan.definitionSpan;
}
return result;
})
);
}

function getDocumentHighlights(fileName: string, position: number, filesToSearch: ReadonlyArray<string>): DocumentHighlights[] | undefined {
Expand Down
8 changes: 8 additions & 0 deletions src/services/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,13 @@ namespace ts {
*/
originalTextSpan?: TextSpan;
originalFileName?: string;

/**
* If DocumentSpan.textSpan is the span for name of the declaration,
* then this is the span for relevant declaration
*/
definitionSpan?: TextSpan;
originalDefinitionSpan?: TextSpan;
}

export interface RenameLocation extends DocumentSpan {
Expand Down Expand Up @@ -647,6 +654,7 @@ namespace ts {
fileName?: string;
isInString?: true;
textSpan: TextSpan;
definitionSpan?: TextSpan;
kind: HighlightSpanKind;
}

Expand Down
Loading

0 comments on commit 5d2653f

Please sign in to comment.