Filter non-contextual keyword auto-imports to prevent keyword shadowing#3400
Filter non-contextual keyword auto-imports to prevent keyword shadowing#3400andrewbranch merged 3 commits intomainfrom
Conversation
…adowing Auto-imports whose names are non-contextual keywords (e.g. `function`, `class`, `const`) now get filtered out during completion processing, matching the TypeScript reference implementation behavior. This ensures that keyword completions are not shadowed by auto-import suggestions with the same name. Agent-Logs-Url: https://github.com/microsoft/typescript-go/sessions/ab9b1d54-fb2f-4faa-8093-d6ac10e25fae Co-authored-by: andrewbranch <3277153+andrewbranch@users.noreply.github.com>
| f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) | ||
| defer done() | ||
| // Both the keyword `type` and the auto-import `type` should appear. | ||
| f.VerifyCompletions(t, "", &fourslash.CompletionsExpectedList{ |
There was a problem hiding this comment.
This is pretty hard to read. What will this end up being?
mod.type, or just type? The latter is fine, but it doesn't work for function, which is a reserved keyword in value-space.
There was a problem hiding this comment.
Removed the contextual keyword test entirely in d60ec53 — it was confusing and the important thing to test is that reserved keywords shadow their auto-imports, which the remaining test covers.
| EditRange: Ignored, | ||
| }, | ||
| Items: &fourslash.CompletionsExpectedItems{ | ||
| Includes: []fourslash.CompletionsExpectedItem{ |
There was a problem hiding this comment.
@copilot while you showed that the global is included, you didn't show whether or not the auto-import is excluded. You either need to use Includes and Excludes together or (preferably) just use Exact. Same for the other test.
That said, if you run node internal/fourslash/_scripts/updateFailing.mts and existing failing tests start passing, you can probably just delete this test. I would be surprised if there's not already coverage for this.
There was a problem hiding this comment.
Updated the test in d60ec53 to use Includes + Excludes together: Includes matches and consumes the keyword function entry, then Excludes: []string{"function"} verifies no auto-import function item remains. Also removed the confusing type contextual keyword test per Daniel's feedback. Ran updateFailing.mts — no existing tests flipped.
…remove confusing contextual keyword test Agent-Logs-Url: https://github.com/microsoft/typescript-go/sessions/2c71ae50-e850-4141-a051-0920d522e251 Co-authored-by: andrewbranch <3277153+andrewbranch@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Prevents auto-import completion entries whose names are non-contextual (reserved) keywords from shadowing keyword completions, so users can type language constructs like function without interference.
Changes:
- Filter auto-import entries by checking whether the symbol name is a non-contextual keyword.
- Add a fourslash regression test asserting keyword completion is present and conflicting auto-import is excluded.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| internal/ls/completions.go | Skips auto-import completion entries whose names are non-contextual keywords. |
| internal/fourslash/tests/keywordShadowsAutoImport_test.go | Adds coverage ensuring function keyword completion is not shadowed by an auto-import. |
| // Non-contextual keywords (e.g., `function`, `class`, `const`) cannot be used as identifiers, | ||
| // so auto-imports with these names should not shadow keyword completions. |
There was a problem hiding this comment.
The comment is a bit imprecise given the example in the PR description/export syntax: these keywords can appear as IdentifierName in some syntactic positions (e.g., export specifiers, object properties), but they cannot be used as binding identifiers (e.g., import { function } ... is invalid). Consider rewording to “cannot be used as binding identifiers (such as in import specifiers)” to match the actual reason for filtering.
| // Non-contextual keywords (e.g., `function`, `class`, `const`) cannot be used as identifiers, | |
| // so auto-imports with these names should not shadow keyword completions. | |
| // Non-contextual keywords (e.g., `function`, `class`, `const`) cannot be used as binding identifiers | |
| // (such as in import specifiers), so auto-imports with these names should not shadow keyword completions. |
Auto-imports with names matching reserved keywords (
function,class,const, etc.) were shadowing the keyword completions, preventing users from typing basic language constructs when a module exports a symbol with a keyword name.Changes
internal/ls/completions.go: Skip auto-imports whose names are non-contextual keywords ingetCompletionEntriesFromSymbols, matching theisStringANonContextualKeywordfilter in TypeScript'scollectAutoImports(completions.ts:4179). Contextual keywords liketype,abstract,asyncare unaffected and continue to coexist with auto-imports.internal/fourslash/tests/keywordShadowsAutoImport_test.go: Test verifying that thefunctionkeyword completion is present and the auto-importfunctionis excluded, usingIncludesto match the keyword entry andExcludesto confirm no auto-import with the same name remains.