Make generator function name a completion list blocker (#26640)
* Make generator function name a completion list blocker * Improvements for class/object members * Separate KeywordCompletionFilter.None and .All
This commit is contained in:
parent
9100047f84
commit
0feeb48783
2 changed files with 42 additions and 21 deletions
|
@ -23,7 +23,8 @@ namespace ts.Completions {
|
||||||
type SymbolOriginInfoMap = (SymbolOriginInfo | undefined)[];
|
type SymbolOriginInfoMap = (SymbolOriginInfo | undefined)[];
|
||||||
|
|
||||||
const enum KeywordCompletionFilters {
|
const enum KeywordCompletionFilters {
|
||||||
None,
|
None, // No keywords
|
||||||
|
All, // Every possible keyword (TODO: This is never appropriate)
|
||||||
ClassElementKeywords, // Keywords inside class body
|
ClassElementKeywords, // Keywords inside class body
|
||||||
InterfaceElementKeywords, // Keywords inside interface body
|
InterfaceElementKeywords, // Keywords inside interface body
|
||||||
ConstructorParameterKeywords, // Keywords at constructor parameter
|
ConstructorParameterKeywords, // Keywords at constructor parameter
|
||||||
|
@ -143,21 +144,13 @@ namespace ts.Completions {
|
||||||
getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target!, log, completionKind, preferences, propertyAccessToConvert, isJsxInitializer, recommendedCompletion, symbolToOriginInfoMap);
|
getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target!, log, completionKind, preferences, propertyAccessToConvert, isJsxInitializer, recommendedCompletion, symbolToOriginInfoMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO add filter for keyword based on type/value/namespace and also location
|
addRange(entries, getKeywordCompletions(keywordFilters));
|
||||||
|
|
||||||
// Add all keywords if
|
|
||||||
// - this is not a member completion list (all the keywords)
|
|
||||||
// - other filters are enabled in required scenario so add those keywords
|
|
||||||
const isMemberCompletion = isMemberCompletionKind(completionKind);
|
|
||||||
if (keywordFilters !== KeywordCompletionFilters.None || !isMemberCompletion) {
|
|
||||||
addRange(entries, getKeywordCompletions(keywordFilters));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const literal of literals) {
|
for (const literal of literals) {
|
||||||
entries.push(createCompletionEntryForLiteral(literal));
|
entries.push(createCompletionEntryForLiteral(literal));
|
||||||
}
|
}
|
||||||
|
|
||||||
return { isGlobalCompletion: isInSnippetScope, isMemberCompletion, isNewIdentifierLocation, entries };
|
return { isGlobalCompletion: isInSnippetScope, isMemberCompletion: isMemberCompletionKind(completionKind), isNewIdentifierLocation, entries };
|
||||||
}
|
}
|
||||||
|
|
||||||
function isUncheckedFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean {
|
function isUncheckedFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean {
|
||||||
|
@ -1014,6 +1007,7 @@ namespace ts.Completions {
|
||||||
tryGetGlobalSymbols();
|
tryGetGlobalSymbols();
|
||||||
symbols = tagSymbols.concat(symbols);
|
symbols = tagSymbols.concat(symbols);
|
||||||
completionKind = CompletionKind.MemberLike;
|
completionKind = CompletionKind.MemberLike;
|
||||||
|
keywordFilters = KeywordCompletionFilters.None;
|
||||||
}
|
}
|
||||||
else if (isStartingCloseTag) {
|
else if (isStartingCloseTag) {
|
||||||
const tagName = (<JsxElement>contextToken.parent.parent).openingElement.tagName;
|
const tagName = (<JsxElement>contextToken.parent.parent).openingElement.tagName;
|
||||||
|
@ -1022,6 +1016,7 @@ namespace ts.Completions {
|
||||||
symbols = [tagSymbol];
|
symbols = [tagSymbol];
|
||||||
}
|
}
|
||||||
completionKind = CompletionKind.MemberLike;
|
completionKind = CompletionKind.MemberLike;
|
||||||
|
keywordFilters = KeywordCompletionFilters.None;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// For JavaScript or TypeScript, if we're not after a dot, then just try to get the
|
// For JavaScript or TypeScript, if we're not after a dot, then just try to get the
|
||||||
|
@ -1191,9 +1186,7 @@ namespace ts.Completions {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGlobalCompletions(): void {
|
function getGlobalCompletions(): void {
|
||||||
if (tryGetFunctionLikeBodyCompletionContainer(contextToken)) {
|
keywordFilters = tryGetFunctionLikeBodyCompletionContainer(contextToken) ? KeywordCompletionFilters.FunctionLikeBodyKeywords : KeywordCompletionFilters.All;
|
||||||
keywordFilters = KeywordCompletionFilters.FunctionLikeBodyKeywords;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get all entities in the current scope.
|
// Get all entities in the current scope.
|
||||||
completionKind = CompletionKind.Global;
|
completionKind = CompletionKind.Global;
|
||||||
|
@ -1648,7 +1641,8 @@ namespace ts.Completions {
|
||||||
completionKind = CompletionKind.MemberLike;
|
completionKind = CompletionKind.MemberLike;
|
||||||
// Declaring new property/method/accessor
|
// Declaring new property/method/accessor
|
||||||
isNewIdentifierLocation = true;
|
isNewIdentifierLocation = true;
|
||||||
keywordFilters = isClassLike(decl) ? KeywordCompletionFilters.ClassElementKeywords : KeywordCompletionFilters.InterfaceElementKeywords;
|
keywordFilters = contextToken.kind === SyntaxKind.AsteriskToken ? KeywordCompletionFilters.None :
|
||||||
|
isClassLike(decl) ? KeywordCompletionFilters.ClassElementKeywords : KeywordCompletionFilters.InterfaceElementKeywords;
|
||||||
|
|
||||||
// If you're in an interface you don't want to repeat things from super-interface. So just stop here.
|
// If you're in an interface you don't want to repeat things from super-interface. So just stop here.
|
||||||
if (!isClassLike(decl)) return GlobalsSearch.Success;
|
if (!isClassLike(decl)) return GlobalsSearch.Success;
|
||||||
|
@ -1686,14 +1680,16 @@ namespace ts.Completions {
|
||||||
*/
|
*/
|
||||||
function tryGetObjectLikeCompletionContainer(contextToken: Node): ObjectLiteralExpression | ObjectBindingPattern | undefined {
|
function tryGetObjectLikeCompletionContainer(contextToken: Node): ObjectLiteralExpression | ObjectBindingPattern | undefined {
|
||||||
if (contextToken) {
|
if (contextToken) {
|
||||||
|
const { parent } = contextToken;
|
||||||
switch (contextToken.kind) {
|
switch (contextToken.kind) {
|
||||||
case SyntaxKind.OpenBraceToken: // const x = { |
|
case SyntaxKind.OpenBraceToken: // const x = { |
|
||||||
case SyntaxKind.CommaToken: // const x = { a: 0, |
|
case SyntaxKind.CommaToken: // const x = { a: 0, |
|
||||||
const parent = contextToken.parent;
|
|
||||||
if (isObjectLiteralExpression(parent) || isObjectBindingPattern(parent)) {
|
if (isObjectLiteralExpression(parent) || isObjectBindingPattern(parent)) {
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SyntaxKind.AsteriskToken:
|
||||||
|
return isMethodDeclaration(parent) ? tryCast(parent.parent, isObjectLiteralExpression) : undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1870,10 +1866,8 @@ namespace ts.Completions {
|
||||||
|
|
||||||
case SyntaxKind.GetKeyword:
|
case SyntaxKind.GetKeyword:
|
||||||
case SyntaxKind.SetKeyword:
|
case SyntaxKind.SetKeyword:
|
||||||
if (isFromObjectTypeDeclaration(contextToken)) {
|
return !isFromObjectTypeDeclaration(contextToken);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// falls through
|
|
||||||
case SyntaxKind.ClassKeyword:
|
case SyntaxKind.ClassKeyword:
|
||||||
case SyntaxKind.EnumKeyword:
|
case SyntaxKind.EnumKeyword:
|
||||||
case SyntaxKind.InterfaceKeyword:
|
case SyntaxKind.InterfaceKeyword:
|
||||||
|
@ -1885,6 +1879,9 @@ namespace ts.Completions {
|
||||||
case SyntaxKind.YieldKeyword:
|
case SyntaxKind.YieldKeyword:
|
||||||
case SyntaxKind.TypeKeyword: // type htm|
|
case SyntaxKind.TypeKeyword: // type htm|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
case SyntaxKind.AsteriskToken:
|
||||||
|
return isFunctionLike(contextToken.parent) && !isMethodDeclaration(contextToken.parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the previous token is keyword correspoding to class member completion keyword
|
// If the previous token is keyword correspoding to class member completion keyword
|
||||||
|
@ -2124,6 +2121,8 @@ namespace ts.Completions {
|
||||||
const kind = stringToToken(entry.name)!;
|
const kind = stringToToken(entry.name)!;
|
||||||
switch (keywordFilter) {
|
switch (keywordFilter) {
|
||||||
case KeywordCompletionFilters.None:
|
case KeywordCompletionFilters.None:
|
||||||
|
return false;
|
||||||
|
case KeywordCompletionFilters.All:
|
||||||
return kind === SyntaxKind.AsyncKeyword || !isContextualKeyword(kind) && !isClassMemberCompletionKeyword(kind) || kind === SyntaxKind.DeclareKeyword || kind === SyntaxKind.ModuleKeyword
|
return kind === SyntaxKind.AsyncKeyword || !isContextualKeyword(kind) && !isClassMemberCompletionKeyword(kind) || kind === SyntaxKind.DeclareKeyword || kind === SyntaxKind.ModuleKeyword
|
||||||
|| isTypeKeyword(kind) && kind !== SyntaxKind.UndefinedKeyword;
|
|| isTypeKeyword(kind) && kind !== SyntaxKind.UndefinedKeyword;
|
||||||
case KeywordCompletionFilters.ClassElementKeywords:
|
case KeywordCompletionFilters.ClassElementKeywords:
|
||||||
|
@ -2236,7 +2235,7 @@ namespace ts.Completions {
|
||||||
default:
|
default:
|
||||||
if (!isFromObjectTypeDeclaration(contextToken)) return undefined;
|
if (!isFromObjectTypeDeclaration(contextToken)) return undefined;
|
||||||
const isValidKeyword = isClassLike(contextToken.parent.parent) ? isClassMemberCompletionKeyword : isInterfaceOrTypeLiteralCompletionKeyword;
|
const isValidKeyword = isClassLike(contextToken.parent.parent) ? isClassMemberCompletionKeyword : isInterfaceOrTypeLiteralCompletionKeyword;
|
||||||
return (isValidKeyword(contextToken.kind) || isIdentifier(contextToken) && isValidKeyword(stringToToken(contextToken.text)!)) // TODO: GH#18217
|
return (isValidKeyword(contextToken.kind) || contextToken.kind === SyntaxKind.AsteriskToken || isIdentifier(contextToken) && isValidKeyword(stringToToken(contextToken.text)!)) // TODO: GH#18217
|
||||||
? contextToken.parent.parent as ObjectTypeDeclaration : undefined;
|
? contextToken.parent.parent as ObjectTypeDeclaration : undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
22
tests/cases/fourslash/completionsGeneratorFunctions.ts
Normal file
22
tests/cases/fourslash/completionsGeneratorFunctions.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/// <reference path="fourslash.ts" />
|
||||||
|
|
||||||
|
////function /*a*/ ;
|
||||||
|
////function* /*b*/ ;
|
||||||
|
////interface I {
|
||||||
|
//// abstract baseMethod(): Iterable<number>;
|
||||||
|
////}
|
||||||
|
////class C implements I {
|
||||||
|
//// */*c*/ ;
|
||||||
|
//// public */*d*/
|
||||||
|
////}
|
||||||
|
////const o: I = {
|
||||||
|
//// */*e*/
|
||||||
|
////};
|
||||||
|
////1 * /*f*/
|
||||||
|
|
||||||
|
verify.completions(
|
||||||
|
{ marker: ["a", "b"], exact: undefined, isNewIdentifierLocation: true },
|
||||||
|
{ marker: ["c", "d"], exact: ["baseMethod"], isNewIdentifierLocation: true },
|
||||||
|
{ marker: "e", exact: ["baseMethod"] },
|
||||||
|
{ marker: "f", includes: ["Number"] },
|
||||||
|
);
|
Loading…
Reference in a new issue