Skip to content

Commit fdec0a5

Browse files
committed
fix(43796): sort deprecated completions lower than others
1 parent 5e4fcfb commit fdec0a5

15 files changed

+243
-38
lines changed

src/services/completions.ts

+40-17
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@ namespace ts.Completions {
88
SuggestedClassMembers = "4",
99
GlobalsOrKeywords = "5",
1010
AutoImportSuggestions = "6",
11-
JavascriptIdentifiers = "7"
11+
DeprecatedLocalDeclarationPriority = "7",
12+
DeprecatedLocationPriority = "8",
13+
DeprecatedOptionalMember = "9",
14+
DeprecatedMemberDeclaredBySpreadAssignment = "10",
15+
DeprecatedSuggestedClassMembers = "11",
16+
DeprecatedGlobalsOrKeywords = "12",
17+
DeprecatedAutoImportSuggestions = "13",
18+
JavascriptIdentifiers = "14"
1219
}
1320
export type Log = (message: string) => void;
1421

@@ -585,9 +592,11 @@ namespace ts.Completions {
585592
}
586593

587594
const { name, needsConvertPropertyAccess } = info;
595+
const sortText = symbolToSortTextMap && symbolToSortTextMap[getSymbolId(symbol)]
596+
|| (isDeprecatedSymbol(symbol, typeChecker) ? SortText.DeprecatedLocationPriority : SortText.LocationPriority);
588597
const entry = createCompletionEntry(
589598
symbol,
590-
symbolToSortTextMap && symbolToSortTextMap[getSymbolId(symbol)] || SortText.LocationPriority,
599+
sortText,
591600
contextToken,
592601
location,
593602
sourceFile,
@@ -641,13 +650,15 @@ namespace ts.Completions {
641650
// module imports then the global keywords will be filtered out so auto
642651
// import suggestions will win in the completion
643652
const symbolOrigin = skipAlias(symbol, typeChecker);
653+
const symbolOriginSortText = symbolToSortTextMap[getSymbolId(symbolOrigin)];
654+
const symbolSortText = symbolToSortTextMap[getSymbolId(symbol)];
644655
// We only want to filter out the global keywords
645656
// Auto Imports are not available for scripts so this conditional is always false
646657
if (!!sourceFile.externalModuleIndicator
647658
&& !compilerOptions.allowUmdGlobalAccess
648-
&& symbolToSortTextMap[getSymbolId(symbol)] === SortText.GlobalsOrKeywords
649-
&& (symbolToSortTextMap[getSymbolId(symbolOrigin)] === SortText.AutoImportSuggestions
650-
|| symbolToSortTextMap[getSymbolId(symbolOrigin)] === SortText.LocationPriority)) {
659+
&& (symbolSortText === SortText.GlobalsOrKeywords || symbolSortText === SortText.DeprecatedGlobalsOrKeywords)
660+
&& ((symbolOriginSortText === SortText.AutoImportSuggestions || symbolOriginSortText === SortText.DeprecatedAutoImportSuggestions)
661+
|| (symbolOriginSortText === SortText.LocationPriority || symbolOriginSortText === SortText.DeprecatedLocationPriority))) {
651662
return false;
652663
}
653664
// Continue with origin symbol
@@ -669,8 +680,6 @@ namespace ts.Completions {
669680
}
670681
}
671682

672-
673-
674683
function getLabelCompletionAtPosition(node: BreakOrContinueStatement): CompletionInfo | undefined {
675684
const entries = getLabelStatementCompletions(node);
676685
if (entries.length) {
@@ -1484,7 +1493,8 @@ namespace ts.Completions {
14841493

14851494
function addSymbolSortInfo(symbol: Symbol) {
14861495
if (isStaticProperty(symbol)) {
1487-
symbolToSortTextMap[getSymbolId(symbol)] = SortText.LocalDeclarationPriority;
1496+
symbolToSortTextMap[getSymbolId(symbol)] =
1497+
isDeprecatedSymbol(symbol, typeChecker) ? SortText.DeprecatedLocalDeclarationPriority : SortText.LocalDeclarationPriority;
14881498
}
14891499
}
14901500

@@ -1599,9 +1609,9 @@ namespace ts.Completions {
15991609
symbols = typeChecker.getSymbolsInScope(scopeNode, symbolMeanings);
16001610
Debug.assertEachIsDefined(symbols, "getSymbolsInScope() should all be defined");
16011611
for (const symbol of symbols) {
1602-
if (!typeChecker.isArgumentsSymbol(symbol) &&
1603-
!some(symbol.declarations, d => d.getSourceFile() === sourceFile)) {
1604-
symbolToSortTextMap[getSymbolId(symbol)] = SortText.GlobalsOrKeywords;
1612+
if (!typeChecker.isArgumentsSymbol(symbol) && !some(symbol.declarations, d => d.getSourceFile() === sourceFile)) {
1613+
symbolToSortTextMap[getSymbolId(symbol)] =
1614+
isDeprecatedSymbol(symbol, typeChecker) ? SortText.DeprecatedGlobalsOrKeywords : SortText.GlobalsOrKeywords;
16051615
}
16061616
}
16071617

@@ -1612,7 +1622,8 @@ namespace ts.Completions {
16121622
for (const symbol of getPropertiesForCompletion(thisType, typeChecker)) {
16131623
symbolToOriginInfoMap[symbols.length] = { kind: SymbolOriginInfoKind.ThisType };
16141624
symbols.push(symbol);
1615-
symbolToSortTextMap[getSymbolId(symbol)] = SortText.SuggestedClassMembers;
1625+
symbolToSortTextMap[getSymbolId(symbol)] =
1626+
isDeprecatedSymbol(symbol, typeChecker) ? SortText.DeprecatedSuggestedClassMembers : SortText.SuggestedClassMembers;
16161627
}
16171628
}
16181629
}
@@ -1765,12 +1776,16 @@ namespace ts.Completions {
17651776

17661777
function pushAutoImportSymbol(symbol: Symbol, origin: SymbolOriginInfoResolvedExport | SymbolOriginInfoExport) {
17671778
const symbolId = getSymbolId(symbol);
1768-
if (symbolToSortTextMap[symbolId] === SortText.GlobalsOrKeywords) {
1779+
if (symbolToSortTextMap[symbolId] === SortText.GlobalsOrKeywords
1780+
|| symbolToSortTextMap[symbolId] === SortText.DeprecatedGlobalsOrKeywords) {
17691781
// If an auto-importable symbol is available as a global, don't add the auto import
17701782
return;
17711783
}
17721784
symbolToOriginInfoMap[symbols.length] = origin;
1773-
symbolToSortTextMap[symbolId] = importCompletionNode ? SortText.LocationPriority : SortText.AutoImportSuggestions;
1785+
symbolToSortTextMap[symbolId] =
1786+
isDeprecatedSymbol(symbol, typeChecker)
1787+
? importCompletionNode ? SortText.DeprecatedLocationPriority : SortText.DeprecatedAutoImportSuggestions
1788+
: importCompletionNode ? SortText.LocationPriority : SortText.AutoImportSuggestions;
17741789
symbols.push(symbol);
17751790
}
17761791

@@ -2085,7 +2100,8 @@ namespace ts.Completions {
20852100
localsContainer.locals?.forEach((symbol, name) => {
20862101
symbols.push(symbol);
20872102
if (localsContainer.symbol?.exports?.has(name)) {
2088-
symbolToSortTextMap[getSymbolId(symbol)] = SortText.OptionalMember;
2103+
symbolToSortTextMap[getSymbolId(symbol)] =
2104+
isDeprecatedSymbol(symbol, typeChecker) ? SortText.DeprecatedOptionalMember : SortText.OptionalMember;
20892105
}
20902106
});
20912107
return GlobalsSearch.Success;
@@ -2500,7 +2516,8 @@ namespace ts.Completions {
25002516
function setSortTextToOptionalMember() {
25012517
symbols.forEach(m => {
25022518
if (m.flags & SymbolFlags.Optional) {
2503-
symbolToSortTextMap[getSymbolId(m)] = symbolToSortTextMap[getSymbolId(m)] || SortText.OptionalMember;
2519+
symbolToSortTextMap[getSymbolId(m)] =
2520+
symbolToSortTextMap[getSymbolId(m)] || (isDeprecatedSymbol(m, typeChecker) ? SortText.DeprecatedOptionalMember : SortText.OptionalMember);
25042521
}
25052522
});
25062523
}
@@ -2512,7 +2529,8 @@ namespace ts.Completions {
25122529
}
25132530
for (const contextualMemberSymbol of contextualMemberSymbols) {
25142531
if (membersDeclaredBySpreadAssignment.has(contextualMemberSymbol.name)) {
2515-
symbolToSortTextMap[getSymbolId(contextualMemberSymbol)] = SortText.MemberDeclaredBySpreadAssignment;
2532+
symbolToSortTextMap[getSymbolId(contextualMemberSymbol)] =
2533+
isDeprecatedSymbol(contextualMemberSymbol, typeChecker) ? SortText.DeprecatedMemberDeclaredBySpreadAssignment : SortText.MemberDeclaredBySpreadAssignment;
25162534
}
25172535
}
25182536
}
@@ -3051,4 +3069,9 @@ namespace ts.Completions {
30513069
addToSeen(seenModules, getSymbolId(sym)) &&
30523070
checker.getExportsOfModule(sym).some(e => symbolCanBeReferencedAtTypeLocation(e, checker, seenModules));
30533071
}
3072+
3073+
function isDeprecatedSymbol(symbol: Symbol, checker: TypeChecker) {
3074+
const declarations = skipAlias(symbol, checker).declarations;
3075+
return !!length(declarations) && every(declarations, isDeprecatedDeclaration);
3076+
}
30543077
}

src/services/symbolDisplay.ts

-4
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,6 @@ namespace ts.SymbolDisplay {
100100
return ScriptElementKind.unknown;
101101
}
102102

103-
function isDeprecatedDeclaration(decl: Declaration) {
104-
return !!(getCombinedNodeFlagsAlwaysIncludeJSDoc(decl) & ModifierFlags.Deprecated);
105-
}
106-
107103
function getNormalizedSymbolModifiers(symbol: Symbol) {
108104
if (symbol.declarations && symbol.declarations.length) {
109105
const [declaration, ...declarations] = symbol.declarations;

src/services/utilities.ts

+4
Original file line numberDiff line numberDiff line change
@@ -3352,5 +3352,9 @@ namespace ts {
33523352
|| (!!globalCachePath && startsWith(getCanonicalFileName(globalCachePath), toNodeModulesParent));
33533353
}
33543354

3355+
export function isDeprecatedDeclaration(decl: Declaration) {
3356+
return !!(getCombinedNodeFlagsAlwaysIncludeJSDoc(decl) & ModifierFlags.Deprecated);
3357+
}
3358+
33553359
// #endregion
33563360
}

tests/baselines/reference/completionsSalsaMethodsOnAssignedFunctionExpressions.baseline

+3-3
Original file line numberDiff line numberDiff line change
@@ -302,21 +302,21 @@
302302
"name": "a",
303303
"kind": "warning",
304304
"kindModifiers": "",
305-
"sortText": "7",
305+
"sortText": "14",
306306
"isFromUncheckedFile": true
307307
},
308308
{
309309
"name": "prototype",
310310
"kind": "warning",
311311
"kindModifiers": "",
312-
"sortText": "7",
312+
"sortText": "14",
313313
"isFromUncheckedFile": true
314314
},
315315
{
316316
"name": "m",
317317
"kind": "property",
318318
"kindModifiers": "",
319-
"sortText": "7",
319+
"sortText": "14",
320320
"isFromUncheckedFile": true,
321321
"displayParts": [
322322
{

tests/cases/fourslash/completionsWithDeprecatedTag1.ts

+6-7
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,26 @@
2525
verify.completions({
2626
marker: "1",
2727
includes: [
28-
{ name: "Foo", kind: "interface", kindModifiers: "deprecated" }
28+
{ name: "Foo", kind: "interface", kindModifiers: "deprecated", sortText: completion.SortText.DeprecatedLocationPriority }
2929
]
3030
}, {
3131
marker: "2",
3232
includes: [
33-
{ name: "bar", kind: "method", kindModifiers: "deprecated" }
33+
{ name: "bar", kind: "method", kindModifiers: "deprecated", sortText: completion.SortText.DeprecatedLocationPriority }
3434
]
3535
}, {
3636
marker: "3",
3737
includes: [
38-
{ name: "prop", kind: "property", kindModifiers: "deprecated" }
38+
{ name: "prop", kind: "property", kindModifiers: "deprecated", sortText: completion.SortText.DeprecatedLocationPriority }
3939
]
4040
}, {
4141
marker: "4",
4242
includes: [
43-
{ name: "foobar", kind: "function", kindModifiers: "export,deprecated" }
43+
{ name: "foobar", kind: "function", kindModifiers: "export,deprecated", sortText: completion.SortText.DeprecatedLocationPriority }
4444
]
4545
}, {
4646
marker: "5",
4747
includes: [
48-
{ name: "foobar", kind: "alias", kindModifiers: "export,deprecated" }
48+
{ name: "foobar", kind: "alias", kindModifiers: "export,deprecated", sortText: completion.SortText.DeprecatedLocationPriority }
4949
]
50-
}
51-
);
50+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @Filename: /foo.ts
4+
/////** @deprecated foo */
5+
////export const foo = 0;
6+
7+
// @Filename: /index.ts
8+
/////**/
9+
10+
verify.completions({
11+
marker: "",
12+
includes: [{
13+
name: "foo",
14+
source: "/foo",
15+
sourceDisplay: "./foo",
16+
hasAction: true,
17+
kind: "const",
18+
kindModifiers: "export,deprecated",
19+
sortText: completion.SortText.DeprecatedAutoImportSuggestions
20+
}],
21+
preferences: {
22+
includeCompletionsForModuleExports: true,
23+
},
24+
});

tests/cases/fourslash/completionsWithDeprecatedTag2.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99

1010
verify.completions({
1111
marker: "",
12-
includes: [
13-
{ name: "foo", kind: "function", kindModifiers: "deprecated,declare" }
14-
]
12+
includes: [{
13+
name: "foo",
14+
kind: "function",
15+
kindModifiers: "deprecated,declare",
16+
sortText: completion.SortText.DeprecatedLocationPriority
17+
}]
1518
});

tests/cases/fourslash/completionsWithDeprecatedTag3.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99

1010
verify.completions({
1111
marker: "",
12-
includes: [
13-
{ name: "foo", kind: "function", kindModifiers: "declare" }
14-
]
12+
includes: [{
13+
name: "foo",
14+
kind: "function",
15+
kindModifiers: "declare",
16+
sortText: completion.SortText.LocationPriority
17+
}]
1518
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @noLib: true
4+
5+
////f({
6+
//// a/**/
7+
//// xyz: ``,
8+
////});
9+
////declare function f(options: {
10+
//// /** @deprecated abc */
11+
//// abc?: number,
12+
//// xyz?: string
13+
////}): void;
14+
15+
verify.completions({
16+
marker: "",
17+
exact: [{
18+
name: "abc",
19+
kind: "property",
20+
kindModifiers: "deprecated,declare,optional",
21+
sortText: completion.SortText.DeprecatedOptionalMember
22+
}],
23+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// <reference path="fourslash.ts"/>
2+
3+
////class Foo {
4+
//// /** @deprecated m */
5+
//// static m() {}
6+
////}
7+
////Foo./**/
8+
9+
verify.completions({
10+
marker: "",
11+
exact: [
12+
{
13+
name: "prototype",
14+
sortText: completion.SortText.LocationPriority
15+
},
16+
{
17+
name: "m",
18+
kind: "method",
19+
kindModifiers: "static,deprecated",
20+
sortText: completion.SortText.DeprecatedLocalDeclarationPriority
21+
},
22+
...completion.functionMembers
23+
]
24+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/// <reference path="fourslash.ts"/>
2+
3+
////module Foo {
4+
//// /** @deprecated foo */
5+
//// export var foo: number;
6+
////}
7+
////Foo./**/
8+
9+
verify.completions({
10+
marker: "",
11+
exact: [{
12+
name: "foo",
13+
kind: "var",
14+
kindModifiers: "export,deprecated",
15+
sortText: completion.SortText.DeprecatedLocationPriority
16+
}]
17+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @strict: true
4+
5+
////interface I {
6+
//// /** @deprecated a */
7+
//// a: number;
8+
////}
9+
10+
////const foo = {
11+
//// a: 1
12+
////}
13+
14+
////const i: I = {
15+
//// ...foo,
16+
//// /**/
17+
////}
18+
19+
verify.completions({
20+
marker: "",
21+
exact: [{
22+
name: "a",
23+
sortText: completion.SortText.DeprecatedMemberDeclaredBySpreadAssignment,
24+
kind: 'property',
25+
kindModifiers: "deprecated"
26+
}]
27+
});

0 commit comments

Comments
 (0)