From 02ee11c35705c3ea3eca5795d35794ab4967a761 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 23 Mar 2018 08:44:21 -0700 Subject: [PATCH] Refactor `tryGetGlobalSymbols` into list of things to try (#22704) * Refactor `tryGetGlobalSymbols` into list of things to try * Refactor to `||` expression --- src/services/completions.ts | 106 ++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/src/services/completions.ts b/src/services/completions.ts index 7e090b3ccd4..1173b2cfd45 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -24,6 +24,8 @@ namespace ts.Completions { TypeKeywords, } + const enum GlobalsSearch { Continue, Success, Fail } + export function getCompletionsAtPosition( host: LanguageServiceHost, typeChecker: TypeChecker, @@ -1046,52 +1048,38 @@ namespace ts.Completions { } function tryGetGlobalSymbols(): boolean { - let objectLikeContainer: ObjectLiteralExpression | BindingPattern; - let namedImportsOrExports: NamedImportsOrExports; - let classLikeContainer: ClassLikeDeclaration; - let jsxContainer: JsxOpeningLikeElement; + const result: GlobalsSearch = tryGetObjectLikeCompletionSymbols() + || tryGetImportOrExportClauseCompletionSymbols() + || tryGetConstructorCompletion() + || tryGetClassLikeCompletionSymbols() + || tryGetJsxCompletionSymbols() + || (getGlobalCompletions(), GlobalsSearch.Success); + return result === GlobalsSearch.Success; + } - if (objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken)) { - return tryGetObjectLikeCompletionSymbols(objectLikeContainer); - } + function tryGetConstructorCompletion(): GlobalsSearch { + if (!tryGetConstructorLikeCompletionContainer(contextToken)) return GlobalsSearch.Continue; + // no members, only keywords + completionKind = CompletionKind.None; + // Declaring new property/method/accessor + isNewIdentifierLocation = true; + // Has keywords for constructor parameter + keywordFilters = KeywordCompletionFilters.ConstructorParameterKeywords; + return GlobalsSearch.Success; + } - if (namedImportsOrExports = tryGetNamedImportsOrExportsForCompletion(contextToken)) { - // cursor is in an import clause - // try to show exported member for imported module - return tryGetImportOrExportClauseCompletionSymbols(namedImportsOrExports); - } - - if (tryGetConstructorLikeCompletionContainer(contextToken)) { - // no members, only keywords - completionKind = CompletionKind.None; - // Declaring new property/method/accessor - isNewIdentifierLocation = true; - // Has keywords for constructor parameter - keywordFilters = KeywordCompletionFilters.ConstructorParameterKeywords; - return true; - } - - if (classLikeContainer = tryGetClassLikeCompletionContainer(contextToken)) { - // cursor inside class declaration - getGetClassLikeCompletionSymbols(classLikeContainer); - return true; - } - - if (jsxContainer = tryGetContainingJsxElement(contextToken)) { - let attrsType: Type; - if ((jsxContainer.kind === SyntaxKind.JsxSelfClosingElement) || (jsxContainer.kind === SyntaxKind.JsxOpeningElement)) { - // Cursor is inside a JSX self-closing element or opening element - attrsType = typeChecker.getAllAttributesTypeFromJsxOpeningLikeElement(jsxContainer); - - if (attrsType) { - symbols = filterJsxAttributes(typeChecker.getPropertiesOfType(attrsType), jsxContainer.attributes.properties); - completionKind = CompletionKind.MemberLike; - isNewIdentifierLocation = false; - return true; - } - } - } + function tryGetJsxCompletionSymbols(): GlobalsSearch { + const jsxContainer = tryGetContainingJsxElement(contextToken); + // Cursor is inside a JSX self-closing element or opening element + const attrsType = jsxContainer && typeChecker.getAllAttributesTypeFromJsxOpeningLikeElement(jsxContainer); + if (!attrsType) return GlobalsSearch.Continue; + symbols = filterJsxAttributes(typeChecker.getPropertiesOfType(attrsType), jsxContainer.attributes.properties); + completionKind = CompletionKind.MemberLike; + isNewIdentifierLocation = false; + return GlobalsSearch.Success; + } + function getGlobalCompletions(): void { if (tryGetFunctionLikeBodyCompletionContainer(contextToken)) { keywordFilters = KeywordCompletionFilters.FunctionLikeBodyKeywords; } @@ -1155,8 +1143,6 @@ namespace ts.Completions { getSymbolsFromOtherSourceFileExports(symbols, previousToken && isIdentifier(previousToken) ? previousToken.text : "", target); } filterGlobalCompletion(symbols); - - return true; } function isSnippetScope(scopeNode: Node): boolean { @@ -1434,7 +1420,10 @@ namespace ts.Completions { * * @returns true if 'symbols' was successfully populated; false otherwise. */ - function tryGetObjectLikeCompletionSymbols(objectLikeContainer: ObjectLiteralExpression | ObjectBindingPattern): boolean { + function tryGetObjectLikeCompletionSymbols(): GlobalsSearch | undefined { + const objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken); + if (!objectLikeContainer) return GlobalsSearch.Continue; + // We're looking up possible property names from contextual/inferred/declared type. completionKind = CompletionKind.ObjectPropertyDeclaration; @@ -1446,7 +1435,7 @@ namespace ts.Completions { // other than those within the declared type. isNewIdentifierLocation = true; const typeForObject = typeChecker.getContextualType(objectLikeContainer); - if (!typeForObject) return false; + if (!typeForObject) return GlobalsSearch.Fail; typeMembers = getPropertiesForCompletion(typeForObject, typeChecker, /*isForAccess*/ false); existingMembers = objectLikeContainer.properties; } @@ -1474,7 +1463,7 @@ namespace ts.Completions { } if (canGetType) { const typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer); - if (!typeForObject) return false; + if (!typeForObject) return GlobalsSearch.Fail; // In a binding pattern, get only known properties. Everywhere else we will get all possible properties. typeMembers = typeChecker.getPropertiesOfType(typeForObject).filter((symbol) => !(getDeclarationModifierFlagsFromSymbol(symbol) & ModifierFlags.NonPublicAccessibilityModifier)); existingMembers = objectLikeContainer.elements; @@ -1485,7 +1474,7 @@ namespace ts.Completions { // Add filtered items to the completion list symbols = filterObjectMembersList(typeMembers, Debug.assertDefined(existingMembers)); } - return true; + return GlobalsSearch.Success; } /** @@ -1503,7 +1492,12 @@ namespace ts.Completions { * * @returns true if 'symbols' was successfully populated; false otherwise. */ - function tryGetImportOrExportClauseCompletionSymbols(namedImportsOrExports: NamedImportsOrExports): boolean { + function tryGetImportOrExportClauseCompletionSymbols(): GlobalsSearch { + const namedImportsOrExports = tryGetNamedImportsOrExportsForCompletion(contextToken); + if (!namedImportsOrExports) return undefined; + + // cursor is in an import clause + // try to show exported member for imported module const declarationKind = namedImportsOrExports.kind === SyntaxKind.NamedImports ? SyntaxKind.ImportDeclaration : SyntaxKind.ExportDeclaration; @@ -1511,7 +1505,7 @@ namespace ts.Completions { const moduleSpecifier = importOrExportDeclaration.moduleSpecifier; if (!moduleSpecifier) { - return false; + return GlobalsSearch.Fail; } completionKind = CompletionKind.MemberLike; @@ -1520,19 +1514,22 @@ namespace ts.Completions { const moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(moduleSpecifier); if (!moduleSpecifierSymbol) { symbols = emptyArray; - return true; + return GlobalsSearch.Fail; } const exports = typeChecker.getExportsAndPropertiesOfModule(moduleSpecifierSymbol); symbols = filterNamedImportOrExportCompletionItems(exports, namedImportsOrExports.elements); - return true; + return GlobalsSearch.Success; } /** * Aggregates relevant symbols for completion in class declaration * Relevant symbols are stored in the captured 'symbols' variable. */ - function getGetClassLikeCompletionSymbols(classLikeDeclaration: ClassLikeDeclaration) { + function tryGetClassLikeCompletionSymbols(): GlobalsSearch { + const classLikeDeclaration = tryGetClassLikeCompletionContainer(contextToken); + if (!classLikeDeclaration) return GlobalsSearch.Continue; + // We're looking up possible property names from parent type. completionKind = CompletionKind.MemberLike; // Declaring new property/method/accessor @@ -1582,6 +1579,7 @@ namespace ts.Completions { classElementModifierFlags); } } + return GlobalsSearch.Success; } /**