diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 0f64321f1be..86db21e3225 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -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(symbol.valueDeclaration)) { - addRange(result, checker.getSymbolsOfParameterPropertyDeclaration(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; diff --git a/tests/cases/fourslash/findAllRefsParameterPropertyDeclaration_inheritance.ts b/tests/cases/fourslash/findAllRefsParameterPropertyDeclaration_inheritance.ts new file mode 100644 index 00000000000..3002cd4d3e7 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsParameterPropertyDeclaration_inheritance.ts @@ -0,0 +1,31 @@ +/// + +////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] }, +]);