diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 68011b586f2..4871c6c6eed 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7143,6 +7143,22 @@ module ts { return mapToArray(symbols); } + function isTypeDeclarationName(name: Node): boolean { + return name.kind == SyntaxKind.Identifier && + isTypeDeclaration(name.parent) && + (name.parent).name === name; + } + + function isTypeDeclaration(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.TypeParameter: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + return true; + } + } + // True if the given identifier is part of a type reference function isTypeReferenceIdentifier(entityName: EntityName): boolean { var node: Node = entityName; @@ -7221,6 +7237,78 @@ module ts { return false; } + function isTypeNode(node: Node): boolean { + if (SyntaxKind.FirstTypeNode <= node.kind && 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: + // Specialized signatures can have string literals as their parameters' type names + 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: + // At this point, node is either a qualified name or an identifier + Debug.assert(node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName, "'node' was expected to be a qualified name or identifier in 'isTypeNode'."); + + var parent = node.parent; + if (parent.kind === SyntaxKind.TypeQuery) { + return false; + } + // Do not recursively call isTypeNode on the parent. In the example: + // + // var a: A.B.C; + // + // Calling isTypeNode would consider the qualified name A.B a type node. Only C or + // A.B.C is a type node. + if (SyntaxKind.FirstTypeNode <= parent.kind && parent.kind <= SyntaxKind.LastTypeNode) { + 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 && (parent).typeArguments.indexOf(node) >= 0; + } + } + + return false; + } + function isInRightSideOfImportOrExportAssignment(node: EntityName) { while (node.parent.kind === SyntaxKind.QualifiedName) { node = node.parent; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a43f31e583a..392a13c26d9 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -391,100 +391,6 @@ module ts { return false; } - /** - * Note: this function only works when given a node with valid parent pointers. - */ - export 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: - // Specialized signatures can have string literals as their parameters' type names - 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: - // At this point, node is either a qualified name or an identifier - var parent = node.parent; - if (parent.kind === SyntaxKind.TypeQuery) { - return false; - } - // Do not recursively call isTypeNode on the parent. In the example: - // - // var a: A.B.C; - // - // Calling isTypeNode would consider the qualified name A.B a type node. Only C or - // A.B.C is a type node. - if (parent.kind >= SyntaxKind.FirstTypeNode && parent.kind <= SyntaxKind.LastTypeNode) { - 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 && (parent).typeArguments.indexOf(node) >= 0; - } - } - - return false; - } - - /** - * Note: this function only works when given a node with valid parent pointers. - * - * returns true if the given identifier is the name of a type declaration node (class, interface, enum, type parameter, etc) - */ - export function isTypeDeclarationName(name: Node): boolean { - return name.kind == SyntaxKind.Identifier && - isTypeDeclaration(name.parent) && - (name.parent).name === name; - } - - - export function isTypeDeclaration(node: Node): boolean { - switch (node.kind) { - case SyntaxKind.TypeParameter: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.EnumDeclaration: - return true; - } - } - export function getContainingFunction(node: Node): SignatureDeclaration { while (true) { node = node.parent; diff --git a/src/services/services.ts b/src/services/services.ts index e2663d5455e..0e1d995ef2c 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1100,9 +1100,9 @@ module ts { filename: string; // the file where the completion was requested position: number; // position in the file where the completion was requested entries: CompletionEntry[]; // entries for this completion - symbols: Map; // symbols by entry name map - location: Node; // the node where the completion was requested - typeChecker: TypeChecker;// the typeChecker used to generate this completion + symbols: Map; // symbols by entry name map + location: Node; // the node where the completion was requested + typeChecker: TypeChecker; // the typeChecker used to generate this completion } interface FormattingOptions { @@ -1639,11 +1639,12 @@ module ts { (node.parent.kind === SyntaxKind.ImportDeclaration && (node.parent).externalModuleName === node)); } - enum SearchMeaning { + enum SemanticMeaning { None = 0x0, Value = 0x1, Type = 0x2, - Namespace = 0x4 + Namespace = 0x4, + All = Value | Type | Namespace } enum BreakContinueSearchType { @@ -1934,16 +1935,20 @@ module ts { return undefined; } + // TODO(drosen): Right now we just permit *all* semantic meanings when calling 'getSymbolKind' + // which is permissible given that it is backwards compatible; but really we should consider + // passing the meaning for the node so that we don't report that a suggestion for a value is an interface. + // We COULD also just do what 'getSymbolModifiers' does, which is to use the first declaration. return { name: displayName, - kind: getSymbolKind(symbol), + kind: getSymbolKind(symbol, SemanticMeaning.All), kindModifiers: getSymbolModifiers(symbol) }; } function getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) { function getCompletionEntriesFromSymbols(symbols: Symbol[], session: CompletionSession): void { - forEach(symbols, (symbol) => { + forEach(symbols, symbol => { var entry = createCompletionEntry(symbol); if (entry && !lookUp(session.symbols, entry.name)) { session.entries.push(entry); @@ -2328,13 +2333,20 @@ module ts { } } - function getSymbolKind(symbol: Symbol): string { + function getSymbolKind(symbol: Symbol, meaningAtLocation: SemanticMeaning): string { var flags = typeInfoResolver.getRootSymbol(symbol).getFlags(); - if (flags & SymbolFlags.Module) return ScriptElementKind.moduleElement; if (flags & SymbolFlags.Class) return ScriptElementKind.classElement; - if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement; if (flags & SymbolFlags.Enum) return ScriptElementKind.enumElement; + + // The following should only apply if encountered at a type position, + // and need to have precedence over other meanings if this is the case. + if (meaningAtLocation & SemanticMeaning.Type) { + if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement; + if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; + } + + if (flags & SymbolFlags.Module) return ScriptElementKind.moduleElement; if (flags & SymbolFlags.Variable) return ScriptElementKind.variableElement; if (flags & SymbolFlags.Function) return ScriptElementKind.functionElement; if (flags & SymbolFlags.GetAccessor) return ScriptElementKind.memberGetAccessorElement; @@ -2345,7 +2357,6 @@ module ts { if (flags & SymbolFlags.ConstructSignature) return ScriptElementKind.constructSignatureElement; if (flags & SymbolFlags.CallSignature) return ScriptElementKind.callSignatureElement; if (flags & SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement; - if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; if (flags & SymbolFlags.EnumMember) return ScriptElementKind.variableElement; if (flags & SymbolFlags.Import) return ScriptElementKind.alias; @@ -2404,6 +2415,8 @@ module ts { return undefined; } + var semanticMeaning = getMeaningFromLocation(node); + var symbol = typeInfoResolver.getSymbolInfo(node); if (!symbol) { return undefined; @@ -2420,11 +2433,6 @@ module ts { totalParts.push(spacePart()); totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile)); } - else if (symbol.flags & SymbolFlags.Interface) { - totalParts.push(keywordPart(SyntaxKind.InterfaceKeyword)); - totalParts.push(spacePart()); - totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile)); - } else if (symbol.flags & SymbolFlags.Enum) { totalParts.push(keywordPart(SyntaxKind.EnumKeyword)); totalParts.push(spacePart()); @@ -2435,12 +2443,19 @@ module ts { totalParts.push(spacePart()); totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile)); } - else if (symbol.flags & SymbolFlags.TypeParameter) { - totalParts.push(punctuationPart(SyntaxKind.OpenParenToken)); - totalParts.push(new SymbolDisplayPart("type parameter", SymbolDisplayPartKind.text, undefined)); - totalParts.push(punctuationPart(SyntaxKind.CloseParenToken)); - totalParts.push(spacePart()); - totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol)); + else if (semanticMeaning & SemanticMeaning.Type) { + if (symbol.flags & SymbolFlags.Interface) { + totalParts.push(keywordPart(SyntaxKind.InterfaceKeyword)); + totalParts.push(spacePart()); + totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile)); + } + else if (symbol.flags & SymbolFlags.TypeParameter) { + totalParts.push(punctuationPart(SyntaxKind.OpenParenToken)); + totalParts.push(new SymbolDisplayPart("type parameter", SymbolDisplayPartKind.text, undefined)); + totalParts.push(punctuationPart(SyntaxKind.CloseParenToken)); + totalParts.push(spacePart()); + totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol)); + } } else { totalParts.push(punctuationPart(SyntaxKind.OpenParenToken)); @@ -2494,7 +2509,7 @@ module ts { } return { - kind: getSymbolKind(symbol), + kind: getSymbolKind(symbol, semanticMeaning), kindModifiers: getSymbolModifiers(symbol), textSpan: new TypeScript.TextSpan(node.getStart(), node.getWidth()), displayParts: totalParts, @@ -2519,7 +2534,7 @@ module ts { memberName: new TypeScript.MemberNameString(typeInfoResolver.typeToString(type)), docComment: "", fullSymbolName: typeInfoResolver.symbolToString(symbol, getContainerNode(node)), - kind: getSymbolKind(symbol), + kind: getSymbolKind(symbol, SemanticMeaning.Type), textSpan: TypeScript.TextSpan.fromBounds(node.pos, node.end) }; } @@ -2632,10 +2647,9 @@ module ts { var declarations = symbol.getDeclarations(); var symbolName = typeInfoResolver.symbolToString(symbol); // Do not get scoped name, just the name of the symbol - var symbolKind = getSymbolKind(symbol); + var symbolKind = getSymbolKind(symbol, getMeaningFromLocation(node)); var containerSymbol = symbol.parent; var containerName = containerSymbol ? typeInfoResolver.symbolToString(containerSymbol, node) : ""; - var containerKind = containerSymbol ? getSymbolKind(symbol) : ""; if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) && !tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) { @@ -3340,7 +3354,7 @@ module ts { searchSymbol: Symbol, searchText: string, searchLocation: Node, - searchMeaning: SearchMeaning, + searchMeaning: SemanticMeaning, findInStrings: boolean, findInComments: boolean, result: ReferenceEntry[]): void { @@ -3639,114 +3653,6 @@ module ts { return undefined; } - function getMeaningFromDeclaration(node: Declaration): SearchMeaning { - switch (node.kind) { - case SyntaxKind.Parameter: - case SyntaxKind.VariableDeclaration: - case SyntaxKind.Property: - case SyntaxKind.PropertyAssignment: - case SyntaxKind.EnumMember: - case SyntaxKind.Method: - case SyntaxKind.Constructor: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - case SyntaxKind.CatchBlock: - return SearchMeaning.Value; - - case SyntaxKind.TypeParameter: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.TypeLiteral: - return SearchMeaning.Type; - - case SyntaxKind.ClassDeclaration: - case SyntaxKind.EnumDeclaration: - return SearchMeaning.Value | SearchMeaning.Type; - - case SyntaxKind.ModuleDeclaration: - if ((node).name.kind === SyntaxKind.StringLiteral) { - return SearchMeaning.Namespace | SearchMeaning.Value; - } - else if (isInstantiated(node)) { - return SearchMeaning.Namespace | SearchMeaning.Value; - } - else { - return SearchMeaning.Namespace; - } - break; - - case SyntaxKind.ImportDeclaration: - return SearchMeaning.Value | SearchMeaning.Type | SearchMeaning.Namespace; - } - Debug.fail("Unknown declaration type"); - } - - function isTypeReference(node: Node): boolean { - if (node.parent.kind === SyntaxKind.QualifiedName && (node.parent).right === node) - node = node.parent; - - return node.parent.kind === SyntaxKind.TypeReference; - } - - function isNamespaceReference(node: Node): boolean { - var root = node; - var isLastClause = true; - if (root.parent.kind === SyntaxKind.QualifiedName) { - while (root.parent && root.parent.kind === SyntaxKind.QualifiedName) - root = root.parent; - - isLastClause = (root).right === node; - } - - return root.parent.kind === SyntaxKind.TypeReference && !isLastClause; - } - - function isInRightSideOfImport(node: EntityName) { - while (node.parent.kind === SyntaxKind.QualifiedName) { - node = node.parent; - } - - return node.parent.kind === SyntaxKind.ImportDeclaration && (node.parent).entityName === node; - } - - function getMeaningFromRightHandSideOfImport(node: Node) { - Debug.assert(node.kind === SyntaxKind.Identifier); - - // import a = |b|; // Namespace - // import a = |b.c|; // Value, type, namespace - // import a = |b.c|.d; // Namespace - - if (node.parent.kind === SyntaxKind.QualifiedName && - (node.parent).right === node && - node.parent.parent.kind === SyntaxKind.ImportDeclaration) { - return SearchMeaning.Value | SearchMeaning.Type | SearchMeaning.Namespace; - } - return SearchMeaning.Namespace; - } - - function getMeaningFromLocation(node: Node): SearchMeaning { - if (node.parent.kind === SyntaxKind.ExportAssignment) { - return SearchMeaning.Value | SearchMeaning.Type | SearchMeaning.Namespace; - } - else if (isInRightSideOfImport(node)) { - return getMeaningFromRightHandSideOfImport(node); - } - else if (isDeclarationOrFunctionExpressionOrCatchVariableName(node)) { - return getMeaningFromDeclaration(node.parent); - } - else if (isTypeReference(node)) { - return SearchMeaning.Type; - } - else if (isNamespaceReference(node)) { - return SearchMeaning.Namespace; - } - else { - return SearchMeaning.Value; - } - } - /** Given an initial searchMeaning, extracted from a location, widen the search scope based on the declarations * of the corresponding symbol. e.g. if we are searching for "Foo" in value position, but "Foo" references a class * then we need to widen the search to include type positions as well. @@ -3754,7 +3660,7 @@ module ts { * module, we want to keep the search limited to only types, as the two declarations (interface and uninstantiated module) * do not intersect in any of the three spaces. */ - function getIntersectingMeaningFromDeclarations(meaning: SearchMeaning, declarations: Declaration[]): SearchMeaning { + function getIntersectingMeaningFromDeclarations(meaning: SemanticMeaning, declarations: Declaration[]): SemanticMeaning { if (declarations) { do { // The result is order-sensitive, for instance if initialMeaning === Namespace, and declarations = [class, instantiated module] @@ -3964,6 +3870,114 @@ module ts { return emitOutput; } + function getMeaningFromDeclaration(node: Declaration): SemanticMeaning { + switch (node.kind) { + case SyntaxKind.Parameter: + case SyntaxKind.VariableDeclaration: + case SyntaxKind.Property: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.EnumMember: + case SyntaxKind.Method: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.CatchBlock: + return SemanticMeaning.Value; + + case SyntaxKind.TypeParameter: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeLiteral: + return SemanticMeaning.Type; + + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + return SemanticMeaning.Value | SemanticMeaning.Type; + + case SyntaxKind.ModuleDeclaration: + if ((node).name.kind === SyntaxKind.StringLiteral) { + return SemanticMeaning.Namespace | SemanticMeaning.Value; + } + else if (isInstantiated(node)) { + return SemanticMeaning.Namespace | SemanticMeaning.Value; + } + else { + return SemanticMeaning.Namespace; + } + break; + + case SyntaxKind.ImportDeclaration: + return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace; + } + Debug.fail("Unknown declaration type"); + } + + function isTypeReference(node: Node): boolean { + if (node.parent.kind === SyntaxKind.QualifiedName && (node.parent).right === node) + node = node.parent; + + return node.parent.kind === SyntaxKind.TypeReference; + } + + function isNamespaceReference(node: Node): boolean { + var root = node; + var isLastClause = true; + if (root.parent.kind === SyntaxKind.QualifiedName) { + while (root.parent && root.parent.kind === SyntaxKind.QualifiedName) + root = root.parent; + + isLastClause = (root).right === node; + } + + return root.parent.kind === SyntaxKind.TypeReference && !isLastClause; + } + + function isInRightSideOfImport(node: EntityName) { + while (node.parent.kind === SyntaxKind.QualifiedName) { + node = node.parent; + } + + return node.parent.kind === SyntaxKind.ImportDeclaration && (node.parent).entityName === node; + } + + function getMeaningFromRightHandSideOfImport(node: Node) { + Debug.assert(node.kind === SyntaxKind.Identifier); + + // import a = |b|; // Namespace + // import a = |b.c|; // Value, type, namespace + // import a = |b.c|.d; // Namespace + + if (node.parent.kind === SyntaxKind.QualifiedName && + (node.parent).right === node && + node.parent.parent.kind === SyntaxKind.ImportDeclaration) { + return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace; + } + return SemanticMeaning.Namespace; + } + + function getMeaningFromLocation(node: Node): SemanticMeaning { + if (node.parent.kind === SyntaxKind.ExportAssignment) { + return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace; + } + else if (isInRightSideOfImport(node)) { + return getMeaningFromRightHandSideOfImport(node); + } + else if (isDeclarationOrFunctionExpressionOrCatchVariableName(node)) { + return getMeaningFromDeclaration(node.parent); + } + else if (isTypeReference(node)) { + return SemanticMeaning.Type; + } + else if (isNamespaceReference(node)) { + return SemanticMeaning.Namespace; + } + else { + return SemanticMeaning.Value; + } + } + // Signature help /** * This is a semantic operation. @@ -4132,7 +4146,7 @@ module ts { return result; - function classifySymbol(symbol: Symbol, isInTypePosition: boolean) { + function classifySymbol(symbol: Symbol, meaningAtPosition: SemanticMeaning) { var flags = symbol.getFlags(); if (flags & SymbolFlags.Class) { @@ -4141,10 +4155,7 @@ module ts { else if (flags & SymbolFlags.Enum) { return ClassificationTypeNames.enumName; } - else if (flags & SymbolFlags.Module) { - return ClassificationTypeNames.moduleName; - } - else if (isInTypePosition) { + else if (meaningAtPosition & SemanticMeaning.Type) { if (flags & SymbolFlags.Interface) { return ClassificationTypeNames.interfaceName; } @@ -4152,6 +4163,9 @@ module ts { return ClassificationTypeNames.typeParameterName; } } + else if (flags & SymbolFlags.Module) { + return ClassificationTypeNames.moduleName; + } } function processNode(node: Node) { @@ -4160,7 +4174,7 @@ module ts { if (node.kind === SyntaxKind.Identifier && node.getWidth() > 0) { var symbol = typeInfoResolver.getSymbolInfo(node); if (symbol) { - var type = classifySymbol(symbol, isTypeNode(node) || isTypeDeclarationName(node)); + var type = classifySymbol(symbol, getMeaningFromLocation(node)); if (type) { result.push({ textSpan: new TypeScript.TextSpan(node.getStart(), node.getWidth()), @@ -4621,7 +4635,7 @@ module ts { // Only allow a symbol to be renamed if it actually has at least one declaration. if (symbol && symbol.getDeclarations() && symbol.getDeclarations().length > 0) { - var kind = getSymbolKind(symbol); + var kind = getSymbolKind(symbol, getMeaningFromLocation(node)); if (kind) { return getRenameInfo(symbol.name, typeInfoResolver.getFullyQualifiedName(symbol), kind, getSymbolModifiers(symbol),