diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6d03242fbc6..952600b6017 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7134,6 +7134,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; @@ -7212,6 +7228,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 4d000798363..b0c69aa99fe 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1259,9 +1259,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 { @@ -1968,11 +1968,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 { @@ -2258,16 +2259,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); @@ -2608,7 +2613,11 @@ module ts { var type = session.typeChecker.getTypeOfSymbol(symbol); Debug.assert(type, "Could not find type for symbol"); var completionEntry = createCompletionEntry(symbol); - var displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getSourceFile(filename), session.location, session.typeChecker, session.location); + // 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. + var displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getSourceFile(filename), session.location, session.typeChecker, session.location, SemanticMeaning.All); return { name: entryName, kind: displayPartsDocumentationsAndSymbolKind.symbolKind, @@ -2651,13 +2660,19 @@ 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; + } + var result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags); if (result === ScriptElementKind.unknown) { if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; @@ -2730,7 +2745,10 @@ module ts { : ScriptElementKindModifier.none; } - function getSymbolDisplayPartsDocumentationAndSymbolKind(symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node, typeResolver: TypeChecker, location: Node) { + function getSymbolDisplayPartsDocumentationAndSymbolKind(symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node, + typeResolver: TypeChecker, location: Node, + // TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location + semanticMeaning = getMeaningFromLocation(location)) { var displayParts: SymbolDisplayPart[] = []; var documentation: SymbolDisplayPart[]; var symbolFlags = typeResolver.getRootSymbol(symbol).flags; @@ -2841,7 +2859,7 @@ module ts { displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)); writeTypeParametersOfSymbol(symbol, sourceFile); } - if (symbolFlags & SymbolFlags.Interface) { + if ((symbolFlags & SymbolFlags.Interface) && (semanticMeaning & SemanticMeaning.Type)) { addNewLineIfDisplayPartsExist(); displayParts.push(keywordPart(SyntaxKind.InterfaceKeyword)); displayParts.push(spacePart()); @@ -2860,7 +2878,7 @@ module ts { displayParts.push(spacePart()); displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile)); } - if (symbolFlags & SymbolFlags.TypeParameter) { + if ((symbolFlags & SymbolFlags.TypeParameter) && (semanticMeaning & SemanticMeaning.Type)) { addNewLineIfDisplayPartsExist(); displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); displayParts.push(textPart("type parameter")); @@ -2940,9 +2958,9 @@ module ts { } } else { - symbolKind = getSymbolKind(symbol); + symbolKind = getSymbolKind(symbol, semanticMeaning); } - } + } if (!documentation) { documentation = symbol.getDocumentationComment(); @@ -3033,8 +3051,8 @@ module ts { var displayPartsDocumentationsAndKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, sourceFile, getContainerNode(node), typeInfoResolver, node); return { - kind: getSymbolKind(symbol), - kindModifiers: displayPartsDocumentationsAndKind.symbolKind, + kind: displayPartsDocumentationsAndKind.symbolKind, + kindModifiers: getSymbolModifiers(symbol), textSpan: new TypeScript.TextSpan(node.getStart(), node.getWidth()), displayParts: displayPartsDocumentationsAndKind.displayParts, documentation: displayPartsDocumentationsAndKind.documentation @@ -3146,10 +3164,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)) { @@ -3854,7 +3871,7 @@ module ts { searchSymbol: Symbol, searchText: string, searchLocation: Node, - searchMeaning: SearchMeaning, + searchMeaning: SemanticMeaning, findInStrings: boolean, findInComments: boolean, result: ReferenceEntry[]): void { @@ -4153,114 +4170,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. @@ -4268,7 +4177,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] @@ -4478,6 +4387,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. @@ -4646,7 +4663,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) { @@ -4655,10 +4672,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; } @@ -4666,6 +4680,9 @@ module ts { return ClassificationTypeNames.typeParameterName; } } + else if (flags & SymbolFlags.Module) { + return ClassificationTypeNames.moduleName; + } } function processNode(node: Node) { @@ -4674,7 +4691,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()), @@ -5135,7 +5152,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), diff --git a/tests/cases/fourslash/commentsInheritance.ts b/tests/cases/fourslash/commentsInheritance.ts index 10926c953ff..eaca1d79ccb 100644 --- a/tests/cases/fourslash/commentsInheritance.ts +++ b/tests/cases/fourslash/commentsInheritance.ts @@ -42,7 +42,7 @@ //// /** c1_nc_l1*/ //// public nc_l1: () => void; ////} -////var i1/*1iq*/_i: i1; +////var i1/*1iq*/_i: /*16i*/i1; ////i1_i./*1*/i/*2q*/1_f1(/*2*/); ////i1_i.i1_n/*3q*/c_f1(/*3*/); ////i1_i.f/*4q*/1(/*4*/); @@ -179,7 +179,7 @@ //// nc_f1(): void; //// nc_l1: () => void; ////} -////var i2/*36iq*/_i: i2; +////var i2/*36iq*/_i: /*51i*/i2; ////var i3/*37iq*/_i: i3; ////i2_i./*36*/i2/*37q*/_f1(/*37*/); ////i2_i.i2_n/*38q*/c_f1(/*38*/); @@ -370,6 +370,9 @@ verify.completionListContains("i1_i", "(var) i1_i: i1", ""); verify.completionListContains("c1", "class c1", ""); verify.completionListContains("c1_i", "(var) c1_i: c1", ""); +goTo.marker('16i'); +verify.completionListContains("i1", "interface i1", "i1 is interface with properties"); + goTo.marker('17iq'); verify.quickInfoIs("(var) c2_i: c2", ""); goTo.marker('18iq'); @@ -653,6 +656,10 @@ verify.completionListContains("i2_i", "(var) i2_i: i2", ""); verify.completionListContains("i3", "interface i3", ""); verify.completionListContains("i3_i", "(var) i3_i: i3", ""); +goTo.marker('51i'); +verify.completionListContains("i2", "interface i2", ""); +verify.completionListContains("i3", "interface i3", ""); + goTo.marker('52'); verify.quickInfoIs("(constructor) c5(): c5", ""); diff --git a/tests/cases/fourslash/commentsInterface.ts b/tests/cases/fourslash/commentsInterface.ts index f1656b7cecf..02856242cee 100644 --- a/tests/cases/fourslash/commentsInterface.ts +++ b/tests/cases/fourslash/commentsInterface.ts @@ -26,7 +26,7 @@ //// fnfoo(/**param help*/b: number): string; //// nc_fnfoo(b: number): string; ////} -////var i2/*6*/_i: i2; +////var i2/*6*/_i: /*34i*/i2; ////var i2_i/*7*/_x = i2_i./*8*/x; ////var i2_i/*9*/_foo = i2_i.f/*10*/oo; ////var i2_i_f/*11*/oo_r = i2_i.f/*12q*/oo(/*12*/30); @@ -218,6 +218,11 @@ verify.completionListContains("i2_i_fnfoo_r", "(var) i2_i_fnfoo_r: string", ""); verify.completionListContains("i2_i_nc_fnfoo", "(var) i2_i_nc_fnfoo: (b: number) => string", ""); verify.completionListContains("i2_i_nc_fnfoo_r", "(var) i2_i_nc_fnfoo_r: string", ""); +goTo.marker('34i'); +verify.completionListContains("i1", "interface i1", "this is interface 1"); +verify.completionListContains("nc_i1", "interface nc_i1", ""); +verify.completionListContains("i2", "interface i2", "this is interface 2 with memebers"); + goTo.marker('36'); verify.completionListContains("a", "(parameter) a: number", "i3_i a");