Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16681,6 +16681,9 @@ namespace ts {
// This is a declaration, call getSymbolOfNode
return getSymbolOfNode(node.parent);
}
else if (isLiteralComputedPropertyDeclarationName(node)) {
return getSymbolOfNode(node.parent.parent);
}

if (node.kind === SyntaxKind.Identifier) {
if (isInRightSideOfImportOrExportAssignment(<Identifier>node)) {
Expand Down Expand Up @@ -16912,7 +16915,11 @@ namespace ts {
return symbols;
}
else if (symbol.flags & SymbolFlags.Transient) {
const target = getSymbolLinks(symbol).target;
let target: Symbol;
let next = symbol;
while (next = getSymbolLinks(next).target) {
target = next;
}
if (target) {
return [target];
}
Expand Down
9 changes: 9 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1565,6 +1565,12 @@ namespace ts {
return false;
}

export function isLiteralComputedPropertyDeclarationName(node: Node) {
return (node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NumericLiteral) &&
node.parent.kind === SyntaxKind.ComputedPropertyName &&
isDeclaration(node.parent.parent);
}

// Return true if the given identifier is classified as an IdentifierName
export function isIdentifierName(node: Identifier): boolean {
let parent = node.parent;
Expand Down Expand Up @@ -1750,6 +1756,9 @@ namespace ts {
const rightHandSideName = (<PropertyAccessExpression>nameExpression).name.text;
return getPropertyNameForKnownSymbolName(rightHandSideName);
}
else if (nameExpression.kind === SyntaxKind.StringLiteral || nameExpression.kind === SyntaxKind.NumericLiteral) {
return (<LiteralExpression>nameExpression).text;
}
}

return undefined;
Expand Down
105 changes: 67 additions & 38 deletions src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2581,10 +2581,33 @@ namespace ts {
isFunctionLike(node.parent) && (<FunctionLikeDeclaration>node.parent).name === node;
}

/** Returns true if node is a name of an object literal property, e.g. "a" in x = { "a": 1 } */
function isNameOfPropertyAssignment(node: Node): boolean {
return (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NumericLiteral) &&
(node.parent.kind === SyntaxKind.PropertyAssignment || node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) && (<PropertyDeclaration>node.parent).name === node;
function isObjectLiteralPropertyDeclaration(node: Node): node is ObjectLiteralElement {
switch (node.kind) {
case SyntaxKind.PropertyAssignment:
case SyntaxKind.ShorthandPropertyAssignment:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return true;
}
return false;
}

/**
* Returns the containing object literal property declaration given a possible name node, e.g. "a" in x = { "a": 1 }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the comment and example!

*/
function getContainingObjectLiteralElement(node: Node): ObjectLiteralElement {
switch (node.kind) {
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
if (node.parent.kind === SyntaxKind.ComputedPropertyName) {
return isObjectLiteralPropertyDeclaration(node.parent.parent) ? node.parent.parent : undefined;
}
// intential fall through
case SyntaxKind.Identifier:
return isObjectLiteralPropertyDeclaration(node.parent) && node.parent.name === node ? node.parent : undefined;
}
return undefined;
}

function isLiteralNameOfPropertyDeclarationOrIndexAccess(node: Node): boolean {
Expand All @@ -2602,6 +2625,8 @@ namespace ts {
return (<Declaration>node.parent).name === node;
case SyntaxKind.ElementAccessExpression:
return (<ElementAccessExpression>node.parent).argumentExpression === node;
case SyntaxKind.ComputedPropertyName:
return true;
}
}

Expand Down Expand Up @@ -6208,7 +6233,8 @@ namespace ts {
// If the location is name of property symbol from object literal destructuring pattern
// Search the property symbol
// for ( { property: p2 } of elems) { }
if (isNameOfPropertyAssignment(location) && location.parent.kind !== SyntaxKind.ShorthandPropertyAssignment) {
const containingObjectLiteralElement = getContainingObjectLiteralElement(location);
if (containingObjectLiteralElement && containingObjectLiteralElement.kind !== SyntaxKind.ShorthandPropertyAssignment) {
const propertySymbol = getPropertySymbolOfDestructuringAssignment(location);
if (propertySymbol) {
result.push(propertySymbol);
Expand All @@ -6234,8 +6260,8 @@ namespace ts {
// If the location is in a context sensitive location (i.e. in an object literal) try
// to get a contextual type for it, and add the property symbol from the contextual
// type to the search set
if (isNameOfPropertyAssignment(location)) {
forEach(getPropertySymbolsFromContextualType(location), contextualSymbol => {
if (containingObjectLiteralElement) {
forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement), contextualSymbol => {
addRange(result, typeChecker.getRootSymbols(contextualSymbol));
});

Expand Down Expand Up @@ -6362,8 +6388,9 @@ namespace ts {
// 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
if (isNameOfPropertyAssignment(referenceLocation)) {
const contextualSymbol = forEach(getPropertySymbolsFromContextualType(referenceLocation), contextualSymbol => {
const containingObjectLiteralElement = getContainingObjectLiteralElement(referenceLocation);
if (containingObjectLiteralElement) {
const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement), contextualSymbol => {
return forEach(typeChecker.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
});

Expand Down Expand Up @@ -6409,37 +6436,38 @@ namespace ts {
});
}

function getPropertySymbolsFromContextualType(node: Node): Symbol[] {
if (isNameOfPropertyAssignment(node)) {
const objectLiteral = <ObjectLiteralExpression>node.parent.parent;
const contextualType = typeChecker.getContextualType(objectLiteral);
const name = (<Identifier>node).text;
if (contextualType) {
if (contextualType.flags & TypeFlags.Union) {
// This is a union type, first see if the property we are looking for is a union property (i.e. exists in all types)
// if not, search the constituent types for the property
const unionProperty = contextualType.getProperty(name);
if (unionProperty) {
return [unionProperty];
}
else {
const result: Symbol[] = [];
forEach((<UnionType>contextualType).types, t => {
const symbol = t.getProperty(name);
if (symbol) {
result.push(symbol);
}
});
return result;
}
}
else {
const symbol = contextualType.getProperty(name);
function getNameFromObjectLiteralElement(node: ObjectLiteralElement) {
if (node.name.kind === SyntaxKind.ComputedPropertyName) {
const nameExpression = (<ComputedPropertyName>node.name).expression;
// treat computed property names where expression is string/numeric literal as just string/numeric literal
if (isStringOrNumericLiteral(nameExpression.kind)) {
return (<LiteralExpression>nameExpression).text;
}
return undefined;
}
return (<Identifier | LiteralExpression>node.name).text;
}

function getPropertySymbolsFromContextualType(node: ObjectLiteralElement): Symbol[] {
const objectLiteral = <ObjectLiteralExpression>node.parent;
const contextualType = typeChecker.getContextualType(objectLiteral);
const name = getNameFromObjectLiteralElement(node);
if (name && contextualType) {
const result: Symbol[] = [];
const symbol = contextualType.getProperty(name);
if (symbol) {
result.push(symbol);
}

if (contextualType.flags & TypeFlags.Union) {
forEach((<UnionType>contextualType).types, t => {
const symbol = t.getProperty(name);
if (symbol) {
return [symbol];
result.push(symbol);
}
}
});
}
return result;
}
return undefined;
}
Expand Down Expand Up @@ -7901,7 +7929,8 @@ namespace ts {
// "a['propname']" then we want to store "propname" in the name table.
if (isDeclarationName(node) ||
node.parent.kind === SyntaxKind.ExternalModuleReference ||
isArgumentOfElementAccessExpression(node)) {
isArgumentOfElementAccessExpression(node) ||
isLiteralComputedPropertyDeclarationName(node)) {

nameTable[(<LiteralExpression>node).text] = nameTable[(<LiteralExpression>node).text] === undefined ? node.pos : -1;
}
Expand Down
4 changes: 4 additions & 0 deletions src/services/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,10 @@ namespace ts {
if (isImportOrExportSpecifierName(location)) {
return location.getText();
}
else if (isStringOrNumericLiteral(location.kind) &&
location.parent.kind === SyntaxKind.ComputedPropertyName) {
return (<LiteralExpression>location).text;
}

// Try to get the local symbol if we're dealing with an 'export default'
// since that symbol has the "true" name.
Expand Down
4 changes: 4 additions & 0 deletions tests/baselines/reference/computedPropertyNames10_ES5.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ var v = {
>s : Symbol(s, Decl(computedPropertyNames10_ES5.ts, 0, 3))

[""]() { },
>"" : Symbol([""], Decl(computedPropertyNames10_ES5.ts, 8, 15))

[0]() { },
>0 : Symbol([0], Decl(computedPropertyNames10_ES5.ts, 9, 15))

[a]() { },
>a : Symbol(a, Decl(computedPropertyNames10_ES5.ts, 2, 3))

Expand Down
4 changes: 4 additions & 0 deletions tests/baselines/reference/computedPropertyNames10_ES6.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ var v = {
>s : Symbol(s, Decl(computedPropertyNames10_ES6.ts, 0, 3))

[""]() { },
>"" : Symbol([""], Decl(computedPropertyNames10_ES6.ts, 8, 15))

[0]() { },
>0 : Symbol([0], Decl(computedPropertyNames10_ES6.ts, 9, 15))

[a]() { },
>a : Symbol(a, Decl(computedPropertyNames10_ES6.ts, 2, 3))

Expand Down
12 changes: 10 additions & 2 deletions tests/baselines/reference/computedPropertyNames11_ES5.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,16 @@ var v = (_a = {},
enumerable: true,
configurable: true
}),
,
,
Object.defineProperty(_a, "", {
set: function (v) { },
enumerable: true,
configurable: true
}),
Object.defineProperty(_a, 0, {
get: function () { return 0; },
enumerable: true,
configurable: true
}),
Object.defineProperty(_a, a, {
set: function (v) { },
enumerable: true,
Expand Down
3 changes: 3 additions & 0 deletions tests/baselines/reference/computedPropertyNames11_ES5.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ var v = {
>s : Symbol(s, Decl(computedPropertyNames11_ES5.ts, 0, 3))

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

get [0]() { return 0; },
>0 : Symbol([0], Decl(computedPropertyNames11_ES5.ts, 9, 20))

set [a](v) { },
>a : Symbol(a, Decl(computedPropertyNames11_ES5.ts, 2, 3))
>v : Symbol(v, Decl(computedPropertyNames11_ES5.ts, 11, 12))
Expand Down
3 changes: 3 additions & 0 deletions tests/baselines/reference/computedPropertyNames11_ES6.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ var v = {
>s : Symbol(s, Decl(computedPropertyNames11_ES6.ts, 0, 3))

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

get [0]() { return 0; },
>0 : Symbol([0], Decl(computedPropertyNames11_ES6.ts, 9, 20))

set [a](v) { },
>a : Symbol(a, Decl(computedPropertyNames11_ES6.ts, 2, 3))
>v : Symbol(v, Decl(computedPropertyNames11_ES6.ts, 11, 12))
Expand Down
4 changes: 4 additions & 0 deletions tests/baselines/reference/computedPropertyNames13_ES5.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ class C {
>s : Symbol(s, Decl(computedPropertyNames13_ES5.ts, 0, 3))

static [""]() { }
>"" : Symbol(C[[""]], Decl(computedPropertyNames13_ES5.ts, 8, 14))

[0]() { }
>0 : Symbol(C[[0]], Decl(computedPropertyNames13_ES5.ts, 9, 21))

[a]() { }
>a : Symbol(a, Decl(computedPropertyNames13_ES5.ts, 2, 3))

Expand Down
4 changes: 4 additions & 0 deletions tests/baselines/reference/computedPropertyNames13_ES6.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ class C {
>s : Symbol(s, Decl(computedPropertyNames13_ES6.ts, 0, 3))

static [""]() { }
>"" : Symbol(C[[""]], Decl(computedPropertyNames13_ES6.ts, 8, 14))

[0]() { }
>0 : Symbol(C[[0]], Decl(computedPropertyNames13_ES6.ts, 9, 21))

[a]() { }
>a : Symbol(a, Decl(computedPropertyNames13_ES6.ts, 2, 3))

Expand Down
10 changes: 10 additions & 0 deletions tests/baselines/reference/computedPropertyNames16_ES5.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ var C = (function () {
enumerable: true,
configurable: true
});
Object.defineProperty(C, "", {
set: function (v) { },
enumerable: true,
configurable: true
});
Object.defineProperty(C.prototype, 0, {
get: function () { return 0; },
enumerable: true,
configurable: true
});
Object.defineProperty(C.prototype, a, {
set: function (v) { },
enumerable: true,
Expand Down
3 changes: 3 additions & 0 deletions tests/baselines/reference/computedPropertyNames16_ES5.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ class C {
>s : Symbol(s, Decl(computedPropertyNames16_ES5.ts, 0, 3))

static set [""](v) { }
>"" : Symbol(C[[""]], Decl(computedPropertyNames16_ES5.ts, 8, 28))
>v : Symbol(v, Decl(computedPropertyNames16_ES5.ts, 9, 20))

get [0]() { return 0; }
>0 : Symbol(C[[0]], Decl(computedPropertyNames16_ES5.ts, 9, 26))

set [a](v) { }
>a : Symbol(a, Decl(computedPropertyNames16_ES5.ts, 2, 3))
>v : Symbol(v, Decl(computedPropertyNames16_ES5.ts, 11, 12))
Expand Down
3 changes: 3 additions & 0 deletions tests/baselines/reference/computedPropertyNames16_ES6.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ class C {
>s : Symbol(s, Decl(computedPropertyNames16_ES6.ts, 0, 3))

static set [""](v) { }
>"" : Symbol(C[[""]], Decl(computedPropertyNames16_ES6.ts, 8, 28))
>v : Symbol(v, Decl(computedPropertyNames16_ES6.ts, 9, 20))

get [0]() { return 0; }
>0 : Symbol(C[[0]], Decl(computedPropertyNames16_ES6.ts, 9, 26))

set [a](v) { }
>a : Symbol(a, Decl(computedPropertyNames16_ES6.ts, 2, 3))
>v : Symbol(v, Decl(computedPropertyNames16_ES6.ts, 11, 12))
Expand Down
4 changes: 4 additions & 0 deletions tests/baselines/reference/computedPropertyNames36_ES5.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ var C = (function () {
Object.defineProperty(C.prototype, "get1", {
// Computed properties
get: function () { return new Foo; },
enumerable: true,
configurable: true
});
Object.defineProperty(C.prototype, "set1", {
set: function (p) { },
enumerable: true,
configurable: true
Expand Down
4 changes: 4 additions & 0 deletions tests/baselines/reference/computedPropertyNames37_ES5.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ var C = (function () {
Object.defineProperty(C.prototype, "get1", {
// Computed properties
get: function () { return new Foo; },
enumerable: true,
configurable: true
});
Object.defineProperty(C.prototype, "set1", {
set: function (p) { },
enumerable: true,
configurable: true
Expand Down
2 changes: 2 additions & 0 deletions tests/baselines/reference/computedPropertyNames37_ES5.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ class C {

// Computed properties
get ["get1"]() { return new Foo }
>"get1" : Symbol(C[["get1"]], Decl(computedPropertyNames37_ES5.ts, 4, 22))
>Foo : Symbol(Foo, Decl(computedPropertyNames37_ES5.ts, 0, 0))

set ["set1"](p: Foo2) { }
>"set1" : Symbol(C[["set1"]], Decl(computedPropertyNames37_ES5.ts, 7, 37))
>p : Symbol(p, Decl(computedPropertyNames37_ES5.ts, 8, 17))
>Foo2 : Symbol(Foo2, Decl(computedPropertyNames37_ES5.ts, 0, 15))
}
2 changes: 2 additions & 0 deletions tests/baselines/reference/computedPropertyNames37_ES6.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ class C {

// Computed properties
get ["get1"]() { return new Foo }
>"get1" : Symbol(C[["get1"]], Decl(computedPropertyNames37_ES6.ts, 4, 22))
>Foo : Symbol(Foo, Decl(computedPropertyNames37_ES6.ts, 0, 0))

set ["set1"](p: Foo2) { }
>"set1" : Symbol(C[["set1"]], Decl(computedPropertyNames37_ES6.ts, 7, 37))
>p : Symbol(p, Decl(computedPropertyNames37_ES6.ts, 8, 17))
>Foo2 : Symbol(Foo2, Decl(computedPropertyNames37_ES6.ts, 0, 15))
}
Loading