mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-12 04:17:34 -06:00
Add support for Call Hierarchies in language server (#35176)
* Add support for Call Hierarchies in language server * Use baselines for callHierarchy tests * Clean up commented code * Support multiple hierarchy items when an implementation can't be found * Use optional chaining in a few places * Use getFileAndProject
This commit is contained in:
parent
114dad7f56
commit
6c413e0bbb
@ -630,10 +630,18 @@ namespace ts {
|
||||
return [...array1, ...array2];
|
||||
}
|
||||
|
||||
function selectIndex(_: unknown, i: number) {
|
||||
return i;
|
||||
}
|
||||
|
||||
export function indicesOf(array: readonly unknown[]): number[] {
|
||||
return array.map(selectIndex);
|
||||
}
|
||||
|
||||
function deduplicateRelational<T>(array: readonly T[], equalityComparer: EqualityComparer<T>, comparer: Comparer<T>) {
|
||||
// Perform a stable sort of the array. This ensures the first entry in a list of
|
||||
// duplicates remains the first entry in the result.
|
||||
const indices = array.map((_, i) => i);
|
||||
const indices = indicesOf(array);
|
||||
stableSortIndices(array, indices, comparer);
|
||||
|
||||
let last = array[indices[0]];
|
||||
@ -939,7 +947,7 @@ namespace ts {
|
||||
* Stable sort of an array. Elements equal to each other maintain their relative position in the array.
|
||||
*/
|
||||
export function stableSort<T>(array: readonly T[], comparer: Comparer<T>): SortedReadonlyArray<T> {
|
||||
const indices = array.map((_, i) => i);
|
||||
const indices = indicesOf(array);
|
||||
stableSortIndices(array, indices, comparer);
|
||||
return indices.map(i => array[i]) as SortedArray<T> as SortedReadonlyArray<T>;
|
||||
}
|
||||
@ -1245,8 +1253,10 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function group<T>(values: readonly T[], getGroupId: (value: T) => string): readonly (readonly T[])[] {
|
||||
return arrayFrom(arrayToMultiMap(values, getGroupId).values());
|
||||
export function group<T>(values: readonly T[], getGroupId: (value: T) => string): readonly (readonly T[])[];
|
||||
export function group<T, R>(values: readonly T[], getGroupId: (value: T) => string, resultSelector: (values: readonly T[]) => R): R[];
|
||||
export function group<T>(values: readonly T[], getGroupId: (value: T) => string, resultSelector: (values: readonly T[]) => readonly T[] = identity): readonly (readonly T[])[] {
|
||||
return arrayFrom(arrayToMultiMap(values, getGroupId).values(), resultSelector);
|
||||
}
|
||||
|
||||
export function clone<T>(object: T): T {
|
||||
|
||||
@ -743,6 +743,51 @@ namespace ts.server {
|
||||
return notImplemented();
|
||||
}
|
||||
|
||||
private convertCallHierarchyItem(item: protocol.CallHierarchyItem): CallHierarchyItem {
|
||||
return {
|
||||
file: item.file,
|
||||
name: item.name,
|
||||
kind: item.kind,
|
||||
span: this.decodeSpan(item.span, item.file),
|
||||
selectionSpan: this.decodeSpan(item.selectionSpan, item.file)
|
||||
};
|
||||
}
|
||||
|
||||
prepareCallHierarchy(fileName: string, position: number): CallHierarchyItem | CallHierarchyItem[] | undefined {
|
||||
const args = this.createFileLocationRequestArgs(fileName, position);
|
||||
const request = this.processRequest<protocol.PrepareCallHierarchyRequest>(CommandNames.PrepareCallHierarchy, args);
|
||||
const response = this.processResponse<protocol.PrepareCallHierarchyResponse>(request);
|
||||
return response.body && mapOneOrMany(response.body, item => this.convertCallHierarchyItem(item));
|
||||
}
|
||||
|
||||
private convertCallHierarchyIncomingCall(item: protocol.CallHierarchyIncomingCall): CallHierarchyIncomingCall {
|
||||
return {
|
||||
from: this.convertCallHierarchyItem(item.from),
|
||||
fromSpans: item.fromSpans.map(span => this.decodeSpan(span, item.from.file))
|
||||
};
|
||||
}
|
||||
|
||||
provideCallHierarchyIncomingCalls(fileName: string, position: number) {
|
||||
const args = this.createFileLocationRequestArgs(fileName, position);
|
||||
const request = this.processRequest<protocol.ProvideCallHierarchyIncomingCallsRequest>(CommandNames.PrepareCallHierarchy, args);
|
||||
const response = this.processResponse<protocol.ProvideCallHierarchyIncomingCallsResponse>(request);
|
||||
return response.body.map(item => this.convertCallHierarchyIncomingCall(item));
|
||||
}
|
||||
|
||||
private convertCallHierarchyOutgoingCall(file: string, item: protocol.CallHierarchyOutgoingCall): CallHierarchyOutgoingCall {
|
||||
return {
|
||||
to: this.convertCallHierarchyItem(item.to),
|
||||
fromSpans: item.fromSpans.map(span => this.decodeSpan(span, file))
|
||||
};
|
||||
}
|
||||
|
||||
provideCallHierarchyOutgoingCalls(fileName: string, position: number) {
|
||||
const args = this.createFileLocationRequestArgs(fileName, position);
|
||||
const request = this.processRequest<protocol.ProvideCallHierarchyOutgoingCallsRequest>(CommandNames.PrepareCallHierarchy, args);
|
||||
const response = this.processResponse<protocol.ProvideCallHierarchyOutgoingCallsResponse>(request);
|
||||
return response.body.map(item => this.convertCallHierarchyOutgoingCall(fileName, item));
|
||||
}
|
||||
|
||||
getProgram(): Program {
|
||||
throw new Error("SourceFile objects are not serializable through the server protocol.");
|
||||
}
|
||||
|
||||
@ -147,6 +147,12 @@ namespace FourSlash {
|
||||
return ts.ScriptSnapshot.fromString(sourceText);
|
||||
}
|
||||
|
||||
const enum CallHierarchyItemDirection {
|
||||
Root,
|
||||
Incoming,
|
||||
Outgoing
|
||||
}
|
||||
|
||||
export class TestState {
|
||||
// Language service instance
|
||||
private languageServiceAdapterHost: Harness.LanguageService.LanguageServiceAdapterHost;
|
||||
@ -734,11 +740,8 @@ namespace FourSlash {
|
||||
if (!range) {
|
||||
this.raiseError(`goToDefinitionsAndBoundSpan failed - found a TextSpan ${JSON.stringify(defs.textSpan)} when it wasn't expected.`);
|
||||
}
|
||||
else if (defs.textSpan.start !== range.pos || defs.textSpan.length !== range.end - range.pos) {
|
||||
const expected: ts.TextSpan = {
|
||||
start: range.pos, length: range.end - range.pos
|
||||
};
|
||||
this.raiseError(`goToDefinitionsAndBoundSpan failed - expected to find TextSpan ${JSON.stringify(expected)} but got ${JSON.stringify(defs.textSpan)}`);
|
||||
else {
|
||||
this.assertTextSpanEqualsRange(defs.textSpan, range, "goToDefinitionsAndBoundSpan failed");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1411,18 +1414,91 @@ namespace FourSlash {
|
||||
|
||||
private alignmentForExtraInfo = 50;
|
||||
|
||||
private spanInfoToString(spanInfo: ts.TextSpan, prefixString: string) {
|
||||
private spanLines(file: FourSlashFile, spanInfo: ts.TextSpan, { selection = false, fullLines = false, lineNumbers = false } = {}) {
|
||||
if (selection) {
|
||||
fullLines = true;
|
||||
}
|
||||
|
||||
let contextStartPos = spanInfo.start;
|
||||
let contextEndPos = contextStartPos + spanInfo.length;
|
||||
if (fullLines) {
|
||||
if (contextStartPos > 0) {
|
||||
while (contextStartPos > 1) {
|
||||
const ch = file.content.charCodeAt(contextStartPos - 1);
|
||||
if (ch === ts.CharacterCodes.lineFeed || ch === ts.CharacterCodes.carriageReturn) {
|
||||
break;
|
||||
}
|
||||
contextStartPos--;
|
||||
}
|
||||
}
|
||||
if (contextEndPos < file.content.length) {
|
||||
while (contextEndPos < file.content.length - 1) {
|
||||
const ch = file.content.charCodeAt(contextEndPos);
|
||||
if (ch === ts.CharacterCodes.lineFeed || ch === ts.CharacterCodes.carriageReturn) {
|
||||
break;
|
||||
}
|
||||
contextEndPos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let contextString: string;
|
||||
let contextLineMap: number[];
|
||||
let contextStart: ts.LineAndCharacter;
|
||||
let contextEnd: ts.LineAndCharacter;
|
||||
let selectionStart: ts.LineAndCharacter;
|
||||
let selectionEnd: ts.LineAndCharacter;
|
||||
let lineNumberPrefixLength: number;
|
||||
if (lineNumbers) {
|
||||
contextString = file.content;
|
||||
contextLineMap = ts.computeLineStarts(contextString);
|
||||
contextStart = ts.computeLineAndCharacterOfPosition(contextLineMap, contextStartPos);
|
||||
contextEnd = ts.computeLineAndCharacterOfPosition(contextLineMap, contextEndPos);
|
||||
selectionStart = ts.computeLineAndCharacterOfPosition(contextLineMap, spanInfo.start);
|
||||
selectionEnd = ts.computeLineAndCharacterOfPosition(contextLineMap, ts.textSpanEnd(spanInfo));
|
||||
lineNumberPrefixLength = (contextEnd.line + 1).toString().length + 2;
|
||||
}
|
||||
else {
|
||||
contextString = file.content.substring(contextStartPos, contextEndPos);
|
||||
contextLineMap = ts.computeLineStarts(contextString);
|
||||
contextStart = { line: 0, character: 0 };
|
||||
contextEnd = { line: contextLineMap.length - 1, character: 0 };
|
||||
selectionStart = selection ? ts.computeLineAndCharacterOfPosition(contextLineMap, spanInfo.start - contextStartPos) : contextStart;
|
||||
selectionEnd = selection ? ts.computeLineAndCharacterOfPosition(contextLineMap, ts.textSpanEnd(spanInfo) - contextStartPos) : contextEnd;
|
||||
lineNumberPrefixLength = 0;
|
||||
}
|
||||
|
||||
const output: string[] = [];
|
||||
for (let lineNumber = contextStart.line; lineNumber <= contextEnd.line; lineNumber++) {
|
||||
const spanLine = contextString.substring(contextLineMap[lineNumber], contextLineMap[lineNumber + 1]);
|
||||
output.push(lineNumbers ? `${`${lineNumber + 1}: `.padStart(lineNumberPrefixLength, " ")}${spanLine}` : spanLine);
|
||||
if (selection) {
|
||||
if (lineNumber < selectionStart.line || lineNumber > selectionEnd.line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const isEmpty = selectionStart.line === selectionEnd.line && selectionStart.character === selectionEnd.character;
|
||||
const selectionPadLength = lineNumber === selectionStart.line ? selectionStart.character : 0;
|
||||
const selectionPad = " ".repeat(selectionPadLength + lineNumberPrefixLength);
|
||||
const selectionLength = isEmpty ? 0 : Math.max(lineNumber < selectionEnd.line ? spanLine.trimRight().length - selectionPadLength : selectionEnd.character - selectionPadLength, 1);
|
||||
const selectionLine = isEmpty ? "<" : "^".repeat(selectionLength);
|
||||
output.push(`${selectionPad}${selectionLine}`);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
private spanInfoToString(spanInfo: ts.TextSpan, prefixString: string, file: FourSlashFile = this.activeFile) {
|
||||
let resultString = "SpanInfo: " + JSON.stringify(spanInfo);
|
||||
if (spanInfo) {
|
||||
const spanString = this.activeFile.content.substr(spanInfo.start, spanInfo.length);
|
||||
const spanLineMap = ts.computeLineStarts(spanString);
|
||||
for (let i = 0; i < spanLineMap.length; i++) {
|
||||
const spanLines = this.spanLines(file, spanInfo);
|
||||
for (let i = 0; i < spanLines.length; i++) {
|
||||
if (!i) {
|
||||
resultString += "\n";
|
||||
}
|
||||
resultString += prefixString + spanString.substring(spanLineMap[i], spanLineMap[i + 1]);
|
||||
resultString += prefixString + spanLines[i];
|
||||
}
|
||||
resultString += "\n" + prefixString + ":=> (" + this.getLineColStringAtPosition(spanInfo.start) + ") to (" + this.getLineColStringAtPosition(ts.textSpanEnd(spanInfo)) + ")";
|
||||
resultString += "\n" + prefixString + ":=> (" + this.getLineColStringAtPosition(spanInfo.start, file) + ") to (" + this.getLineColStringAtPosition(ts.textSpanEnd(spanInfo), file) + ")";
|
||||
}
|
||||
|
||||
return resultString;
|
||||
@ -1701,13 +1777,13 @@ namespace FourSlash {
|
||||
Harness.IO.log(stringify(help.items[help.selectedItemIndex]));
|
||||
}
|
||||
|
||||
private getBaselineFileNameForInternalFourslashFile() {
|
||||
private getBaselineFileNameForInternalFourslashFile(ext = ".baseline") {
|
||||
return this.testData.globalOptions[MetadataOptionNames.baselineFile] ||
|
||||
ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ".baseline");
|
||||
ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ext);
|
||||
}
|
||||
|
||||
private getBaselineFileNameForContainingTestFile() {
|
||||
return ts.getBaseFileName(this.originalInputFileName).replace(ts.Extension.Ts, ".baseline");
|
||||
private getBaselineFileNameForContainingTestFile(ext = ".baseline") {
|
||||
return ts.getBaseFileName(this.originalInputFileName).replace(ts.Extension.Ts, ext);
|
||||
}
|
||||
|
||||
private getSignatureHelp({ triggerReason }: FourSlashInterface.VerifySignatureHelpOptions): ts.SignatureHelpItems | undefined {
|
||||
@ -3164,6 +3240,131 @@ namespace FourSlash {
|
||||
Harness.IO.log(stringify(codeFixes));
|
||||
}
|
||||
|
||||
private formatCallHierarchyItemSpan(file: FourSlashFile, span: ts.TextSpan, prefix: string, trailingPrefix = prefix) {
|
||||
const startLc = this.languageServiceAdapterHost.positionToLineAndCharacter(file.fileName, span.start);
|
||||
const endLc = this.languageServiceAdapterHost.positionToLineAndCharacter(file.fileName, ts.textSpanEnd(span));
|
||||
const lines = this.spanLines(file, span, { fullLines: true, lineNumbers: true, selection: true });
|
||||
let text = "";
|
||||
text += `${prefix}╭ ${file.fileName}:${startLc.line + 1}:${startLc.character + 1}-${endLc.line + 1}:${endLc.character + 1}\n`;
|
||||
for (const line of lines) {
|
||||
text += `${prefix}│ ${line.trimRight()}\n`;
|
||||
}
|
||||
text += `${trailingPrefix}╰\n`;
|
||||
return text;
|
||||
}
|
||||
|
||||
private formatCallHierarchyItemSpans(file: FourSlashFile, spans: ts.TextSpan[], prefix: string, trailingPrefix = prefix) {
|
||||
let text = "";
|
||||
for (let i = 0; i < spans.length; i++) {
|
||||
text += this.formatCallHierarchyItemSpan(file, spans[i], prefix, i < spans.length - 1 ? prefix : trailingPrefix);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
private formatCallHierarchyItem(file: FourSlashFile, callHierarchyItem: ts.CallHierarchyItem, direction: CallHierarchyItemDirection, seen: ts.Map<boolean>, prefix: string, trailingPrefix: string = prefix) {
|
||||
const key = `${callHierarchyItem.file}|${JSON.stringify(callHierarchyItem.span)}|${direction}`;
|
||||
const alreadySeen = seen.has(key);
|
||||
seen.set(key, true);
|
||||
|
||||
const incomingCalls =
|
||||
direction === CallHierarchyItemDirection.Outgoing ? { result: "skip" } as const :
|
||||
alreadySeen ? { result: "seen" } as const :
|
||||
{ result: "show", values: this.languageService.provideCallHierarchyIncomingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const;
|
||||
|
||||
const outgoingCalls =
|
||||
direction === CallHierarchyItemDirection.Incoming ? { result: "skip" } as const :
|
||||
alreadySeen ? { result: "seen" } as const :
|
||||
{ result: "show", values: this.languageService.provideCallHierarchyOutgoingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const;
|
||||
|
||||
let text = "";
|
||||
text += `${prefix}╭ name: ${callHierarchyItem.name}\n`;
|
||||
text += `${prefix}├ kind: ${callHierarchyItem.kind}\n`;
|
||||
text += `${prefix}├ file: ${callHierarchyItem.file}\n`;
|
||||
text += `${prefix}├ span:\n`;
|
||||
text += this.formatCallHierarchyItemSpan(file, callHierarchyItem.span, `${prefix}│ `);
|
||||
text += `${prefix}├ selectionSpan:\n`;
|
||||
text += this.formatCallHierarchyItemSpan(file, callHierarchyItem.selectionSpan, `${prefix}│ `,
|
||||
incomingCalls.result !== "skip" || outgoingCalls.result !== "skip" ? `${prefix}│ ` :
|
||||
`${trailingPrefix}╰ `);
|
||||
|
||||
if (incomingCalls.result === "seen") {
|
||||
if (outgoingCalls.result === "skip") {
|
||||
text += `${trailingPrefix}╰ incoming: ...\n`;
|
||||
}
|
||||
else {
|
||||
text += `${prefix}├ incoming: ...\n`;
|
||||
}
|
||||
}
|
||||
else if (incomingCalls.result === "show") {
|
||||
if (!ts.some(incomingCalls.values)) {
|
||||
if (outgoingCalls.result === "skip") {
|
||||
text += `${trailingPrefix}╰ incoming: none\n`;
|
||||
}
|
||||
else {
|
||||
text += `${prefix}├ incoming: none\n`;
|
||||
}
|
||||
}
|
||||
else {
|
||||
text += `${prefix}├ incoming:\n`;
|
||||
for (let i = 0; i < incomingCalls.values.length; i++) {
|
||||
const incomingCall = incomingCalls.values[i];
|
||||
const file = this.findFile(incomingCall.from.file);
|
||||
text += `${prefix}│ ╭ from:\n`;
|
||||
text += this.formatCallHierarchyItem(file, incomingCall.from, CallHierarchyItemDirection.Incoming, seen, `${prefix}│ │ `);
|
||||
text += `${prefix}│ ├ fromSpans:\n`;
|
||||
text += this.formatCallHierarchyItemSpans(file, incomingCall.fromSpans, `${prefix}│ │ `,
|
||||
i < incomingCalls.values.length - 1 ? `${prefix}│ ╰ ` :
|
||||
outgoingCalls.result !== "skip" ? `${prefix}│ ╰ ` :
|
||||
`${trailingPrefix}╰ ╰ `);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (outgoingCalls.result === "seen") {
|
||||
text += `${trailingPrefix}╰ outgoing: ...\n`;
|
||||
}
|
||||
else if (outgoingCalls.result === "show") {
|
||||
if (!ts.some(outgoingCalls.values)) {
|
||||
text += `${trailingPrefix}╰ outgoing: none\n`;
|
||||
}
|
||||
else {
|
||||
text += `${prefix}├ outgoing:\n`;
|
||||
for (let i = 0; i < outgoingCalls.values.length; i++) {
|
||||
const outgoingCall = outgoingCalls.values[i];
|
||||
text += `${prefix}│ ╭ to:\n`;
|
||||
text += this.formatCallHierarchyItem(this.findFile(outgoingCall.to.file), outgoingCall.to, CallHierarchyItemDirection.Outgoing, seen, `${prefix}│ │ `);
|
||||
text += `${prefix}│ ├ fromSpans:\n`;
|
||||
text += this.formatCallHierarchyItemSpans(file, outgoingCall.fromSpans, `${prefix}│ │ `,
|
||||
i < outgoingCalls.values.length - 1 ? `${prefix}│ ╰ ` :
|
||||
`${trailingPrefix}╰ ╰ `);
|
||||
}
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
private formatCallHierarchy(callHierarchyItem: ts.CallHierarchyItem | undefined) {
|
||||
let text = "";
|
||||
if (callHierarchyItem) {
|
||||
const file = this.findFile(callHierarchyItem.file);
|
||||
text += this.formatCallHierarchyItem(file, callHierarchyItem, CallHierarchyItemDirection.Root, ts.createMap(), "");
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public baselineCallHierarchy() {
|
||||
const baselineFile = this.getBaselineFileNameForContainingTestFile(".callHierarchy.txt");
|
||||
const callHierarchyItem = this.languageService.prepareCallHierarchy(this.activeFile.fileName, this.currentCaretPosition);
|
||||
const text = callHierarchyItem ? ts.mapOneOrMany(callHierarchyItem, item => this.formatCallHierarchy(item), result => result.join("")) : "none";
|
||||
Harness.Baseline.runBaseline(baselineFile, text);
|
||||
}
|
||||
|
||||
private assertTextSpanEqualsRange(span: ts.TextSpan, range: Range, message?: string) {
|
||||
if (!textSpanEqualsRange(span, range)) {
|
||||
this.raiseError(`${prefixMessage(message)}Expected to find TextSpan ${JSON.stringify({ start: range.pos, length: range.end - range.pos })} but got ${JSON.stringify(span)} instead.`);
|
||||
}
|
||||
}
|
||||
|
||||
private getLineContent(index: number) {
|
||||
const text = this.getFileContent(this.activeFile.fileName);
|
||||
const pos = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { line: index, character: 0 });
|
||||
@ -3243,8 +3444,8 @@ namespace FourSlash {
|
||||
return this.tryFindFileWorker(name).file !== undefined;
|
||||
}
|
||||
|
||||
private getLineColStringAtPosition(position: number) {
|
||||
const pos = this.languageServiceAdapterHost.positionToLineAndCharacter(this.activeFile.fileName, position);
|
||||
private getLineColStringAtPosition(position: number, file: FourSlashFile = this.activeFile) {
|
||||
const pos = this.languageServiceAdapterHost.positionToLineAndCharacter(file.fileName, position);
|
||||
return `line ${(pos.line + 1)}, col ${pos.character}`;
|
||||
}
|
||||
|
||||
@ -3297,6 +3498,14 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
function prefixMessage(message: string | undefined) {
|
||||
return message ? `${message} - ` : "";
|
||||
}
|
||||
|
||||
function textSpanEqualsRange(span: ts.TextSpan, range: Range) {
|
||||
return span.start === range.pos && span.length === range.end - range.pos;
|
||||
}
|
||||
|
||||
function updateTextRangeForTextChanges({ pos, end }: ts.TextRange, textChanges: readonly ts.TextChange[]): ts.TextRange {
|
||||
forEachTextChange(textChanges, change => {
|
||||
const update = (p: number): number => updatePosition(p, change.span.start, ts.textSpanEnd(change.span), change.newText);
|
||||
|
||||
@ -541,9 +541,14 @@ namespace FourSlashInterface {
|
||||
this.state.getEditsForFileRename(options);
|
||||
}
|
||||
|
||||
public baselineCallHierarchy() {
|
||||
this.state.baselineCallHierarchy();
|
||||
}
|
||||
|
||||
public moveToNewFile(options: MoveToNewFileOptions): void {
|
||||
this.state.moveToNewFile(options);
|
||||
}
|
||||
|
||||
public noMoveToNewFile(): void {
|
||||
this.state.noMoveToNewFile();
|
||||
}
|
||||
|
||||
@ -574,6 +574,15 @@ namespace Harness.LanguageService {
|
||||
getEditsForFileRename(): readonly ts.FileTextChanges[] {
|
||||
throw new Error("Not supported on the shim.");
|
||||
}
|
||||
prepareCallHierarchy(fileName: string, position: number) {
|
||||
return unwrapJSONCallResult(this.shim.prepareCallHierarchy(fileName, position));
|
||||
}
|
||||
provideCallHierarchyIncomingCalls(fileName: string, position: number) {
|
||||
return unwrapJSONCallResult(this.shim.provideCallHierarchyIncomingCalls(fileName, position));
|
||||
}
|
||||
provideCallHierarchyOutgoingCalls(fileName: string, position: number) {
|
||||
return unwrapJSONCallResult(this.shim.provideCallHierarchyOutgoingCalls(fileName, position));
|
||||
}
|
||||
getEmitOutput(fileName: string): ts.EmitOutput {
|
||||
return unwrapJSONCallResult(this.shim.getEmitOutput(fileName));
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* Declaration module describing the TypeScript Server protocol
|
||||
*/
|
||||
namespace ts.server.protocol {
|
||||
// NOTE: If updating this, be sure to also update `allCommandNames` in `harness/unittests/session.ts`.
|
||||
// NOTE: If updating this, be sure to also update `allCommandNames` in `testRunner/unittests/tsserver/session.ts`.
|
||||
export const enum CommandTypes {
|
||||
JsxClosingTag = "jsxClosingTag",
|
||||
Brace = "brace",
|
||||
@ -137,7 +137,11 @@ namespace ts.server.protocol {
|
||||
/* @internal */
|
||||
SelectionRangeFull = "selectionRange-full",
|
||||
|
||||
// NOTE: If updating this, be sure to also update `allCommandNames` in `harness/unittests/session.ts`.
|
||||
PrepareCallHierarchy = "prepareCallHierarchy",
|
||||
ProvideCallHierarchyIncomingCalls = "provideCallHierarchyIncomingCalls",
|
||||
ProvideCallHierarchyOutgoingCalls = "provideCallHierarchyOutgoingCalls",
|
||||
|
||||
// NOTE: If updating this, be sure to also update `allCommandNames` in `testRunner/unittests/tsserver/session.ts`.
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2983,6 +2987,48 @@ namespace ts.server.protocol {
|
||||
body?: NavigationTree;
|
||||
}
|
||||
|
||||
export interface CallHierarchyItem {
|
||||
name: string;
|
||||
kind: ScriptElementKind;
|
||||
file: string;
|
||||
span: TextSpan;
|
||||
selectionSpan: TextSpan;
|
||||
}
|
||||
|
||||
export interface CallHierarchyIncomingCall {
|
||||
from: CallHierarchyItem;
|
||||
fromSpans: TextSpan[];
|
||||
}
|
||||
|
||||
export interface CallHierarchyOutgoingCall {
|
||||
to: CallHierarchyItem;
|
||||
fromSpans: TextSpan[];
|
||||
}
|
||||
|
||||
export interface PrepareCallHierarchyRequest extends FileLocationRequest {
|
||||
command: CommandTypes.PrepareCallHierarchy;
|
||||
}
|
||||
|
||||
export interface PrepareCallHierarchyResponse extends Response {
|
||||
readonly body: CallHierarchyItem | CallHierarchyItem[];
|
||||
}
|
||||
|
||||
export interface ProvideCallHierarchyIncomingCallsRequest extends FileLocationRequest {
|
||||
command: CommandTypes.ProvideCallHierarchyIncomingCalls;
|
||||
}
|
||||
|
||||
export interface ProvideCallHierarchyIncomingCallsResponse extends Response {
|
||||
readonly body: CallHierarchyIncomingCall[];
|
||||
}
|
||||
|
||||
export interface ProvideCallHierarchyOutgoingCallsRequest extends FileLocationRequest {
|
||||
command: CommandTypes.ProvideCallHierarchyOutgoingCalls;
|
||||
}
|
||||
|
||||
export interface ProvideCallHierarchyOutgoingCallsResponse extends Response {
|
||||
readonly body: CallHierarchyOutgoingCall[];
|
||||
}
|
||||
|
||||
export const enum IndentStyle {
|
||||
None = "None",
|
||||
Block = "Block",
|
||||
|
||||
@ -1060,7 +1060,7 @@ namespace ts.server {
|
||||
if (simplifiedResult) {
|
||||
return {
|
||||
definitions: this.mapDefinitionInfo(definitions, project),
|
||||
textSpan: toProcolTextSpan(textSpan, scriptInfo)
|
||||
textSpan: toProtocolTextSpan(textSpan, scriptInfo)
|
||||
};
|
||||
}
|
||||
|
||||
@ -1315,7 +1315,7 @@ namespace ts.server {
|
||||
if (info.canRename) {
|
||||
const { canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan } = info;
|
||||
return identity<protocol.RenameInfoSuccess>(
|
||||
{ canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan: toProcolTextSpan(triggerSpan, scriptInfo) });
|
||||
{ canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan: toProtocolTextSpan(triggerSpan, scriptInfo) });
|
||||
}
|
||||
else {
|
||||
return info;
|
||||
@ -1415,8 +1415,8 @@ namespace ts.server {
|
||||
if (simplifiedResult) {
|
||||
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
|
||||
return spans.map(s => ({
|
||||
textSpan: toProcolTextSpan(s.textSpan, scriptInfo),
|
||||
hintSpan: toProcolTextSpan(s.hintSpan, scriptInfo),
|
||||
textSpan: toProtocolTextSpan(s.textSpan, scriptInfo),
|
||||
hintSpan: toProtocolTextSpan(s.hintSpan, scriptInfo),
|
||||
bannerText: s.bannerText,
|
||||
autoCollapse: s.autoCollapse,
|
||||
kind: s.kind
|
||||
@ -1605,7 +1605,7 @@ namespace ts.server {
|
||||
const entries = mapDefined<CompletionEntry, protocol.CompletionEntry>(completions.entries, entry => {
|
||||
if (completions.isMemberCompletion || startsWith(entry.name.toLowerCase(), prefix.toLowerCase())) {
|
||||
const { name, kind, kindModifiers, sortText, insertText, replacementSpan, hasAction, source, isRecommended } = entry;
|
||||
const convertedSpan = replacementSpan ? toProcolTextSpan(replacementSpan, scriptInfo) : undefined;
|
||||
const convertedSpan = replacementSpan ? toProtocolTextSpan(replacementSpan, scriptInfo) : undefined;
|
||||
// Use `hasAction || undefined` to avoid serializing `false`.
|
||||
return { name, kind, kindModifiers, sortText, insertText, replacementSpan: convertedSpan, hasAction: hasAction || undefined, source, isRecommended };
|
||||
}
|
||||
@ -1775,7 +1775,7 @@ namespace ts.server {
|
||||
text: item.text,
|
||||
kind: item.kind,
|
||||
kindModifiers: item.kindModifiers,
|
||||
spans: item.spans.map(span => toProcolTextSpan(span, scriptInfo)),
|
||||
spans: item.spans.map(span => toProtocolTextSpan(span, scriptInfo)),
|
||||
childItems: this.mapLocationNavigationBarItems(item.childItems, scriptInfo),
|
||||
indent: item.indent
|
||||
}));
|
||||
@ -1796,8 +1796,8 @@ namespace ts.server {
|
||||
text: tree.text,
|
||||
kind: tree.kind,
|
||||
kindModifiers: tree.kindModifiers,
|
||||
spans: tree.spans.map(span => toProcolTextSpan(span, scriptInfo)),
|
||||
nameSpan: tree.nameSpan && toProcolTextSpan(tree.nameSpan, scriptInfo),
|
||||
spans: tree.spans.map(span => toProtocolTextSpan(span, scriptInfo)),
|
||||
nameSpan: tree.nameSpan && toProtocolTextSpan(tree.nameSpan, scriptInfo),
|
||||
childItems: map(tree.childItems, item => this.toLocationNavigationTree(item, scriptInfo))
|
||||
};
|
||||
}
|
||||
@ -2059,7 +2059,7 @@ namespace ts.server {
|
||||
return !spans
|
||||
? undefined
|
||||
: simplifiedResult
|
||||
? spans.map(span => toProcolTextSpan(span, scriptInfo))
|
||||
? spans.map(span => toProtocolTextSpan(span, scriptInfo))
|
||||
: spans;
|
||||
}
|
||||
|
||||
@ -2131,7 +2131,7 @@ namespace ts.server {
|
||||
|
||||
private mapSelectionRange(selectionRange: SelectionRange, scriptInfo: ScriptInfo): protocol.SelectionRange {
|
||||
const result: protocol.SelectionRange = {
|
||||
textSpan: toProcolTextSpan(selectionRange.textSpan, scriptInfo),
|
||||
textSpan: toProtocolTextSpan(selectionRange.textSpan, scriptInfo),
|
||||
};
|
||||
if (selectionRange.parent) {
|
||||
result.parent = this.mapSelectionRange(selectionRange.parent, scriptInfo);
|
||||
@ -2139,6 +2139,71 @@ namespace ts.server {
|
||||
return result;
|
||||
}
|
||||
|
||||
private toProtocolCallHierarchyItem(item: CallHierarchyItem, scriptInfo?: ScriptInfo): protocol.CallHierarchyItem {
|
||||
if (!scriptInfo) {
|
||||
const file = toNormalizedPath(item.file);
|
||||
scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file);
|
||||
if (!scriptInfo) {
|
||||
this.projectService.logErrorForScriptInfoNotFound(file);
|
||||
return Errors.ThrowNoProject();
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: item.name,
|
||||
kind: item.kind,
|
||||
file: item.file,
|
||||
span: toProtocolTextSpan(item.span, scriptInfo),
|
||||
selectionSpan: toProtocolTextSpan(item.selectionSpan, scriptInfo)
|
||||
};
|
||||
}
|
||||
|
||||
private toProtocolCallHierarchyIncomingCall(incomingCall: CallHierarchyIncomingCall, scriptInfo: ScriptInfo): protocol.CallHierarchyIncomingCall {
|
||||
return {
|
||||
from: this.toProtocolCallHierarchyItem(incomingCall.from),
|
||||
fromSpans: incomingCall.fromSpans.map(fromSpan => toProtocolTextSpan(fromSpan, scriptInfo))
|
||||
};
|
||||
}
|
||||
|
||||
private toProtocolCallHierarchyOutgoingCall(outgoingCall: CallHierarchyOutgoingCall, scriptInfo: ScriptInfo): protocol.CallHierarchyOutgoingCall {
|
||||
return {
|
||||
to: this.toProtocolCallHierarchyItem(outgoingCall.to),
|
||||
fromSpans: outgoingCall.fromSpans.map(fromSpan => toProtocolTextSpan(fromSpan, scriptInfo))
|
||||
};
|
||||
}
|
||||
|
||||
private prepareCallHierarchy(args: protocol.FileLocationRequestArgs): protocol.CallHierarchyItem | protocol.CallHierarchyItem[] | undefined {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file);
|
||||
if (scriptInfo) {
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
const result = project.getLanguageService().prepareCallHierarchy(file, position);
|
||||
return result && mapOneOrMany(result, item => this.toProtocolCallHierarchyItem(item, scriptInfo));
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private provideCallHierarchyIncomingCalls(args: protocol.FileLocationRequestArgs): protocol.CallHierarchyIncomingCall[] {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file);
|
||||
if (!scriptInfo) {
|
||||
this.projectService.logErrorForScriptInfoNotFound(file);
|
||||
return Errors.ThrowNoProject();
|
||||
}
|
||||
const incomingCalls = project.getLanguageService().provideCallHierarchyIncomingCalls(file, this.getPosition(args, scriptInfo));
|
||||
return incomingCalls.map(call => this.toProtocolCallHierarchyIncomingCall(call, scriptInfo));
|
||||
}
|
||||
|
||||
private provideCallHierarchyOutgoingCalls(args: protocol.FileLocationRequestArgs): protocol.CallHierarchyOutgoingCall[] {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file);
|
||||
if (!scriptInfo) {
|
||||
this.projectService.logErrorForScriptInfoNotFound(file);
|
||||
return Errors.ThrowNoProject();
|
||||
}
|
||||
const outgoingCalls = project.getLanguageService().provideCallHierarchyOutgoingCalls(file, this.getPosition(args, scriptInfo));
|
||||
return outgoingCalls.map(call => this.toProtocolCallHierarchyOutgoingCall(call, scriptInfo));
|
||||
}
|
||||
|
||||
getCanonicalFileName(fileName: string) {
|
||||
const name = this.host.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
return normalizePath(name);
|
||||
@ -2504,6 +2569,15 @@ namespace ts.server {
|
||||
[CommandNames.SelectionRangeFull]: (request: protocol.SelectionRangeRequest) => {
|
||||
return this.requiredResponse(this.getSmartSelectionRange(request.arguments, /*simplifiedResult*/ false));
|
||||
},
|
||||
[CommandNames.PrepareCallHierarchy]: (request: protocol.PrepareCallHierarchyRequest) => {
|
||||
return this.requiredResponse(this.prepareCallHierarchy(request.arguments));
|
||||
},
|
||||
[CommandNames.ProvideCallHierarchyIncomingCalls]: (request: protocol.ProvideCallHierarchyIncomingCallsRequest) => {
|
||||
return this.requiredResponse(this.provideCallHierarchyIncomingCalls(request.arguments));
|
||||
},
|
||||
[CommandNames.ProvideCallHierarchyOutgoingCalls]: (request: protocol.ProvideCallHierarchyOutgoingCallsRequest) => {
|
||||
return this.requiredResponse(this.provideCallHierarchyOutgoingCalls(request.arguments));
|
||||
},
|
||||
});
|
||||
|
||||
public addProtocolHandler(command: string, handler: (request: protocol.Request) => HandlerResponse) {
|
||||
@ -2627,7 +2701,7 @@ namespace ts.server {
|
||||
readonly project: Project;
|
||||
}
|
||||
|
||||
function toProcolTextSpan(textSpan: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan {
|
||||
function toProtocolTextSpan(textSpan: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan {
|
||||
return {
|
||||
start: scriptInfo.positionToLineOffset(textSpan.start),
|
||||
end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan))
|
||||
@ -2635,8 +2709,8 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
function toProtocolTextSpanWithContext(span: TextSpan, contextSpan: TextSpan | undefined, scriptInfo: ScriptInfo): protocol.TextSpanWithContext {
|
||||
const textSpan = toProcolTextSpan(span, scriptInfo);
|
||||
const contextTextSpan = contextSpan && toProcolTextSpan(contextSpan, scriptInfo);
|
||||
const textSpan = toProtocolTextSpan(span, scriptInfo);
|
||||
const contextTextSpan = contextSpan && toProtocolTextSpan(contextSpan, scriptInfo);
|
||||
return contextTextSpan ?
|
||||
{ ...textSpan, contextStart: contextTextSpan.start, contextEnd: contextTextSpan.end } :
|
||||
textSpan;
|
||||
|
||||
485
src/services/callHierarchy.ts
Normal file
485
src/services/callHierarchy.ts
Normal file
@ -0,0 +1,485 @@
|
||||
/* @internal */
|
||||
namespace ts.CallHierarchy {
|
||||
export type NamedExpression =
|
||||
| ClassExpression & { name: Identifier }
|
||||
| FunctionExpression & { name: Identifier }
|
||||
;
|
||||
|
||||
/** Indictates whether a node is named function or class expression. */
|
||||
function isNamedExpression(node: Node): node is NamedExpression {
|
||||
return (isFunctionExpression(node) || isClassExpression(node)) && isNamedDeclaration(node);
|
||||
}
|
||||
|
||||
export type ConstNamedExpression =
|
||||
| ClassExpression & { name: undefined, parent: VariableDeclaration & { name: Identifier } }
|
||||
| FunctionExpression & { name: undefined, parent: VariableDeclaration & { name: Identifier } }
|
||||
| ArrowFunction & { name: undefined, parent: VariableDeclaration & { name: Identifier } }
|
||||
;
|
||||
|
||||
/** Indicates whether a node is a function, arrow, or class expression assigned to a constant variable. */
|
||||
function isConstNamedExpression(node: Node): node is ConstNamedExpression {
|
||||
return (isFunctionExpression(node) || isArrowFunction(node) || isClassExpression(node))
|
||||
&& isVariableDeclaration(node.parent)
|
||||
&& node === node.parent.initializer
|
||||
&& isIdentifier(node.parent.name)
|
||||
&& !!(getCombinedNodeFlags(node.parent) & NodeFlags.Const);
|
||||
}
|
||||
|
||||
export type CallHierarchyDeclaration =
|
||||
| SourceFile
|
||||
| ModuleDeclaration & { name: Identifier }
|
||||
| FunctionDeclaration
|
||||
| ClassDeclaration
|
||||
| MethodDeclaration
|
||||
| GetAccessorDeclaration
|
||||
| SetAccessorDeclaration
|
||||
| NamedExpression
|
||||
| ConstNamedExpression
|
||||
;
|
||||
|
||||
/**
|
||||
* Indicates whether a node could possibly be a call hierarchy declaration.
|
||||
*
|
||||
* See `resolveCallHierarchyDeclaration` for the specific rules.
|
||||
*/
|
||||
function isPossibleCallHierarchyDeclaration(node: Node) {
|
||||
return isSourceFile(node)
|
||||
|| isModuleDeclaration(node)
|
||||
|| isFunctionDeclaration(node)
|
||||
|| isFunctionExpression(node)
|
||||
|| isClassDeclaration(node)
|
||||
|| isClassExpression(node)
|
||||
|| isMethodDeclaration(node)
|
||||
|| isMethodSignature(node)
|
||||
|| isGetAccessorDeclaration(node)
|
||||
|| isSetAccessorDeclaration(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether a node is a valid a call hierarchy declaration.
|
||||
*
|
||||
* See `resolveCallHierarchyDeclaration` for the specific rules.
|
||||
*/
|
||||
function isValidCallHierarchyDeclaration(node: Node): node is CallHierarchyDeclaration {
|
||||
return isSourceFile(node)
|
||||
|| isModuleDeclaration(node) && isIdentifier(node.name)
|
||||
|| isFunctionDeclaration(node)
|
||||
|| isClassDeclaration(node)
|
||||
|| isMethodDeclaration(node)
|
||||
|| isMethodSignature(node)
|
||||
|| isGetAccessorDeclaration(node)
|
||||
|| isSetAccessorDeclaration(node)
|
||||
|| isNamedExpression(node)
|
||||
|| isConstNamedExpression(node);
|
||||
}
|
||||
|
||||
/** Gets the node that can be used as a reference to a call hierarchy declaration. */
|
||||
function getCallHierarchyDeclarationReferenceNode(node: CallHierarchyDeclaration) {
|
||||
if (isSourceFile(node)) return node;
|
||||
if (isNamedDeclaration(node)) return node.name;
|
||||
if (isConstNamedExpression(node)) return node.parent.name;
|
||||
return Debug.assertDefined(node.modifiers && find(node.modifiers, isDefaultModifier));
|
||||
}
|
||||
|
||||
function isDefaultModifier(node: Node) {
|
||||
return node.kind === SyntaxKind.DefaultKeyword;
|
||||
}
|
||||
|
||||
/** Gets the symbol for a call hierarchy declaration. */
|
||||
function getSymbolOfCallHierarchyDeclaration(typeChecker: TypeChecker, node: CallHierarchyDeclaration) {
|
||||
const location = getCallHierarchyDeclarationReferenceNode(node);
|
||||
return location && typeChecker.getSymbolAtLocation(location);
|
||||
}
|
||||
|
||||
/** Gets the text and range for the name of a call hierarchy declaration. */
|
||||
function getCallHierarchyItemName(program: Program, node: CallHierarchyDeclaration): { text: string, pos: number, end: number } {
|
||||
if (isSourceFile(node)) {
|
||||
return { text: node.fileName, pos: 0, end: 0 };
|
||||
}
|
||||
|
||||
if ((isFunctionDeclaration(node) || isClassDeclaration(node)) && !isNamedDeclaration(node)) {
|
||||
const defaultModifier = node.modifiers && find(node.modifiers, isDefaultModifier);
|
||||
if (defaultModifier) {
|
||||
return { text: "default", pos: defaultModifier.getStart(), end: defaultModifier.getEnd() };
|
||||
}
|
||||
}
|
||||
|
||||
const declName = isConstNamedExpression(node) ? node.parent.name :
|
||||
Debug.assertDefined(getNameOfDeclaration(node), "Expected call hierarchy item to have a name");
|
||||
|
||||
let text =
|
||||
isIdentifier(declName) ? idText(declName) :
|
||||
isStringOrNumericLiteralLike(declName) ? declName.text :
|
||||
isComputedPropertyName(declName) ?
|
||||
isStringOrNumericLiteralLike(declName.expression) ? declName.expression.text :
|
||||
undefined :
|
||||
undefined;
|
||||
if (text === undefined) {
|
||||
const typeChecker = program.getTypeChecker();
|
||||
const symbol = typeChecker.getSymbolAtLocation(declName);
|
||||
if (symbol) {
|
||||
text = typeChecker.symbolToString(symbol, node);
|
||||
}
|
||||
}
|
||||
if (text === undefined) {
|
||||
// get the text from printing the node on a single line without comments...
|
||||
const printer = createPrinter({ removeComments: true, omitTrailingSemicolon: true });
|
||||
text = usingSingleLineStringWriter(writer => printer.writeNode(EmitHint.Unspecified, node, node.getSourceFile(), writer));
|
||||
}
|
||||
return { text, pos: declName.getStart(), end: declName.getEnd() };
|
||||
}
|
||||
|
||||
/** Finds the implementation of a function-like declaration, if one exists. */
|
||||
function findImplementation(typeChecker: TypeChecker, node: Extract<CallHierarchyDeclaration, FunctionLikeDeclaration>): Extract<CallHierarchyDeclaration, FunctionLikeDeclaration> | undefined;
|
||||
function findImplementation(typeChecker: TypeChecker, node: FunctionLikeDeclaration): FunctionLikeDeclaration | undefined;
|
||||
function findImplementation(typeChecker: TypeChecker, node: FunctionLikeDeclaration): FunctionLikeDeclaration | undefined {
|
||||
if (node.body) {
|
||||
return node;
|
||||
}
|
||||
if (isConstructorDeclaration(node)) {
|
||||
return getFirstConstructorWithBody(node.parent);
|
||||
}
|
||||
if (isFunctionDeclaration(node) || isMethodDeclaration(node)) {
|
||||
const symbol = getSymbolOfCallHierarchyDeclaration(typeChecker, node);
|
||||
if (symbol && symbol.valueDeclaration && isFunctionLikeDeclaration(symbol.valueDeclaration) && symbol.valueDeclaration.body) {
|
||||
return symbol.valueDeclaration;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function findAllInitialDeclarations(typeChecker: TypeChecker, node: CallHierarchyDeclaration) {
|
||||
const symbol = getSymbolOfCallHierarchyDeclaration(typeChecker, node);
|
||||
let declarations: CallHierarchyDeclaration[] | undefined;
|
||||
if (symbol && symbol.declarations) {
|
||||
const indices = indicesOf(symbol.declarations);
|
||||
const keys = map(symbol.declarations, decl => ({ file: decl.getSourceFile().fileName, pos: decl.pos }));
|
||||
indices.sort((a, b) => compareStringsCaseSensitive(keys[a].file, keys[b].file) || keys[a].pos - keys[b].pos);
|
||||
const sortedDeclarations = map(indices, i => symbol.declarations[i]);
|
||||
let lastDecl: CallHierarchyDeclaration | undefined;
|
||||
for (const decl of sortedDeclarations) {
|
||||
if (isValidCallHierarchyDeclaration(decl)) {
|
||||
if (!lastDecl || lastDecl.parent !== decl.parent || lastDecl.end !== decl.pos) {
|
||||
declarations = append(declarations, decl);
|
||||
}
|
||||
lastDecl = decl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return declarations;
|
||||
}
|
||||
|
||||
/** Find the implementation or the first declaration for a call hierarchy declaration. */
|
||||
function findImplementationOrAllInitialDeclarations(typeChecker: TypeChecker, node: CallHierarchyDeclaration): CallHierarchyDeclaration | CallHierarchyDeclaration[] {
|
||||
if (isFunctionLikeDeclaration(node)) {
|
||||
return findImplementation(typeChecker, node) ??
|
||||
findAllInitialDeclarations(typeChecker, node) ??
|
||||
node;
|
||||
}
|
||||
return findAllInitialDeclarations(typeChecker, node) ?? node;
|
||||
}
|
||||
|
||||
/** Resolves the call hierarchy declaration for a node. */
|
||||
export function resolveCallHierarchyDeclaration(program: Program, location: Node): CallHierarchyDeclaration | CallHierarchyDeclaration[] | undefined {
|
||||
// A call hierarchy item must refer to either a SourceFile, Module Declaration, or something intrinsically callable that has a name:
|
||||
// - Class Declarations
|
||||
// - Class Expressions (with a name)
|
||||
// - Function Declarations
|
||||
// - Function Expressions (with a name or assigned to a const variable)
|
||||
// - Arrow Functions (assigned to a const variable)
|
||||
// - Constructors
|
||||
// - Methods
|
||||
// - Accessors
|
||||
//
|
||||
// If a call is contained in a non-named callable Node (function expression, arrow function, etc.), then
|
||||
// its containing `CallHierarchyItem` is a containing function or SourceFile that matches the above list.
|
||||
|
||||
const typeChecker = program.getTypeChecker();
|
||||
let followingSymbol = false;
|
||||
while (true) {
|
||||
if (isValidCallHierarchyDeclaration(location)) {
|
||||
return findImplementationOrAllInitialDeclarations(typeChecker, location);
|
||||
}
|
||||
if (isPossibleCallHierarchyDeclaration(location)) {
|
||||
const ancestor = findAncestor(location, isValidCallHierarchyDeclaration);
|
||||
return ancestor && findImplementationOrAllInitialDeclarations(typeChecker, ancestor);
|
||||
}
|
||||
if (isDeclarationName(location)) {
|
||||
if (isValidCallHierarchyDeclaration(location.parent)) {
|
||||
return findImplementationOrAllInitialDeclarations(typeChecker, location.parent);
|
||||
}
|
||||
if (isPossibleCallHierarchyDeclaration(location.parent)) {
|
||||
const ancestor = findAncestor(location.parent, isValidCallHierarchyDeclaration);
|
||||
return ancestor && findImplementationOrAllInitialDeclarations(typeChecker, ancestor);
|
||||
}
|
||||
if (isVariableDeclaration(location.parent) && location.parent.initializer && isConstNamedExpression(location.parent.initializer)) {
|
||||
return location.parent.initializer;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
if (isConstructorDeclaration(location)) {
|
||||
if (isValidCallHierarchyDeclaration(location.parent)) {
|
||||
return location.parent;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
if (!followingSymbol) {
|
||||
let symbol = typeChecker.getSymbolAtLocation(location);
|
||||
if (symbol) {
|
||||
if (symbol.flags & SymbolFlags.Alias) {
|
||||
symbol = typeChecker.getAliasedSymbol(symbol);
|
||||
}
|
||||
if (symbol.valueDeclaration) {
|
||||
followingSymbol = true;
|
||||
location = symbol.valueDeclaration;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates a `CallHierarchyItem` for a call hierarchy declaration. */
|
||||
export function createCallHierarchyItem(program: Program, node: CallHierarchyDeclaration): CallHierarchyItem {
|
||||
const sourceFile = node.getSourceFile();
|
||||
const name = getCallHierarchyItemName(program, node);
|
||||
const kind = getNodeKind(node);
|
||||
const span = createTextSpanFromBounds(skipTrivia(sourceFile.text, node.getFullStart(), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true), node.getEnd());
|
||||
const selectionSpan = createTextSpanFromBounds(name.pos, name.end);
|
||||
return { file: sourceFile.fileName, kind, name: name.text, span, selectionSpan };
|
||||
}
|
||||
|
||||
function isDefined<T>(x: T): x is NonNullable<T> {
|
||||
return x !== undefined;
|
||||
}
|
||||
|
||||
interface CallSite {
|
||||
declaration: CallHierarchyDeclaration;
|
||||
range: TextRange;
|
||||
}
|
||||
|
||||
function convertEntryToCallSite(entry: FindAllReferences.Entry, _originalNode: Node, typeChecker: TypeChecker): CallSite | undefined {
|
||||
if (entry.kind === FindAllReferences.EntryKind.Node) {
|
||||
if (isCallOrNewExpressionTarget(entry.node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true)
|
||||
|| isTaggedTemplateTag(entry.node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true)
|
||||
|| isDecoratorTarget(entry.node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true)
|
||||
|| isJsxOpeningLikeElementTagName(entry.node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true)
|
||||
|| isRightSideOfPropertyAccess(entry.node)
|
||||
|| isArgumentExpressionOfElementAccess(entry.node)) {
|
||||
const ancestor = findAncestor(entry.node, isValidCallHierarchyDeclaration) || entry.node.getSourceFile();
|
||||
return { declaration: firstOrOnly(findImplementationOrAllInitialDeclarations(typeChecker, ancestor)), range: createTextRangeFromNode(entry.node, entry.node.getSourceFile()) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCallSiteGroupKey(entry: CallSite) {
|
||||
return "" + getNodeId(entry.declaration);
|
||||
}
|
||||
|
||||
function createCallHierarchyIncomingCall(from: CallHierarchyItem, fromSpans: TextSpan[]): CallHierarchyIncomingCall {
|
||||
return { from, fromSpans };
|
||||
}
|
||||
|
||||
function convertCallSiteGroupToIncomingCall(program: Program, entries: readonly CallSite[]) {
|
||||
return createCallHierarchyIncomingCall(createCallHierarchyItem(program, entries[0].declaration), map(entries, entry => createTextSpanFromRange(entry.range)));
|
||||
}
|
||||
|
||||
/** Gets the call sites that call into the provided call hierarchy declaration. */
|
||||
export function getIncomingCalls(program: Program, declaration: CallHierarchyDeclaration, cancellationToken: CancellationToken): CallHierarchyIncomingCall[] {
|
||||
// Source files and modules have no incoming calls.
|
||||
if (isSourceFile(declaration) || isModuleDeclaration(declaration)) {
|
||||
return [];
|
||||
}
|
||||
const location = getCallHierarchyDeclarationReferenceNode(declaration);
|
||||
const calls = filter(FindAllReferences.findReferenceOrRenameEntries(program, cancellationToken, program.getSourceFiles(), location, /*position*/ 0, /*options*/ undefined, convertEntryToCallSite), isDefined);
|
||||
return calls ? group(calls, getCallSiteGroupKey, entries => convertCallSiteGroupToIncomingCall(program, entries)) : [];
|
||||
}
|
||||
|
||||
function createCallSiteCollector(program: Program, callSites: CallSite[]): (node: Node | undefined) => void {
|
||||
function recordCallSite(node: CallExpression | NewExpression | TaggedTemplateExpression | PropertyAccessExpression | ElementAccessExpression | Decorator | JsxOpeningLikeElement) {
|
||||
const target =
|
||||
isTaggedTemplateExpression(node) ? node.tag :
|
||||
isJsxOpeningLikeElement(node) ? node.tagName :
|
||||
isAccessExpression(node) ? node :
|
||||
node.expression;
|
||||
const declaration = resolveCallHierarchyDeclaration(program, target);
|
||||
if (declaration) {
|
||||
const range = createTextRangeFromNode(target, node.getSourceFile());
|
||||
if (isArray(declaration)) {
|
||||
for (const decl of declaration) {
|
||||
callSites.push({ declaration: decl, range });
|
||||
}
|
||||
}
|
||||
else {
|
||||
callSites.push({ declaration, range });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function collect(node: Node | undefined) {
|
||||
if (!node) return;
|
||||
if (node.flags & NodeFlags.Ambient) {
|
||||
// do not descend into ambient nodes.
|
||||
return;
|
||||
}
|
||||
|
||||
if (isValidCallHierarchyDeclaration(node)) {
|
||||
// do not descend into other call site declarations, other than class member names
|
||||
if (isClassLike(node)) {
|
||||
for (const member of node.members) {
|
||||
if (member.name && isComputedPropertyName(member.name)) {
|
||||
collect(member.name.expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
// do not descend into nodes that cannot contain callable nodes
|
||||
return;
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
case SyntaxKind.AsExpression:
|
||||
// do not descend into the type side of an assertion
|
||||
collect((node as TypeAssertion | AsExpression).expression);
|
||||
return;
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.Parameter:
|
||||
// do not descend into the type of a variable or parameter declaration
|
||||
collect((node as VariableDeclaration | ParameterDeclaration).name);
|
||||
collect((node as VariableDeclaration | ParameterDeclaration).initializer);
|
||||
return;
|
||||
case SyntaxKind.CallExpression:
|
||||
// do not descend into the type arguments of a call expression
|
||||
recordCallSite(node as CallExpression);
|
||||
collect((node as CallExpression).expression);
|
||||
forEach((node as CallExpression).arguments, collect);
|
||||
return;
|
||||
case SyntaxKind.NewExpression:
|
||||
// do not descend into the type arguments of a new expression
|
||||
recordCallSite(node as NewExpression);
|
||||
collect((node as NewExpression).expression);
|
||||
forEach((node as NewExpression).arguments, collect);
|
||||
return;
|
||||
case SyntaxKind.TaggedTemplateExpression:
|
||||
// do not descend into the type arguments of a tagged template expression
|
||||
recordCallSite(node as TaggedTemplateExpression);
|
||||
collect((node as TaggedTemplateExpression).tag);
|
||||
collect((node as TaggedTemplateExpression).template);
|
||||
return;
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
// do not descend into the type arguments of a JsxOpeningLikeElement
|
||||
recordCallSite(node as JsxOpeningLikeElement);
|
||||
collect((node as JsxOpeningLikeElement).tagName);
|
||||
collect((node as JsxOpeningLikeElement).attributes);
|
||||
return;
|
||||
case SyntaxKind.Decorator:
|
||||
recordCallSite(node as Decorator);
|
||||
collect((node as Decorator).expression);
|
||||
return;
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
recordCallSite(node as AccessExpression);
|
||||
forEachChild(node, collect);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isPartOfTypeNode(node)) {
|
||||
// do not descend into types
|
||||
return;
|
||||
}
|
||||
|
||||
forEachChild(node, collect);
|
||||
}
|
||||
return collect;
|
||||
}
|
||||
|
||||
function collectCallSitesOfSourceFile(node: SourceFile, collect: (node: Node | undefined) => void) {
|
||||
forEach(node.statements, collect);
|
||||
}
|
||||
|
||||
function collectCallSitesOfModuleDeclaration(node: ModuleDeclaration, collect: (node: Node | undefined) => void) {
|
||||
if (!hasModifier(node, ModifierFlags.Ambient) && node.body && isModuleBlock(node.body)) {
|
||||
forEach(node.body.statements, collect);
|
||||
}
|
||||
}
|
||||
|
||||
function collectCallSitesOfFunctionLikeDeclaration(typeChecker: TypeChecker, node: FunctionLikeDeclaration, collect: (node: Node | undefined) => void) {
|
||||
const implementation = findImplementation(typeChecker, node);
|
||||
if (implementation) {
|
||||
forEach(implementation.parameters, collect);
|
||||
collect(implementation.body);
|
||||
}
|
||||
}
|
||||
|
||||
function collectCallSitesOfClassLikeDeclaration(node: ClassLikeDeclaration, collect: (node: Node | undefined) => void) {
|
||||
forEach(node.decorators, collect);
|
||||
const heritage = getClassExtendsHeritageElement(node);
|
||||
if (heritage) {
|
||||
collect(heritage.expression);
|
||||
}
|
||||
for (const member of node.members) {
|
||||
forEach(member.decorators, collect);
|
||||
if (isPropertyDeclaration(member)) {
|
||||
collect(member.initializer);
|
||||
}
|
||||
else if (isConstructorDeclaration(member) && member.body) {
|
||||
forEach(member.parameters, collect);
|
||||
collect(member.body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function collectCallSites(program: Program, node: CallHierarchyDeclaration) {
|
||||
const callSites: CallSite[] = [];
|
||||
const collect = createCallSiteCollector(program, callSites);
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
collectCallSitesOfSourceFile(node, collect);
|
||||
break;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
collectCallSitesOfModuleDeclaration(node, collect);
|
||||
break;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
collectCallSitesOfFunctionLikeDeclaration(program.getTypeChecker(), node, collect);
|
||||
break;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ClassExpression:
|
||||
collectCallSitesOfClassLikeDeclaration(node, collect);
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(node);
|
||||
}
|
||||
return callSites;
|
||||
}
|
||||
|
||||
function createCallHierarchyOutgoingCall(to: CallHierarchyItem, fromSpans: TextSpan[]): CallHierarchyOutgoingCall {
|
||||
return { to, fromSpans };
|
||||
}
|
||||
|
||||
function convertCallSiteGroupToOutgoingCall(program: Program, entries: readonly CallSite[]) {
|
||||
return createCallHierarchyOutgoingCall(createCallHierarchyItem(program, entries[0].declaration), map(entries, entry => createTextSpanFromRange(entry.range)));
|
||||
}
|
||||
|
||||
/** Gets the call sites that call out of the provided call hierarchy declaration. */
|
||||
export function getOutgoingCalls(program: Program, declaration: CallHierarchyDeclaration): CallHierarchyOutgoingCall[] {
|
||||
if (declaration.flags & NodeFlags.Ambient || isMethodSignature(declaration)) {
|
||||
return [];
|
||||
}
|
||||
return group(collectCallSites(program, declaration), getCallSiteGroupKey, entries => convertCallSiteGroupToOutgoingCall(program, entries));
|
||||
}
|
||||
}
|
||||
@ -2137,6 +2137,26 @@ namespace ts {
|
||||
return refactor.getEditsForRefactor(getRefactorContext(file, positionOrRange, preferences, formatOptions), refactorName, actionName);
|
||||
}
|
||||
|
||||
function prepareCallHierarchy(fileName: string, position: number): CallHierarchyItem | CallHierarchyItem[] | undefined {
|
||||
synchronizeHostData();
|
||||
const declarations = CallHierarchy.resolveCallHierarchyDeclaration(program, getTouchingPropertyName(getValidSourceFile(fileName), position));
|
||||
return declarations && mapOneOrMany(declarations, declaration => CallHierarchy.createCallHierarchyItem(program, declaration));
|
||||
}
|
||||
|
||||
function provideCallHierarchyIncomingCalls(fileName: string, position: number): CallHierarchyIncomingCall[] {
|
||||
synchronizeHostData();
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
const declaration = firstOrOnly(CallHierarchy.resolveCallHierarchyDeclaration(program, position === 0 ? sourceFile : getTouchingPropertyName(sourceFile, position)));
|
||||
return declaration ? CallHierarchy.getIncomingCalls(program, declaration, cancellationToken) : [];
|
||||
}
|
||||
|
||||
function provideCallHierarchyOutgoingCalls(fileName: string, position: number): CallHierarchyOutgoingCall[] {
|
||||
synchronizeHostData();
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
const declaration = firstOrOnly(CallHierarchy.resolveCallHierarchyDeclaration(program, position === 0 ? sourceFile : getTouchingPropertyName(sourceFile, position)));
|
||||
return declaration ? CallHierarchy.getOutgoingCalls(program, declaration) : [];
|
||||
}
|
||||
|
||||
return {
|
||||
dispose,
|
||||
cleanupSemanticCache,
|
||||
@ -2192,6 +2212,9 @@ namespace ts {
|
||||
getEditsForRefactor,
|
||||
toLineColumnOffset: sourceMapper.toLineColumnOffset,
|
||||
getSourceMapper: () => sourceMapper,
|
||||
prepareCallHierarchy,
|
||||
provideCallHierarchyIncomingCalls,
|
||||
provideCallHierarchyOutgoingCalls
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -271,6 +271,10 @@ namespace ts {
|
||||
*/
|
||||
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): string;
|
||||
|
||||
prepareCallHierarchy(fileName: string, position: number): string;
|
||||
provideCallHierarchyIncomingCalls(fileName: string, position: number): string;
|
||||
provideCallHierarchyOutgoingCalls(fileName: string, position: number): string;
|
||||
|
||||
getEmitOutput(fileName: string): string;
|
||||
getEmitOutputObject(fileName: string): EmitOutput;
|
||||
}
|
||||
@ -1020,6 +1024,29 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
/// CALL HIERARCHY
|
||||
|
||||
public prepareCallHierarchy(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
`prepareCallHierarchy('${fileName}', ${position})`,
|
||||
() => this.languageService.prepareCallHierarchy(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
public provideCallHierarchyIncomingCalls(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
`provideCallHierarchyIncomingCalls('${fileName}', ${position})`,
|
||||
() => this.languageService.provideCallHierarchyIncomingCalls(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
public provideCallHierarchyOutgoingCalls(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
`provideCallHierarchyOutgoingCalls('${fileName}', ${position})`,
|
||||
() => this.languageService.provideCallHierarchyOutgoingCalls(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
/// Emit
|
||||
public getEmitOutput(fileName: string): string {
|
||||
return this.forwardJSONCall(
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
"documentRegistry.ts",
|
||||
"importTracker.ts",
|
||||
"findAllReferences.ts",
|
||||
"callHierarchy.ts",
|
||||
"getEditsForFileRename.ts",
|
||||
"goToDefinition.ts",
|
||||
"jsDoc.ts",
|
||||
|
||||
@ -351,6 +351,10 @@ namespace ts {
|
||||
getNavigationBarItems(fileName: string): NavigationBarItem[];
|
||||
getNavigationTree(fileName: string): NavigationTree;
|
||||
|
||||
prepareCallHierarchy(fileName: string, position: number): CallHierarchyItem | CallHierarchyItem[] | undefined;
|
||||
provideCallHierarchyIncomingCalls(fileName: string, position: number): CallHierarchyIncomingCall[];
|
||||
provideCallHierarchyOutgoingCalls(fileName: string, position: number): CallHierarchyOutgoingCall[];
|
||||
|
||||
getOutliningSpans(fileName: string): OutliningSpan[];
|
||||
getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[];
|
||||
getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[];
|
||||
@ -522,6 +526,24 @@ namespace ts {
|
||||
childItems?: NavigationTree[];
|
||||
}
|
||||
|
||||
export interface CallHierarchyItem {
|
||||
name: string;
|
||||
kind: ScriptElementKind;
|
||||
file: string;
|
||||
span: TextSpan;
|
||||
selectionSpan: TextSpan;
|
||||
}
|
||||
|
||||
export interface CallHierarchyIncomingCall {
|
||||
from: CallHierarchyItem;
|
||||
fromSpans: TextSpan[];
|
||||
}
|
||||
|
||||
export interface CallHierarchyOutgoingCall {
|
||||
to: CallHierarchyItem;
|
||||
fromSpans: TextSpan[];
|
||||
}
|
||||
|
||||
export interface TodoCommentDescriptor {
|
||||
text: string;
|
||||
priority: number;
|
||||
|
||||
@ -196,27 +196,58 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isCallExpressionTarget(node: Node): boolean {
|
||||
return isCallOrNewExpressionTargetWorker(node, isCallExpression);
|
||||
export function isCallExpressionTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean {
|
||||
return isCalleeWorker(node, isCallExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions);
|
||||
}
|
||||
|
||||
export function isNewExpressionTarget(node: Node): boolean {
|
||||
return isCallOrNewExpressionTargetWorker(node, isNewExpression);
|
||||
export function isNewExpressionTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean {
|
||||
return isCalleeWorker(node, isNewExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions);
|
||||
}
|
||||
|
||||
export function isCallOrNewExpressionTarget(node: Node): boolean {
|
||||
return isCallOrNewExpressionTargetWorker(node, isCallOrNewExpression);
|
||||
export function isCallOrNewExpressionTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean {
|
||||
return isCalleeWorker(node, isCallOrNewExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions);
|
||||
}
|
||||
|
||||
function isCallOrNewExpressionTargetWorker<T extends CallExpression | NewExpression>(node: Node, pred: (node: Node) => node is T): boolean {
|
||||
const target = climbPastPropertyAccess(node);
|
||||
return !!target && !!target.parent && pred(target.parent) && target.parent.expression === target;
|
||||
export function isTaggedTemplateTag(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean {
|
||||
return isCalleeWorker(node, isTaggedTemplateExpression, selectTagOfTaggedTemplateExpression, includeElementAccess, skipPastOuterExpressions);
|
||||
}
|
||||
|
||||
export function isDecoratorTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean {
|
||||
return isCalleeWorker(node, isDecorator, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions);
|
||||
}
|
||||
|
||||
export function isJsxOpeningLikeElementTagName(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean {
|
||||
return isCalleeWorker(node, isJsxOpeningLikeElement, selectTagNameOfJsxOpeningLikeElement, includeElementAccess, skipPastOuterExpressions);
|
||||
}
|
||||
|
||||
function selectExpressionOfCallOrNewExpressionOrDecorator(node: CallExpression | NewExpression | Decorator) {
|
||||
return node.expression;
|
||||
}
|
||||
|
||||
function selectTagOfTaggedTemplateExpression(node: TaggedTemplateExpression) {
|
||||
return node.tag;
|
||||
}
|
||||
|
||||
function selectTagNameOfJsxOpeningLikeElement(node: JsxOpeningLikeElement) {
|
||||
return node.tagName;
|
||||
}
|
||||
|
||||
function isCalleeWorker<T extends CallExpression | NewExpression | TaggedTemplateExpression | Decorator | JsxOpeningLikeElement>(node: Node, pred: (node: Node) => node is T, calleeSelector: (node: T) => Expression, includeElementAccess: boolean, skipPastOuterExpressions: boolean) {
|
||||
let target = includeElementAccess ? climbPastPropertyOrElementAccess(node) : climbPastPropertyAccess(node);
|
||||
if (skipPastOuterExpressions) {
|
||||
target = skipOuterExpressions(target);
|
||||
}
|
||||
return !!target && !!target.parent && pred(target.parent) && calleeSelector(target.parent) === target;
|
||||
}
|
||||
|
||||
export function climbPastPropertyAccess(node: Node) {
|
||||
return isRightSideOfPropertyAccess(node) ? node.parent : node;
|
||||
}
|
||||
|
||||
export function climbPastPropertyOrElementAccess(node: Node) {
|
||||
return isRightSideOfPropertyAccess(node) || isArgumentExpressionOfElementAccess(node) ? node.parent : node;
|
||||
}
|
||||
|
||||
export function getTargetLabel(referenceNode: Node, labelName: string): Identifier | undefined {
|
||||
while (referenceNode) {
|
||||
if (referenceNode.kind === SyntaxKind.LabeledStatement && (<LabeledStatement>referenceNode).label.escapedText === labelName) {
|
||||
@ -236,11 +267,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function isJumpStatementTarget(node: Node): node is Identifier & { parent: BreakOrContinueStatement } {
|
||||
return node.kind === SyntaxKind.Identifier && isBreakOrContinueStatement(node.parent) && node.parent.label === node;
|
||||
return isIdentifier(node) && tryCast(node.parent, isBreakOrContinueStatement)?.label === node;
|
||||
}
|
||||
|
||||
export function isLabelOfLabeledStatement(node: Node): node is Identifier {
|
||||
return node.kind === SyntaxKind.Identifier && isLabeledStatement(node.parent) && node.parent.label === node;
|
||||
return isIdentifier(node) && tryCast(node.parent, isLabeledStatement)?.label === node;
|
||||
}
|
||||
|
||||
export function isLabelName(node: Node): boolean {
|
||||
@ -248,24 +279,27 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function isTagName(node: Node): boolean {
|
||||
return isJSDocTag(node.parent) && node.parent.tagName === node;
|
||||
return tryCast(node.parent, isJSDocTag)?.tagName === node;
|
||||
}
|
||||
|
||||
export function isRightSideOfQualifiedName(node: Node) {
|
||||
return node.parent.kind === SyntaxKind.QualifiedName && (<QualifiedName>node.parent).right === node;
|
||||
return tryCast(node.parent, isQualifiedName)?.right === node;
|
||||
}
|
||||
|
||||
export function isRightSideOfPropertyAccess(node: Node) {
|
||||
return node && node.parent && node.parent.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>node.parent).name === node;
|
||||
return tryCast(node.parent, isPropertyAccessExpression)?.name === node;
|
||||
}
|
||||
|
||||
export function isArgumentExpressionOfElementAccess(node: Node) {
|
||||
return tryCast(node.parent, isElementAccessExpression)?.argumentExpression === node;
|
||||
}
|
||||
|
||||
export function isNameOfModuleDeclaration(node: Node) {
|
||||
return node.parent.kind === SyntaxKind.ModuleDeclaration && (<ModuleDeclaration>node.parent).name === node;
|
||||
return tryCast(node.parent, isModuleDeclaration)?.name === node;
|
||||
}
|
||||
|
||||
export function isNameOfFunctionDeclaration(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.Identifier &&
|
||||
isFunctionLike(node.parent) && (<FunctionLikeDeclaration>node.parent).name === node;
|
||||
return isIdentifier(node) && tryCast(node.parent, isFunctionLike)?.name === node;
|
||||
}
|
||||
|
||||
export function isLiteralNameOfPropertyDeclarationOrIndexAccess(node: StringLiteral | NumericLiteral | NoSubstitutionTemplateLiteral): boolean {
|
||||
@ -2298,4 +2332,23 @@ namespace ts {
|
||||
export function getRefactorContextSpan({ startPosition, endPosition }: RefactorContext): TextSpan {
|
||||
return createTextSpanFromBounds(startPosition, endPosition === undefined ? startPosition : endPosition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the provided value is an array, the mapping function is applied to each element; otherwise, the mapping function is applied
|
||||
* to the provided value itself.
|
||||
*/
|
||||
export function mapOneOrMany<T, U>(valueOrArray: T | readonly T[], f: (x: T, i: number) => U): U | U[];
|
||||
export function mapOneOrMany<T, U>(valueOrArray: T | readonly T[] | undefined, f: (x: T, i: number) => U): U | U[] | undefined;
|
||||
export function mapOneOrMany<T, U>(valueOrArray: T | readonly T[], f: (x: T, i: number) => U, resultSelector: (x: U[]) => U): U;
|
||||
export function mapOneOrMany<T, U>(valueOrArray: T | readonly T[] | undefined, f: (x: T, i: number) => U, resultSelector: (x: U[]) => U): U | undefined;
|
||||
export function mapOneOrMany<T, U>(valueOrArray: T | readonly T[] | undefined, f: (x: T, i: number) => U, resultSelector: (x: U[]) => U | U[] = identity): U | U[] | undefined {
|
||||
return valueOrArray ? isArray(valueOrArray) ? resultSelector(map(valueOrArray, f)) : f(valueOrArray, 0) : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the provided value is an array, the first element of the array is returned; otherwise, the provided value is returned instead.
|
||||
*/
|
||||
export function firstOrOnly<T>(valueOrArray: T | readonly T[]): T {
|
||||
return isArray(valueOrArray) ? first(valueOrArray) : valueOrArray;
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,6 +267,9 @@ namespace ts.server {
|
||||
CommandNames.GetEditsForFileRename,
|
||||
CommandNames.GetEditsForFileRenameFull,
|
||||
CommandNames.SelectionRange,
|
||||
CommandNames.PrepareCallHierarchy,
|
||||
CommandNames.ProvideCallHierarchyIncomingCalls,
|
||||
CommandNames.ProvideCallHierarchyOutgoingCalls,
|
||||
];
|
||||
|
||||
it("should not throw when commands are executed with invalid arguments", () => {
|
||||
|
||||
@ -5113,6 +5113,9 @@ declare namespace ts {
|
||||
getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean): NavigateToItem[];
|
||||
getNavigationBarItems(fileName: string): NavigationBarItem[];
|
||||
getNavigationTree(fileName: string): NavigationTree;
|
||||
prepareCallHierarchy(fileName: string, position: number): CallHierarchyItem | CallHierarchyItem[] | undefined;
|
||||
provideCallHierarchyIncomingCalls(fileName: string, position: number): CallHierarchyIncomingCall[];
|
||||
provideCallHierarchyOutgoingCalls(fileName: string, position: number): CallHierarchyOutgoingCall[];
|
||||
getOutliningSpans(fileName: string): OutliningSpan[];
|
||||
getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[];
|
||||
getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[];
|
||||
@ -5252,6 +5255,21 @@ declare namespace ts {
|
||||
/** Present if non-empty */
|
||||
childItems?: NavigationTree[];
|
||||
}
|
||||
interface CallHierarchyItem {
|
||||
name: string;
|
||||
kind: ScriptElementKind;
|
||||
file: string;
|
||||
span: TextSpan;
|
||||
selectionSpan: TextSpan;
|
||||
}
|
||||
interface CallHierarchyIncomingCall {
|
||||
from: CallHierarchyItem;
|
||||
fromSpans: TextSpan[];
|
||||
}
|
||||
interface CallHierarchyOutgoingCall {
|
||||
to: CallHierarchyItem;
|
||||
fromSpans: TextSpan[];
|
||||
}
|
||||
interface TodoCommentDescriptor {
|
||||
text: string;
|
||||
priority: number;
|
||||
@ -6113,6 +6131,9 @@ declare namespace ts.server.protocol {
|
||||
GetEditsForFileRename = "getEditsForFileRename",
|
||||
ConfigurePlugin = "configurePlugin",
|
||||
SelectionRange = "selectionRange",
|
||||
PrepareCallHierarchy = "prepareCallHierarchy",
|
||||
ProvideCallHierarchyIncomingCalls = "provideCallHierarchyIncomingCalls",
|
||||
ProvideCallHierarchyOutgoingCalls = "provideCallHierarchyOutgoingCalls"
|
||||
}
|
||||
/**
|
||||
* A TypeScript Server message
|
||||
@ -8342,6 +8363,39 @@ declare namespace ts.server.protocol {
|
||||
interface NavTreeResponse extends Response {
|
||||
body?: NavigationTree;
|
||||
}
|
||||
interface CallHierarchyItem {
|
||||
name: string;
|
||||
kind: ScriptElementKind;
|
||||
file: string;
|
||||
span: TextSpan;
|
||||
selectionSpan: TextSpan;
|
||||
}
|
||||
interface CallHierarchyIncomingCall {
|
||||
from: CallHierarchyItem;
|
||||
fromSpans: TextSpan[];
|
||||
}
|
||||
interface CallHierarchyOutgoingCall {
|
||||
to: CallHierarchyItem;
|
||||
fromSpans: TextSpan[];
|
||||
}
|
||||
interface PrepareCallHierarchyRequest extends FileLocationRequest {
|
||||
command: CommandTypes.PrepareCallHierarchy;
|
||||
}
|
||||
interface PrepareCallHierarchyResponse extends Response {
|
||||
readonly body: CallHierarchyItem | CallHierarchyItem[];
|
||||
}
|
||||
interface ProvideCallHierarchyIncomingCallsRequest extends FileLocationRequest {
|
||||
command: CommandTypes.ProvideCallHierarchyIncomingCalls;
|
||||
}
|
||||
interface ProvideCallHierarchyIncomingCallsResponse extends Response {
|
||||
readonly body: CallHierarchyIncomingCall[];
|
||||
}
|
||||
interface ProvideCallHierarchyOutgoingCallsRequest extends FileLocationRequest {
|
||||
command: CommandTypes.ProvideCallHierarchyOutgoingCalls;
|
||||
}
|
||||
interface ProvideCallHierarchyOutgoingCallsResponse extends Response {
|
||||
readonly body: CallHierarchyOutgoingCall[];
|
||||
}
|
||||
enum IndentStyle {
|
||||
None = "None",
|
||||
Block = "Block",
|
||||
@ -9433,6 +9487,12 @@ declare namespace ts.server {
|
||||
private configurePlugin;
|
||||
private getSmartSelectionRange;
|
||||
private mapSelectionRange;
|
||||
private toProtocolCallHierarchyItem;
|
||||
private toProtocolCallHierarchyIncomingCall;
|
||||
private toProtocolCallHierarchyOutgoingCall;
|
||||
private prepareCallHierarchy;
|
||||
private provideCallHierarchyIncomingCalls;
|
||||
private provideCallHierarchyOutgoingCalls;
|
||||
getCanonicalFileName(fileName: string): string;
|
||||
exit(): void;
|
||||
private notRequired;
|
||||
|
||||
18
tests/baselines/reference/api/typescript.d.ts
vendored
18
tests/baselines/reference/api/typescript.d.ts
vendored
@ -5113,6 +5113,9 @@ declare namespace ts {
|
||||
getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean): NavigateToItem[];
|
||||
getNavigationBarItems(fileName: string): NavigationBarItem[];
|
||||
getNavigationTree(fileName: string): NavigationTree;
|
||||
prepareCallHierarchy(fileName: string, position: number): CallHierarchyItem | CallHierarchyItem[] | undefined;
|
||||
provideCallHierarchyIncomingCalls(fileName: string, position: number): CallHierarchyIncomingCall[];
|
||||
provideCallHierarchyOutgoingCalls(fileName: string, position: number): CallHierarchyOutgoingCall[];
|
||||
getOutliningSpans(fileName: string): OutliningSpan[];
|
||||
getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[];
|
||||
getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[];
|
||||
@ -5252,6 +5255,21 @@ declare namespace ts {
|
||||
/** Present if non-empty */
|
||||
childItems?: NavigationTree[];
|
||||
}
|
||||
interface CallHierarchyItem {
|
||||
name: string;
|
||||
kind: ScriptElementKind;
|
||||
file: string;
|
||||
span: TextSpan;
|
||||
selectionSpan: TextSpan;
|
||||
}
|
||||
interface CallHierarchyIncomingCall {
|
||||
from: CallHierarchyItem;
|
||||
fromSpans: TextSpan[];
|
||||
}
|
||||
interface CallHierarchyOutgoingCall {
|
||||
to: CallHierarchyItem;
|
||||
fromSpans: TextSpan[];
|
||||
}
|
||||
interface TodoCommentDescriptor {
|
||||
text: string;
|
||||
priority: number;
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
╭ name: bar
|
||||
├ kind: getter
|
||||
├ file: /tests/cases/fourslash/callHierarchyAccessor.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyAccessor.ts:6:5-8:6
|
||||
│ │ 6: get bar() {
|
||||
│ │ ^^^^^^^^^^^
|
||||
│ │ 7: return baz();
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^^^
|
||||
│ │ 8: }
|
||||
│ │ ^^^^^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyAccessor.ts:6:9-6:12
|
||||
│ │ 6: get bar() {
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: foo
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyAccessor.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyAccessor.ts:1:1-3:2
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: new C().bar;
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyAccessor.ts:1:10-1:13
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyAccessor.ts:2:13-2:16
|
||||
│ │ │ 2: new C().bar;
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
├ outgoing:
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: baz
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyAccessor.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyAccessor.ts:11:1-12:2
|
||||
│ │ │ │ 11: function baz() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 12: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyAccessor.ts:11:10-11:13
|
||||
│ │ │ │ 11: function baz() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyAccessor.ts:7:16-7:19
|
||||
│ │ │ 7: return baz();
|
||||
│ │ │ ^^^
|
||||
╰ ╰ ╰
|
||||
@ -0,0 +1,65 @@
|
||||
╭ name: bar
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/callHierarchyClass.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyClass.ts:5:1-7:2
|
||||
│ │ 5: function bar() {
|
||||
│ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ 6: new Baz();
|
||||
│ │ ^^^^^^^^^^^^^^
|
||||
│ │ 7: }
|
||||
│ │ ^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyClass.ts:5:10-5:13
|
||||
│ │ 5: function bar() {
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: foo
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyClass.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyClass.ts:1:1-3:2
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: bar();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyClass.ts:1:10-1:13
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyClass.ts:2:5-2:8
|
||||
│ │ │ 2: bar();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
├ outgoing:
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: Baz
|
||||
│ │ ├ kind: class
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyClass.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyClass.ts:9:1-10:2
|
||||
│ │ │ │ 9: class Baz {
|
||||
│ │ │ │ ^^^^^^^^^^^
|
||||
│ │ │ │ 10: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyClass.ts:9:7-9:10
|
||||
│ │ │ │ 9: class Baz {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyClass.ts:6:9-6:12
|
||||
│ │ │ 6: new Baz();
|
||||
│ │ │ ^^^
|
||||
╰ ╰ ╰
|
||||
@ -0,0 +1,65 @@
|
||||
╭ name: bar
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/callHierarchyConstNamedArrowFunction.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyConstNamedArrowFunction.ts:5:13-7:2
|
||||
│ │ 5: const bar = () => {
|
||||
│ │ ^^^^^^^
|
||||
│ │ 6: baz();
|
||||
│ │ ^^^^^^^^^^
|
||||
│ │ 7: }
|
||||
│ │ ^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyConstNamedArrowFunction.ts:5:7-5:10
|
||||
│ │ 5: const bar = () => {
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: foo
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyConstNamedArrowFunction.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedArrowFunction.ts:1:1-3:2
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: bar();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedArrowFunction.ts:1:10-1:13
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedArrowFunction.ts:2:5-2:8
|
||||
│ │ │ 2: bar();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
├ outgoing:
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: baz
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyConstNamedArrowFunction.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedArrowFunction.ts:9:1-10:2
|
||||
│ │ │ │ 9: function baz() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 10: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedArrowFunction.ts:9:10-9:13
|
||||
│ │ │ │ 9: function baz() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedArrowFunction.ts:6:5-6:8
|
||||
│ │ │ 6: baz();
|
||||
│ │ │ ^^^
|
||||
╰ ╰ ╰
|
||||
@ -0,0 +1,69 @@
|
||||
╭ name: Bar
|
||||
├ kind: class
|
||||
├ file: /tests/cases/fourslash/callHierarchyConstNamedClassExpression.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyConstNamedClassExpression.ts:5:13-9:2
|
||||
│ │ 5: const Bar = class {
|
||||
│ │ ^^^^^^^
|
||||
│ │ 6: constructor() {
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^
|
||||
│ │ 7: baz();
|
||||
│ │ ^^^^^^^^^^^^^^
|
||||
│ │ 8: }
|
||||
│ │ ^^^^^
|
||||
│ │ 9: }
|
||||
│ │ ^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyConstNamedClassExpression.ts:5:7-5:10
|
||||
│ │ 5: const Bar = class {
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: foo
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyConstNamedClassExpression.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedClassExpression.ts:1:1-3:2
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: new Bar();
|
||||
│ │ │ │ ^^^^^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedClassExpression.ts:1:10-1:13
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedClassExpression.ts:2:9-2:12
|
||||
│ │ │ 2: new Bar();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
├ outgoing:
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: baz
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyConstNamedClassExpression.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedClassExpression.ts:11:1-12:2
|
||||
│ │ │ │ 11: function baz() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 12: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedClassExpression.ts:11:10-11:13
|
||||
│ │ │ │ 11: function baz() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedClassExpression.ts:7:9-7:12
|
||||
│ │ │ 7: baz();
|
||||
│ │ │ ^^^
|
||||
╰ ╰ ╰
|
||||
@ -0,0 +1,65 @@
|
||||
╭ name: bar
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/callHierarchyConstNamedFunctionExpression.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyConstNamedFunctionExpression.ts:5:13-7:2
|
||||
│ │ 5: const bar = function () {
|
||||
│ │ ^^^^^^^^^^^^^
|
||||
│ │ 6: baz();
|
||||
│ │ ^^^^^^^^^^
|
||||
│ │ 7: }
|
||||
│ │ ^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyConstNamedFunctionExpression.ts:5:7-5:10
|
||||
│ │ 5: const bar = function () {
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: foo
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyConstNamedFunctionExpression.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedFunctionExpression.ts:1:1-3:2
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: bar();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedFunctionExpression.ts:1:10-1:13
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedFunctionExpression.ts:2:5-2:8
|
||||
│ │ │ 2: bar();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
├ outgoing:
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: baz
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyConstNamedFunctionExpression.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedFunctionExpression.ts:9:1-10:2
|
||||
│ │ │ │ 9: function baz() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 10: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedFunctionExpression.ts:9:10-9:13
|
||||
│ │ │ │ 9: function baz() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyConstNamedFunctionExpression.ts:6:5-6:8
|
||||
│ │ │ 6: baz();
|
||||
│ │ │ ^^^
|
||||
╰ ╰ ╰
|
||||
@ -0,0 +1,65 @@
|
||||
╭ name: bar
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/callHierarchyDecorator.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyDecorator.ts:5:1-7:2
|
||||
│ │ 5: function bar() {
|
||||
│ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ 6: baz();
|
||||
│ │ ^^^^^^^^^^
|
||||
│ │ 7: }
|
||||
│ │ ^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyDecorator.ts:5:10-5:13
|
||||
│ │ 5: function bar() {
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: Foo
|
||||
│ │ ├ kind: class
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyDecorator.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyDecorator.ts:1:1-3:2
|
||||
│ │ │ │ 1: @bar
|
||||
│ │ │ │ ^^^^
|
||||
│ │ │ │ 2: class Foo {
|
||||
│ │ │ │ ^^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyDecorator.ts:2:7-2:10
|
||||
│ │ │ │ 2: class Foo {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyDecorator.ts:1:2-1:5
|
||||
│ │ │ 1: @bar
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
├ outgoing:
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: baz
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyDecorator.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyDecorator.ts:9:1-10:2
|
||||
│ │ │ │ 9: function baz() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 10: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyDecorator.ts:9:10-9:13
|
||||
│ │ │ │ 9: function baz() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyDecorator.ts:6:5-6:8
|
||||
│ │ │ 6: baz();
|
||||
│ │ │ ^^^
|
||||
╰ ╰ ╰
|
||||
@ -0,0 +1,69 @@
|
||||
╭ name: default
|
||||
├ kind: class
|
||||
├ file: /tests/cases/fourslash/other.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/other.ts:1:1-5:2
|
||||
│ │ 1: export default class {
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ │ 2: constructor() {
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^
|
||||
│ │ 3: baz();
|
||||
│ │ ^^^^^^^^^^^^^^
|
||||
│ │ 4: }
|
||||
│ │ ^^^^^
|
||||
│ │ 5: }
|
||||
│ │ ^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/other.ts:1:8-1:15
|
||||
│ │ 1: export default class {
|
||||
│ │ ^^^^^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: foo
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/main.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:3:1-5:2
|
||||
│ │ │ │ 3: function foo() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 4: new Bar();
|
||||
│ │ │ │ ^^^^^^^^^^^^^^
|
||||
│ │ │ │ 5: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:3:10-3:13
|
||||
│ │ │ │ 3: function foo() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.ts:4:9-4:12
|
||||
│ │ │ 4: new Bar();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
├ outgoing:
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: baz
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/other.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/other.ts:7:1-8:2
|
||||
│ │ │ │ 7: function baz() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 8: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/other.ts:7:10-7:13
|
||||
│ │ │ │ 7: function baz() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/other.ts:3:9-3:12
|
||||
│ │ │ 3: baz();
|
||||
│ │ │ ^^^
|
||||
╰ ╰ ╰
|
||||
@ -0,0 +1,65 @@
|
||||
╭ name: default
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/other.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/other.ts:1:1-3:2
|
||||
│ │ 1: export default function () {
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ │ 2: baz();
|
||||
│ │ ^^^^^^^^^^
|
||||
│ │ 3: }
|
||||
│ │ ^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/other.ts:1:8-1:15
|
||||
│ │ 1: export default function () {
|
||||
│ │ ^^^^^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: foo
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/main.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:3:1-5:2
|
||||
│ │ │ │ 3: function foo() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 4: bar();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ │ 5: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:3:10-3:13
|
||||
│ │ │ │ 3: function foo() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.ts:4:5-4:8
|
||||
│ │ │ 4: bar();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
├ outgoing:
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: baz
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/other.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/other.ts:5:1-6:2
|
||||
│ │ │ │ 5: function baz() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 6: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/other.ts:5:10-5:13
|
||||
│ │ │ │ 5: function baz() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/other.ts:2:5-2:8
|
||||
│ │ │ 2: baz();
|
||||
│ │ │ ^^^
|
||||
╰ ╰ ╰
|
||||
@ -0,0 +1,47 @@
|
||||
╭ name: /tests/cases/fourslash/other.ts
|
||||
├ kind: module
|
||||
├ file: /tests/cases/fourslash/other.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/other.ts:1:1-6:2
|
||||
│ │ 1: export = function () {
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ │ 2: baz();
|
||||
│ │ ^^^^^^^^^^
|
||||
│ │ 3: }
|
||||
│ │ ^
|
||||
│ │ 4:
|
||||
│ │ ^
|
||||
│ │ 5: function baz() {
|
||||
│ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ 6: }
|
||||
│ │ ^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/other.ts:1:1-1:1
|
||||
│ │ 1: export = function () {
|
||||
│ │ <
|
||||
│ ╰
|
||||
├ incoming: none
|
||||
├ outgoing:
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: baz
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/other.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/other.ts:5:1-6:2
|
||||
│ │ │ │ 5: function baz() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 6: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/other.ts:5:10-5:13
|
||||
│ │ │ │ 5: function baz() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/other.ts:2:5-2:8
|
||||
│ │ │ 2: baz();
|
||||
│ │ │ ^^^
|
||||
╰ ╰ ╰
|
||||
@ -0,0 +1,41 @@
|
||||
╭ name: foo
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/callHierarchyFile.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyFile.ts:2:1-3:2
|
||||
│ │ 2: function foo() {
|
||||
│ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ 3: }
|
||||
│ │ ^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyFile.ts:2:10-2:13
|
||||
│ │ 2: function foo() {
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: /tests/cases/fourslash/callHierarchyFile.ts
|
||||
│ │ ├ kind: script
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyFile.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyFile.ts:1:1-3:2
|
||||
│ │ │ │ 1: foo();
|
||||
│ │ │ │ ^^^^^^
|
||||
│ │ │ │ 2: function foo() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyFile.ts:1:1-1:1
|
||||
│ │ │ │ 1: foo();
|
||||
│ │ │ │ <
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyFile.ts:1:1-1:4
|
||||
│ │ │ 1: foo();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
╰ outgoing: none
|
||||
@ -0,0 +1,95 @@
|
||||
╭ name: bar
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/callHierarchyFunction.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyFunction.ts:5:1-9:2
|
||||
│ │ 5: function bar() {
|
||||
│ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ 6: baz();
|
||||
│ │ ^^^^^^^^^^
|
||||
│ │ 7: quxx();
|
||||
│ │ ^^^^^^^^^^^
|
||||
│ │ 8: baz();
|
||||
│ │ ^^^^^^^^^^
|
||||
│ │ 9: }
|
||||
│ │ ^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyFunction.ts:5:10-5:13
|
||||
│ │ 5: function bar() {
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: foo
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyFunction.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyFunction.ts:1:1-3:2
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: bar();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyFunction.ts:1:10-1:13
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyFunction.ts:2:5-2:8
|
||||
│ │ │ 2: bar();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
├ outgoing:
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: baz
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyFunction.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyFunction.ts:11:1-12:2
|
||||
│ │ │ │ 11: function baz() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 12: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyFunction.ts:11:10-11:13
|
||||
│ │ │ │ 11: function baz() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyFunction.ts:6:5-6:8
|
||||
│ │ │ 6: baz();
|
||||
│ │ │ ^^^
|
||||
│ │ ╰
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyFunction.ts:8:5-8:8
|
||||
│ │ │ 8: baz();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: quxx
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyFunction.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyFunction.ts:14:1-15:2
|
||||
│ │ │ │ 14: function quxx() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 15: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyFunction.ts:14:10-14:14
|
||||
│ │ │ │ 14: function quxx() {
|
||||
│ │ │ │ ^^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyFunction.ts:7:5-7:9
|
||||
│ │ │ 7: quxx();
|
||||
│ │ │ ^^^^
|
||||
╰ ╰ ╰
|
||||
@ -0,0 +1,78 @@
|
||||
╭ name: foo
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/a.d.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/a.d.ts:1:1-1:40
|
||||
│ │ 1: declare function foo(x?: number): void;
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/a.d.ts:1:18-1:21
|
||||
│ │ 1: declare function foo(x?: number): void;
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: bar
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/main.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:1-3:2
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: foo();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:10-1:13
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.ts:2:5-2:8
|
||||
│ │ │ 2: foo();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
╰ outgoing: none
|
||||
╭ name: foo
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/b.d.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/b.d.ts:1:1-1:40
|
||||
│ │ 1: declare function foo(x?: string): void;
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/b.d.ts:1:18-1:21
|
||||
│ │ 1: declare function foo(x?: string): void;
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: bar
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/main.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:1-3:2
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: foo();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:10-1:13
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.ts:2:5-2:8
|
||||
│ │ │ 2: foo();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
╰ outgoing: none
|
||||
@ -0,0 +1,78 @@
|
||||
╭ name: foo
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/a.d.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/a.d.ts:1:1-1:40
|
||||
│ │ 1: declare function foo(x?: number): void;
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/a.d.ts:1:18-1:21
|
||||
│ │ 1: declare function foo(x?: number): void;
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: bar
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/main.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:1-3:2
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: foo();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:10-1:13
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.ts:2:5-2:8
|
||||
│ │ │ 2: foo();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
╰ outgoing: none
|
||||
╭ name: foo
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/b.d.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/b.d.ts:1:1-1:40
|
||||
│ │ 1: declare function foo(x?: string): void;
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/b.d.ts:1:18-1:21
|
||||
│ │ 1: declare function foo(x?: string): void;
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: bar
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/main.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:1-3:2
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: foo();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:10-1:13
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.ts:2:5-2:8
|
||||
│ │ │ 2: foo();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
╰ outgoing: none
|
||||
@ -0,0 +1,78 @@
|
||||
╭ name: foo
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/a.d.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/a.d.ts:1:1-1:40
|
||||
│ │ 1: declare function foo(x?: number): void;
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/a.d.ts:1:18-1:21
|
||||
│ │ 1: declare function foo(x?: number): void;
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: bar
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/main.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:1-3:2
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: foo();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:10-1:13
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.ts:2:5-2:8
|
||||
│ │ │ 2: foo();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
╰ outgoing: none
|
||||
╭ name: foo
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/b.d.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/b.d.ts:1:1-1:40
|
||||
│ │ 1: declare function foo(x?: string): void;
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/b.d.ts:1:18-1:21
|
||||
│ │ 1: declare function foo(x?: string): void;
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: bar
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/main.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:1-3:2
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: foo();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:10-1:13
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.ts:2:5-2:8
|
||||
│ │ │ 2: foo();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
╰ outgoing: none
|
||||
@ -0,0 +1,78 @@
|
||||
╭ name: foo
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/a.d.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/a.d.ts:1:1-1:40
|
||||
│ │ 1: declare function foo(x?: number): void;
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/a.d.ts:1:18-1:21
|
||||
│ │ 1: declare function foo(x?: number): void;
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: bar
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/main.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:1-3:2
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: foo();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:10-1:13
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.ts:2:5-2:8
|
||||
│ │ │ 2: foo();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
╰ outgoing: none
|
||||
╭ name: foo
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/b.d.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/b.d.ts:1:1-1:40
|
||||
│ │ 1: declare function foo(x?: string): void;
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/b.d.ts:1:18-1:21
|
||||
│ │ 1: declare function foo(x?: string): void;
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: bar
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/main.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:1-3:2
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: foo();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.ts:1:10-1:13
|
||||
│ │ │ │ 1: function bar() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.ts:2:5-2:8
|
||||
│ │ │ 2: foo();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
╰ outgoing: none
|
||||
@ -0,0 +1,59 @@
|
||||
╭ name: bar
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/main.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/main.ts:1:1-3:2
|
||||
│ │ 1: function bar() {
|
||||
│ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ 2: foo();
|
||||
│ │ ^^^^^^^^^^
|
||||
│ │ 3: }
|
||||
│ │ ^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/main.ts:1:10-1:13
|
||||
│ │ 1: function bar() {
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming: none
|
||||
├ outgoing:
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: foo
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/a.d.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/a.d.ts:1:1-1:40
|
||||
│ │ │ │ 1: declare function foo(x?: number): void;
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/a.d.ts:1:18-1:21
|
||||
│ │ │ │ 1: declare function foo(x?: number): void;
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.ts:2:5-2:8
|
||||
│ │ │ 2: foo();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: foo
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/b.d.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/b.d.ts:1:1-1:40
|
||||
│ │ │ │ 1: declare function foo(x?: string): void;
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/b.d.ts:1:18-1:21
|
||||
│ │ │ │ 1: declare function foo(x?: string): void;
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.ts:2:5-2:8
|
||||
│ │ │ 2: foo();
|
||||
│ │ │ ^^^
|
||||
╰ ╰ ╰
|
||||
@ -0,0 +1,47 @@
|
||||
╭ name: foo
|
||||
├ kind: method
|
||||
├ file: /tests/cases/fourslash/callHierarchyInterfaceMethod.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyInterfaceMethod.ts:2:5-2:17
|
||||
│ │ 2: foo(): void;
|
||||
│ │ ^^^^^^^^^^^^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyInterfaceMethod.ts:2:5-2:8
|
||||
│ │ 2: foo(): void;
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: /tests/cases/fourslash/callHierarchyInterfaceMethod.ts
|
||||
│ │ ├ kind: script
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyInterfaceMethod.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyInterfaceMethod.ts:1:1-7:11
|
||||
│ │ │ │ 1: interface I {
|
||||
│ │ │ │ ^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: foo(): void;
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ │ 4:
|
||||
│ │ │ │ ^
|
||||
│ │ │ │ 5: const obj: I = { foo() {} };
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 6:
|
||||
│ │ │ │ ^
|
||||
│ │ │ │ 7: obj.foo();
|
||||
│ │ │ │ ^^^^^^^^^^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyInterfaceMethod.ts:1:1-1:1
|
||||
│ │ │ │ 1: interface I {
|
||||
│ │ │ │ <
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyInterfaceMethod.ts:7:5-7:8
|
||||
│ │ │ 7: obj.foo();
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
╰ outgoing: none
|
||||
@ -0,0 +1,65 @@
|
||||
╭ name: Bar
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/main.tsx
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/main.tsx:5:1-7:2
|
||||
│ │ 5: function Bar() {
|
||||
│ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ 6: baz();
|
||||
│ │ ^^^^^^^^^^
|
||||
│ │ 7: }
|
||||
│ │ ^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/main.tsx:5:10-5:13
|
||||
│ │ 5: function Bar() {
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: foo
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/main.tsx
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.tsx:1:1-3:2
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: return <Bar/>;
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.tsx:1:10-1:13
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.tsx:2:13-2:16
|
||||
│ │ │ 2: return <Bar/>;
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
├ outgoing:
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: baz
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/main.tsx
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.tsx:9:1-10:2
|
||||
│ │ │ │ 9: function baz() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 10: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/main.tsx:9:10-9:13
|
||||
│ │ │ │ 9: function baz() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/main.tsx:6:5-6:8
|
||||
│ │ │ 6: baz();
|
||||
│ │ │ ^^^
|
||||
╰ ╰ ╰
|
||||
@ -0,0 +1,65 @@
|
||||
╭ name: bar
|
||||
├ kind: function
|
||||
├ file: /tests/cases/fourslash/callHierarchyTaggedTemplate.ts
|
||||
├ span:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyTaggedTemplate.ts:5:1-7:2
|
||||
│ │ 5: function bar(array: TemplateStringsArray, ...args: any[]) {
|
||||
│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
│ │ 6: baz();
|
||||
│ │ ^^^^^^^^^^
|
||||
│ │ 7: }
|
||||
│ │ ^
|
||||
│ ╰
|
||||
├ selectionSpan:
|
||||
│ ╭ /tests/cases/fourslash/callHierarchyTaggedTemplate.ts:5:10-5:13
|
||||
│ │ 5: function bar(array: TemplateStringsArray, ...args: any[]) {
|
||||
│ │ ^^^
|
||||
│ ╰
|
||||
├ incoming:
|
||||
│ ╭ from:
|
||||
│ │ ╭ name: foo
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyTaggedTemplate.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyTaggedTemplate.ts:1:1-3:2
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 2: bar`a${1}b`;
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 3: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyTaggedTemplate.ts:1:10-1:13
|
||||
│ │ │ │ 1: function foo() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ incoming: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyTaggedTemplate.ts:2:5-2:8
|
||||
│ │ │ 2: bar`a${1}b`;
|
||||
│ │ │ ^^^
|
||||
│ ╰ ╰
|
||||
├ outgoing:
|
||||
│ ╭ to:
|
||||
│ │ ╭ name: baz
|
||||
│ │ ├ kind: function
|
||||
│ │ ├ file: /tests/cases/fourslash/callHierarchyTaggedTemplate.ts
|
||||
│ │ ├ span:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyTaggedTemplate.ts:9:1-10:2
|
||||
│ │ │ │ 9: function baz() {
|
||||
│ │ │ │ ^^^^^^^^^^^^^^^^
|
||||
│ │ │ │ 10: }
|
||||
│ │ │ │ ^
|
||||
│ │ │ ╰
|
||||
│ │ ├ selectionSpan:
|
||||
│ │ │ ╭ /tests/cases/fourslash/callHierarchyTaggedTemplate.ts:9:10-9:13
|
||||
│ │ │ │ 9: function baz() {
|
||||
│ │ │ │ ^^^
|
||||
│ │ │ ╰
|
||||
│ │ ╰ outgoing: none
|
||||
│ ├ fromSpans:
|
||||
│ │ ╭ /tests/cases/fourslash/callHierarchyTaggedTemplate.ts:6:5-6:8
|
||||
│ │ │ 6: baz();
|
||||
│ │ │ ^^^
|
||||
╰ ╰ ╰
|
||||
17
tests/cases/fourslash/callHierarchyAccessor.ts
Normal file
17
tests/cases/fourslash/callHierarchyAccessor.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// function foo() {
|
||||
//// new C().bar;
|
||||
//// }
|
||||
////
|
||||
//// class C {
|
||||
//// get /**/bar() {
|
||||
//// return baz();
|
||||
//// }
|
||||
//// }
|
||||
////
|
||||
//// function baz() {
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
15
tests/cases/fourslash/callHierarchyClass.ts
Normal file
15
tests/cases/fourslash/callHierarchyClass.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// function foo() {
|
||||
//// bar();
|
||||
//// }
|
||||
////
|
||||
//// function /**/bar() {
|
||||
//// new Baz();
|
||||
//// }
|
||||
////
|
||||
//// class Baz {
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
@ -0,0 +1,15 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// function foo() {
|
||||
//// bar();
|
||||
//// }
|
||||
////
|
||||
//// const /**/bar = () => {
|
||||
//// baz();
|
||||
//// }
|
||||
////
|
||||
//// function baz() {
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
@ -0,0 +1,17 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// function foo() {
|
||||
//// new Bar();
|
||||
//// }
|
||||
////
|
||||
//// const /**/Bar = class {
|
||||
//// constructor() {
|
||||
//// baz();
|
||||
//// }
|
||||
//// }
|
||||
////
|
||||
//// function baz() {
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
@ -0,0 +1,15 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// function foo() {
|
||||
//// bar();
|
||||
//// }
|
||||
////
|
||||
//// const /**/bar = function () {
|
||||
//// baz();
|
||||
//// }
|
||||
////
|
||||
//// function baz() {
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
16
tests/cases/fourslash/callHierarchyDecorator.ts
Normal file
16
tests/cases/fourslash/callHierarchyDecorator.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @experimentalDecorators: true
|
||||
//// @bar
|
||||
//// class Foo {
|
||||
//// }
|
||||
////
|
||||
//// function /**/bar() {
|
||||
//// baz();
|
||||
//// }
|
||||
////
|
||||
//// function baz() {
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
21
tests/cases/fourslash/callHierarchyExportDefaultClass.ts
Normal file
21
tests/cases/fourslash/callHierarchyExportDefaultClass.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @filename: main.ts
|
||||
//// import Bar from "./other";
|
||||
////
|
||||
//// function foo() {
|
||||
//// new Bar();
|
||||
//// }
|
||||
|
||||
// @filename: other.ts
|
||||
//// export /**/default class {
|
||||
//// constructor() {
|
||||
//// baz();
|
||||
//// }
|
||||
//// }
|
||||
////
|
||||
//// function baz() {
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
19
tests/cases/fourslash/callHierarchyExportDefaultFunction.ts
Normal file
19
tests/cases/fourslash/callHierarchyExportDefaultFunction.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @filename: main.ts
|
||||
//// import bar from "./other";
|
||||
////
|
||||
//// function foo() {
|
||||
//// bar();
|
||||
//// }
|
||||
|
||||
// @filename: other.ts
|
||||
//// export /**/default function () {
|
||||
//// baz();
|
||||
//// }
|
||||
////
|
||||
//// function baz() {
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
20
tests/cases/fourslash/callHierarchyExportEqualsFunction.ts
Normal file
20
tests/cases/fourslash/callHierarchyExportEqualsFunction.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @filename: main.ts
|
||||
//// import bar = require("./other");
|
||||
////
|
||||
//// function foo() {
|
||||
//// bar();
|
||||
//// }
|
||||
|
||||
// @filename: other.ts
|
||||
//// export = /**/function () {
|
||||
//// baz();
|
||||
//// }
|
||||
////
|
||||
//// function baz() {
|
||||
//// }
|
||||
|
||||
// NOTE: exported function is unnamed, so we expand the item to the entire file...
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
8
tests/cases/fourslash/callHierarchyFile.ts
Normal file
8
tests/cases/fourslash/callHierarchyFile.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// foo();
|
||||
//// function /**/foo() {
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
20
tests/cases/fourslash/callHierarchyFunction.ts
Normal file
20
tests/cases/fourslash/callHierarchyFunction.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// function foo() {
|
||||
//// bar();
|
||||
//// }
|
||||
////
|
||||
//// function /**/bar() {
|
||||
//// baz();
|
||||
//// quxx();
|
||||
//// baz();
|
||||
//// }
|
||||
////
|
||||
//// function baz() {
|
||||
//// }
|
||||
////
|
||||
//// function quxx() {
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
16
tests/cases/fourslash/callHierarchyFunctionAmbiguity.1.ts
Normal file
16
tests/cases/fourslash/callHierarchyFunctionAmbiguity.1.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @filename: a.d.ts
|
||||
//// declare function foo(x?: number): void;
|
||||
|
||||
// @filename: b.d.ts
|
||||
//// declare function foo(x?: string): void;
|
||||
//// declare function foo(x?: boolean): void;
|
||||
|
||||
// @filename: main.ts
|
||||
//// function bar() {
|
||||
//// /**/foo();
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
16
tests/cases/fourslash/callHierarchyFunctionAmbiguity.2.ts
Normal file
16
tests/cases/fourslash/callHierarchyFunctionAmbiguity.2.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @filename: a.d.ts
|
||||
//// declare function /**/foo(x?: number): void;
|
||||
|
||||
// @filename: b.d.ts
|
||||
//// declare function foo(x?: string): void;
|
||||
//// declare function foo(x?: boolean): void;
|
||||
|
||||
// @filename: main.ts
|
||||
//// function bar() {
|
||||
//// foo();
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
16
tests/cases/fourslash/callHierarchyFunctionAmbiguity.3.ts
Normal file
16
tests/cases/fourslash/callHierarchyFunctionAmbiguity.3.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @filename: a.d.ts
|
||||
//// declare function foo(x?: number): void;
|
||||
|
||||
// @filename: b.d.ts
|
||||
//// declare function /**/foo(x?: string): void;
|
||||
//// declare function foo(x?: boolean): void;
|
||||
|
||||
// @filename: main.ts
|
||||
//// function bar() {
|
||||
//// foo();
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
16
tests/cases/fourslash/callHierarchyFunctionAmbiguity.4.ts
Normal file
16
tests/cases/fourslash/callHierarchyFunctionAmbiguity.4.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @filename: a.d.ts
|
||||
//// declare function foo(x?: number): void;
|
||||
|
||||
// @filename: b.d.ts
|
||||
//// declare function foo(x?: string): void;
|
||||
//// declare function /**/foo(x?: boolean): void;
|
||||
|
||||
// @filename: main.ts
|
||||
//// function bar() {
|
||||
//// foo();
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
16
tests/cases/fourslash/callHierarchyFunctionAmbiguity.5.ts
Normal file
16
tests/cases/fourslash/callHierarchyFunctionAmbiguity.5.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @filename: a.d.ts
|
||||
//// declare function foo(x?: number): void;
|
||||
|
||||
// @filename: b.d.ts
|
||||
//// declare function foo(x?: string): void;
|
||||
//// declare function foo(x?: boolean): void;
|
||||
|
||||
// @filename: main.ts
|
||||
//// function /**/bar() {
|
||||
//// foo();
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
12
tests/cases/fourslash/callHierarchyInterfaceMethod.ts
Normal file
12
tests/cases/fourslash/callHierarchyInterfaceMethod.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// interface I {
|
||||
//// /**/foo(): void;
|
||||
//// }
|
||||
////
|
||||
//// const obj: I = { foo() {} };
|
||||
////
|
||||
//// obj.foo();
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
17
tests/cases/fourslash/callHierarchyJsxElement.ts
Normal file
17
tests/cases/fourslash/callHierarchyJsxElement.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @jsx: preserve
|
||||
// @filename: main.tsx
|
||||
//// function foo() {
|
||||
//// return <Bar/>;
|
||||
//// }
|
||||
////
|
||||
//// function /**/Bar() {
|
||||
//// baz();
|
||||
//// }
|
||||
////
|
||||
//// function baz() {
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
15
tests/cases/fourslash/callHierarchyTaggedTemplate.ts
Normal file
15
tests/cases/fourslash/callHierarchyTaggedTemplate.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// function foo() {
|
||||
//// bar`a${1}b`;
|
||||
//// }
|
||||
////
|
||||
//// function /**/bar(array: TemplateStringsArray, ...args: any[]) {
|
||||
//// baz();
|
||||
//// }
|
||||
////
|
||||
//// function baz() {
|
||||
//// }
|
||||
|
||||
goTo.marker();
|
||||
verify.baselineCallHierarchy();
|
||||
@ -383,6 +383,7 @@ declare namespace FourSlashInterface {
|
||||
readonly newFileContents: { readonly [fileName: string]: string };
|
||||
readonly preferences?: UserPreferences;
|
||||
}): void;
|
||||
baselineCallHierarchy(): void;
|
||||
moveToNewFile(options: {
|
||||
readonly newFileContents: { readonly [fileName: string]: string };
|
||||
readonly preferences?: UserPreferences;
|
||||
@ -773,4 +774,4 @@ declare namespace completion {
|
||||
export const statementKeywordsWithTypes: ReadonlyArray<Entry>;
|
||||
export const statementKeywords: ReadonlyArray<Entry>;
|
||||
export const statementInJsKeywords: ReadonlyArray<Entry>;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user