Skip to content

Commit 0120d7b

Browse files
committed
Merge pull request #8456 from Microsoft/Fix8415
Fix #8415: consider accessors when searching for contextually typed properties
2 parents 16fccf5 + 0de4106 commit 0120d7b

File tree

42 files changed

+392
-44
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+392
-44
lines changed

src/compiler/checker.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16688,6 +16688,9 @@ namespace ts {
1668816688
// This is a declaration, call getSymbolOfNode
1668916689
return getSymbolOfNode(node.parent);
1669016690
}
16691+
else if (isLiteralComputedPropertyDeclarationName(node)) {
16692+
return getSymbolOfNode(node.parent.parent);
16693+
}
1669116694

1669216695
if (node.kind === SyntaxKind.Identifier) {
1669316696
if (isInRightSideOfImportOrExportAssignment(<Identifier>node)) {
@@ -16919,7 +16922,11 @@ namespace ts {
1691916922
return symbols;
1692016923
}
1692116924
else if (symbol.flags & SymbolFlags.Transient) {
16922-
const target = getSymbolLinks(symbol).target;
16925+
let target: Symbol;
16926+
let next = symbol;
16927+
while (next = getSymbolLinks(next).target) {
16928+
target = next;
16929+
}
1692316930
if (target) {
1692416931
return [target];
1692516932
}

src/compiler/utilities.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,6 +1565,12 @@ namespace ts {
15651565
return false;
15661566
}
15671567

1568+
export function isLiteralComputedPropertyDeclarationName(node: Node) {
1569+
return (node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NumericLiteral) &&
1570+
node.parent.kind === SyntaxKind.ComputedPropertyName &&
1571+
isDeclaration(node.parent.parent);
1572+
}
1573+
15681574
// Return true if the given identifier is classified as an IdentifierName
15691575
export function isIdentifierName(node: Identifier): boolean {
15701576
let parent = node.parent;
@@ -1750,6 +1756,9 @@ namespace ts {
17501756
const rightHandSideName = (<PropertyAccessExpression>nameExpression).name.text;
17511757
return getPropertyNameForKnownSymbolName(rightHandSideName);
17521758
}
1759+
else if (nameExpression.kind === SyntaxKind.StringLiteral || nameExpression.kind === SyntaxKind.NumericLiteral) {
1760+
return (<LiteralExpression>nameExpression).text;
1761+
}
17531762
}
17541763

17551764
return undefined;

src/services/services.ts

Lines changed: 67 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2581,10 +2581,33 @@ namespace ts {
25812581
isFunctionLike(node.parent) && (<FunctionLikeDeclaration>node.parent).name === node;
25822582
}
25832583

2584-
/** Returns true if node is a name of an object literal property, e.g. "a" in x = { "a": 1 } */
2585-
function isNameOfPropertyAssignment(node: Node): boolean {
2586-
return (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NumericLiteral) &&
2587-
(node.parent.kind === SyntaxKind.PropertyAssignment || node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) && (<PropertyDeclaration>node.parent).name === node;
2584+
function isObjectLiteralPropertyDeclaration(node: Node): node is ObjectLiteralElement {
2585+
switch (node.kind) {
2586+
case SyntaxKind.PropertyAssignment:
2587+
case SyntaxKind.ShorthandPropertyAssignment:
2588+
case SyntaxKind.MethodDeclaration:
2589+
case SyntaxKind.GetAccessor:
2590+
case SyntaxKind.SetAccessor:
2591+
return true;
2592+
}
2593+
return false;
2594+
}
2595+
2596+
/**
2597+
* Returns the containing object literal property declaration given a possible name node, e.g. "a" in x = { "a": 1 }
2598+
*/
2599+
function getContainingObjectLiteralElement(node: Node): ObjectLiteralElement {
2600+
switch (node.kind) {
2601+
case SyntaxKind.StringLiteral:
2602+
case SyntaxKind.NumericLiteral:
2603+
if (node.parent.kind === SyntaxKind.ComputedPropertyName) {
2604+
return isObjectLiteralPropertyDeclaration(node.parent.parent) ? node.parent.parent : undefined;
2605+
}
2606+
// intential fall through
2607+
case SyntaxKind.Identifier:
2608+
return isObjectLiteralPropertyDeclaration(node.parent) && node.parent.name === node ? node.parent : undefined;
2609+
}
2610+
return undefined;
25882611
}
25892612

25902613
function isLiteralNameOfPropertyDeclarationOrIndexAccess(node: Node): boolean {
@@ -2602,6 +2625,8 @@ namespace ts {
26022625
return (<Declaration>node.parent).name === node;
26032626
case SyntaxKind.ElementAccessExpression:
26042627
return (<ElementAccessExpression>node.parent).argumentExpression === node;
2628+
case SyntaxKind.ComputedPropertyName:
2629+
return true;
26052630
}
26062631
}
26072632

@@ -6208,7 +6233,8 @@ namespace ts {
62086233
// If the location is name of property symbol from object literal destructuring pattern
62096234
// Search the property symbol
62106235
// for ( { property: p2 } of elems) { }
6211-
if (isNameOfPropertyAssignment(location) && location.parent.kind !== SyntaxKind.ShorthandPropertyAssignment) {
6236+
const containingObjectLiteralElement = getContainingObjectLiteralElement(location);
6237+
if (containingObjectLiteralElement && containingObjectLiteralElement.kind !== SyntaxKind.ShorthandPropertyAssignment) {
62126238
const propertySymbol = getPropertySymbolOfDestructuringAssignment(location);
62136239
if (propertySymbol) {
62146240
result.push(propertySymbol);
@@ -6234,8 +6260,8 @@ namespace ts {
62346260
// If the location is in a context sensitive location (i.e. in an object literal) try
62356261
// to get a contextual type for it, and add the property symbol from the contextual
62366262
// type to the search set
6237-
if (isNameOfPropertyAssignment(location)) {
6238-
forEach(getPropertySymbolsFromContextualType(location), contextualSymbol => {
6263+
if (containingObjectLiteralElement) {
6264+
forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement), contextualSymbol => {
62396265
addRange(result, typeChecker.getRootSymbols(contextualSymbol));
62406266
});
62416267

@@ -6362,8 +6388,9 @@ namespace ts {
63626388
// If the reference location is in an object literal, try to get the contextual type for the
63636389
// object literal, lookup the property symbol in the contextual type, and use this symbol to
63646390
// compare to our searchSymbol
6365-
if (isNameOfPropertyAssignment(referenceLocation)) {
6366-
const contextualSymbol = forEach(getPropertySymbolsFromContextualType(referenceLocation), contextualSymbol => {
6391+
const containingObjectLiteralElement = getContainingObjectLiteralElement(referenceLocation);
6392+
if (containingObjectLiteralElement) {
6393+
const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement), contextualSymbol => {
63676394
return forEach(typeChecker.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
63686395
});
63696396

@@ -6409,37 +6436,38 @@ namespace ts {
64096436
});
64106437
}
64116438

6412-
function getPropertySymbolsFromContextualType(node: Node): Symbol[] {
6413-
if (isNameOfPropertyAssignment(node)) {
6414-
const objectLiteral = <ObjectLiteralExpression>node.parent.parent;
6415-
const contextualType = typeChecker.getContextualType(objectLiteral);
6416-
const name = (<Identifier>node).text;
6417-
if (contextualType) {
6418-
if (contextualType.flags & TypeFlags.Union) {
6419-
// This is a union type, first see if the property we are looking for is a union property (i.e. exists in all types)
6420-
// if not, search the constituent types for the property
6421-
const unionProperty = contextualType.getProperty(name);
6422-
if (unionProperty) {
6423-
return [unionProperty];
6424-
}
6425-
else {
6426-
const result: Symbol[] = [];
6427-
forEach((<UnionType>contextualType).types, t => {
6428-
const symbol = t.getProperty(name);
6429-
if (symbol) {
6430-
result.push(symbol);
6431-
}
6432-
});
6433-
return result;
6434-
}
6435-
}
6436-
else {
6437-
const symbol = contextualType.getProperty(name);
6439+
function getNameFromObjectLiteralElement(node: ObjectLiteralElement) {
6440+
if (node.name.kind === SyntaxKind.ComputedPropertyName) {
6441+
const nameExpression = (<ComputedPropertyName>node.name).expression;
6442+
// treat computed property names where expression is string/numeric literal as just string/numeric literal
6443+
if (isStringOrNumericLiteral(nameExpression.kind)) {
6444+
return (<LiteralExpression>nameExpression).text;
6445+
}
6446+
return undefined;
6447+
}
6448+
return (<Identifier | LiteralExpression>node.name).text;
6449+
}
6450+
6451+
function getPropertySymbolsFromContextualType(node: ObjectLiteralElement): Symbol[] {
6452+
const objectLiteral = <ObjectLiteralExpression>node.parent;
6453+
const contextualType = typeChecker.getContextualType(objectLiteral);
6454+
const name = getNameFromObjectLiteralElement(node);
6455+
if (name && contextualType) {
6456+
const result: Symbol[] = [];
6457+
const symbol = contextualType.getProperty(name);
6458+
if (symbol) {
6459+
result.push(symbol);
6460+
}
6461+
6462+
if (contextualType.flags & TypeFlags.Union) {
6463+
forEach((<UnionType>contextualType).types, t => {
6464+
const symbol = t.getProperty(name);
64386465
if (symbol) {
6439-
return [symbol];
6466+
result.push(symbol);
64406467
}
6441-
}
6468+
});
64426469
}
6470+
return result;
64436471
}
64446472
return undefined;
64456473
}
@@ -7901,7 +7929,8 @@ namespace ts {
79017929
// "a['propname']" then we want to store "propname" in the name table.
79027930
if (isDeclarationName(node) ||
79037931
node.parent.kind === SyntaxKind.ExternalModuleReference ||
7904-
isArgumentOfElementAccessExpression(node)) {
7932+
isArgumentOfElementAccessExpression(node) ||
7933+
isLiteralComputedPropertyDeclarationName(node)) {
79057934

79067935
nameTable[(<LiteralExpression>node).text] = nameTable[(<LiteralExpression>node).text] === undefined ? node.pos : -1;
79077936
}

src/services/utilities.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,10 @@ namespace ts {
821821
if (isImportOrExportSpecifierName(location)) {
822822
return location.getText();
823823
}
824+
else if (isStringOrNumericLiteral(location.kind) &&
825+
location.parent.kind === SyntaxKind.ComputedPropertyName) {
826+
return (<LiteralExpression>location).text;
827+
}
824828

825829
// Try to get the local symbol if we're dealing with an 'export default'
826830
// since that symbol has the "true" name.

tests/baselines/reference/computedPropertyNames10_ES5.symbols

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ var v = {
2929
>s : Symbol(s, Decl(computedPropertyNames10_ES5.ts, 0, 3))
3030

3131
[""]() { },
32+
>"" : Symbol([""], Decl(computedPropertyNames10_ES5.ts, 8, 15))
33+
3234
[0]() { },
35+
>0 : Symbol([0], Decl(computedPropertyNames10_ES5.ts, 9, 15))
36+
3337
[a]() { },
3438
>a : Symbol(a, Decl(computedPropertyNames10_ES5.ts, 2, 3))
3539

tests/baselines/reference/computedPropertyNames10_ES6.symbols

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ var v = {
2929
>s : Symbol(s, Decl(computedPropertyNames10_ES6.ts, 0, 3))
3030

3131
[""]() { },
32+
>"" : Symbol([""], Decl(computedPropertyNames10_ES6.ts, 8, 15))
33+
3234
[0]() { },
35+
>0 : Symbol([0], Decl(computedPropertyNames10_ES6.ts, 9, 15))
36+
3337
[a]() { },
3438
>a : Symbol(a, Decl(computedPropertyNames10_ES6.ts, 2, 3))
3539

tests/baselines/reference/computedPropertyNames11_ES5.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,16 @@ var v = (_a = {},
4646
enumerable: true,
4747
configurable: true
4848
}),
49-
,
50-
,
49+
Object.defineProperty(_a, "", {
50+
set: function (v) { },
51+
enumerable: true,
52+
configurable: true
53+
}),
54+
Object.defineProperty(_a, 0, {
55+
get: function () { return 0; },
56+
enumerable: true,
57+
configurable: true
58+
}),
5159
Object.defineProperty(_a, a, {
5260
set: function (v) { },
5361
enumerable: true,

tests/baselines/reference/computedPropertyNames11_ES5.symbols

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@ var v = {
3131
>s : Symbol(s, Decl(computedPropertyNames11_ES5.ts, 0, 3))
3232

3333
set [""](v) { },
34+
>"" : Symbol([""], Decl(computedPropertyNames11_ES5.ts, 8, 29))
3435
>v : Symbol(v, Decl(computedPropertyNames11_ES5.ts, 9, 13))
3536

3637
get [0]() { return 0; },
38+
>0 : Symbol([0], Decl(computedPropertyNames11_ES5.ts, 9, 20))
39+
3740
set [a](v) { },
3841
>a : Symbol(a, Decl(computedPropertyNames11_ES5.ts, 2, 3))
3942
>v : Symbol(v, Decl(computedPropertyNames11_ES5.ts, 11, 12))

tests/baselines/reference/computedPropertyNames11_ES6.symbols

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@ var v = {
3131
>s : Symbol(s, Decl(computedPropertyNames11_ES6.ts, 0, 3))
3232

3333
set [""](v) { },
34+
>"" : Symbol([""], Decl(computedPropertyNames11_ES6.ts, 8, 29))
3435
>v : Symbol(v, Decl(computedPropertyNames11_ES6.ts, 9, 13))
3536

3637
get [0]() { return 0; },
38+
>0 : Symbol([0], Decl(computedPropertyNames11_ES6.ts, 9, 20))
39+
3740
set [a](v) { },
3841
>a : Symbol(a, Decl(computedPropertyNames11_ES6.ts, 2, 3))
3942
>v : Symbol(v, Decl(computedPropertyNames11_ES6.ts, 11, 12))

tests/baselines/reference/computedPropertyNames13_ES5.symbols

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ class C {
2929
>s : Symbol(s, Decl(computedPropertyNames13_ES5.ts, 0, 3))
3030

3131
static [""]() { }
32+
>"" : Symbol(C[[""]], Decl(computedPropertyNames13_ES5.ts, 8, 14))
33+
3234
[0]() { }
35+
>0 : Symbol(C[[0]], Decl(computedPropertyNames13_ES5.ts, 9, 21))
36+
3337
[a]() { }
3438
>a : Symbol(a, Decl(computedPropertyNames13_ES5.ts, 2, 3))
3539

0 commit comments

Comments
 (0)