diff --git a/src/services/completions.ts b/src/services/completions.ts index dd623aadeb156..6d0cbf7183ed3 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -2738,78 +2738,76 @@ export function getCompletionEntriesFromSymbols( function shouldIncludeSymbol(symbol: Symbol, symbolToSortTextMap: SymbolSortTextMap): boolean { let allFlags = symbol.flags; - if (!isSourceFile(location)) { - // export = /**/ here we want to get all meanings, so any symbol is ok - if (isExportAssignment(location.parent)) { - return true; + // export = /**/ here we want to get all meanings, so any symbol is ok + if (location.parent && isExportAssignment(location.parent)) { + return true; + } + // Filter out variables from their own initializers + // `const a = /* no 'a' here */` + if (closestSymbolDeclaration && tryCast(closestSymbolDeclaration, isVariableDeclaration)) { + if (symbol.valueDeclaration === closestSymbolDeclaration) { + return false; } - // Filter out variables from their own initializers - // `const a = /* no 'a' here */` - if (closestSymbolDeclaration && tryCast(closestSymbolDeclaration, isVariableDeclaration)) { - if (symbol.valueDeclaration === closestSymbolDeclaration) { + // const { a } = /* no 'a' here */; + if (isBindingPattern(closestSymbolDeclaration.name) && closestSymbolDeclaration.name.elements.some(e => e === symbol.valueDeclaration)) { + return false; + } + } + + // Filter out current and latter parameters from defaults + // `function f(a = /* no 'a' and 'b' here */, b) { }` or + // `function f(a: T, b: T2) { }` + const symbolDeclaration = symbol.valueDeclaration ?? symbol.declarations?.[0]; + if (closestSymbolDeclaration && symbolDeclaration) { + if (isParameter(closestSymbolDeclaration) && isParameter(symbolDeclaration)) { + const parameters = closestSymbolDeclaration.parent.parameters; + if (symbolDeclaration.pos >= closestSymbolDeclaration.pos && symbolDeclaration.pos < parameters.end) { return false; } - // const { a } = /* no 'a' here */; - if (isBindingPattern(closestSymbolDeclaration.name) && closestSymbolDeclaration.name.elements.some(e => e === symbol.valueDeclaration)) { + } + else if (isTypeParameterDeclaration(closestSymbolDeclaration) && isTypeParameterDeclaration(symbolDeclaration)) { + if (closestSymbolDeclaration === symbolDeclaration && contextToken?.kind === SyntaxKind.ExtendsKeyword) { + // filter out the directly self-recursive type parameters + // `type A = K` return false; } - } - - // Filter out current and latter parameters from defaults - // `function f(a = /* no 'a' and 'b' here */, b) { }` or - // `function f(a: T, b: T2) { }` - const symbolDeclaration = symbol.valueDeclaration ?? symbol.declarations?.[0]; - if (closestSymbolDeclaration && symbolDeclaration) { - if (isParameter(closestSymbolDeclaration) && isParameter(symbolDeclaration)) { - const parameters = closestSymbolDeclaration.parent.parameters; - if (symbolDeclaration.pos >= closestSymbolDeclaration.pos && symbolDeclaration.pos < parameters.end) { + if (isInTypeParameterDefault(contextToken) && !isInferTypeNode(closestSymbolDeclaration.parent)) { + const typeParameters = closestSymbolDeclaration.parent.typeParameters; + if (typeParameters && symbolDeclaration.pos >= closestSymbolDeclaration.pos && symbolDeclaration.pos < typeParameters.end) { return false; } } - else if (isTypeParameterDeclaration(closestSymbolDeclaration) && isTypeParameterDeclaration(symbolDeclaration)) { - if (closestSymbolDeclaration === symbolDeclaration && contextToken?.kind === SyntaxKind.ExtendsKeyword) { - // filter out the directly self-recursive type parameters - // `type A = K` - return false; - } - if (isInTypeParameterDefault(contextToken) && !isInferTypeNode(closestSymbolDeclaration.parent)) { - const typeParameters = closestSymbolDeclaration.parent.typeParameters; - if (typeParameters && symbolDeclaration.pos >= closestSymbolDeclaration.pos && symbolDeclaration.pos < typeParameters.end) { - return false; - } - } - } } + } - // External modules can have global export declarations that will be - // available as global keywords in all scopes. But if the external module - // already has an explicit export and user only wants to user explicit - // module imports then the global keywords will be filtered out so auto - // import suggestions will win in the completion - const symbolOrigin = skipAlias(symbol, typeChecker); - // We only want to filter out the global keywords - // Auto Imports are not available for scripts so this conditional is always false - if ( - !!sourceFile.externalModuleIndicator - && !compilerOptions.allowUmdGlobalAccess - && symbolToSortTextMap[getSymbolId(symbol)] === SortText.GlobalsOrKeywords - && (symbolToSortTextMap[getSymbolId(symbolOrigin)] === SortText.AutoImportSuggestions - || symbolToSortTextMap[getSymbolId(symbolOrigin)] === SortText.LocationPriority) - ) { - return false; - } + // External modules can have global export declarations that will be + // available as global keywords in all scopes. But if the external module + // already has an explicit export and user only wants to user explicit + // module imports then the global keywords will be filtered out so auto + // import suggestions will win in the completion + const symbolOrigin = skipAlias(symbol, typeChecker); + // We only want to filter out the global keywords + // Auto Imports are not available for scripts so this conditional is always false + if ( + !!sourceFile.externalModuleIndicator + && !compilerOptions.allowUmdGlobalAccess + && symbolToSortTextMap[getSymbolId(symbol)] === SortText.GlobalsOrKeywords + && (symbolToSortTextMap[getSymbolId(symbolOrigin)] === SortText.AutoImportSuggestions + || symbolToSortTextMap[getSymbolId(symbolOrigin)] === SortText.LocationPriority) + ) { + return false; + } - allFlags |= getCombinedLocalAndExportSymbolFlags(symbolOrigin); + allFlags |= getCombinedLocalAndExportSymbolFlags(symbolOrigin); - // import m = /**/ <-- It can only access namespace (if typing import = x. this would get member symbols and not namespace) - if (isInRightSideOfInternalImportEqualsDeclaration(location)) { - return !!(allFlags & SymbolFlags.Namespace); - } + // import m = /**/ <-- It can only access namespace (if typing import = x. this would get member symbols and not namespace) + if (isInRightSideOfInternalImportEqualsDeclaration(location)) { + return !!(allFlags & SymbolFlags.Namespace); + } - if (isTypeOnlyLocation) { - // It's a type, but you can reach it by namespace.type as well - return symbolCanBeReferencedAtTypeLocation(symbol, typeChecker); - } + if (isTypeOnlyLocation) { + // It's a type, but you can reach it by namespace.type as well + return symbolCanBeReferencedAtTypeLocation(symbol, typeChecker); } // expressions are value space (which includes the value namespaces) diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 75a1cbc94c315..bec7d4b266d20 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -520,6 +520,9 @@ function getMeaningFromRightHandSideOfImportEquals(node: Node): SemanticMeaning /** @internal */ export function isInRightSideOfInternalImportEqualsDeclaration(node: Node): boolean { + if (!node.parent) { + return false; + } while (node.parent.kind === SyntaxKind.QualifiedName) { node = node.parent; } diff --git a/tests/baselines/reference/tsserver/completions/in-project-reference-setup-with-path-mapping-with-existing-import-without-includeCompletionsForModuleExports.js b/tests/baselines/reference/tsserver/completions/in-project-reference-setup-with-path-mapping-with-existing-import-without-includeCompletionsForModuleExports.js index 8b20553e962dc..be58940da541a 100644 --- a/tests/baselines/reference/tsserver/completions/in-project-reference-setup-with-path-mapping-with-existing-import-without-includeCompletionsForModuleExports.js +++ b/tests/baselines/reference/tsserver/completions/in-project-reference-setup-with-path-mapping-with-existing-import-without-includeCompletionsForModuleExports.js @@ -407,6 +407,12 @@ Info seq [hh:mm:ss:mss] response: "isMemberCompletion": false, "isNewIdentifierLocation": false, "entries": [ + { + "name": "MyClass", + "kind": "alias", + "kindModifiers": "export", + "sortText": "11" + }, { "name": "abstract", "kind": "keyword", @@ -814,19 +820,6 @@ Info seq [hh:mm:ss:mss] response: "kind": "keyword", "kindModifiers": "", "sortText": "15" - }, - { - "name": "MyClass", - "kind": "class", - "kindModifiers": "export", - "sortText": "16", - "source": "/user/username/projects/shared/src/index", - "hasAction": true, - "data": { - "exportName": "MyClass", - "exportMapKey": "7 * MyClass ", - "fileName": "/user/username/projects/shared/src/index.ts" - } } ], "defaultCommitCharacters": [ @@ -898,6 +891,12 @@ Info seq [hh:mm:ss:mss] response: "isMemberCompletion": false, "isNewIdentifierLocation": false, "entries": [ + { + "name": "MyClass", + "kind": "alias", + "kindModifiers": "export", + "sortText": "11" + }, { "name": "abstract", "kind": "keyword", @@ -1305,19 +1304,6 @@ Info seq [hh:mm:ss:mss] response: "kind": "keyword", "kindModifiers": "", "sortText": "15" - }, - { - "name": "MyClass", - "kind": "class", - "kindModifiers": "export", - "sortText": "16", - "source": "/user/username/projects/shared/src/index", - "hasAction": true, - "data": { - "exportName": "MyClass", - "exportMapKey": "7 * MyClass ", - "fileName": "/user/username/projects/shared/src/index.ts" - } } ], "defaultCommitCharacters": [ @@ -1401,6 +1387,12 @@ Info seq [hh:mm:ss:mss] response: "isMemberCompletion": false, "isNewIdentifierLocation": false, "entries": [ + { + "name": "MyClass", + "kind": "alias", + "kindModifiers": "export", + "sortText": "11" + }, { "name": "abstract", "kind": "keyword", @@ -1808,19 +1800,6 @@ Info seq [hh:mm:ss:mss] response: "kind": "keyword", "kindModifiers": "", "sortText": "15" - }, - { - "name": "MyClass", - "kind": "class", - "kindModifiers": "export", - "sortText": "16", - "source": "/user/username/projects/shared/src/index", - "hasAction": true, - "data": { - "exportName": "MyClass", - "exportMapKey": "7 * MyClass ", - "fileName": "/user/username/projects/shared/src/index.ts" - } } ], "defaultCommitCharacters": [ @@ -1922,6 +1901,12 @@ Info seq [hh:mm:ss:mss] response: "isMemberCompletion": false, "isNewIdentifierLocation": false, "entries": [ + { + "name": "MyClass", + "kind": "alias", + "kindModifiers": "export", + "sortText": "11" + }, { "name": "abstract", "kind": "keyword", @@ -2329,19 +2314,6 @@ Info seq [hh:mm:ss:mss] response: "kind": "keyword", "kindModifiers": "", "sortText": "15" - }, - { - "name": "MyClass", - "kind": "class", - "kindModifiers": "export", - "sortText": "16", - "source": "/user/username/projects/shared/src/index", - "hasAction": true, - "data": { - "exportName": "MyClass", - "exportMapKey": "7 * MyClass ", - "fileName": "/user/username/projects/shared/src/index.ts" - } } ], "defaultCommitCharacters": [ diff --git a/tests/baselines/reference/tsserver/completions/in-project-reference-setup-with-path-mapping-with-existing-import.js b/tests/baselines/reference/tsserver/completions/in-project-reference-setup-with-path-mapping-with-existing-import.js index d2bb01734c1f6..51b48dffffcbc 100644 --- a/tests/baselines/reference/tsserver/completions/in-project-reference-setup-with-path-mapping-with-existing-import.js +++ b/tests/baselines/reference/tsserver/completions/in-project-reference-setup-with-path-mapping-with-existing-import.js @@ -436,6 +436,12 @@ Info seq [hh:mm:ss:mss] response: "isMemberCompletion": false, "isNewIdentifierLocation": false, "entries": [ + { + "name": "MyClass", + "kind": "alias", + "kindModifiers": "export", + "sortText": "11" + }, { "name": "abstract", "kind": "keyword", @@ -844,19 +850,6 @@ Info seq [hh:mm:ss:mss] response: "kindModifiers": "", "sortText": "15" }, - { - "name": "MyClass", - "kind": "class", - "kindModifiers": "export", - "sortText": "16", - "source": "/user/username/projects/shared/src/index", - "hasAction": true, - "data": { - "exportName": "MyClass", - "exportMapKey": "7 * MyClass ", - "fileName": "/user/username/projects/shared/src/index.ts" - } - }, { "name": "MyHelper", "kind": "class", @@ -966,6 +959,12 @@ Info seq [hh:mm:ss:mss] response: "isMemberCompletion": false, "isNewIdentifierLocation": false, "entries": [ + { + "name": "MyClass", + "kind": "alias", + "kindModifiers": "export", + "sortText": "11" + }, { "name": "abstract", "kind": "keyword", @@ -1374,19 +1373,6 @@ Info seq [hh:mm:ss:mss] response: "kindModifiers": "", "sortText": "15" }, - { - "name": "MyClass", - "kind": "class", - "kindModifiers": "export", - "sortText": "16", - "source": "/user/username/projects/shared/src/index", - "hasAction": true, - "data": { - "exportName": "MyClass", - "exportMapKey": "7 * MyClass ", - "fileName": "/user/username/projects/shared/src/index.ts" - } - }, { "name": "MyHelper", "kind": "class", @@ -1564,6 +1550,12 @@ Info seq [hh:mm:ss:mss] response: "isMemberCompletion": false, "isNewIdentifierLocation": false, "entries": [ + { + "name": "MyClass", + "kind": "alias", + "kindModifiers": "export", + "sortText": "11" + }, { "name": "abstract", "kind": "keyword", @@ -1972,19 +1964,6 @@ Info seq [hh:mm:ss:mss] response: "kindModifiers": "", "sortText": "15" }, - { - "name": "MyClass", - "kind": "class", - "kindModifiers": "export", - "sortText": "16", - "source": "/user/username/projects/shared/src/index", - "hasAction": true, - "data": { - "exportName": "MyClass", - "exportMapKey": "7 * MyClass ", - "fileName": "/user/username/projects/shared/src/index.ts" - } - }, { "name": "MyHelper", "kind": "class", @@ -2113,6 +2092,12 @@ Info seq [hh:mm:ss:mss] response: "isMemberCompletion": false, "isNewIdentifierLocation": false, "entries": [ + { + "name": "MyClass", + "kind": "alias", + "kindModifiers": "export", + "sortText": "11" + }, { "name": "abstract", "kind": "keyword", @@ -2520,19 +2505,6 @@ Info seq [hh:mm:ss:mss] response: "kind": "keyword", "kindModifiers": "", "sortText": "15" - }, - { - "name": "MyClass", - "kind": "class", - "kindModifiers": "export", - "sortText": "16", - "source": "/user/username/projects/shared/src/index", - "hasAction": true, - "data": { - "exportName": "MyClass", - "exportMapKey": "7 * MyClass ", - "fileName": "/user/username/projects/shared/src/index.ts" - } } ], "defaultCommitCharacters": [ diff --git a/tests/cases/fourslash/asOperatorCompletion2.ts b/tests/cases/fourslash/asOperatorCompletion2.ts new file mode 100644 index 0000000000000..feb1c37930b91 --- /dev/null +++ b/tests/cases/fourslash/asOperatorCompletion2.ts @@ -0,0 +1,9 @@ +/// + +//// type T = number; +//// var x; +//// var y = x as /**/ +//// + +verify.completions({ marker: "", includes: "T" }); + diff --git a/tests/cases/fourslash/asOperatorCompletion3.ts b/tests/cases/fourslash/asOperatorCompletion3.ts new file mode 100644 index 0000000000000..d7840d8baa3f8 --- /dev/null +++ b/tests/cases/fourslash/asOperatorCompletion3.ts @@ -0,0 +1,8 @@ +/// + +//// type T = number; +//// var x; +//// var y = x as /**/ // comment + +verify.completions({ marker: "", includes: "T" }); +