Skip to content

Don't ignore completions at source file locations #61909

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 57 additions & 59 deletions src/services/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is simply outdented because I removed the wrapping if statement. Within the outdented codepaths I had to guard 2 places against missing location.parent and that's it.

cc @gabritto as you have a fresh context on all of this and related topics

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<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;
}
// 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 extends /* no 'K' here*/> = K`
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) {
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 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;
}
// 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)
Expand Down
3 changes: 3 additions & 0 deletions src/services/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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": [
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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": [
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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": [
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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": [
Expand Down
Loading