Destructuring of object binding pattern element without property name should reference property

Fixes #6312
This commit is contained in:
Sheetal Nandi
2016-04-05 16:16:54 -07:00
parent 3acff6def6
commit ace2285ac2
7 changed files with 77 additions and 11 deletions

View File

@@ -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 => {

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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);

View File

@@ -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();

View 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);
}

View File

@@ -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);
}