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 // 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. // 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 // 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 && addRange(result, getParameterPropertySymbols(symbol, checker));
isParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration)) {
addRange(result, checker.getSymbolsOfParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration, symbol.name));
}
// If this is symbol of binding element without propertyName declaration in Object binding pattern // If this is symbol of binding element without propertyName declaration in Object binding pattern
// Include the property in the search // 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 * 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 * @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 { function getRelatedSymbol(search: Search, referenceSymbol: Symbol, referenceLocation: Node, state: State): Symbol | undefined {
const { checker } = state;
if (search.includes(referenceSymbol)) { if (search.includes(referenceSymbol)) {
return 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 // 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 // object literal, lookup the property symbol in the contextual type, and use this symbol to
// compare to our searchSymbol // compare to our searchSymbol
const containingObjectLiteralElement = getContainingObjectLiteralElement(referenceLocation); const containingObjectLiteralElement = getContainingObjectLiteralElement(referenceLocation);
if (containingObjectLiteralElement) { if (containingObjectLiteralElement) {
const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement, state.checker), contextualSymbol => const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement, checker), contextualSymbol =>
find(state.checker.getRootSymbols(contextualSymbol), search.includes)); find(checker.getRootSymbols(contextualSymbol), search.includes));
if (contextualSymbol) { if (contextualSymbol) {
return 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 // 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 // In below eg. get 'property' from type of elems iterating type
// for ( { property: p2 } of elems) { } // for ( { property: p2 } of elems) { }
const propertySymbol = getPropertySymbolOfDestructuringAssignment(referenceLocation, state.checker); const propertySymbol = getPropertySymbolOfDestructuringAssignment(referenceLocation, checker);
if (propertySymbol && search.includes(propertySymbol)) { if (propertySymbol && search.includes(propertySymbol)) {
return 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 // If the reference location is the binding element and doesn't have property name
// then include the binding element in the related symbols // then include the binding element in the related symbols
// let { a } : { a }; // let { a } : { a };
const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol, state.checker); const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol, checker);
if (bindingElementPropertySymbol) { if (bindingElementPropertySymbol) {
const fromBindingElement = findRootSymbol(bindingElementPropertySymbol); const fromBindingElement = findRootSymbol(bindingElementPropertySymbol);
if (fromBindingElement) return fromBindingElement; 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] },
]);