Skip to content

Commit e6e9979

Browse files
getRefs/getOccs support for 'this' keyword.
1 parent 492e1c5 commit e6e9979

File tree

3 files changed

+171
-79
lines changed

3 files changed

+171
-79
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3449,29 +3449,6 @@ module ts {
34493449
return getTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol));
34503450
}
34513451

3452-
function getThisContainer(node: Node): Node {
3453-
while (true) {
3454-
node = node.parent;
3455-
if (!node) {
3456-
return node;
3457-
}
3458-
switch (node.kind) {
3459-
case SyntaxKind.FunctionDeclaration:
3460-
case SyntaxKind.FunctionExpression:
3461-
case SyntaxKind.ModuleDeclaration:
3462-
case SyntaxKind.Property:
3463-
case SyntaxKind.Method:
3464-
case SyntaxKind.Constructor:
3465-
case SyntaxKind.GetAccessor:
3466-
case SyntaxKind.SetAccessor:
3467-
case SyntaxKind.EnumDeclaration:
3468-
case SyntaxKind.SourceFile:
3469-
case SyntaxKind.ArrowFunction:
3470-
return node;
3471-
}
3472-
}
3473-
}
3474-
34753452
function captureLexicalThis(node: Node, container: Node): void {
34763453
var classNode = container.parent && container.parent.kind === SyntaxKind.ClassDeclaration ? container.parent : undefined;
34773454
getNodeLinks(node).flags |= NodeCheckFlags.LexicalThis;
@@ -3484,11 +3461,11 @@ module ts {
34843461
}
34853462

34863463
function checkThisExpression(node: Node): Type {
3487-
var container = getThisContainer(node);
3464+
var container = getThisContainerOrArrowFunction(node);
34883465
var needToCaptureLexicalThis = false;
34893466
// skip arrow functions
34903467
while (container.kind === SyntaxKind.ArrowFunction) {
3491-
container = getThisContainer(container);
3468+
container = getThisContainerOrArrowFunction(container);
34923469
needToCaptureLexicalThis = true;
34933470
}
34943471

src/compiler/parser.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,29 @@ module ts {
407407
}
408408
}
409409

410+
export function getThisContainerOrArrowFunction(node: Node): Node {
411+
while (true) {
412+
node = node.parent;
413+
if (!node) {
414+
return node;
415+
}
416+
switch (node.kind) {
417+
case SyntaxKind.FunctionDeclaration:
418+
case SyntaxKind.FunctionExpression:
419+
case SyntaxKind.ModuleDeclaration:
420+
case SyntaxKind.Property:
421+
case SyntaxKind.Method:
422+
case SyntaxKind.Constructor:
423+
case SyntaxKind.GetAccessor:
424+
case SyntaxKind.SetAccessor:
425+
case SyntaxKind.EnumDeclaration:
426+
case SyntaxKind.SourceFile:
427+
case SyntaxKind.ArrowFunction:
428+
return node;
429+
}
430+
}
431+
}
432+
410433
export function hasRestParameters(s: SignatureDeclaration): boolean {
411434
return s.parameters.length > 0 && (s.parameters[s.parameters.length - 1].flags & NodeFlags.Rest) !== 0;
412435
}

src/services/services.ts

Lines changed: 146 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2146,7 +2146,8 @@ module ts {
21462146
return undefined;
21472147
}
21482148

2149-
if (node.kind === SyntaxKind.Identifier || isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || isNameOfExternalModuleImportOrDeclaration(node)) {
2149+
if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword ||
2150+
isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || isNameOfExternalModuleImportOrDeclaration(node)) {
21502151
return getReferencesForNode(node, [sourceFile]);
21512152
}
21522153

@@ -2243,7 +2244,7 @@ module ts {
22432244
}
22442245

22452246
// Ordinary case: just highlight the keyword.
2246-
result.push(keywordToReferenceEntry(keywords[i]));
2247+
result.push(getReferenceEntryFromNode(keywords[i]));
22472248
}
22482249

22492250
return result;
@@ -2262,7 +2263,7 @@ module ts {
22622263
pushKeywordIf(keywords, returnStatement.getFirstToken(), SyntaxKind.ReturnKeyword);
22632264
});
22642265

2265-
return map(keywords, keywordToReferenceEntry);
2266+
return map(keywords, getReferenceEntryFromNode);
22662267
}
22672268

22682269
function getTryCatchFinallyOccurrences(tryStatement: TryStatement): ReferenceEntry[] {
@@ -2278,7 +2279,7 @@ module ts {
22782279
pushKeywordIf(keywords, tryStatement.finallyBlock.getFirstToken(), SyntaxKind.FinallyKeyword);
22792280
}
22802281

2281-
return map(keywords, keywordToReferenceEntry);
2282+
return map(keywords, getReferenceEntryFromNode);
22822283
}
22832284

22842285
function getSwitchCaseDefaultOccurrences(switchStatement: SwitchStatement) {
@@ -2314,7 +2315,7 @@ module ts {
23142315
});
23152316
});
23162317

2317-
return map(keywords, keywordToReferenceEntry);
2318+
return map(keywords, getReferenceEntryFromNode);
23182319
}
23192320

23202321
function getBreakStatementOccurences(breakStatement: BreakOrContinueStatement): ReferenceEntry[]{
@@ -2363,10 +2364,6 @@ module ts {
23632364

23642365
return false;
23652366
}
2366-
2367-
function keywordToReferenceEntry(keyword: Node): ReferenceEntry {
2368-
return new ReferenceEntry(filename, TypeScript.TextSpan.fromBounds(keyword.getStart(), keyword.end), /* isWriteAccess */ false);
2369-
}
23702367
}
23712368

23722369
function getReferencesAtPosition(filename: string, position: number): ReferenceEntry[] {
@@ -2381,6 +2378,7 @@ module ts {
23812378
}
23822379

23832380
if (node.kind !== SyntaxKind.Identifier &&
2381+
node.kind !== SyntaxKind.ThisKeyword &&
23842382
!isLiteralNameOfPropertyDeclarationOrIndexAccess(node) &&
23852383
!isNameOfExternalModuleImportOrDeclaration(node)) {
23862384
return undefined;
@@ -2396,21 +2394,25 @@ module ts {
23962394
var labelDefinition = getTargetLabel((<BreakOrContinueStatement>node.parent), (<Identifier>node).text);
23972395
// if we have a label definition, look within its statement for references, if not, then
23982396
// the label is undefined, just return a set of one for the current node.
2399-
return labelDefinition ? getLabelReferencesInNode(labelDefinition.parent, labelDefinition) : [getReferenceEntry(node)];
2397+
return labelDefinition ? getLabelReferencesInNode(labelDefinition.parent, labelDefinition) : [getReferenceEntryFromNode(node)];
24002398
}
24012399
else {
24022400
// it is a label definition and not a target, search within the parent labeledStatement
24032401
return getLabelReferencesInNode(node.parent, <Identifier>node);
24042402
}
24052403
}
24062404

2405+
if (node.kind === SyntaxKind.ThisKeyword) {
2406+
return getReferencesForThisKeyword(node, sourceFiles);
2407+
}
2408+
24072409
var symbol = typeInfoResolver.getSymbolInfo(node);
24082410

24092411
// Could not find a symbol e.g. unknown identifier
24102412
if (!symbol) {
24112413
// Even if we did not find a symbol, we have an identifer, so there is at least
2412-
// one reference that we know of. return than instead of undefined.
2413-
return [getReferenceEntry(node)];
2414+
// one reference that we know of. return that instead of undefined.
2415+
return [getReferenceEntryFromNode(node)];
24142416
}
24152417

24162418
// the symbol was an internal symbol and does not have a declaration e.g.undefined symbol
@@ -2554,7 +2556,7 @@ module ts {
25542556
// Only pick labels that are either the target label, or have a target that is the target label
25552557
if (node === targetLabel ||
25562558
(isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel)) {
2557-
result.push(getReferenceEntry(node));
2559+
result.push(getReferenceEntryFromNode(node));
25582560
}
25592561
});
25602562
return result;
@@ -2619,7 +2621,97 @@ module ts {
26192621
}
26202622

26212623
if (isRelatableToSearchSet(searchSymbols, referenceSymbol, referenceLocation)) {
2622-
result.push(getReferenceEntry(referenceLocation));
2624+
result.push(getReferenceEntryFromNode(referenceLocation));
2625+
}
2626+
});
2627+
}
2628+
}
2629+
2630+
function getReferencesForThisKeyword(thisKeyword: Node, sourceFiles: SourceFile[]) {
2631+
// Get the owner" of the 'this' keyword.
2632+
var thisContainer = thisKeyword;
2633+
do {
2634+
thisContainer = getThisContainerOrArrowFunction(thisContainer);
2635+
} while (thisContainer.kind === SyntaxKind.ArrowFunction);
2636+
2637+
var searchSpaceNode: Node;
2638+
2639+
// Whether 'this' occurs in a static context within a class;
2640+
var staticFlag = NodeFlags.Static;
2641+
2642+
switch (thisContainer.kind) {
2643+
case SyntaxKind.Property:
2644+
case SyntaxKind.Method:
2645+
case SyntaxKind.Constructor:
2646+
case SyntaxKind.GetAccessor:
2647+
case SyntaxKind.SetAccessor:
2648+
searchSpaceNode = thisContainer.parent; // should be the owning class
2649+
staticFlag &= thisContainer.flags
2650+
break;
2651+
case SyntaxKind.FunctionDeclaration:
2652+
case SyntaxKind.FunctionExpression:
2653+
case SyntaxKind.SourceFile:
2654+
searchSpaceNode = thisContainer;
2655+
break;
2656+
default:
2657+
return undefined;
2658+
}
2659+
2660+
var result: ReferenceEntry[] = [];
2661+
2662+
if (searchSpaceNode.kind === SyntaxKind.SourceFile) {
2663+
forEach(sourceFiles, sourceFile => {
2664+
var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", sourceFile.getStart(), sourceFile.getEnd());
2665+
getThisReferencesInFile(sourceFile, sourceFile, possiblePositions, result);
2666+
});
2667+
}
2668+
else {
2669+
var sourceFile = searchSpaceNode.getSourceFile();
2670+
var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", searchSpaceNode.getStart(), searchSpaceNode.getEnd());
2671+
getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, result);
2672+
}
2673+
2674+
return result;
2675+
2676+
function getThisReferencesInFile(sourceFile: SourceFile, searchSpaceNode: Node, possiblePositions: number[], result: ReferenceEntry[]): void {
2677+
forEach(possiblePositions, position => {
2678+
cancellationToken.throwIfCancellationRequested();
2679+
2680+
var node = getNodeAtPosition(sourceFile, position);
2681+
if (!node || node.kind !== SyntaxKind.ThisKeyword) {
2682+
return;
2683+
}
2684+
2685+
// Get the owner" of the 'this' keyword.
2686+
var container = node;
2687+
do {
2688+
container = getThisContainerOrArrowFunction(container);
2689+
} while (container.kind === SyntaxKind.ArrowFunction);
2690+
2691+
switch (container.kind) {
2692+
case SyntaxKind.Property:
2693+
case SyntaxKind.Method:
2694+
case SyntaxKind.Constructor:
2695+
case SyntaxKind.GetAccessor:
2696+
case SyntaxKind.SetAccessor:
2697+
// Make sure the container belongs to the same class
2698+
// and has the appropriate static modifier from the original container.
2699+
if (searchSpaceNode.symbol === container.parent.symbol && (container.flags & NodeFlags.Static) === staticFlag) {
2700+
result.push(getReferenceEntryFromNode(node));
2701+
}
2702+
break;
2703+
case SyntaxKind.FunctionDeclaration:
2704+
case SyntaxKind.FunctionExpression:
2705+
if (searchSpaceNode.symbol === container.symbol) {
2706+
result.push(getReferenceEntryFromNode(node));
2707+
}
2708+
break;
2709+
case SyntaxKind.SourceFile:
2710+
// Add all 'this' keywords that belong to the top-level scope.
2711+
if (searchSpaceNode.kind === SyntaxKind.SourceFile) {
2712+
result.push(getReferenceEntryFromNode(node));
2713+
}
2714+
break;
26232715
}
26242716
});
26252717
}
@@ -2721,18 +2813,6 @@ module ts {
27212813
return undefined;
27222814
}
27232815

2724-
function getReferenceEntry(node: Node): ReferenceEntry {
2725-
var start = node.getStart();
2726-
var end = node.getEnd();
2727-
2728-
if (node.kind === SyntaxKind.StringLiteral) {
2729-
start += 1;
2730-
end -= 1;
2731-
}
2732-
2733-
return new ReferenceEntry(node.getSourceFile().filename, TypeScript.TextSpan.fromBounds(start, end), isWriteAccess(node));
2734-
}
2735-
27362816
function getMeaningFromDeclaration(node: Declaration): SearchMeaning {
27372817
switch (node.kind) {
27382818
case SyntaxKind.Parameter:
@@ -2869,40 +2949,52 @@ module ts {
28692949
}
28702950
return meaning;
28712951
}
2952+
}
2953+
2954+
function getReferenceEntryFromNode(node: Node): ReferenceEntry {
2955+
var start = node.getStart();
2956+
var end = node.getEnd();
2957+
2958+
if (node.kind === SyntaxKind.StringLiteral) {
2959+
start += 1;
2960+
end -= 1;
2961+
}
2962+
2963+
return new ReferenceEntry(node.getSourceFile().filename, TypeScript.TextSpan.fromBounds(start, end), isWriteAccess(node));
2964+
}
2965+
2966+
/// A node is considedered a writeAccess iff it is a name of a declaration or a target of an assignment
2967+
function isWriteAccess(node: Node): boolean {
2968+
if (node.kind === SyntaxKind.Identifier && isDeclarationOrFunctionExpressionOrCatchVariableName(node)) {
2969+
return true;
2970+
}
28722971

2873-
/// A node is considedered a writeAccess iff it is a name of a declaration or a target of an assignment
2874-
function isWriteAccess(node: Node): boolean {
2875-
if (node.kind === SyntaxKind.Identifier && isDeclarationOrFunctionExpressionOrCatchVariableName(node)) {
2972+
var parent = node.parent;
2973+
if (parent) {
2974+
if (parent.kind === SyntaxKind.PostfixOperator || parent.kind === SyntaxKind.PrefixOperator) {
28762975
return true;
28772976
}
2878-
2879-
var parent = node.parent;
2880-
if (parent) {
2881-
if (parent.kind === SyntaxKind.PostfixOperator || parent.kind === SyntaxKind.PrefixOperator) {
2882-
return true;
2883-
}
2884-
else if (parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>parent).left === node) {
2885-
var operator = (<BinaryExpression>parent).operator;
2886-
switch (operator) {
2887-
case SyntaxKind.AsteriskEqualsToken:
2888-
case SyntaxKind.SlashEqualsToken:
2889-
case SyntaxKind.PercentEqualsToken:
2890-
case SyntaxKind.MinusEqualsToken:
2891-
case SyntaxKind.LessThanLessThanEqualsToken:
2892-
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
2893-
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
2894-
case SyntaxKind.BarEqualsToken:
2895-
case SyntaxKind.CaretEqualsToken:
2896-
case SyntaxKind.AmpersandEqualsToken:
2897-
case SyntaxKind.PlusEqualsToken:
2898-
case SyntaxKind.EqualsToken:
2899-
return true;
2900-
}
2977+
else if (parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>parent).left === node) {
2978+
var operator = (<BinaryExpression>parent).operator;
2979+
switch (operator) {
2980+
case SyntaxKind.AsteriskEqualsToken:
2981+
case SyntaxKind.SlashEqualsToken:
2982+
case SyntaxKind.PercentEqualsToken:
2983+
case SyntaxKind.MinusEqualsToken:
2984+
case SyntaxKind.LessThanLessThanEqualsToken:
2985+
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
2986+
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
2987+
case SyntaxKind.BarEqualsToken:
2988+
case SyntaxKind.CaretEqualsToken:
2989+
case SyntaxKind.AmpersandEqualsToken:
2990+
case SyntaxKind.PlusEqualsToken:
2991+
case SyntaxKind.EqualsToken:
2992+
return true;
29012993
}
2902-
2903-
return false;
29042994
}
29052995
}
2996+
2997+
return false;
29062998
}
29072999

29083000
/// Syntactic features

0 commit comments

Comments
 (0)