diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 3ef578cda42..645d914e0fb 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -304,7 +304,7 @@ namespace ts { } function getDisplayName(node: Declaration): string { - return (node as RealDeclaration).name ? declarationNameToString((node as RealDeclaration).name) : getDeclarationName(node); + return (node as DeclarationBase).name ? declarationNameToString((node as DeclarationBase).name) : getDeclarationName(node); } /** @@ -367,8 +367,8 @@ namespace ts { symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name)); } else { - if ((node as RealDeclaration).name) { - (node as RealDeclaration).name.parent = node; + if ((node as DeclarationBase).name) { + (node as DeclarationBase).name.parent = node; } // Report errors every position with duplicate declaration diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8311bd00503..b293da3e74e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3617,7 +3617,7 @@ namespace ts { }); } - function isDeclarationVisible(node: Declaration): boolean { + function isDeclarationVisible(node: Node): boolean { if (node) { const links = getNodeLinks(node); if (links.isVisible === undefined) { @@ -3631,10 +3631,10 @@ namespace ts { function determineIfDeclarationIsVisible() { switch (node.kind) { case SyntaxKind.BindingElement: - return isDeclarationVisible(node.parent.parent); + return isDeclarationVisible(node.parent.parent); case SyntaxKind.VariableDeclaration: - if (isBindingPattern(node.name) && - !(node.name).elements.length) { + const declaration = node as VariableDeclaration; + if (isBindingPattern(declaration.name) && !declaration.name.elements.length) { // If the binding pattern is empty, this variable declaration is not visible return false; } @@ -3657,7 +3657,7 @@ namespace ts { return isGlobalSourceFile(parent); } // Exported members/ambient module elements (exception import declaration) are visible if parent is visible - return isDeclarationVisible(parent); + return isDeclarationVisible(parent); case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: @@ -3687,7 +3687,7 @@ namespace ts { case SyntaxKind.UnionType: case SyntaxKind.IntersectionType: case SyntaxKind.ParenthesizedType: - return isDeclarationVisible(node.parent); + return isDeclarationVisible(node.parent); // Default binding, import specifier and namespace import is visible // only on demand so by default it is not visible @@ -6235,8 +6235,8 @@ namespace ts { case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return (node).name.kind === SyntaxKind.ComputedPropertyName - && traverse((node).name); + return (node).name.kind === SyntaxKind.ComputedPropertyName + && traverse((node).name); default: return !nodeStartsNewLexicalEnvironment(node) && !isPartOfTypeNode(node) && forEachChild(node, traverse); @@ -21841,7 +21841,7 @@ namespace ts { function isTypeDeclarationName(name: Node): boolean { return name.kind === SyntaxKind.Identifier && isTypeDeclaration(name.parent) && - (name.parent).name === name; + (name.parent).name === name; } function isTypeDeclaration(node: Node): boolean { @@ -22469,7 +22469,7 @@ namespace ts { // Return true if the given node is a declaration of a nested block scoped entity with a name that either hides an // existing name or might hide a name when compiled downlevel - function isDeclarationWithCollidingName(node: Declaration): boolean { + function isDeclarationWithCollidingName(node: Node): boolean { node = getParseTreeNode(node, isDeclaration); if (node) { const symbol = getSymbolOfNode(node); diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 188da04b36c..4165b0679e1 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -3748,7 +3748,7 @@ namespace ts { case SyntaxKind.ClassDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.VariableDeclaration: - return (parent).name === node + return (parent).name === node && resolver.isDeclarationWithCollidingName(parent); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index fe499e0433d..c7ab80c888e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -603,15 +603,75 @@ namespace ts { export type DeclarationName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | BindingPattern; - export interface RealDeclaration extends Node { + export interface DeclarationBase extends Node { _declarationBrand: any; name?: DeclarationName; } - // Binary expressions can be declarations if they are 'exports.foo = bar' expressions in JS files - export type Declaration = RealDeclaration | BinaryExpression; + export type Declaration = + | ArrowFunction + // Binary expressions can be declarations if they are 'exports.foo = bar' expressions in JS files + | BinaryExpression + | BindingElement + | CallExpression + | CallSignatureDeclaration + | ClassDeclaration + | ClassElement + | ClassExpression + | ClassLikeDeclaration + | ConstructSignatureDeclaration + | ConstructorDeclaration + | ConstructorTypeNode + | EnumDeclaration + | EnumMember + | ExportAssignment + | ExportDeclaration + | ExportSpecifier + | FunctionDeclaration + | FunctionExpression + | FunctionTypeNode + | GetAccessorDeclaration + | ImportClause + | ImportEqualsDeclaration + | ImportSpecifier + | IndexSignatureDeclaration + | InterfaceDeclaration + | JSDocFunctionType + | JSDocNamespaceDeclaration + | JSDocPropertyTag + | JSDocTypedefTag + | JsxAttribute + | JsxAttributes + | JsxSpreadAttribute + | MappedTypeNode + | MethodDeclaration + | MethodSignature + | MissingDeclaration + | ModuleDeclaration + | NamespaceDeclaration + | NamespaceExportDeclaration + | NamespaceImport + | NewExpression + | ObjectLiteralExpression + | ParameterDeclaration + | PropertyAccessExpression + | PropertyAssignment + | PropertyDeclaration + | PropertySignature + | SemicolonClassElement + | SetAccessorDeclaration + | ShorthandPropertyAssignment + | SignatureDeclaration + | SourceFile + | SpreadAssignment + | TypeAliasDeclaration + | TypeElement + | TypeLiteralNode + | TypeParameterDeclaration + | VariableDeclaration + | VariableLikeDeclaration; - export interface DeclarationStatement extends RealDeclaration, Statement { + export interface DeclarationStatement extends DeclarationBase, Statement { name?: Identifier | StringLiteral | NumericLiteral; } @@ -625,7 +685,7 @@ namespace ts { expression: LeftHandSideExpression; } - export interface TypeParameterDeclaration extends RealDeclaration { + export interface TypeParameterDeclaration extends DeclarationBase { kind: SyntaxKind.TypeParameter; parent?: DeclarationWithTypeParameters; name: Identifier; @@ -636,7 +696,23 @@ namespace ts { expression?: Expression; } - export interface SignatureDeclaration extends RealDeclaration { + export interface SignatureDeclaration extends DeclarationBase { + kind: + | SyntaxKind.CallSignature + | SyntaxKind.ConstructSignature + | SyntaxKind.ConstructorType + | SyntaxKind.MethodSignature + | SyntaxKind.IndexSignature + | SyntaxKind.FunctionType + | SyntaxKind.JSDocFunctionType + | SyntaxKind.FunctionDeclaration + | SyntaxKind.MethodDeclaration + | SyntaxKind.GetAccessor + | SyntaxKind.SetAccessor + | SyntaxKind.Constructor + | SyntaxKind.ArrowFunction + | SyntaxKind.FunctionExpression + name?: PropertyName; typeParameters?: NodeArray; parameters: NodeArray; @@ -653,7 +729,7 @@ namespace ts { export type BindingName = Identifier | BindingPattern; - export interface VariableDeclaration extends RealDeclaration { + export interface VariableDeclaration extends DeclarationBase { kind: SyntaxKind.VariableDeclaration; parent?: VariableDeclarationList | CatchClause; name: BindingName; // Declared variable name @@ -667,7 +743,7 @@ namespace ts { declarations: NodeArray; } - export interface ParameterDeclaration extends RealDeclaration { + export interface ParameterDeclaration extends DeclarationBase { kind: SyntaxKind.Parameter; parent?: SignatureDeclaration; dotDotDotToken?: DotDotDotToken; // Present on rest parameter @@ -677,7 +753,7 @@ namespace ts { initializer?: Expression; // Optional initializer } - export interface BindingElement extends RealDeclaration { + export interface BindingElement extends DeclarationBase { kind: SyntaxKind.BindingElement; parent?: BindingPattern; propertyName?: PropertyName; // Binding property name (in object binding pattern) @@ -702,7 +778,7 @@ namespace ts { initializer?: Expression; // Optional initializer } - export interface ObjectLiteralElement extends RealDeclaration { + export interface ObjectLiteralElement extends DeclarationBase { _objectLiteralBrandBrand: any; name?: PropertyName; } @@ -737,16 +813,24 @@ namespace ts { expression: Expression; } - // SyntaxKind.VariableDeclaration - // SyntaxKind.Parameter - // SyntaxKind.BindingElement - // SyntaxKind.Property - // SyntaxKind.PropertyAssignment - // SyntaxKind.JsxAttribute - // SyntaxKind.ShorthandPropertyAssignment - // SyntaxKind.EnumMember - // SyntaxKind.JSDocPropertyTag - export interface VariableLikeDeclaration extends RealDeclaration { + /** + * There aren't any explicit subtypes of VariableLikeDeclaration; + * it's just structurally relatable to a number of types. + * (Maybe it should be an intersection of the below types.) + */ + export interface VariableLikeDeclaration extends DeclarationBase { + kind: + | SyntaxKind.VariableDeclaration + | SyntaxKind.Parameter + | SyntaxKind.BindingElement + | SyntaxKind.PropertyAssignment + | SyntaxKind.PropertyDeclaration + | SyntaxKind.PropertySignature + | SyntaxKind.JsxAttribute + | SyntaxKind.ShorthandPropertyAssignment + | SyntaxKind.EnumMember + | SyntaxKind.JSDocPropertyTag + | SyntaxKind.JSDocRecordMember; propertyName?: PropertyName; dotDotDotToken?: DotDotDotToken; name: DeclarationName; @@ -755,10 +839,6 @@ namespace ts { initializer?: Expression; } - export interface PropertyLikeDeclaration extends RealDeclaration { - name: PropertyName; - } - export interface ObjectBindingPattern extends Node { kind: SyntaxKind.ObjectBindingPattern; parent?: VariableDeclaration | ParameterDeclaration | BindingElement; @@ -904,7 +984,7 @@ namespace ts { } // A TypeLiteral is the declaration node for an anonymous symbol. - export interface TypeLiteralNode extends TypeNode, RealDeclaration { + export interface TypeLiteralNode extends TypeNode, DeclarationBase { kind: SyntaxKind.TypeLiteral; members: NodeArray; } @@ -948,7 +1028,7 @@ namespace ts { indexType: TypeNode; } - export interface MappedTypeNode extends TypeNode, RealDeclaration { + export interface MappedTypeNode extends TypeNode, DeclarationBase { kind: SyntaxKind.MappedType; parent?: TypeAliasDeclaration; readonlyToken?: ReadonlyToken; @@ -1405,7 +1485,7 @@ namespace ts { * JSXAttribute or JSXSpreadAttribute. ObjectLiteralExpression, on the other hand, can only have properties of type * ObjectLiteralElement (e.g. PropertyAssignment, ShorthandPropertyAssignment etc.) */ - export interface ObjectLiteralExpressionBase extends PrimaryExpression, RealDeclaration { + export interface ObjectLiteralExpressionBase extends PrimaryExpression, DeclarationBase { properties: NodeArray; } @@ -1419,7 +1499,7 @@ namespace ts { export type EntityNameExpression = Identifier | PropertyAccessEntityNameExpression | ParenthesizedExpression; export type EntityNameOrEntityNameExpression = EntityName | EntityNameExpression; - export interface PropertyAccessExpression extends MemberExpression, RealDeclaration { + export interface PropertyAccessExpression extends MemberExpression, DeclarationBase { kind: SyntaxKind.PropertyAccessExpression; expression: LeftHandSideExpression; name: Identifier; @@ -1451,7 +1531,7 @@ namespace ts { | SuperElementAccessExpression ; - export interface CallExpression extends LeftHandSideExpression, RealDeclaration { + export interface CallExpression extends LeftHandSideExpression, DeclarationBase { kind: SyntaxKind.CallExpression; expression: LeftHandSideExpression; typeArguments?: NodeArray; @@ -1470,7 +1550,7 @@ namespace ts { typeArguments?: NodeArray; } - export interface NewExpression extends PrimaryExpression, RealDeclaration { + export interface NewExpression extends PrimaryExpression, DeclarationBase { kind: SyntaxKind.NewExpression; expression: LeftHandSideExpression; typeArguments?: NodeArray; @@ -1528,6 +1608,7 @@ namespace ts { export type JsxTagNameExpression = PrimaryExpression | PropertyAccessExpression; export interface JsxAttributes extends ObjectLiteralExpressionBase { + kind: SyntaxKind.JsxAttributes; parent?: JsxOpeningLikeElement; } @@ -1764,7 +1845,10 @@ namespace ts { export type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration; - export interface ClassLikeDeclaration extends RealDeclaration { + export interface ClassLikeDeclaration extends DeclarationBase { + kind: + | SyntaxKind.ClassDeclaration + | SyntaxKind.ClassExpression; name?: Identifier; typeParameters?: NodeArray; heritageClauses?: NodeArray; @@ -1780,12 +1864,30 @@ namespace ts { kind: SyntaxKind.ClassExpression; } - export interface ClassElement extends RealDeclaration { + export interface ClassElement extends DeclarationBase { + kind: + | SyntaxKind.PropertyDeclaration + | SyntaxKind.MethodDeclaration + | SyntaxKind.Constructor + | SyntaxKind.SemicolonClassElement + | SyntaxKind.GetAccessor + | SyntaxKind.SetAccessor + | SyntaxKind.IndexSignature + | SyntaxKind.MissingDeclaration; _classElementBrand: any; name?: PropertyName; } - export interface TypeElement extends RealDeclaration { + export interface TypeElement extends DeclarationBase { + kind: + | SyntaxKind.CallSignature + | SyntaxKind.ConstructSignature + | SyntaxKind.PropertySignature + | SyntaxKind.MethodSignature + | SyntaxKind.IndexSignature + | SyntaxKind.MissingDeclaration + | SyntaxKind.JSDocPropertyTag + | SyntaxKind.JSDocRecordMember; _typeElementBrand: any; name?: PropertyName; questionToken?: QuestionToken; @@ -1813,7 +1915,7 @@ namespace ts { type: TypeNode; } - export interface EnumMember extends RealDeclaration { + export interface EnumMember extends DeclarationBase { kind: SyntaxKind.EnumMember; parent?: EnumDeclaration; // This does include ComputedPropertyName, but the parser will give an error @@ -1902,14 +2004,14 @@ namespace ts { // import d, * as ns from "mod" => name = d, namedBinding: NamespaceImport = { name: ns } // import { a, b as x } from "mod" => name = undefined, namedBinding: NamedImports = { elements: [{ name: a }, { name: x, propertyName: b}]} // import d, { a, b as x } from "mod" => name = d, namedBinding: NamedImports = { elements: [{ name: a }, { name: x, propertyName: b}]} - export interface ImportClause extends RealDeclaration { + export interface ImportClause extends DeclarationBase { kind: SyntaxKind.ImportClause; parent?: ImportDeclaration; name?: Identifier; // Default binding namedBindings?: NamedImportBindings; } - export interface NamespaceImport extends RealDeclaration { + export interface NamespaceImport extends DeclarationBase { kind: SyntaxKind.NamespaceImport; parent?: ImportClause; name: Identifier; @@ -1942,14 +2044,14 @@ namespace ts { export type NamedImportsOrExports = NamedImports | NamedExports; - export interface ImportSpecifier extends RealDeclaration { + export interface ImportSpecifier extends DeclarationBase { kind: SyntaxKind.ImportSpecifier; parent?: NamedImports; propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent) name: Identifier; // Declared name } - export interface ExportSpecifier extends RealDeclaration { + export interface ExportSpecifier extends DeclarationBase { kind: SyntaxKind.ExportSpecifier; parent?: NamedExports; propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent) @@ -2115,7 +2217,7 @@ namespace ts { typeExpression: JSDocTypeExpression; } - export interface JSDocTypedefTag extends JSDocTag, RealDeclaration { + export interface JSDocTypedefTag extends JSDocTag, DeclarationBase { kind: SyntaxKind.JSDocTypedefTag; fullName?: JSDocNamespaceDeclaration | Identifier; name?: Identifier; @@ -2249,7 +2351,7 @@ namespace ts { // Source files are declarations when they are external modules. - export interface SourceFile extends RealDeclaration { + export interface SourceFile extends DeclarationBase { kind: SyntaxKind.SourceFile; statements: NodeArray; endOfFileToken: Token; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index df2a10bc99e..b08a53f7c4c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -11,36 +11,6 @@ namespace ts { isTypeReferenceDirective?: boolean; } - export function getNameOfDeclaration(declaration: Declaration): DeclarationName { - if (!declaration) { - return undefined; - } - if (declaration.kind === SyntaxKind.BinaryExpression) { - const kind = getSpecialPropertyAssignmentKind(declaration as BinaryExpression); - const lhs = (declaration as BinaryExpression).left; - switch (kind) { - case SpecialPropertyAssignmentKind.None: - case SpecialPropertyAssignmentKind.ModuleExports: - return undefined; - case SpecialPropertyAssignmentKind.ExportsProperty: - if (lhs.kind === SyntaxKind.Identifier) { - return (lhs as PropertyAccessExpression).name; - } - else { - return ((lhs as PropertyAccessExpression).expression as PropertyAccessExpression).name; - } - case SpecialPropertyAssignmentKind.ThisProperty: - case SpecialPropertyAssignmentKind.Property: - return (lhs as PropertyAccessExpression).name; - case SpecialPropertyAssignmentKind.PrototypeProperty: - return ((lhs as PropertyAccessExpression).expression as PropertyAccessExpression).name; - } - } - else { - return declaration.name; - } - } - export function getDeclarationOfKind(symbol: Symbol, kind: SyntaxKind): Declaration { const declarations = symbol.declarations; if (declarations) { @@ -597,7 +567,7 @@ namespace ts { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.TypeAliasDeclaration: - errorNode = (node).name; + errorNode = (node).name; break; case SyntaxKind.ArrowFunction: return getErrorSpanForArrowFunction(sourceFile, node); @@ -1803,6 +1773,37 @@ namespace ts { return false; } + export function getNameOfDeclaration(declaration: Declaration): DeclarationName { + if (!declaration) { + return undefined; + } + if (declaration.kind === SyntaxKind.BinaryExpression) { + const kind = getSpecialPropertyAssignmentKind(declaration); + const lhs = (declaration as BinaryExpression).left; + switch (kind) { + case SpecialPropertyAssignmentKind.None: + case SpecialPropertyAssignmentKind.ModuleExports: + return undefined; + case SpecialPropertyAssignmentKind.ExportsProperty: + if (lhs.kind === SyntaxKind.Identifier) { + return (lhs as PropertyAccessExpression).name; + } + else { + return ((lhs as PropertyAccessExpression).expression as PropertyAccessExpression).name; + } + case SpecialPropertyAssignmentKind.ThisProperty: + case SpecialPropertyAssignmentKind.Property: + return (lhs as PropertyAccessExpression).name; + case SpecialPropertyAssignmentKind.PrototypeProperty: + return ((lhs as PropertyAccessExpression).expression as PropertyAccessExpression).name; + } + } + else { + return declaration.name; + } + } + + export function isLiteralComputedPropertyDeclarationName(node: Node) { return (node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NumericLiteral) && node.parent.kind === SyntaxKind.ComputedPropertyName && @@ -1823,7 +1824,7 @@ namespace ts { case SyntaxKind.PropertyAssignment: case SyntaxKind.PropertyAccessExpression: // Name in member declaration or property name in property access - return (parent).name === node; + return (parent).name === node; case SyntaxKind.QualifiedName: // Name on right hand side of dot in a type query if ((parent).right === node) { @@ -4102,7 +4103,7 @@ namespace ts { || kind === SyntaxKind.MergeDeclarationMarker; } - export function isDeclaration(node: Node): node is RealDeclaration { + export function isDeclaration(node: Node): node is DeclarationBase { return isDeclarationKind(node.kind); }