mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-30 04:16:48 -05:00
Destructuring of object binding pattern element without property name should reference property
Fixes #6312
This commit is contained in:
@@ -5615,6 +5615,21 @@ namespace ts {
|
||||
return (symbol.flags & SymbolFlags.Alias) && !!getDeclarationOfKind(symbol, SyntaxKind.ImportSpecifier);
|
||||
}
|
||||
|
||||
function isObjectBindingPatternElementWithoutPropertyName(symbol: Symbol) {
|
||||
const bindingElement = <BindingElement>getDeclarationOfKind(symbol, SyntaxKind.BindingElement);
|
||||
return bindingElement &&
|
||||
bindingElement.parent.kind === SyntaxKind.ObjectBindingPattern &&
|
||||
!bindingElement.propertyName;
|
||||
}
|
||||
|
||||
function getPropertySymbolIfObjectBindingPatternWithoutPropertyName(symbol: Symbol) {
|
||||
if (isObjectBindingPatternElementWithoutPropertyName(symbol)) {
|
||||
const bindingElement = <BindingElement>getDeclarationOfKind(symbol, SyntaxKind.BindingElement);
|
||||
const typeOfPattern = typeChecker.getTypeAtLocation(bindingElement.parent);
|
||||
return typeOfPattern && typeChecker.getPropertyOfType(typeOfPattern, (<Identifier>bindingElement.name).text);
|
||||
}
|
||||
}
|
||||
|
||||
function getInternedName(symbol: Symbol, location: Node, declarations: Declaration[]): string {
|
||||
// If this is an export or import specifier it could have been renamed using the 'as' syntax.
|
||||
// If so we want to search for whatever under the cursor.
|
||||
@@ -5660,6 +5675,12 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If symbol is of object binding pattern element without property name we would want to
|
||||
// look for property too and that could be anywhere
|
||||
if (isObjectBindingPatternElementWithoutPropertyName(symbol)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// if this symbol is visible from its parent container, e.g. exported, then bail out
|
||||
// if symbol correspond to the union property - bail out
|
||||
if (symbol.parent || (symbol.flags & SymbolFlags.SyntheticProperty)) {
|
||||
@@ -6103,6 +6124,13 @@ namespace ts {
|
||||
result = result.concat(typeChecker.getSymbolsOfParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration, symbol.name));
|
||||
}
|
||||
|
||||
// If this is symbol of binding element without propertyName declaration in Object binding pattern
|
||||
// Include the property in the search
|
||||
const bindingElementPropertySymbol = getPropertySymbolIfObjectBindingPatternWithoutPropertyName(symbol);
|
||||
if (bindingElementPropertySymbol) {
|
||||
result.push(bindingElementPropertySymbol);
|
||||
}
|
||||
|
||||
// If this is a union property, add all the symbols from all its source symbols in all unioned types.
|
||||
// If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list
|
||||
forEach(typeChecker.getRootSymbols(symbol), rootSymbol => {
|
||||
@@ -6212,6 +6240,14 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
// 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 = getPropertySymbolIfObjectBindingPatternWithoutPropertyName(referenceSymbol);
|
||||
if (bindingElementPropertySymbol && searchSymbols.indexOf(bindingElementPropertySymbol) >= 0) {
|
||||
return bindingElementPropertySymbol;
|
||||
}
|
||||
|
||||
// Unwrap symbols to get to the root (e.g. transient symbols as a result of widening)
|
||||
// Or a union property, use its underlying unioned symbols
|
||||
return forEach(typeChecker.getRootSymbols(referenceSymbol), rootSymbol => {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
////}
|
||||
////
|
||||
////var foo: I;
|
||||
////var [{ [|property1|]: prop1 }, { property1, property2 } ] = [foo, foo];
|
||||
////var [{ [|property1|]: prop1 }, { [|property1|], property2 } ] = [foo, foo];
|
||||
|
||||
let ranges = test.ranges();
|
||||
for (let range of ranges) {
|
||||
|
||||
@@ -6,14 +6,12 @@
|
||||
////}
|
||||
////
|
||||
////function f({ /**/[|property1|]: p1 }: I,
|
||||
//// { /*SHOULD_BE_A_REFERENCE*/property1 }: I,
|
||||
//// { [|property1|] }: I,
|
||||
//// { property1: p2 }) {
|
||||
////
|
||||
//// return property1 + 1;
|
||||
//// return [|property1|] + 1;
|
||||
////}
|
||||
|
||||
// NOTE: In the future, the identifier at
|
||||
// SHOULD_BE_A_REFERENCE should be in the set of ranges.
|
||||
goTo.marker();
|
||||
|
||||
let ranges = test.ranges();
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
////var elems: I[];
|
||||
////for (let { [|property1|]: p } of elems) {
|
||||
////}
|
||||
////for (let { property1 } of elems) {
|
||||
////for (let { [|property1|] } of elems) {
|
||||
////}
|
||||
////for (var { [|property1|]: p1 } of elems) {
|
||||
////}
|
||||
////var p2;
|
||||
////for ({ property1 : p2 } of elems) {
|
||||
////for ({ /*This should be referenced too*/property1 : p2 } of elems) {
|
||||
////}
|
||||
|
||||
// Note: if this test ever changes, consider updating
|
||||
@@ -23,6 +23,7 @@ let ranges = test.ranges();
|
||||
for (let range of ranges) {
|
||||
goTo.position(range.start);
|
||||
|
||||
debugger;
|
||||
verify.referencesCountIs(ranges.length);
|
||||
for (let expectedRange of ranges) {
|
||||
verify.referencesAtPositionContains(expectedRange);
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////interface I {
|
||||
//// /*SHOULD_BE_A_REFERENCE1*/property1: number;
|
||||
//// [|property1|]: number;
|
||||
//// property2: string;
|
||||
////}
|
||||
////
|
||||
////function f({ /*SHOULD_BE_A_REFERENCE2*/property1: p1 }: I,
|
||||
////function f({ [|property1|]: p1 }: I,
|
||||
//// { /**/[|property1|] }: I,
|
||||
//// { property1: p2 }) {
|
||||
////
|
||||
//// return [|property1|] + 1;
|
||||
////}
|
||||
|
||||
// NOTE: In the future, the identifiers at
|
||||
// SHOULD_BE_A_REFERENCE[1/2] should be in the set of ranges.
|
||||
goTo.marker();
|
||||
|
||||
let ranges = test.ranges();
|
||||
|
||||
23
tests/cases/fourslash/renameDestructuringClassProperty.ts
Normal file
23
tests/cases/fourslash/renameDestructuringClassProperty.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////class A {
|
||||
//// [|foo|]: string;
|
||||
////}
|
||||
////class B {
|
||||
//// syntax1(a: A): void {
|
||||
//// let { [|foo|] } = a;
|
||||
//// }
|
||||
//// syntax2(a: A): void {
|
||||
//// let { [|foo|]: foo } = a;
|
||||
//// }
|
||||
//// syntax11(a: A): void {
|
||||
//// let { [|foo|] } = a;
|
||||
//// [|foo|] = "newString";
|
||||
//// }
|
||||
////}
|
||||
|
||||
let ranges = test.ranges()
|
||||
for (let range of ranges) {
|
||||
goTo.position(range.start);
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////function f({[|a|]}: {[|a|]}) {
|
||||
//// f({[|a|]});
|
||||
////}
|
||||
let ranges = test.ranges();
|
||||
for (let range of ranges) {
|
||||
goTo.position(range.start);
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
|
||||
}
|
||||
Reference in New Issue
Block a user