Skip to content

Commit 0feeb48

Browse files
author
Andy
authored
Make generator function name a completion list blocker (microsoft#26640)
* Make generator function name a completion list blocker * Improvements for class/object members * Separate KeywordCompletionFilter.None and .All
1 parent 9100047 commit 0feeb48

File tree

2 files changed

+42
-21
lines changed

2 files changed

+42
-21
lines changed

src/services/completions.ts

+20-21
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ namespace ts.Completions {
2323
type SymbolOriginInfoMap = (SymbolOriginInfo | undefined)[];
2424

2525
const enum KeywordCompletionFilters {
26-
None,
26+
None, // No keywords
27+
All, // Every possible keyword (TODO: This is never appropriate)
2728
ClassElementKeywords, // Keywords inside class body
2829
InterfaceElementKeywords, // Keywords inside interface body
2930
ConstructorParameterKeywords, // Keywords at constructor parameter
@@ -143,21 +144,13 @@ namespace ts.Completions {
143144
getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target!, log, completionKind, preferences, propertyAccessToConvert, isJsxInitializer, recommendedCompletion, symbolToOriginInfoMap);
144145
}
145146

146-
// TODO add filter for keyword based on type/value/namespace and also location
147-
148-
// Add all keywords if
149-
// - this is not a member completion list (all the keywords)
150-
// - other filters are enabled in required scenario so add those keywords
151-
const isMemberCompletion = isMemberCompletionKind(completionKind);
152-
if (keywordFilters !== KeywordCompletionFilters.None || !isMemberCompletion) {
153-
addRange(entries, getKeywordCompletions(keywordFilters));
154-
}
147+
addRange(entries, getKeywordCompletions(keywordFilters));
155148

156149
for (const literal of literals) {
157150
entries.push(createCompletionEntryForLiteral(literal));
158151
}
159152

160-
return { isGlobalCompletion: isInSnippetScope, isMemberCompletion, isNewIdentifierLocation, entries };
153+
return { isGlobalCompletion: isInSnippetScope, isMemberCompletion: isMemberCompletionKind(completionKind), isNewIdentifierLocation, entries };
161154
}
162155

163156
function isUncheckedFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean {
@@ -1014,6 +1007,7 @@ namespace ts.Completions {
10141007
tryGetGlobalSymbols();
10151008
symbols = tagSymbols.concat(symbols);
10161009
completionKind = CompletionKind.MemberLike;
1010+
keywordFilters = KeywordCompletionFilters.None;
10171011
}
10181012
else if (isStartingCloseTag) {
10191013
const tagName = (<JsxElement>contextToken.parent.parent).openingElement.tagName;
@@ -1022,6 +1016,7 @@ namespace ts.Completions {
10221016
symbols = [tagSymbol];
10231017
}
10241018
completionKind = CompletionKind.MemberLike;
1019+
keywordFilters = KeywordCompletionFilters.None;
10251020
}
10261021
else {
10271022
// For JavaScript or TypeScript, if we're not after a dot, then just try to get the
@@ -1191,9 +1186,7 @@ namespace ts.Completions {
11911186
}
11921187

11931188
function getGlobalCompletions(): void {
1194-
if (tryGetFunctionLikeBodyCompletionContainer(contextToken)) {
1195-
keywordFilters = KeywordCompletionFilters.FunctionLikeBodyKeywords;
1196-
}
1189+
keywordFilters = tryGetFunctionLikeBodyCompletionContainer(contextToken) ? KeywordCompletionFilters.FunctionLikeBodyKeywords : KeywordCompletionFilters.All;
11971190

11981191
// Get all entities in the current scope.
11991192
completionKind = CompletionKind.Global;
@@ -1648,7 +1641,8 @@ namespace ts.Completions {
16481641
completionKind = CompletionKind.MemberLike;
16491642
// Declaring new property/method/accessor
16501643
isNewIdentifierLocation = true;
1651-
keywordFilters = isClassLike(decl) ? KeywordCompletionFilters.ClassElementKeywords : KeywordCompletionFilters.InterfaceElementKeywords;
1644+
keywordFilters = contextToken.kind === SyntaxKind.AsteriskToken ? KeywordCompletionFilters.None :
1645+
isClassLike(decl) ? KeywordCompletionFilters.ClassElementKeywords : KeywordCompletionFilters.InterfaceElementKeywords;
16521646

16531647
// If you're in an interface you don't want to repeat things from super-interface. So just stop here.
16541648
if (!isClassLike(decl)) return GlobalsSearch.Success;
@@ -1686,14 +1680,16 @@ namespace ts.Completions {
16861680
*/
16871681
function tryGetObjectLikeCompletionContainer(contextToken: Node): ObjectLiteralExpression | ObjectBindingPattern | undefined {
16881682
if (contextToken) {
1683+
const { parent } = contextToken;
16891684
switch (contextToken.kind) {
16901685
case SyntaxKind.OpenBraceToken: // const x = { |
16911686
case SyntaxKind.CommaToken: // const x = { a: 0, |
1692-
const parent = contextToken.parent;
16931687
if (isObjectLiteralExpression(parent) || isObjectBindingPattern(parent)) {
16941688
return parent;
16951689
}
16961690
break;
1691+
case SyntaxKind.AsteriskToken:
1692+
return isMethodDeclaration(parent) ? tryCast(parent.parent, isObjectLiteralExpression) : undefined;
16971693
}
16981694
}
16991695

@@ -1870,10 +1866,8 @@ namespace ts.Completions {
18701866

18711867
case SyntaxKind.GetKeyword:
18721868
case SyntaxKind.SetKeyword:
1873-
if (isFromObjectTypeDeclaration(contextToken)) {
1874-
return false;
1875-
}
1876-
// falls through
1869+
return !isFromObjectTypeDeclaration(contextToken);
1870+
18771871
case SyntaxKind.ClassKeyword:
18781872
case SyntaxKind.EnumKeyword:
18791873
case SyntaxKind.InterfaceKeyword:
@@ -1885,6 +1879,9 @@ namespace ts.Completions {
18851879
case SyntaxKind.YieldKeyword:
18861880
case SyntaxKind.TypeKeyword: // type htm|
18871881
return true;
1882+
1883+
case SyntaxKind.AsteriskToken:
1884+
return isFunctionLike(contextToken.parent) && !isMethodDeclaration(contextToken.parent);
18881885
}
18891886

18901887
// If the previous token is keyword correspoding to class member completion keyword
@@ -2124,6 +2121,8 @@ namespace ts.Completions {
21242121
const kind = stringToToken(entry.name)!;
21252122
switch (keywordFilter) {
21262123
case KeywordCompletionFilters.None:
2124+
return false;
2125+
case KeywordCompletionFilters.All:
21272126
return kind === SyntaxKind.AsyncKeyword || !isContextualKeyword(kind) && !isClassMemberCompletionKeyword(kind) || kind === SyntaxKind.DeclareKeyword || kind === SyntaxKind.ModuleKeyword
21282127
|| isTypeKeyword(kind) && kind !== SyntaxKind.UndefinedKeyword;
21292128
case KeywordCompletionFilters.ClassElementKeywords:
@@ -2236,7 +2235,7 @@ namespace ts.Completions {
22362235
default:
22372236
if (!isFromObjectTypeDeclaration(contextToken)) return undefined;
22382237
const isValidKeyword = isClassLike(contextToken.parent.parent) ? isClassMemberCompletionKeyword : isInterfaceOrTypeLiteralCompletionKeyword;
2239-
return (isValidKeyword(contextToken.kind) || isIdentifier(contextToken) && isValidKeyword(stringToToken(contextToken.text)!)) // TODO: GH#18217
2238+
return (isValidKeyword(contextToken.kind) || contextToken.kind === SyntaxKind.AsteriskToken || isIdentifier(contextToken) && isValidKeyword(stringToToken(contextToken.text)!)) // TODO: GH#18217
22402239
? contextToken.parent.parent as ObjectTypeDeclaration : undefined;
22412240
}
22422241
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
////function /*a*/ ;
4+
////function* /*b*/ ;
5+
////interface I {
6+
//// abstract baseMethod(): Iterable<number>;
7+
////}
8+
////class C implements I {
9+
//// */*c*/ ;
10+
//// public */*d*/
11+
////}
12+
////const o: I = {
13+
//// */*e*/
14+
////};
15+
////1 * /*f*/
16+
17+
verify.completions(
18+
{ marker: ["a", "b"], exact: undefined, isNewIdentifierLocation: true },
19+
{ marker: ["c", "d"], exact: ["baseMethod"], isNewIdentifierLocation: true },
20+
{ marker: "e", exact: ["baseMethod"] },
21+
{ marker: "f", includes: ["Number"] },
22+
);

0 commit comments

Comments
 (0)