Skip to content

Commit c8c547a

Browse files
author
Andy
authored
Only add completion for a symbol if it is accessible (microsoft#25096)
1 parent ab9e913 commit c8c547a

File tree

3 files changed

+60
-8
lines changed

3 files changed

+60
-8
lines changed

src/services/completions.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,15 +1117,19 @@ namespace ts.Completions {
11171117
}
11181118

11191119
function addPropertySymbol(symbol: Symbol) {
1120+
// For a computed property with an accessible name like `Symbol.iterator`,
1121+
// we'll add a completion for the *name* `Symbol` instead of for the property.
11201122
// If this is e.g. [Symbol.iterator], add a completion for `Symbol`.
1121-
const symbolSymbol = firstDefined(symbol.declarations, decl => {
1122-
const name = getNameOfDeclaration(decl);
1123-
const leftName = name && name.kind === SyntaxKind.ComputedPropertyName ? getLeftMostName(name.expression) : undefined;
1124-
return leftName && typeChecker.getSymbolAtLocation(leftName);
1125-
});
1126-
if (symbolSymbol) {
1127-
symbols.push(symbolSymbol);
1128-
symbolToOriginInfoMap[getSymbolId(symbolSymbol)] = { type: "symbol-member" };
1123+
const computedPropertyName = firstDefined(symbol.declarations, decl => tryCast(getNameOfDeclaration(decl), isComputedPropertyName));
1124+
if (computedPropertyName) {
1125+
const leftMostName = getLeftMostName(computedPropertyName.expression); // The completion is for `Symbol`, not `iterator`.
1126+
const nameSymbol = leftMostName && typeChecker.getSymbolAtLocation(leftMostName);
1127+
// If this is nested like for `namespace N { export const sym = Symbol(); }`, we'll add the completion for `N`.
1128+
const firstAccessibleSymbol = nameSymbol && getFirstSymbolInChain(nameSymbol, contextToken, typeChecker);
1129+
if (firstAccessibleSymbol && !symbolToOriginInfoMap[getSymbolId(firstAccessibleSymbol)]) {
1130+
symbols.push(firstAccessibleSymbol);
1131+
symbolToOriginInfoMap[getSymbolId(firstAccessibleSymbol)] = { type: "symbol-member" };
1132+
}
11291133
}
11301134
else {
11311135
symbols.push(symbol);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
////declare const Symbol: () => symbol;
4+
////namespace M {
5+
//// export const sym = Symbol();
6+
////}
7+
////namespace N {
8+
//// const sym = Symbol();
9+
//// export interface I {
10+
//// [sym]: number;
11+
//// [M.sym]: number;
12+
//// }
13+
////}
14+
////
15+
////declare const i: N.I;
16+
////i[|./**/|];
17+
18+
verify.completions({
19+
marker: "",
20+
exact: { name: "M", insertText: "[M]", replacementSpan: test.ranges()[0] },
21+
preferences: { includeInsertTextCompletions: true },
22+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @Filename: /a.ts
4+
////declare const Symbol: () => symbol;
5+
////const privateSym = Symbol();
6+
////export const publicSym = Symbol();
7+
////export interface I {
8+
//// [privateSym]: number;
9+
//// [publicSym]: number;
10+
//// n: number;
11+
////}
12+
////export const i: I;
13+
14+
// @Filename: /user.ts
15+
////import { i } from "./a";
16+
////i[|./**/|];
17+
18+
verify.completions({
19+
marker: "",
20+
// TODO: GH#25095 Should include `publicSym`
21+
exact: "n",
22+
preferences: {
23+
includeInsertTextCompletions: true,
24+
includeCompletionsForModuleExports: true,
25+
},
26+
});

0 commit comments

Comments
 (0)