Don't ignore completions at source file locations (#61909)

This commit is contained in:
Mateusz Burzyński
2025-06-23 22:20:43 +02:00
committed by GitHub
parent 479285d0ac
commit 78c16795cd
6 changed files with 133 additions and 171 deletions

View File

@@ -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;
}
// Filter out variables from their own initializers
// `const a = /* no 'a' here */`
if (closestSymbolDeclaration && tryCast(closestSymbolDeclaration, isVariableDeclaration)) {
if (symbol.valueDeclaration === closestSymbolDeclaration) {
return false;
}
// 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<T = /* no 'T' and 'T2' here */>(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;
}
}
else if (isTypeParameterDeclaration(closestSymbolDeclaration) && isTypeParameterDeclaration(symbolDeclaration)) {
if (closestSymbolDeclaration === symbolDeclaration && contextToken?.kind === SyntaxKind.ExtendsKeyword) {
// filter out the directly self-recursive type parameters
// `type A<K extends /* no 'K' here*/> = 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)
) {
// 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;
}
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);
// const { a } = /* no 'a' here */;
if (isBindingPattern(closestSymbolDeclaration.name) && closestSymbolDeclaration.name.elements.some(e => e === symbol.valueDeclaration)) {
return false;
}
}
if (isTypeOnlyLocation) {
// It's a type, but you can reach it by namespace.type as well
return symbolCanBeReferencedAtTypeLocation(symbol, typeChecker);
// Filter out current and latter parameters from defaults
// `function f(a = /* no 'a' and 'b' here */, b) { }` or
// `function f<T = /* no 'T' and 'T2' here */>(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;
}
}
else if (isTypeParameterDeclaration(closestSymbolDeclaration) && isTypeParameterDeclaration(symbolDeclaration)) {
if (closestSymbolDeclaration === symbolDeclaration && contextToken?.kind === SyntaxKind.ExtendsKeyword) {
// filter out the directly self-recursive type parameters
// `type A<K extends /* no 'K' here*/> = 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;
}
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);
}
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)

View File

@@ -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;
}

View File

@@ -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": [

View File

@@ -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": [

View File

@@ -0,0 +1,9 @@
/// <reference path="fourslash.ts" />
//// type T = number;
//// var x;
//// var y = x as /**/
////
verify.completions({ marker: "", includes: "T" });

View File

@@ -0,0 +1,8 @@
/// <reference path="fourslash.ts" />
//// type T = number;
//// var x;
//// var y = x as /**/ // comment
verify.completions({ marker: "", includes: "T" });