Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(51017): Make lineText in the references response opt-out (#51081)
* add option to exclude lineText from the response

* add comments

* update baseline
  • Loading branch information
a-tarasyuk committed Oct 7, 2022
1 parent d06a592 commit dbeae5d
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 16 deletions.
17 changes: 12 additions & 5 deletions src/server/protocol.ts
Expand Up @@ -1158,12 +1158,14 @@ namespace ts.server.protocol {
}

export interface ReferencesResponseItem extends FileSpanWithContext {
/** Text of line containing the reference. Including this
* with the response avoids latency of editor loading files
* to show text of reference line (the server already has
* loaded the referencing files).
/**
* Text of line containing the reference. Including this
* with the response avoids latency of editor loading files
* to show text of reference line (the server already has loaded the referencing files).
*
* If {@link UserPreferences.disableLineTextInReferences} is enabled, the property won't be filled
*/
lineText: string;
lineText?: string;

/**
* True if reference is a write location, false otherwise.
Expand Down Expand Up @@ -3478,6 +3480,11 @@ namespace ts.server.protocol {
readonly includeInlayFunctionLikeReturnTypeHints?: boolean;
readonly includeInlayEnumMemberValueHints?: boolean;
readonly autoImportFileExcludePatterns?: string[];

/**
* Indicates whether {@link ReferencesResponseItem.lineText} is supported.
*/
readonly disableLineTextInReferences?: boolean;
}

export interface CompilerOptions {
Expand Down
16 changes: 11 additions & 5 deletions src/server/session.ts
Expand Up @@ -1807,6 +1807,7 @@ namespace ts.server {

if (!simplifiedResult) return references;

const preferences = this.getPreferences(file);
const defaultProject = this.getDefaultProject(args);
const scriptInfo = defaultProject.getScriptInfoForNormalizedPath(file)!;
const nameInfo = defaultProject.getLanguageService().getQuickInfoAtPosition(file, position);
Expand All @@ -1815,14 +1816,15 @@ namespace ts.server {
const symbolStartOffset = nameSpan ? scriptInfo.positionToLineOffset(nameSpan.start).offset : 0;
const symbolName = nameSpan ? scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan)) : "";
const refs: readonly protocol.ReferencesResponseItem[] = flatMap(references, referencedSymbol => {
return referencedSymbol.references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry));
return referencedSymbol.references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry, preferences));
});
return { refs, symbolName, symbolStartOffset, symbolDisplayString };
}

private getFileReferences(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.FileReferencesResponseBody | readonly ReferenceEntry[] {
const projects = this.getProjects(args);
const fileName = args.file;
const preferences = this.getPreferences(toNormalizedPath(fileName));

const references: ReferenceEntry[] = [];
const seen = createDocumentSpanSet();
Expand All @@ -1842,7 +1844,7 @@ namespace ts.server {
});

if (!simplifiedResult) return references;
const refs = references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry));
const refs = references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry, preferences));
return {
refs,
symbolName: `"${args.file}"`
Expand Down Expand Up @@ -3516,11 +3518,10 @@ namespace ts.server {
return text;
}

function referenceEntryToReferencesResponseItem(projectService: ProjectService, { fileName, textSpan, contextSpan, isWriteAccess, isDefinition }: ReferencedSymbolEntry): protocol.ReferencesResponseItem {
function referenceEntryToReferencesResponseItem(projectService: ProjectService, { fileName, textSpan, contextSpan, isWriteAccess, isDefinition }: ReferencedSymbolEntry, { disableLineTextInReferences }: protocol.UserPreferences): protocol.ReferencesResponseItem {
const scriptInfo = Debug.checkDefined(projectService.getScriptInfo(fileName));
const span = toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo);
const lineSpan = scriptInfo.lineToTextSpan(span.start.line - 1);
const lineText = scriptInfo.getSnapshot().getText(lineSpan.start, textSpanEnd(lineSpan)).replace(/\r|\n/g, "");
const lineText = disableLineTextInReferences ? undefined : getLineText(scriptInfo, span);
return {
file: fileName,
...span,
Expand All @@ -3530,6 +3531,11 @@ namespace ts.server {
};
}

function getLineText(scriptInfo: ScriptInfo, span: protocol.TextSpanWithContext) {
const lineSpan = scriptInfo.lineToTextSpan(span.start.line - 1);
return scriptInfo.getSnapshot().getText(lineSpan.start, textSpanEnd(lineSpan)).replace(/\r|\n/g, "");
}

function isCompletionEntryData(data: any): data is CompletionEntryData {
return data === undefined || data && typeof data === "object"
&& typeof data.exportName === "string"
Expand Down
23 changes: 23 additions & 0 deletions src/testRunner/unittests/tsserver/getFileReferences.ts
Expand Up @@ -54,5 +54,28 @@ namespace ts.projectSystem {

assert.deepEqual(response, expectResponse);
});

it("should skip lineText from file references", () => {
const session = makeSampleSession();
session.getProjectService().setHostConfiguration({ preferences: { disableLineTextInReferences: true } });

const response = executeSessionRequest<protocol.FileReferencesRequest, protocol.FileReferencesResponse>(
session,
protocol.CommandTypes.FileReferences,
{ file: aTs.path },
);

const expectResponse: protocol.FileReferencesResponseBody = {
refs: [
makeReferenceItem({ file: bTs, text: "./a", lineText: undefined, contextText: importA, isWriteAccess: false }),
makeReferenceItem({ file: cTs, text: "./a", lineText: undefined, contextText: importCurlyFromA, isWriteAccess: false }),
makeReferenceItem({ file: dTs, text: "/project/a", lineText: undefined, contextText: importAFromA, isWriteAccess: false }),
makeReferenceItem({ file: dTs, text: "./a", lineText: undefined, contextText: typeofImportA, isWriteAccess: false }),
],
symbolName: `"${aTs.path}"`,
};

assert.deepEqual(response, expectResponse);
});
});
}
2 changes: 1 addition & 1 deletion src/testRunner/unittests/tsserver/helpers.ts
Expand Up @@ -810,7 +810,7 @@ namespace ts.projectSystem {
export interface MakeReferenceItem extends DocumentSpanFromSubstring {
isDefinition?: boolean;
isWriteAccess?: boolean;
lineText: string;
lineText?: string;
}

export function makeReferenceItem({ isDefinition, isWriteAccess, lineText, ...rest }: MakeReferenceItem): protocol.ReferencesResponseItem {
Expand Down
16 changes: 11 additions & 5 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Expand Up @@ -7982,12 +7982,14 @@ declare namespace ts.server.protocol {
command: CommandTypes.References;
}
interface ReferencesResponseItem extends FileSpanWithContext {
/** Text of line containing the reference. Including this
* with the response avoids latency of editor loading files
* to show text of reference line (the server already has
* loaded the referencing files).
/**
* Text of line containing the reference. Including this
* with the response avoids latency of editor loading files
* to show text of reference line (the server already has loaded the referencing files).
*
* If {@link UserPreferences.disableLineTextInReferences} is enabled, the property won't be filled
*/
lineText: string;
lineText?: string;
/**
* True if reference is a write location, false otherwise.
*/
Expand Down Expand Up @@ -9833,6 +9835,10 @@ declare namespace ts.server.protocol {
readonly includeInlayFunctionLikeReturnTypeHints?: boolean;
readonly includeInlayEnumMemberValueHints?: boolean;
readonly autoImportFileExcludePatterns?: string[];
/**
* Indicates whether {@link ReferencesResponseItem.lineText} is supported.
*/
readonly disableLineTextInReferences?: boolean;
}
interface CompilerOptions {
allowJs?: boolean;
Expand Down

0 comments on commit dbeae5d

Please sign in to comment.