refactor(compiler-cli): Add additional shim locations to reference and variable symbols (#39715)

Both `ReferenceSymbol` and `VariableSymbol` have two locations of
interest to an external consumer.
1. The location for the initializers of the local TCB variables allow consumers
to query the TypeScript Language Service for information about the initialized type of the variable.
2. The location of the local variable itself (i.e. `_t1`) allows
consumers to query the TypeScript LS for references to that variable
from within the template.

PR Close #39715
This commit is contained in:
Andrew Scott 2020-11-16 11:22:11 -08:00 committed by Andrew Kushnir
parent 066126ae2f
commit fae2769f44
5 changed files with 62 additions and 15 deletions

View File

@ -155,8 +155,24 @@ export interface ReferenceSymbol {
*/ */
declaration: TmplAstReference; declaration: TmplAstReference;
/** The location in the shim file of a variable that holds the type of the local ref. */ /**
shimLocation: ShimLocation; * The location in the shim file of a variable that holds the type of the local ref.
* For example, a reference declaration like the following:
* ```
* var _t1 = document.createElement('div');
* var _t2 = _t1; // This is the reference declaration
* ```
* This `targetLocation` is `[_t1 variable declaration].getStart()`.
*/
targetLocation: ShimLocation;
/**
* The location in the TCB for the identifier node in the reference variable declaration.
* For example, given a variable declaration statement for a template reference:
* `var _t2 = _t1`, this location is `[_t2 node].getStart()`. This location can
* be used to find references to the variable within the template.
*/
referenceVarLocation: ShimLocation;
} }
/** /**
@ -185,8 +201,16 @@ export interface VariableSymbol {
*/ */
declaration: TmplAstVariable; declaration: TmplAstVariable;
/** The location in the shim file of a variable that holds the type of the template variable. */ /**
shimLocation: ShimLocation; * The location in the shim file for the identifier that was declared for the template variable.
*/
localVarLocation: ShimLocation;
/**
* The location in the shim file for the initializer node of the variable that represents the
* template variable.
*/
initializerLocation: ShimLocation;
} }
/** /**

View File

@ -13,7 +13,7 @@ import {AbsoluteFsPath} from '../../file_system';
import {ClassDeclaration} from '../../reflection'; import {ClassDeclaration} from '../../reflection';
import {ComponentScopeReader} from '../../scope'; import {ComponentScopeReader} from '../../scope';
import {isAssignment} from '../../util/src/typescript'; import {isAssignment} from '../../util/src/typescript';
import {DirectiveSymbol, DomBindingSymbol, ElementSymbol, ExpressionSymbol, InputBindingSymbol, OutputBindingSymbol, ReferenceSymbol, Symbol, SymbolKind, TemplateSymbol, TsNodeSymbolInfo, TypeCheckableDirectiveMeta, VariableSymbol} from '../api'; import {DirectiveSymbol, DomBindingSymbol, ElementSymbol, ExpressionSymbol, InputBindingSymbol, OutputBindingSymbol, ReferenceSymbol, ShimLocation, Symbol, SymbolKind, TemplateSymbol, TsNodeSymbolInfo, TypeCheckableDirectiveMeta, VariableSymbol} from '../api';
import {ExpressionIdentifier, findAllMatchingNodes, findFirstMatchingNode, hasExpressionIdentifier} from './comments'; import {ExpressionIdentifier, findAllMatchingNodes, findFirstMatchingNode, hasExpressionIdentifier} from './comments';
import {TemplateData} from './context'; import {TemplateData} from './context';
@ -303,7 +303,17 @@ export class SymbolBuilder {
return null; return null;
} }
return {...expressionSymbol, kind: SymbolKind.Variable, declaration: variable}; return {
tsType: expressionSymbol.tsType,
tsSymbol: expressionSymbol.tsSymbol,
initializerLocation: expressionSymbol.shimLocation,
kind: SymbolKind.Variable,
declaration: variable,
localVarLocation: {
shimPath: this.shimPath,
positionInShimFile: this.getShimPositionForNode(node.name),
}
};
} }
private getSymbolOfReference(ref: TmplAstReference): ReferenceSymbol|null { private getSymbolOfReference(ref: TmplAstReference): ReferenceSymbol|null {
@ -331,13 +341,19 @@ export class SymbolBuilder {
return null; return null;
} }
const referenceVarShimLocation: ShimLocation = {
shimPath: this.shimPath,
positionInShimFile: this.getShimPositionForNode(node),
};
if (target instanceof TmplAstTemplate || target instanceof TmplAstElement) { if (target instanceof TmplAstTemplate || target instanceof TmplAstElement) {
return { return {
...symbol,
tsSymbol: symbol.tsSymbol,
kind: SymbolKind.Reference, kind: SymbolKind.Reference,
tsSymbol: symbol.tsSymbol,
tsType: symbol.tsType,
target, target,
declaration: ref, declaration: ref,
targetLocation: symbol.shimLocation,
referenceVarLocation: referenceVarShimLocation,
}; };
} else { } else {
if (!ts.isClassDeclaration(target.directive.ref.node)) { if (!ts.isClassDeclaration(target.directive.ref.node)) {
@ -345,11 +361,13 @@ export class SymbolBuilder {
} }
return { return {
...symbol,
kind: SymbolKind.Reference, kind: SymbolKind.Reference,
tsSymbol: symbol.tsSymbol, tsSymbol: symbol.tsSymbol,
tsType: symbol.tsType,
declaration: ref, declaration: ref,
target: target.directive.ref.node, target: target.directive.ref.node,
targetLocation: symbol.shimLocation,
referenceVarLocation: referenceVarShimLocation,
}; };
} }
} }

View File

@ -90,7 +90,8 @@ export class DefinitionBuilder {
}); });
} }
if (symbol.kind === SymbolKind.Variable) { if (symbol.kind === SymbolKind.Variable) {
definitions.push(...this.getDefinitionsForSymbols(symbol)); definitions.push(
...this.getDefinitionsForSymbols({shimLocation: symbol.initializerLocation}));
} }
return definitions; return definitions;
} }
@ -135,9 +136,11 @@ export class DefinitionBuilder {
return [...bindingDefs, ...directiveDefs]; return [...bindingDefs, ...directiveDefs];
} }
case SymbolKind.Reference: case SymbolKind.Reference:
return this.getTypeDefinitionsForSymbols({shimLocation: symbol.targetLocation});
case SymbolKind.Expression: case SymbolKind.Expression:
case SymbolKind.Variable:
return this.getTypeDefinitionsForSymbols(symbol); return this.getTypeDefinitionsForSymbols(symbol);
case SymbolKind.Variable:
return this.getTypeDefinitionsForSymbols({shimLocation: symbol.initializerLocation});
} }
} }

View File

@ -56,7 +56,9 @@ export function getDisplayInfo(
const displayParts = createDisplayParts( const displayParts = createDisplayParts(
symbol.declaration.name, kind, /* containerName */ undefined, symbol.declaration.name, kind, /* containerName */ undefined,
typeChecker.typeToString(symbol.tsType)); typeChecker.typeToString(symbol.tsType));
const documentation = getDocumentationFromTypeDefAtLocation(tsLS, symbol.shimLocation); const documentation = symbol.kind === SymbolKind.Reference ?
getDocumentationFromTypeDefAtLocation(tsLS, symbol.targetLocation) :
getDocumentationFromTypeDefAtLocation(tsLS, symbol.initializerLocation);
return { return {
kind, kind,
displayParts, displayParts,

View File

@ -80,14 +80,14 @@ export class QuickInfoBuilder {
} }
private getQuickInfoForVariableSymbol(symbol: VariableSymbol): ts.QuickInfo { private getQuickInfoForVariableSymbol(symbol: VariableSymbol): ts.QuickInfo {
const documentation = this.getDocumentationFromTypeDefAtLocation(symbol.shimLocation); const documentation = this.getDocumentationFromTypeDefAtLocation(symbol.initializerLocation);
return createQuickInfo( return createQuickInfo(
symbol.declaration.name, DisplayInfoKind.VARIABLE, getTextSpanOfNode(this.node), symbol.declaration.name, DisplayInfoKind.VARIABLE, getTextSpanOfNode(this.node),
undefined /* containerName */, this.typeChecker.typeToString(symbol.tsType), documentation); undefined /* containerName */, this.typeChecker.typeToString(symbol.tsType), documentation);
} }
private getQuickInfoForReferenceSymbol(symbol: ReferenceSymbol): ts.QuickInfo { private getQuickInfoForReferenceSymbol(symbol: ReferenceSymbol): ts.QuickInfo {
const documentation = this.getDocumentationFromTypeDefAtLocation(symbol.shimLocation); const documentation = this.getDocumentationFromTypeDefAtLocation(symbol.targetLocation);
return createQuickInfo( return createQuickInfo(
symbol.declaration.name, DisplayInfoKind.REFERENCE, getTextSpanOfNode(this.node), symbol.declaration.name, DisplayInfoKind.REFERENCE, getTextSpanOfNode(this.node),
undefined /* containerName */, this.typeChecker.typeToString(symbol.tsType), documentation); undefined /* containerName */, this.typeChecker.typeToString(symbol.tsType), documentation);