Skip to content

Commit 51d4970

Browse files
author
Andy
authored
Merge pull request microsoft#13760 from Microsoft/find_all_refs_tests
Change find-all-references tests to test for groups
2 parents 0a1d75d + f458331 commit 51d4970

File tree

166 files changed

+1349
-776
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

166 files changed

+1349
-776
lines changed

src/harness/fourslash.ts

Lines changed: 92 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,8 @@ namespace FourSlash {
452452
}
453453

454454
private messageAtLastKnownMarker(message: string) {
455-
return "Marker: " + this.lastKnownMarker + "\n" + message;
455+
const locationDescription = this.lastKnownMarker ? this.lastKnownMarker : this.getLineColStringAtPosition(this.currentCaretPosition);
456+
return `At ${locationDescription}: ${message}`;
456457
}
457458

458459
private assertionMessageAtLastKnownMarker(msg: string) {
@@ -562,7 +563,7 @@ namespace FourSlash {
562563
}
563564

564565
public verifyGoToDefinitionIs(endMarker: string | string[]) {
565-
this.verifyGoToXWorker(endMarker instanceof Array ? endMarker : [endMarker], () => this.getGoToDefinition());
566+
this.verifyGoToXWorker(toArray(endMarker), () => this.getGoToDefinition());
566567
}
567568

568569
public verifyGoToDefinition(arg0: any, endMarkerNames?: string | string[]) {
@@ -582,7 +583,7 @@ namespace FourSlash {
582583
if (endMarkerNames) {
583584
this.verifyGoToXPlain(arg0, endMarkerNames, getDefs);
584585
}
585-
else if (arg0 instanceof Array) {
586+
else if (ts.isArray(arg0)) {
586587
const pairs: [string | string[], string | string[]][] = arg0;
587588
for (const [start, end] of pairs) {
588589
this.verifyGoToXPlain(start, end, getDefs);
@@ -599,13 +600,8 @@ namespace FourSlash {
599600
}
600601

601602
private verifyGoToXPlain(startMarkerNames: string | string[], endMarkerNames: string | string[], getDefs: () => ts.DefinitionInfo[] | undefined) {
602-
if (startMarkerNames instanceof Array) {
603-
for (const start of startMarkerNames) {
604-
this.verifyGoToXSingle(start, endMarkerNames, getDefs);
605-
}
606-
}
607-
else {
608-
this.verifyGoToXSingle(startMarkerNames, endMarkerNames, getDefs);
603+
for (const start of toArray(startMarkerNames)) {
604+
this.verifyGoToXSingle(start, endMarkerNames, getDefs);
609605
}
610606
}
611607

@@ -617,7 +613,7 @@ namespace FourSlash {
617613

618614
private verifyGoToXSingle(startMarkerName: string, endMarkerNames: string | string[], getDefs: () => ts.DefinitionInfo[] | undefined) {
619615
this.goToMarker(startMarkerName);
620-
this.verifyGoToXWorker(endMarkerNames instanceof Array ? endMarkerNames : [endMarkerNames], getDefs);
616+
this.verifyGoToXWorker(toArray(endMarkerNames), getDefs);
621617
}
622618

623619
private verifyGoToXWorker(endMarkers: string[], getDefs: () => ts.DefinitionInfo[] | undefined) {
@@ -899,8 +895,74 @@ namespace FourSlash {
899895
}
900896
}
901897

902-
public verifyRangesWithSameTextReferenceEachOther() {
903-
this.rangesByText().forEach(ranges => this.verifyRangesReferenceEachOther(ranges));
898+
public verifyReferenceGroups(startRanges: Range | Range[], parts: Array<{ definition: string, ranges: Range[] }>): void {
899+
interface ReferenceJson { definition: string; ranges: ts.ReferenceEntry[]; }
900+
type ReferencesJson = ReferenceJson[];
901+
const fullExpected = parts.map<ReferenceJson>(({ definition, ranges }) => ({ definition, ranges: ranges.map(rangeToReferenceEntry) }));
902+
903+
for (const startRange of toArray(startRanges)) {
904+
this.goToRangeStart(startRange);
905+
const fullActual = this.findReferencesAtCaret().map<ReferenceJson>(({ definition, references }) => ({
906+
definition: definition.displayParts.map(d => d.text).join(""),
907+
ranges: references
908+
}));
909+
this.assertObjectsEqual<ReferencesJson>(fullActual, fullExpected);
910+
}
911+
912+
function rangeToReferenceEntry(r: Range) {
913+
let { isWriteAccess, isDefinition } = (r.marker && r.marker.data) || { isWriteAccess: false, isDefinition: false };
914+
isWriteAccess = !!isWriteAccess; isDefinition = !!isDefinition;
915+
return { fileName: r.fileName, textSpan: { start: r.start, length: r.end - r.start }, isWriteAccess, isDefinition }
916+
}
917+
}
918+
919+
public verifyNoReferences(markerNameOrRange?: string | Range) {
920+
if (markerNameOrRange) {
921+
if (typeof markerNameOrRange === "string") {
922+
this.goToMarker(markerNameOrRange);
923+
}
924+
else {
925+
this.goToRangeStart(markerNameOrRange);
926+
}
927+
}
928+
929+
const refs = this.getReferencesAtCaret();
930+
if (refs && refs.length) {
931+
console.log(refs);
932+
this.raiseError("Expected getReferences to fail");
933+
}
934+
}
935+
936+
public verifySingleReferenceGroup(definition: string, ranges?: Range[]) {
937+
ranges = ranges || this.getRanges();
938+
this.verifyReferenceGroups(ranges, [{ definition, ranges }]);
939+
}
940+
941+
private assertObjectsEqual<T>(fullActual: T, fullExpected: T, msgPrefix = ""): void {
942+
const recur = <U>(actual: U, expected: U, path: string) => {
943+
const fail = (msg: string) => {
944+
console.log("Expected:", stringify(fullExpected));
945+
console.log("Actual: ", stringify(fullActual));
946+
this.raiseError(`${msgPrefix}At ${path}: ${msg}`);
947+
};
948+
949+
for (const key in actual) if (ts.hasProperty(actual as any, key)) {
950+
const ak = actual[key], ek = expected[key];
951+
if (typeof ak === "object" && typeof ek === "object") {
952+
recur(ak, ek, path ? path + "." + key : key);
953+
}
954+
else if (ak !== ek) {
955+
fail(`Expected '${key}' to be '${ek}', got '${ak}'`);
956+
}
957+
}
958+
for (const key in expected) if (ts.hasProperty(expected as any, key)) {
959+
if (!ts.hasProperty(actual as any, key)) {
960+
fail(`${msgPrefix}Missing property '${key}'`);
961+
}
962+
}
963+
};
964+
recur(fullActual, fullExpected, "");
965+
904966
}
905967

906968
public verifyDisplayPartsOfReferencedSymbol(expected: ts.SymbolDisplayPart[]) {
@@ -974,7 +1036,7 @@ namespace FourSlash {
9741036
public verifyQuickInfos(namesAndTexts: { [name: string]: string | [string, string] }) {
9751037
for (const name in namesAndTexts) if (ts.hasProperty(namesAndTexts, name)) {
9761038
const text = namesAndTexts[name];
977-
if (text instanceof Array) {
1039+
if (ts.isArray(text)) {
9781040
assert(text.length === 2);
9791041
const [expectedText, expectedDocumentation] = text;
9801042
this.verifyQuickInfoAt(name, expectedText, expectedDocumentation);
@@ -1411,13 +1473,6 @@ namespace FourSlash {
14111473
Harness.IO.log(membersString);
14121474
}
14131475

1414-
public printReferences() {
1415-
const references = this.getReferencesAtCaret();
1416-
ts.forEach(references, entry => {
1417-
Harness.IO.log(stringify(entry));
1418-
});
1419-
}
1420-
14211476
public printContext() {
14221477
ts.forEach(this.languageServiceAdapterHost.getFilenames(), Harness.IO.log);
14231478
}
@@ -3082,6 +3137,10 @@ ${code}
30823137
}
30833138
return ts.arrayFrom(set.keys());
30843139
}
3140+
3141+
function toArray<T>(x: T | T[]): T[] {
3142+
return ts.isArray(x) ? x : [x];
3143+
}
30853144
}
30863145

30873146
namespace FourSlashInterface {
@@ -3346,6 +3405,18 @@ namespace FourSlashInterface {
33463405
this.state.verifyReferencesOf(start, references);
33473406
}
33483407

3408+
public referenceGroups(startRanges: FourSlash.Range[], parts: Array<{ definition: string, ranges: FourSlash.Range[] }>) {
3409+
this.state.verifyReferenceGroups(startRanges, parts);
3410+
}
3411+
3412+
public noReferences(markerNameOrRange?: string | FourSlash.Range) {
3413+
this.state.verifyNoReferences(markerNameOrRange);
3414+
}
3415+
3416+
public singleReferenceGroup(definition: string, ranges?: FourSlash.Range[]) {
3417+
this.state.verifySingleReferenceGroup(definition, ranges);
3418+
}
3419+
33493420
public rangesReferenceEachOther(ranges?: FourSlash.Range[]) {
33503421
this.state.verifyRangesReferenceEachOther(ranges);
33513422
}
@@ -3354,10 +3425,6 @@ namespace FourSlashInterface {
33543425
this.state.verifyDisplayPartsOfReferencedSymbol(expected);
33553426
}
33563427

3357-
public rangesWithSameTextReferenceEachOther() {
3358-
this.state.verifyRangesWithSameTextReferenceEachOther();
3359-
}
3360-
33613428
public currentParameterHelpArgumentNameIs(name: string) {
33623429
this.state.verifyCurrentParameterHelpName(name);
33633430
}
@@ -3660,10 +3727,6 @@ namespace FourSlashInterface {
36603727
this.state.printNavigationBar();
36613728
}
36623729

3663-
public printReferences() {
3664-
this.state.printReferences();
3665-
}
3666-
36673730
public printContext() {
36683731
this.state.printContext();
36693732
}

src/services/findAllReferences.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ namespace ts.FindAllReferences {
55
return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, isForRename);
66
}
77

8+
export function convertReferences(referenceSymbols: ReferencedSymbol[]): ReferenceEntry[] {
9+
return referenceSymbols && flatMap(referenceSymbols, r => r.references);
10+
}
11+
812
export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings?: boolean, findInComments?: boolean, isForRename?: boolean, implementations?: boolean): ReferencedSymbol[] | undefined {
913
if (!implementations) {
1014
const special = getReferencedSymbolsSpecial(node, sourceFiles, typeChecker, cancellationToken);
@@ -411,7 +415,6 @@ namespace ts.FindAllReferences {
411415
textSpan: createTextSpan(0, 1),
412416
displayParts: [{ text: name, kind: ScriptElementKind.keyword }]
413417
}
414-
415418
const references: ReferenceEntry[] = [];
416419
for (const sourceFile of sourceFiles) {
417420
cancellationToken.throwIfCancellationRequested();
@@ -1316,20 +1319,6 @@ namespace ts.FindAllReferences {
13161319
return meaning;
13171320
}
13181321

1319-
export function convertReferences(referenceSymbols: ReferencedSymbol[]): ReferenceEntry[] {
1320-
if (!referenceSymbols) {
1321-
return undefined;
1322-
}
1323-
1324-
const referenceEntries: ReferenceEntry[] = [];
1325-
1326-
for (const referenceSymbol of referenceSymbols) {
1327-
addRange(referenceEntries, referenceSymbol.references);
1328-
}
1329-
1330-
return referenceEntries;
1331-
}
1332-
13331322
function isImplementation(node: Node): boolean {
13341323
if (!node) {
13351324
return false;

src/services/services.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,7 +1415,6 @@ namespace ts {
14151415

14161416
function findReferences(fileName: string, position: number): ReferencedSymbol[] {
14171417
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false);
1418-
14191418
// Only include referenced symbols that have a valid definition.
14201419
return filter(referencedSymbols, rs => !!rs.definition);
14211420
}
@@ -2015,9 +2014,5 @@ namespace ts {
20152014
throw new Error("getDefaultLibFilePath is only supported when consumed as a node module. ");
20162015
}
20172016

2018-
function initializeServices() {
2019-
objectAllocator = getServicesObjectAllocator();
2020-
}
2021-
2022-
initializeServices();
2017+
objectAllocator = getServicesObjectAllocator();
20232018
}

tests/cases/fourslash/ambientShorthandFindAllRefs.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,18 @@
44
////declare module "jquery";
55

66
// @Filename: user.ts
7-
////import {[|x|]} from "jquery";
7+
////import {[|{| "isWriteAccess": true, "isDefinition": true |}x|]} from "jquery";
88

99
// @Filename: user2.ts
10-
////import {[|x|]} from "jquery";
10+
////import {[|{| "isWriteAccess": true, "isDefinition": true |}x|]} from "jquery";
1111

12-
verify.rangesReferenceEachOther();
12+
const ranges = test.ranges();
13+
const [r0, r1] = ranges;
14+
verify.referenceGroups(r0, [
15+
{ definition: "import x", ranges: [r0] },
16+
{ definition: 'module "jquery"', ranges: [r1] }
17+
]);
18+
verify.referenceGroups(r1, [
19+
{ definition: 'module "jquery"', ranges: [r0] },
20+
{ definition: "import x", ranges: [r1] }
21+
]);

tests/cases/fourslash/cancellationWhenfindingAllRefsOnDefinition.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
////
88
//// }
99
////
10-
//// public /**/[|start|](){
10+
//// public /**/[|{| "isWriteAccess": true, "isDefinition": true |}start|](){
1111
//// return this;
1212
//// }
1313
////
@@ -23,11 +23,21 @@
2323
////second.[|start|]();
2424
////second.stop();
2525

26-
verify.rangesReferenceEachOther();
26+
checkRefs();
2727

2828
cancellation.setCancelled();
29-
verifyOperationIsCancelled(() => verify.rangesReferenceEachOther());
29+
verifyOperationIsCancelled(checkRefs);
3030

3131
// verify that internal state is still correct
3232
cancellation.resetCancelled();
33-
verify.rangesReferenceEachOther();
33+
checkRefs();
34+
35+
function checkRefs() {
36+
const ranges = test.ranges();
37+
const [r0, r1] = ranges;
38+
verify.referenceGroups(r0, [{ definition: "(method) Test.start(): this", ranges }]);
39+
verify.referenceGroups(r1, [
40+
{ definition: "(method) Second.Test.start(): Second.Test", ranges: [r0] },
41+
{ definition: "(method) Second.Test.start(): Second.Test", ranges: [r1] }
42+
]);
43+
}

tests/cases/fourslash/findAllReferencesOfConstructor.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@
4141
////class d extends a.C { constructor() { [|super|](); }
4242

4343
const ranges = test.ranges();
44-
for (const ctr of ranges.slice(0, 3)) {
45-
verify.referencesOf(ctr, ranges);
46-
}
44+
const [r0, r1, r2] = ranges;
45+
verify.referenceGroups([r0, r2], [{ definition: "constructor C(n: number): C (+1 overload)", ranges }]);
46+
verify.referenceGroups(r1, [{ definition: "constructor C(): C (+1 overload)", ranges }]);

tests/cases/fourslash/findAllReferencesOfConstructor_badOverload.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
//// [|constructor|](){}
66
////}
77

8-
verify.rangesReferenceEachOther();
8+
verify.singleReferenceGroup("constructor C(n: number): C");
Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
/// <reference path='fourslash.ts'/>
22

3-
43
////interface I {
5-
//// ["[|prop1|]"]: () => void;
4+
//// ["[|{| "isDefinition": true |}prop1|]"]: () => void;
65
////}
76
////
87
////class C implements I {
9-
//// ["[|prop1|]"]: any;
8+
//// ["[|{| "isDefinition": true |}prop1|]"]: any;
109
////}
1110
////
1211
////var x: I = {
13-
//// ["[|prop1|]"]: function () { },
12+
//// ["[|{| "isDefinition": true |}prop1|]"]: function () { },
1413
////}
1514

16-
verify.rangesReferenceEachOther();
15+
const ranges = test.ranges();
16+
const [r0, r1, r2] = ranges;
17+
verify.referenceGroups(r0, [{ definition: '(property) I[["prop1"]]: () => void', ranges }]);
18+
verify.referenceGroups(r1, [
19+
{ definition: '(property) I[["prop1"]]: () => void', ranges: [r0, r2] },
20+
{ definition: '(property) C[["prop1"]]: any', ranges: [r1] }
21+
]);
22+
verify.referenceGroups(r2, [
23+
{ definition: '(property) I[["prop1"]]: () => void', ranges: [r0, r1] },
24+
{ definition: '(property) ["prop1"]: () => void', ranges: [r2] }
25+
]);
26+
Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
/// <reference path='fourslash.ts'/>
22

33
////interface I {
4-
//// [[|42|]](): void;
4+
//// [[|{| "isDefinition": true |}42|]](): void;
55
////}
66
////
77
////class C implements I {
8-
//// [[|42|]]: any;
8+
//// [[|{| "isDefinition": true |}42|]]: any;
99
////}
1010
////
1111
////var x: I = {
12-
//// ["[|42|]"]: function () { }
12+
//// ["[|{| "isDefinition": true |}42|]"]: function () { }
1313
////}
1414

15-
verify.rangesReferenceEachOther();
15+
const ranges = test.ranges();
16+
const [r0, r1, r2] = ranges;
17+
verify.referenceGroups(r0, [{ definition: "(method) I[[42]](): void", ranges }]);
18+
verify.referenceGroups(r1, [
19+
{ definition: "(method) I[[42]](): void", ranges: [r0, r2] },
20+
{ definition: "(property) C[[42]]: any", ranges: [r1] }
21+
]);
22+
verify.referenceGroups(r2, [
23+
{ definition: "(method) I[[42]](): void", ranges: [r0, r1] },
24+
{ definition: '(property) ["42"]: () => void', ranges: [r2] }
25+
]);

0 commit comments

Comments
 (0)