fix(hover): bare-word lookup no longer matches unrelated CLASS/INTERF… - #391
Open
geircodes wants to merge 1 commit into
Open
fix(hover): bare-word lookup no longer matches unrelated CLASS/INTERF…#391geircodes wants to merge 1 commit into
geircodes wants to merge 1 commit into
Conversation
…ACE members isVariableLookupCandidate() (used by hover/F12/Ctrl+F12's bare-word MEMBER-parent and INCLUDE-chain walk) accepted any column-0 or procedure-shaped token with no check for CLASS/INTERFACE containment. A class method/property prototype is tokenized identically to a real top-level global, so an undeclared word sharing a name with some unrelated class's method resolved to that method instead of correctly finding nothing - since class members are only reachable via qualified access (SELF.X / instance.X), never as a bare word. Guard the lookup with the token's own structure context (inClass / inInterface) so only genuine top-level globals satisfy the bare-word search. Structure-opening lines themselves are unaffected, so global class/queue/group type-name lookups keep working.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(hover): bare-word lookup no longer matches unrelated CLASS/INTERFACE members
What happened
Hovering a bare, undeclared word can resolve to an unrelated CLASS's or INTERFACE's method/property
elsewhere in the include chain — labeled correctly as "🔷 Class property of X", but shown as if it
were a legitimate match, when the correct behavior is to show nothing.
testis not declared in the procedure, but still the hover found a match and told thattestwas a method inMyClass.Repro (see the new test
MemberLocatorService.BareWordClassMemberGuard.test.ts): a file includesdeclarations.inc, which declaresSomeClass CLASS,TYPE ... DoWork PROCEDURE(*?) ... END. Hoveringthe bare word
DoWorkanywhere else in that file — where it is not declared and has no local scope— resolves to
SomeClass.DoWorkinstead of correctly finding nothing. Same shape for an INTERFACEmember.
Root cause
MemberLocatorService.isVariableLookupCandidate(t)— the gate for the bare-word MEMBER-parent andINCLUDE-chain walk used by hover/F12/Ctrl+F12 — accepted any
TokenType.Structure, anyprocedure/function-shaped token, or any column-0 token, with no check for CLASS/INTERFACE
containment. A class method prototype (
DoWork PROCEDURE(...)insideCLASS...END) tokenizesidentically to a real top-level global procedure, so it passed the gate unfiltered.
Class members are never reachable as a bare unqualified word in Clarion — only via
SELF.X/instance.X— so this was always a wrong candidate; the check just never existed.VariableHoverResolver.buildGlobalVariableHoveralready computesisInClassBlockfor the exactsame token, but only to relabel the hover text ("🔷 Class property of X"), never to reject the
match.
This surfaces through either bare-word walk branch — the current file's own INCLUDE chain, or the
MEMBER-parent file's INCLUDE chain (via the one-hop
INCLUDE('member.clw')shim convention handledby
resolveMemberHeaderToken(), a separate in-flight fix onfix/member-header-via-include) — bothshare the same
isVariableLookupCandidategate, so this fix applies to both.Fix
isVariableLookupCandidatenow takes the token's owningTextDocumentand rejects the match whentokenCache.getStructure(doc).getStructureContextAt(t.line)reportsinClassorinInterface. All5 call sites in this base updated to pass the right doc (
data.doc/parentData.doc/ the ambientdocumentparam, matched per call site).Structure-opening lines themselves are NOT considered "inside" the structure per
DocumentStructure's existing containment semantics (matchesisInClassBlock's existing behavior),so a global CLASS/QUEUE/GROUP type name lookup is unaffected — only members nested between
CLASS...END/INTERFACE...ENDare excluded.Testing
New test file
MemberLocatorService.BareWordClassMemberGuard.test.ts: pins that a CLASS method nameand an INTERFACE method name both resolve to nothing via
findVariableTokenInParentChain, and that agenuine top-level global declared in the very same include chain still resolves (guards against the
fix overreaching).
npx tsc -b: clean.npm run test:server(isolated worktree offorigin/master): 2126 passing,3 pending (pre-existing), 0 failing.
Scope
One file changed + one new test:
server/src/services/MemberLocatorService.ts,server/src/test/MemberLocatorService.BareWordClassMemberGuard.test.ts(new). Plain scope-resolutionbug in the shared bare-word lookup, unrelated to any in-flight feature work, so it goes out as its
own PR.