diff --git a/src/services/completions.ts b/src/services/completions.ts index 40f3cac68c9..02f4700b051 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -447,7 +447,7 @@ namespace ts.Completions { return { name, kind: SymbolDisplay.getSymbolKind(typeChecker, symbol, location!), // TODO: GH#18217 - kindModifiers: SymbolDisplay.getSymbolModifiers(symbol), + kindModifiers: SymbolDisplay.getSymbolModifiers(typeChecker, symbol), sortText, source: getSourceFromOrigin(origin), hasAction: origin && originIsExport(origin) || undefined, @@ -697,7 +697,7 @@ namespace ts.Completions { checker.runWithCancellationToken(cancellationToken, checker => SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(checker, symbol, sourceFile, location, location, SemanticMeaning.All) ); - return createCompletionDetails(symbol.name, SymbolDisplay.getSymbolModifiers(symbol), symbolKind, displayParts, documentation, tags, codeActions, sourceDisplay); + return createCompletionDetails(symbol.name, SymbolDisplay.getSymbolModifiers(checker, symbol), symbolKind, displayParts, documentation, tags, codeActions, sourceDisplay); } export function createCompletionDetails(name: string, kindModifiers: string, kind: ScriptElementKind, displayParts: SymbolDisplayPart[], documentation?: SymbolDisplayPart[], tags?: JSDocTagInfo[], codeActions?: CodeAction[], source?: SymbolDisplayPart[]): CompletionEntryDetails { diff --git a/src/services/rename.ts b/src/services/rename.ts index 59efe2f7a20..e75de5151cc 100644 --- a/src/services/rename.ts +++ b/src/services/rename.ts @@ -52,7 +52,7 @@ namespace ts.Rename { : undefined; const displayName = specifierName || typeChecker.symbolToString(symbol); const fullDisplayName = specifierName || typeChecker.getFullyQualifiedName(symbol); - return getRenameInfoSuccess(displayName, fullDisplayName, kind, SymbolDisplay.getSymbolModifiers(symbol), node, sourceFile); + return getRenameInfoSuccess(displayName, fullDisplayName, kind, SymbolDisplay.getSymbolModifiers(typeChecker,symbol), node, sourceFile); } function getRenameInfoForModule(node: StringLiteralLike, sourceFile: SourceFile, moduleSymbol: Symbol): RenameInfo | undefined { diff --git a/src/services/services.ts b/src/services/services.ts index f909360a28d..a891c2297d6 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1607,7 +1607,7 @@ namespace ts { ); return { kind: symbolKind, - kindModifiers: SymbolDisplay.getSymbolModifiers(symbol), + kindModifiers: SymbolDisplay.getSymbolModifiers(typeChecker, symbol), textSpan: createTextSpanFromNode(nodeForQuickInfo, sourceFile), displayParts, documentation, diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 65543399c30..6813ad3f9bc 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -102,15 +102,32 @@ namespace ts.SymbolDisplay { return ScriptElementKind.unknown; } - export function getSymbolModifiers(symbol: Symbol): string { - const nodeModifiers = symbol && symbol.declarations && symbol.declarations.length > 0 - ? getNodeModifiers(symbol.declarations[0]) - : ScriptElementKindModifier.none; + export function getSymbolModifiers(typeChecker: TypeChecker, symbol: Symbol): string { + if (!symbol) { + return ScriptElementKindModifier.none; + } - const symbolModifiers = symbol && symbol.flags & SymbolFlags.Optional ? - ScriptElementKindModifier.optionalModifier - : ScriptElementKindModifier.none; - return nodeModifiers && symbolModifiers ? nodeModifiers + "," + symbolModifiers : nodeModifiers || symbolModifiers; + const modifiers = new Set(); + if (symbol.declarations && symbol.declarations.length > 0) { + const kindModifiers = getNodeModifiers(symbol.declarations[0]); + if (kindModifiers !== ScriptElementKindModifier.none) { + kindModifiers.split(",").forEach(m => modifiers.add(m)); + } + } + if (symbol.flags & SymbolFlags.Alias) { + const resolvedSymbol = typeChecker.getAliasedSymbol(symbol); + if (resolvedSymbol !== symbol && resolvedSymbol.declarations && resolvedSymbol.declarations.length > 0) { + const kindModifiers = getNodeModifiers(resolvedSymbol.declarations[0]); + if (kindModifiers !== ScriptElementKindModifier.none) { + kindModifiers.split(",").forEach(m => modifiers.add(m)); + } + } + } + if (symbol.flags & SymbolFlags.Optional) { + modifiers.add(ScriptElementKindModifier.optionalModifier); + } + + return modifiers.size > 0 ? arrayFrom(modifiers.values()).join(",") : ScriptElementKindModifier.none; } interface SymbolDisplayPartsDocumentationAndSymbolKind { diff --git a/tests/baselines/reference/quickInfoDisplayPartsInternalModuleAlias.baseline b/tests/baselines/reference/quickInfoDisplayPartsInternalModuleAlias.baseline index 0d4660e51d5..447ba587e1c 100644 --- a/tests/baselines/reference/quickInfoDisplayPartsInternalModuleAlias.baseline +++ b/tests/baselines/reference/quickInfoDisplayPartsInternalModuleAlias.baseline @@ -160,7 +160,7 @@ }, "quickInfo": { "kind": "alias", - "kindModifiers": "", + "kindModifiers": "export", "textSpan": { "start": 104, "length": 2 @@ -245,7 +245,7 @@ }, "quickInfo": { "kind": "alias", - "kindModifiers": "", + "kindModifiers": "export", "textSpan": { "start": 123, "length": 2 diff --git a/tests/cases/fourslash/completionsExportImport.ts b/tests/cases/fourslash/completionsExportImport.ts index d9468708652..0650b247a52 100644 --- a/tests/cases/fourslash/completionsExportImport.ts +++ b/tests/cases/fourslash/completionsExportImport.ts @@ -11,7 +11,7 @@ verify.completions({ marker: "", exact: [ - { name: "foo", kind: "alias", kindModifiers: "export", text: "(alias) const foo: number\nimport foo = N.foo" }, + { name: "foo", kind: "alias", kindModifiers: "export,declare", text: "(alias) const foo: number\nimport foo = N.foo" }, ...completion.globalsPlus([{ name: "N", kind: "module", kindModifiers: "declare", text: "namespace N" }]), ], }); diff --git a/tests/cases/fourslash/completionsImport_named_didNotExistBefore.ts b/tests/cases/fourslash/completionsImport_named_didNotExistBefore.ts index 59766f81fcf..237baaeb336 100644 --- a/tests/cases/fourslash/completionsImport_named_didNotExistBefore.ts +++ b/tests/cases/fourslash/completionsImport_named_didNotExistBefore.ts @@ -16,7 +16,8 @@ verify.completions({ { name: "Test2", text: "(alias) function Test2(): void\nimport Test2", - kind: "alias" + kind: "alias", + kindModifiers: "export" }, completion.globalThisEntry, completion.undefinedVarEntry, diff --git a/tests/cases/fourslash/completionsImport_reExportDefault.ts b/tests/cases/fourslash/completionsImport_reExportDefault.ts index b67daf7132e..3ec987a7215 100644 --- a/tests/cases/fourslash/completionsImport_reExportDefault.ts +++ b/tests/cases/fourslash/completionsImport_reExportDefault.ts @@ -34,6 +34,7 @@ verify.completions({ sourceDisplay: "./a", text: "(alias) function foo(): void\nexport foo", kind: "alias", + kindModifiers: "export", hasAction: true, sortText: completion.SortText.AutoImportSuggestions }, diff --git a/tests/cases/fourslash/completionsWithDeprecatedTag.ts b/tests/cases/fourslash/completionsWithDeprecatedTag.ts index 4de10cc12f2..f3bd7e93d6a 100644 --- a/tests/cases/fourslash/completionsWithDeprecatedTag.ts +++ b/tests/cases/fourslash/completionsWithDeprecatedTag.ts @@ -1,6 +1,13 @@ /// // @strict: true +// @filename: /foobar.ts +//// /** @deprecated */ +//// export function foobar() {} + +// @filename: /foo.ts +//// import { foobar/*4*/ } from "./foobar"; +//// //// /** @deprecated */ //// interface Foo { //// /** @deprecated */ @@ -12,6 +19,8 @@ //// declare const foooo: Fo/*1*/; //// foo.ba/*2*/; //// foo.pro/*3*/; +//// +//// fooba/*5*/; verify.completions({ marker: "1", @@ -28,5 +37,15 @@ verify.completions({ includes: [ { name: "prop", kind: "property", kindModifiers: "deprecated" } ] -}); - +}, { + marker: "4", + includes: [ + { name: "foobar", kind: "function", kindModifiers: "export,deprecated" } + ] +}, { + marker: "5", + includes: [ + { name: "foobar", kind: "alias", kindModifiers: "export,deprecated" } + ] +} +); diff --git a/tests/cases/fourslash/quickInfoAlias.ts b/tests/cases/fourslash/quickInfoAlias.ts index cfbe8ed3692..d1b2e3b5ded 100644 --- a/tests/cases/fourslash/quickInfoAlias.ts +++ b/tests/cases/fourslash/quickInfoAlias.ts @@ -28,7 +28,7 @@ goTo.eachMarker((_, index) => { verify.verifyQuickInfoDisplayParts( "alias", - "", + "export", { start: index === 0 ? 25 : 117, length: 1 }, [ { text:"(",kind:"punctuation" },