diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 99c21d9ff15..fcb986e5933 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -81,19 +81,16 @@ module ts { getTypeCount: () => typeCount, checkProgram: checkProgram, emitFiles: invokeEmitter, - getSymbolOfNode: getSymbolOfNode, getParentOfSymbol: getParentOfSymbol, getTypeOfSymbol: getTypeOfSymbol, - getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol, getPropertiesOfType: getPropertiesOfType, getPropertyOfType: getPropertyOfType, getSignaturesOfType: getSignaturesOfType, getIndexTypeOfType: getIndexTypeOfType, getReturnTypeOfSignature: getReturnTypeOfSignature, - resolveEntityName: resolveEntityName, getSymbolsInScope: getSymbolsInScope, getSymbolInfo: getSymbolInfo, - getTypeOfExpression: getTypeOfExpression, + getTypeOfNode: getTypeOfNode, typeToString: typeToString, symbolToString: symbolToString, getAugmentedPropertiesOfApparentType: getAugmentedPropertiesOfApparentType @@ -6546,30 +6543,42 @@ module ts { return mapToArray(symbols); } - // True if the given identifier is the identifier of a declaration node - function isDeclarationIdentifier(identifier: Identifier): boolean { - if (identifier.parent) { - switch (identifier.parent.kind) { - case SyntaxKind.TypeParameter: - case SyntaxKind.Parameter: - case SyntaxKind.VariableDeclaration: - case SyntaxKind.Property: - case SyntaxKind.PropertyAssignment: - case SyntaxKind.EnumMember: - case SyntaxKind.Method: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.FunctionExpression: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.ImportDeclaration: - return (identifier.parent).name === identifier; - case SyntaxKind.CatchBlock: - return (identifier.parent).variable === identifier; - } + // True if the given identifier, string literal, or number literal is the name of a declaration node + function isDeclarationName(name: Node): boolean { + if (name.kind !== SyntaxKind.Identifier && name.kind !== SyntaxKind.StringLiteral && name.kind !== SyntaxKind.NumericLiteral) { + return false; + } + + var parent = name.parent; + if (isDeclaration(parent) || parent.kind === SyntaxKind.FunctionExpression) { + return (parent).name === name; + } + + if (parent.kind === SyntaxKind.CatchBlock) { + return (parent).variable === name; + } + + return false; + } + + function isDeclaration(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.TypeParameter: + case SyntaxKind.Parameter: + case SyntaxKind.VariableDeclaration: + case SyntaxKind.Property: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.EnumMember: + case SyntaxKind.Method: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ImportDeclaration: + return true; } return false; } @@ -6582,6 +6591,7 @@ module ts { } function isExpression(node: Node): boolean { + // Omitted expression? switch (node.kind) { case SyntaxKind.ThisKeyword: case SyntaxKind.SuperKeyword: @@ -6605,49 +6615,119 @@ module ts { case SyntaxKind.ConditionalExpression: return true; case SyntaxKind.QualifiedName: - while (node.parent && node.parent.kind === SyntaxKind.QualifiedName) node = node.parent; - return node.parent && node.parent.kind === SyntaxKind.TypeQuery; + while (node.parent.kind === SyntaxKind.QualifiedName) node = node.parent; + return node.parent.kind === SyntaxKind.TypeQuery; case SyntaxKind.Identifier: + if (node.parent.kind === SyntaxKind.TypeQuery) { + return true; + } + // Fall through case SyntaxKind.NumericLiteral: case SyntaxKind.StringLiteral: var parent = node.parent; - if (parent) { - if (isExpression(parent)) return true; - switch (parent.kind) { - case SyntaxKind.VariableDeclaration: - case SyntaxKind.Parameter: - case SyntaxKind.Property: - case SyntaxKind.EnumMember: - return (parent).initializer === node; - case SyntaxKind.ExpressionStatement: - case SyntaxKind.IfStatement: - case SyntaxKind.DoStatement: - case SyntaxKind.WhileStatement: - case SyntaxKind.ReturnStatement: - case SyntaxKind.WithStatement: - case SyntaxKind.SwitchStatement: - case SyntaxKind.CaseClause: - case SyntaxKind.ThrowStatement: - case SyntaxKind.SwitchStatement: - return (parent).expression === node; - case SyntaxKind.ForStatement: - return (parent).initializer === node || (parent).condition === node || - (parent).iterator === node; - case SyntaxKind.ForInStatement: - return (parent).variable === node || (parent).expression === node; - } + if (parent.kind === SyntaxKind.TypeAssertion) { + return node === (parent).operand; + } + + if (isExpression(parent)) { + return true; + } + + switch (parent.kind) { + case SyntaxKind.VariableDeclaration: + case SyntaxKind.Parameter: + case SyntaxKind.Property: + case SyntaxKind.EnumMember: + return (parent).initializer === node; + case SyntaxKind.ExpressionStatement: + case SyntaxKind.IfStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.ReturnStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.CaseClause: + case SyntaxKind.ThrowStatement: + case SyntaxKind.SwitchStatement: + return (parent).expression === node; + case SyntaxKind.ForStatement: + return (parent).initializer === node || (parent).condition === node || + (parent).iterator === node; + case SyntaxKind.ForInStatement: + return (parent).variable === node || (parent).expression === node; } } return false; } + function isTypeNode(node: Node): boolean { + if (node.kind >= SyntaxKind.FirstTypeNode && node.kind <= SyntaxKind.LastTypeNode) { + return true; + } + + switch (node.kind) { + case SyntaxKind.AnyKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.BooleanKeyword: + return true; + case SyntaxKind.VoidKeyword: + return node.parent.kind !== SyntaxKind.PrefixOperator; + case SyntaxKind.StringLiteral: + return node.parent.kind === SyntaxKind.Parameter; + // Identifiers and qualified names may be type nodes, depending on their context. Climb + // above them to find the lowest container + case SyntaxKind.Identifier: + // If the identifier is the RHS of a qualified name, then it's a type iff its parent is. + if (node.parent.kind === SyntaxKind.QualifiedName) { + node = node.parent; + } + // Fall through + case SyntaxKind.QualifiedName: + var parent = node.parent; + if (parent.kind === SyntaxKind.TypeQuery) { + return false; + } + if (isTypeNode(parent)) { + return true; + } + switch (parent.kind) { + case SyntaxKind.TypeParameter: + return node === (parent).constraint; + case SyntaxKind.Property: + case SyntaxKind.Parameter: + case SyntaxKind.VariableDeclaration: + return node === (parent).type; + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.Constructor: + case SyntaxKind.Method: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return node === (parent).type; + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + return node === (parent).type; + case SyntaxKind.TypeAssertion: + return node === (parent).type; + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + return (parent).typeArguments.indexOf(node) >= 0; + } + } + + return false; + } + function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) { return (node.parent.kind === SyntaxKind.QualifiedName || node.parent.kind === SyntaxKind.PropertyAccess) && (node.parent).right === node; } function getSymbolOfIdentifier(identifier: Identifier) { - if (isDeclarationIdentifier(identifier)) { + if (isDeclarationName(identifier)) { return getSymbolOfNode(identifier.parent); } @@ -6725,14 +6805,36 @@ module ts { return undefined; } - function getTypeOfExpression(node: Node) { + function getTypeOfNode(node: Node): Type { if (isExpression(node)) { - while (isRightSideOfQualifiedNameOrPropertyAccess(node)) { - node = node.parent; - } - return getApparentType(checkExpression(node)); + return getTypeOfExpression(node); } - return unknownType; + if (isTypeNode(node)) { + if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) { + var symbol = getSymbolInfo(node); + return getDeclaredTypeOfSymbol(symbol); + } + return getTypeFromTypeNode(node); + } + + if (isDeclaration(node)) { + // In this case, we call getSymbolOfNode instead of getSymbolInfo because it is a declaration + var symbol = getSymbolOfNode(node); + return getTypeOfSymbol(symbol); + } + + var isExportAssignment = node.kind === SyntaxKind.Identifier && node.parent.kind === SyntaxKind.ExportAssignment; + if (isDeclarationName(node) || isExportAssignment) { + var symbol = getSymbolInfo(node); + return getTypeOfSymbol(symbol); + } + } + + function getTypeOfExpression(expr: Expression): Type { + if (isRightSideOfQualifiedNameOrPropertyAccess(expr)) { + expr = expr.parent; + } + return getApparentType(checkExpression(expr)); } function getAugmentedPropertiesOfApparentType(type: Type): Symbol[]{ @@ -6743,13 +6845,13 @@ module ts { var propertiesByName: Map = {}; var results: Symbol[] = []; - forEach(getPropertiesOfType(apparentType), (s) => { + forEach(getPropertiesOfType(apparentType), s => { propertiesByName[s.name] = s; results.push(s); }); var resolved = resolveObjectTypeMembers(type); - forEachValue(resolved.members, (s) => { + forEachValue(resolved.members, s => { if (symbolIsValue(s) && !propertiesByName[s.name]) { propertiesByName[s.name] = s; results.push(s); @@ -6757,7 +6859,7 @@ module ts { }); if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) { - forEach(getPropertiesOfType(globalFunctionType), (s) => { + forEach(getPropertiesOfType(globalFunctionType), s => { if (!propertiesByName[s.name]) { propertiesByName[s.name] = s; results.push(s); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ff1d344d733..bebd79fe58b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -217,7 +217,9 @@ module ts { FirstKeyword = BreakKeyword, LastKeyword = StringKeyword, FirstFutureReservedWord = ImplementsKeyword, - LastFutureReservedWord = YieldKeyword + LastFutureReservedWord = YieldKeyword, + FirstTypeNode = TypeReference, + LastTypeNode = ArrayType } export enum NodeFlags { @@ -593,19 +595,16 @@ module ts { getTypeCount(): number; checkProgram(): void; emitFiles(): EmitResult; - getSymbolOfNode(node: Node): Symbol; getParentOfSymbol(symbol: Symbol): Symbol; getTypeOfSymbol(symbol: Symbol): Type; - getDeclaredTypeOfSymbol(symbol: Symbol): Type; getPropertiesOfType(type: Type): Symbol[]; getPropertyOfType(type: Type, propetyName: string): Symbol; getSignaturesOfType(type: Type, kind: SignatureKind): Signature[]; getIndexTypeOfType(type: Type, kind: IndexKind): Type; getReturnTypeOfSignature(signature: Signature): Type; - resolveEntityName(location: Node, name: EntityName, meaning: SymbolFlags): Symbol; getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; getSymbolInfo(node: Node): Symbol; - getTypeOfExpression(node: Expression, contextualType?: Type, contextualMapper?: TypeMapper): Type; + getTypeOfNode(node: Node): Type; typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string; symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string; getAugmentedPropertiesOfApparentType(type: Type): Symbol[]; diff --git a/src/services/services.ts b/src/services/services.ts index f1a8960c54b..51ab48a9251 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1693,7 +1693,7 @@ module ts { // Right of dot member completion list if (isRightOfDot) { - var type: Type = typeInfoResolver.getTypeOfExpression(mappedNode); + var type: Type = typeInfoResolver.getTypeOfNode(mappedNode); if (!type) { return undefined; }