diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 3da46d8dedb4a..bf5f46de2480c 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1102,20 +1102,30 @@ namespace FourSlash { } public verifyReferenceGroups(startRanges: Range | Range[], parts: FourSlashInterface.ReferenceGroup[]): void { - const fullExpected = ts.map(parts, ({ definition, ranges }) => ({ definition, ranges: ranges.map(rangeToReferenceEntry) })); + interface ReferenceGroupJson { + definition: string | { text: string, range: ts.TextSpan }; + references: ts.ReferenceEntry[]; + } + const fullExpected = ts.map(parts, ({ definition, ranges }) => ({ + definition: typeof definition === "string" ? definition : { ...definition, range: textSpanFromRange(definition.range) }, + references: ranges.map(rangeToReferenceEntry), + })); for (const startRange of toArray(startRanges)) { this.goToRangeStart(startRange); - const fullActual = ts.map(this.findReferencesAtCaret(), ({ definition, references }) => ({ - definition: definition.displayParts.map(d => d.text).join(""), - ranges: references - })); + const fullActual = ts.map(this.findReferencesAtCaret(), ({ definition, references }, i) => { + const text = definition.displayParts.map(d => d.text).join(""); + return { + definition: typeof fullExpected[i].definition === "string" ? text : { text, range: definition.textSpan }, + references, + }; + }); this.assertObjectsEqual(fullActual, fullExpected); } function rangeToReferenceEntry(r: Range): ts.ReferenceEntry { const { isWriteAccess, isDefinition, isInString } = (r.marker && r.marker.data) || { isWriteAccess: false, isDefinition: false, isInString: undefined }; - const result: ts.ReferenceEntry = { fileName: r.fileName, textSpan: { start: r.start, length: r.end - r.start }, isWriteAccess: !!isWriteAccess, isDefinition: !!isDefinition }; + const result: ts.ReferenceEntry = { fileName: r.fileName, textSpan: textSpanFromRange(r), isWriteAccess: !!isWriteAccess, isDefinition: !!isDefinition }; if (isInString !== undefined) { result.isInString = isInString; } @@ -1139,7 +1149,7 @@ namespace FourSlash { } } - public verifySingleReferenceGroup(definition: string, ranges?: Range[]) { + public verifySingleReferenceGroup(definition: FourSlashInterface.ReferenceGroupDefinition, ranges?: Range[]) { ranges = ranges || this.getRanges(); this.verifyReferenceGroups(ranges, [{ definition, ranges }]); } @@ -4080,7 +4090,7 @@ namespace FourSlashInterface { this.state.verifyNoReferences(markerNameOrRange); } - public singleReferenceGroup(definition: string, ranges?: FourSlash.Range[]) { + public singleReferenceGroup(definition: ReferenceGroupDefinition, ranges?: FourSlash.Range[]) { this.state.verifySingleReferenceGroup(definition, ranges); } @@ -4592,10 +4602,12 @@ namespace FourSlashInterface { } export interface ReferenceGroup { - definition: string; + definition: ReferenceGroupDefinition; ranges: FourSlash.Range[]; } + export type ReferenceGroupDefinition = string | { text: string, range: FourSlash.Range }; + export interface ApplyRefactorOptions { refactorName: string; actionName: string; diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 8b7473357fe63..f7529e69d7734 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -44,7 +44,7 @@ namespace ts.FindAllReferences { export function findReferencedSymbols(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray, sourceFile: SourceFile, position: number): ReferencedSymbol[] | undefined { const referencedSymbols = findAllReferencedSymbols(program, cancellationToken, sourceFiles, sourceFile, position); const checker = program.getTypeChecker(); - return !referencedSymbols || !referencedSymbols.length ? undefined : mapDefined(referencedSymbols, ({ definition, references }) => + return !referencedSymbols || !referencedSymbols.length ? undefined : mapDefined(referencedSymbols, ({ definition, references }) => // Only include referenced symbols that have a valid definition. definition && { definition: definitionToReferencedSymbolDefinitionInfo(definition, checker), references: references.map(toReferenceEntry) }); } diff --git a/tests/cases/fourslash/findAllRefsDefinition.ts b/tests/cases/fourslash/findAllRefsDefinition.ts new file mode 100644 index 0000000000000..611bacf52ca8e --- /dev/null +++ b/tests/cases/fourslash/findAllRefsDefinition.ts @@ -0,0 +1,15 @@ +/// + +////const [|{| "isWriteAccess": true, "isDefinition": true |}x|] = 0; +////[|x|]; + +// TODO: GH#21301 + +const ranges = test.ranges(); +const [r0, r1] = ranges; +verify.referenceGroups(r1, [ + { + definition: { text: "const x: 0", range: r1 }, + ranges, + }, +]) diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 0bf62eaef9240..774c2191fd069 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -258,8 +258,8 @@ declare namespace FourSlashInterface { * For each of startRanges, asserts the ranges that are referenced from there. * This uses the 'findReferences' command instead of 'getReferencesAtPosition', so references are grouped by their definition. */ - referenceGroups(startRanges: Range | Range[], parts: Array<{ definition: string, ranges: Range[] }>): void; - singleReferenceGroup(definition: string, ranges?: Range[]): void; + referenceGroups(startRanges: Range | Range[], parts: Array<{ definition: ReferencesDefinition, ranges: Range[] }>): void; + singleReferenceGroup(definition: ReferencesDefinition, ranges?: Range[]): void; rangesAreOccurrences(isWriteAccess?: boolean): void; rangesWithSameTextAreRenameLocations(): void; rangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: Range[] }); @@ -512,6 +512,11 @@ declare namespace FourSlashInterface { textSpan?: TextSpan; }; } + + interface ReferencesDefinition { + text: string; + range: Range; + } } declare function verifyOperationIsCancelled(f: any): void; declare var test: FourSlashInterface.test_;