-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Support some late-bound special property assignments #33220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
37674e0
a2e3797
5d4ba79
489a01b
108ea20
d4ed5e9
5b1f766
b8be6d9
11b3448
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2622,7 +2622,12 @@ namespace ts { | |
// Declare a 'member' if the container is an ES5 class or ES6 constructor | ||
constructorSymbol.members = constructorSymbol.members || createSymbolTable(); | ||
// It's acceptable for multiple 'this' assignments of the same identifier to occur | ||
declareSymbol(constructorSymbol.members, constructorSymbol, node, SymbolFlags.Property | SymbolFlags.Assignment, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property); | ||
if (hasDynamicName(node)) { | ||
bindDynamicallyNamedThisPropertyAssignment(node, constructorSymbol); | ||
} | ||
else { | ||
declareSymbol(constructorSymbol.members, constructorSymbol, node, SymbolFlags.Property | SymbolFlags.Assignment, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property); | ||
} | ||
addDeclarationToSymbol(constructorSymbol, constructorSymbol.valueDeclaration, SymbolFlags.Class); | ||
} | ||
break; | ||
|
@@ -2636,7 +2641,12 @@ namespace ts { | |
// Bind this property to the containing class | ||
const containingClass = thisContainer.parent; | ||
const symbolTable = hasModifier(thisContainer, ModifierFlags.Static) ? containingClass.symbol.exports! : containingClass.symbol.members!; | ||
declareSymbol(symbolTable, containingClass.symbol, node, SymbolFlags.Property | SymbolFlags.Assignment, SymbolFlags.None, /*isReplaceableByMethod*/ true); | ||
if (hasDynamicName(node)) { | ||
bindDynamicallyNamedThisPropertyAssignment(node, containingClass.symbol); | ||
} | ||
else { | ||
declareSymbol(symbolTable, containingClass.symbol, node, SymbolFlags.Property | SymbolFlags.Assignment, SymbolFlags.None, /*isReplaceableByMethod*/ true); | ||
} | ||
break; | ||
case SyntaxKind.SourceFile: | ||
// this.property = assignment in a source file -- declare symbol in exports for a module, in locals for a script | ||
|
@@ -2653,6 +2663,18 @@ namespace ts { | |
} | ||
} | ||
|
||
function bindDynamicallyNamedThisPropertyAssignment(node: BinaryExpression | DynamicNamedDeclaration, symbol: Symbol) { | ||
bindAnonymousDeclaration(node, SymbolFlags.Property, InternalSymbolName.Computed); | ||
addLateBoundAssignmentDeclarationToSymbol(node, symbol); | ||
} | ||
|
||
function addLateBoundAssignmentDeclarationToSymbol(node: BinaryExpression | DynamicNamedDeclaration, symbol: Symbol | undefined) { | ||
if (symbol) { | ||
const members = symbol.assignmentDeclarationMembers || (symbol.assignmentDeclarationMembers = createMap()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. changing the shape of |
||
members.set("" + getNodeId(node), node); | ||
} | ||
} | ||
|
||
function bindSpecialPropertyDeclaration(node: PropertyAccessExpression) { | ||
if (node.expression.kind === SyntaxKind.ThisKeyword) { | ||
bindThisPropertyAssignment(node); | ||
|
@@ -2722,7 +2744,14 @@ namespace ts { | |
bindExportsPropertyAssignment(node); | ||
} | ||
else { | ||
bindStaticPropertyAssignment(lhs); | ||
if (hasDynamicName(node)) { | ||
bindAnonymousDeclaration(node, SymbolFlags.Property | SymbolFlags.Assignment, InternalSymbolName.Computed); | ||
const sym = bindPotentiallyMissingNamespaces(parentSymbol, lhs.expression, isTopLevelNamespaceAssignment(lhs), /*isPrototype*/ false, /*containerIsClass*/ false); | ||
addLateBoundAssignmentDeclarationToSymbol(node, sym); | ||
} | ||
else { | ||
bindStaticPropertyAssignment(lhs); | ||
} | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -814,7 +814,7 @@ namespace ts { | |
|
||
export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName; | ||
|
||
export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern; | ||
export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. navigationBar uses There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm, it uses There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tests\cases\fourslash\navigationBarItemsSymbols1.ts There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, turns out js assignment members aren't syntactically children, so they can't be in the nav bar (which only looks at syntax members). Additionally, the nav bar excludes dynamically named members, so on two fronts these shouldn't appear in the nav bar. I've added a test showing the behavior~ |
||
|
||
export interface Declaration extends Node { | ||
_declarationBrand: any; | ||
|
@@ -829,12 +829,27 @@ namespace ts { | |
name: ComputedPropertyName; | ||
} | ||
|
||
/* @internal */ | ||
export interface DynamicNamedBinaryExpression extends BinaryExpression { | ||
left: ElementAccessExpression; | ||
} | ||
|
||
/* @internal */ | ||
// A declaration that supports late-binding (used in checker) | ||
export interface LateBoundDeclaration extends DynamicNamedDeclaration { | ||
name: LateBoundName; | ||
} | ||
|
||
/* @internal */ | ||
export interface LateBoundBinaryExpressionDeclaration extends DynamicNamedBinaryExpression { | ||
left: LateBoundElementAccessExpression; | ||
} | ||
|
||
/* @internal */ | ||
export interface LateBoundElementAccessExpression extends ElementAccessExpression { | ||
argumentExpression: EntityNameExpression; | ||
} | ||
|
||
export interface DeclarationStatement extends NamedDeclaration, Statement { | ||
name?: Identifier | StringLiteral | NumericLiteral; | ||
} | ||
|
@@ -3827,7 +3842,7 @@ namespace ts { | |
Classifiable = Class | Enum | TypeAlias | Interface | TypeParameter | Module | Alias, | ||
|
||
/* @internal */ | ||
LateBindingContainer = Class | Interface | TypeLiteral | ObjectLiteral, | ||
LateBindingContainer = Class | Interface | TypeLiteral | ObjectLiteral | Function, | ||
} | ||
|
||
export interface Symbol { | ||
|
@@ -3847,6 +3862,7 @@ namespace ts { | |
/* @internal */ isReferenced?: SymbolFlags; // True if the symbol is referenced elsewhere. Keeps track of the meaning of a reference in case a symbol is both a type parameter and parameter. | ||
/* @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol? | ||
/* @internal */ isAssigned?: boolean; // True if the symbol is a parameter with assignments | ||
/* @internal */ assignmentDeclarationMembers?: Map<Declaration>; // detected late-bound assignment declarations associated with the symbol | ||
} | ||
|
||
/* @internal */ | ||
|
Uh oh!
There was an error while loading. Please reload this page.