Support parameter properties in getRelatedSymbol (#20202)

This commit is contained in:
Andy 2017-11-28 14:12:28 -05:00 committed by GitHub
parent 185f15d2af
commit bbb56fed11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 8 deletions

View file

@ -1427,10 +1427,7 @@ namespace ts.FindAllReferences.Core {
// we should include both parameter declaration symbol and property declaration symbol
// Parameter Declaration symbol is only visible within function scope, so the symbol is stored in constructor.locals.
// Property Declaration symbol is a member of the class, so the symbol is stored in its class Declaration.symbol.members
if (symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.Parameter &&
isParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration)) {
addRange(result, checker.getSymbolsOfParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration, symbol.name));
}
addRange(result, getParameterPropertySymbols(symbol, checker));
// If this is symbol of binding element without propertyName declaration in Object binding pattern
// Include the property in the search
@ -1460,6 +1457,12 @@ namespace ts.FindAllReferences.Core {
}
}
function getParameterPropertySymbols(symbol: Symbol, checker: TypeChecker): Symbol[] {
return symbol.valueDeclaration && isParameter(symbol.valueDeclaration) && isParameterPropertyDeclaration(symbol.valueDeclaration)
? checker.getSymbolsOfParameterPropertyDeclaration(symbol.valueDeclaration, symbol.name)
: undefined;
}
/**
* Find symbol of the given property-name and add the symbol to the given result array
* @param symbol a symbol to start searching for the given propertyName
@ -1519,17 +1522,26 @@ namespace ts.FindAllReferences.Core {
}
function getRelatedSymbol(search: Search, referenceSymbol: Symbol, referenceLocation: Node, state: State): Symbol | undefined {
const { checker } = state;
if (search.includes(referenceSymbol)) {
return referenceSymbol;
}
if (referenceSymbol.flags & SymbolFlags.FunctionScopedVariable) {
Debug.assert(!(referenceSymbol.flags & SymbolFlags.Property));
const paramProps = getParameterPropertySymbols(referenceSymbol, checker);
if (paramProps) {
return getRelatedSymbol(search, find(paramProps, x => !!(x.flags & SymbolFlags.Property))!, referenceLocation, state);
}
}
// If the reference location is in an object literal, try to get the contextual type for the
// object literal, lookup the property symbol in the contextual type, and use this symbol to
// compare to our searchSymbol
const containingObjectLiteralElement = getContainingObjectLiteralElement(referenceLocation);
if (containingObjectLiteralElement) {
const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement, state.checker), contextualSymbol =>
find(state.checker.getRootSymbols(contextualSymbol), search.includes));
const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement, checker), contextualSymbol =>
find(checker.getRootSymbols(contextualSymbol), search.includes));
if (contextualSymbol) {
return contextualSymbol;
@ -1539,7 +1551,7 @@ namespace ts.FindAllReferences.Core {
// Get the property symbol from the object literal's type and look if thats the search symbol
// In below eg. get 'property' from type of elems iterating type
// for ( { property: p2 } of elems) { }
const propertySymbol = getPropertySymbolOfDestructuringAssignment(referenceLocation, state.checker);
const propertySymbol = getPropertySymbolOfDestructuringAssignment(referenceLocation, checker);
if (propertySymbol && search.includes(propertySymbol)) {
return propertySymbol;
}
@ -1548,7 +1560,7 @@ namespace ts.FindAllReferences.Core {
// If the reference location is the binding element and doesn't have property name
// then include the binding element in the related symbols
// let { a } : { a };
const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol, state.checker);
const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol, checker);
if (bindingElementPropertySymbol) {
const fromBindingElement = findRootSymbol(bindingElementPropertySymbol);
if (fromBindingElement) return fromBindingElement;

View file

@ -0,0 +1,31 @@
/// <reference path='fourslash.ts'/>
////class C {
//// constructor(public [|{| "isWriteAccess": true, "isDefinition": true |}x|]: string) {
//// [|x|];
//// }
////}
////class D extends C {
//// constructor(public [|{| "isWriteAccess": true, "isDefinition": true |}x|]: string) {
//// super([|x|]);
//// }
////}
const [r0, r1, r2, r3] = test.ranges();
verify.referenceGroups(r0, [
{ definition: "(property) C.x: string", ranges: [r0, r2, r3] },
{ definition: "(parameter) x: string", ranges: [r1] },
]);
verify.referenceGroups(r1, [
{ definition: "(property) C.x: string", ranges: [r0] },
{ definition: "(parameter) x: string", ranges: [r1] },
]);
verify.referenceGroups(r2, [
{ definition: "(property) C.x: string", ranges: [r0, r1] },
{ definition: "(property) D.x: string", ranges: [r2] },
{ definition: "(parameter) x: string", ranges: [r3] },
]);
verify.referenceGroups(r3, [
{ definition: "(property) D.x: string", ranges: [r2] },
{ definition: "(parameter) x: string", ranges: [r3] },
]);