Skip to content

Commit e1f8aa7

Browse files
Merge pull request #632 from Microsoft/getOccurrencesSuperThanksForAsking
Get occurrences for 'super' keywords
2 parents dd5d216 + 83c35ad commit e1f8aa7

File tree

6 files changed

+247
-31
lines changed

6 files changed

+247
-31
lines changed

src/compiler/parser.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ module ts {
411411
while (true) {
412412
node = node.parent;
413413
if (!node) {
414-
return node;
414+
return undefined;
415415
}
416416
switch (node.kind) {
417417
case SyntaxKind.ArrowFunction:
@@ -434,6 +434,23 @@ module ts {
434434
}
435435
}
436436

437+
export function getSuperContainer(node: Node): Node {
438+
while (true) {
439+
node = node.parent;
440+
if (!node) {
441+
return undefined;
442+
}
443+
switch (node.kind) {
444+
case SyntaxKind.Property:
445+
case SyntaxKind.Method:
446+
case SyntaxKind.Constructor:
447+
case SyntaxKind.GetAccessor:
448+
case SyntaxKind.SetAccessor:
449+
return node;
450+
}
451+
}
452+
}
453+
437454
export function hasRestParameters(s: SignatureDeclaration): boolean {
438455
return s.parameters.length > 0 && (s.parameters[s.parameters.length - 1].flags & NodeFlags.Rest) !== 0;
439456
}

src/services/services.ts

Lines changed: 70 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2134,7 +2134,6 @@ module ts {
21342134
return result;
21352135
}
21362136

2137-
/// Find references
21382137
function getOccurrencesAtPosition(filename: string, position: number): ReferenceEntry[] {
21392138
synchronizeHostData();
21402139

@@ -2146,7 +2145,7 @@ module ts {
21462145
return undefined;
21472146
}
21482147

2149-
if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword ||
2148+
if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword ||
21502149
isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || isNameOfExternalModuleImportOrDeclaration(node)) {
21512150
return getReferencesForNode(node, [sourceFile]);
21522151
}
@@ -2378,7 +2377,9 @@ module ts {
23782377
}
23792378

23802379
if (node.kind !== SyntaxKind.Identifier &&
2381-
node.kind !== SyntaxKind.ThisKeyword &&
2380+
// TODO (drosen): This should be enabled in a later release - currently breaks rename.
2381+
//node.kind !== SyntaxKind.ThisKeyword &&
2382+
//node.kind !== SyntaxKind.SuperKeyword &&
23822383
!isLiteralNameOfPropertyDeclarationOrIndexAccess(node) &&
23832384
!isNameOfExternalModuleImportOrDeclaration(node)) {
23842385
return undefined;
@@ -2406,6 +2407,10 @@ module ts {
24062407
return getReferencesForThisKeyword(node, sourceFiles);
24072408
}
24082409

2410+
if (node.kind === SyntaxKind.SuperKeyword) {
2411+
return getReferencesForSuperKeyword(node);
2412+
}
2413+
24092414
var symbol = typeInfoResolver.getSymbolInfo(node);
24102415

24112416
// Could not find a symbol e.g. unknown identifier
@@ -2627,32 +2632,75 @@ module ts {
26272632
}
26282633
}
26292634

2630-
function getReferencesForThisKeyword(thisKeyword: Node, sourceFiles: SourceFile[]) {
2631-
// Get the owner" of the 'this' keyword.
2632-
var thisContainer = getThisContainer(thisKeyword, /* includeArrowFunctions */ false);
2635+
function getReferencesForSuperKeyword(superKeyword: Node): ReferenceEntry[]{
2636+
var searchSpaceNode = getSuperContainer(superKeyword);
2637+
if (!searchSpaceNode) {
2638+
return undefined;
2639+
}
2640+
// Whether 'super' occurs in a static context within a class.
2641+
var staticFlag = NodeFlags.Static;
2642+
2643+
switch (searchSpaceNode.kind) {
2644+
case SyntaxKind.Property:
2645+
case SyntaxKind.Method:
2646+
case SyntaxKind.Constructor:
2647+
case SyntaxKind.GetAccessor:
2648+
case SyntaxKind.SetAccessor:
2649+
staticFlag &= searchSpaceNode.flags;
2650+
searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class
2651+
break;
2652+
default:
2653+
return undefined;
2654+
}
2655+
2656+
var result: ReferenceEntry[] = [];
26332657

2634-
var searchSpaceNode: Node;
2658+
var sourceFile = searchSpaceNode.getSourceFile();
2659+
var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "super", searchSpaceNode.getStart(), searchSpaceNode.getEnd());
2660+
forEach(possiblePositions, position => {
2661+
cancellationToken.throwIfCancellationRequested();
26352662

2636-
// Whether 'this' occurs in a static context within a class;
2663+
var node = getNodeAtPosition(sourceFile, position);
2664+
2665+
if (!node || node.kind !== SyntaxKind.SuperKeyword) {
2666+
return;
2667+
}
2668+
2669+
var container = getSuperContainer(node);
2670+
2671+
// If we have a 'super' container, we must have an enclosing class.
2672+
// Now make sure the owning class is the same as the search-space
2673+
// and has the same static qualifier as the original 'super's owner.
2674+
if (container && (NodeFlags.Static & container.flags) === staticFlag && container.parent.symbol === searchSpaceNode.symbol) {
2675+
result.push(getReferenceEntryFromNode(node));
2676+
}
2677+
});
2678+
2679+
return result;
2680+
}
2681+
2682+
function getReferencesForThisKeyword(thisOrSuperKeyword: Node, sourceFiles: SourceFile[]): ReferenceEntry[] {
2683+
var searchSpaceNode = getThisContainer(thisOrSuperKeyword, /* includeArrowFunctions */ false);
2684+
2685+
// Whether 'this' occurs in a static context within a class.
26372686
var staticFlag = NodeFlags.Static;
26382687

2639-
switch (thisContainer.kind) {
2688+
switch (searchSpaceNode.kind) {
26402689
case SyntaxKind.Property:
26412690
case SyntaxKind.Method:
26422691
case SyntaxKind.Constructor:
26432692
case SyntaxKind.GetAccessor:
26442693
case SyntaxKind.SetAccessor:
2645-
searchSpaceNode = thisContainer.parent; // should be the owning class
2646-
staticFlag &= thisContainer.flags
2694+
staticFlag &= searchSpaceNode.flags
2695+
searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class
26472696
break;
26482697
case SyntaxKind.SourceFile:
2649-
if (isExternalModule(<SourceFile>thisContainer)) {
2698+
if (isExternalModule(<SourceFile>searchSpaceNode)) {
26502699
return undefined;
26512700
}
26522701
// Fall through
26532702
case SyntaxKind.FunctionDeclaration:
26542703
case SyntaxKind.FunctionExpression:
2655-
searchSpaceNode = thisContainer;
26562704
break;
26572705
default:
26582706
return undefined;
@@ -2683,31 +2731,24 @@ module ts {
26832731
return;
26842732
}
26852733

2686-
// Get the owner of the 'this' keyword.
2687-
// This *should* be a node that occurs somewhere within searchSpaceNode.
26882734
var container = getThisContainer(node, /* includeArrowFunctions */ false);
26892735

2690-
switch (container.kind) {
2691-
case SyntaxKind.Property:
2692-
case SyntaxKind.Method:
2693-
case SyntaxKind.Constructor:
2694-
case SyntaxKind.GetAccessor:
2695-
case SyntaxKind.SetAccessor:
2696-
// Make sure the container belongs to the same class
2697-
// and has the appropriate static modifier from the original container.
2698-
if (searchSpaceNode.symbol === container.parent.symbol && (container.flags & NodeFlags.Static) === staticFlag) {
2736+
switch (searchSpaceNode.kind) {
2737+
case SyntaxKind.FunctionExpression:
2738+
case SyntaxKind.FunctionDeclaration:
2739+
if (searchSpaceNode.symbol === container.symbol) {
26992740
result.push(getReferenceEntryFromNode(node));
27002741
}
27012742
break;
2702-
case SyntaxKind.FunctionDeclaration:
2703-
case SyntaxKind.FunctionExpression:
2704-
if (searchSpaceNode.symbol === container.symbol) {
2743+
case SyntaxKind.ClassDeclaration:
2744+
// Make sure the container belongs to the same class
2745+
// and has the appropriate static modifier from the original container.
2746+
if (container.parent && searchSpaceNode.symbol === container.parent.symbol && (container.flags & NodeFlags.Static) === staticFlag) {
27052747
result.push(getReferenceEntryFromNode(node));
27062748
}
27072749
break;
27082750
case SyntaxKind.SourceFile:
2709-
// Add all 'this' keywords that belong to the top-level scope.
2710-
if (searchSpaceNode.kind === SyntaxKind.SourceFile && !isExternalModule(<SourceFile>searchSpaceNode)) {
2751+
if (container.kind === SyntaxKind.SourceFile && !isExternalModule(<SourceFile>container)) {
27112752
result.push(getReferenceEntryFromNode(node));
27122753
}
27132754
break;

tests/cases/fourslash/findAllRefsThisKeywordMultipleFiles.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@
1212

1313
goTo.file("file1.ts");
1414
goTo.marker();
15-
verify.referencesCountIs(8);
15+
16+
// TODO (drosen): The CURRENT behavior is that findAllRefs doesn't work on 'this' or 'super' keywords.
17+
// This should change down the line.
18+
verify.referencesCountIs(0);
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////class SuperType {
4+
//// superMethod() {
5+
//// }
6+
////
7+
//// static superStaticMethod() {
8+
//// return 10;
9+
//// }
10+
////}
11+
////
12+
////class SubType extends SuperType {
13+
//// public prop1 = [|s/**/uper|].superMethod;
14+
//// private prop2 = [|super|].superMethod;
15+
////
16+
//// constructor() {
17+
//// [|super|]();
18+
//// }
19+
////
20+
//// public method1() {
21+
//// return [|super|].superMethod();
22+
//// }
23+
////
24+
//// private method2() {
25+
//// return [|super|].superMethod();
26+
//// }
27+
////
28+
//// public method3() {
29+
//// var x = () => [|super|].superMethod();
30+
////
31+
//// // Bad but still gets highlighted
32+
//// function f() {
33+
//// [|super|].superMethod();
34+
//// }
35+
//// }
36+
////
37+
//// // Bad but still gets highlighted.
38+
//// public static statProp1 = super.superStaticMethod;
39+
////
40+
//// public static staticMethod1() {
41+
//// return super.superStaticMethod();
42+
//// }
43+
////
44+
//// private static staticMethod2() {
45+
//// return super.superStaticMethod();
46+
//// }
47+
////
48+
//// // Are not actually 'super' keywords.
49+
//// super = 10;
50+
//// static super = 20;
51+
////}
52+
53+
test.ranges().forEach(r => {
54+
goTo.position(r.start);
55+
56+
test.ranges().forEach(range => {
57+
verify.occurrencesAtPositionContains(range, false);
58+
});
59+
});
60+
61+
goTo.marker();
62+
test.ranges().forEach(range => {
63+
verify.occurrencesAtPositionContains(range, false);
64+
});
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////class SuperType {
4+
//// superMethod() {
5+
//// }
6+
////
7+
//// static superStaticMethod() {
8+
//// return 10;
9+
//// }
10+
////}
11+
////
12+
////class SubType extends SuperType {
13+
//// public prop1 = super.superMethod;
14+
//// private prop2 = super.superMethod;
15+
////
16+
//// constructor() {
17+
//// super();
18+
//// }
19+
////
20+
//// public method1() {
21+
//// return super.superMethod();
22+
//// }
23+
////
24+
//// private method2() {
25+
//// return super.superMethod();
26+
//// }
27+
////
28+
//// public method3() {
29+
//// var x = () => super.superMethod();
30+
////
31+
//// // Bad but still gets highlighted
32+
//// function f() {
33+
//// super.superMethod();
34+
//// }
35+
//// }
36+
////
37+
//// // Bad but still gets highlighted.
38+
//// public static statProp1 = [|super|].superStaticMethod;
39+
////
40+
//// public static staticMethod1() {
41+
//// return [|super|].superStaticMethod();
42+
//// }
43+
////
44+
//// private static staticMethod2() {
45+
//// return [|supe/**/r|].superStaticMethod();
46+
//// }
47+
////
48+
//// // Are not actually 'super' keywords.
49+
//// super = 10;
50+
//// static super = 20;
51+
////}
52+
53+
test.ranges().forEach(r => {
54+
goTo.position(r.start);
55+
56+
test.ranges().forEach(range => {
57+
verify.occurrencesAtPositionContains(range, false);
58+
});
59+
});
60+
61+
goTo.marker();
62+
test.ranges().forEach(range => {
63+
verify.occurrencesAtPositionContains(range, false);
64+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////function f(x = [|super|]) {
4+
//// [|super|];
5+
////}
6+
////
7+
////module M {
8+
//// [|super|];
9+
//// function f(x = [|super|]) {
10+
//// [|super|];
11+
//// }
12+
////
13+
//// class A {
14+
//// }
15+
////
16+
//// class B extends A {
17+
//// constructor() {
18+
//// super();
19+
//// }
20+
//// }
21+
////}
22+
23+
test.ranges().forEach(r => {
24+
goTo.position(r.start);
25+
26+
verify.occurrencesAtPositionCount(0);
27+
});

0 commit comments

Comments
 (0)