fix(extract): resolve explicit C++ operator-overload calls (#1247 case 1)#1260
Open
aznikline wants to merge 1 commit into
Open
fix(extract): resolve explicit C++ operator-overload calls (#1247 case 1)#1260aznikline wants to merge 1 commit into
aznikline wants to merge 1 commit into
Conversation
…nry#1247 case 1) Closes the explicit-form half of colbymchenry#1247. tree-sitter-cpp can't parse the `.operator<sym>` member access in `a.operator+(b)` / `a.operator[](i)` / `a.operator==(b)` and lands it in an ERROR node wrapping an `operator_name`, with the receiver as the call_expression's first named child and no `function` field — so the extractor took the receiver as the callee (`calls:"a"`) and the `operator+` method node never gained a caller. Two-part recovery, both C/C++-only: - extractor: read the `operator_name` out of the ERROR subtree and qualify it with a simple-identifier receiver (`a.operator+`) so receiver-type inference routes it to the right overload; bare `operator+` fallback for non-identifier receivers resolves via exact-name match when unique. - resolver: widen the `recv.method` / `Class::method` method-segment gate to also accept `operator` + an overload-symbol tail; `+`/`[`/`(` aren't in \w so the old pattern dropped these refs before inference could run. Infix `a + b` and subscript `a[i]` parse as binary_expression / subscript_expression (not call_expression) and need receiver type inference from an expression — tracked separately in colbymchenry#1258. Test: `resolves an explicit a.operator+(b) call to the operator+ method`. Full suite green (2363 tests).
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.
What
Closes the explicit-form half of #1247: a call to an operator-overload method written in its explicit
a.operator+(b)form never recorded a call edge, so theoperator+method node had zero callers and its impact radius was invisible.This is case (1) from the scoping discussion in the issue. The harder cases — infix
a + band subscripta[i]— parse asbinary_expression/subscript_expression(notcall_expression) and need receiver type inference from an expression, which @Dshuishui split off into #1258. This PR does not touch those.Root cause
tree-sitter-cppcan't parse the.operator<sym>member access. For every explicit form —a.operator+(b),a.operator[](i),a.operator==(b)— the AST comes out as:The
call_expressionhas nofunctionfield and an ERROR node wrappingoperator_name. So the extractor's generic path tooknamedChild(0)(the receivera) as the callee and emitted a uselesscalls:"a"ref — theoperator+method node was never linked.The
operator+method node itself is indexed correctly on the definition side (namedoperator+), so this is purely a call-site extraction + resolution gap.Fix (C/C++ only, both parts gated)
Extractor (
tree-sitter.ts): before the genericnamedChild(0)fallback, detect acall_expressionwhose subtree contains anoperator_name(nested under the ERROR node), read it as the callee, and qualify it with a simple-identifier receiver →a.operator+. For a non-identifier receiver (call result, deref, …) with no static name to route through inference, emit the bareoperator+somatchByExactNamestill links it when the overload name is unique in scope.Resolver (
name-matcher.ts): therecv.method/Class::methodmethod-segment gate was\w+, which excludes+/[/(— so even after the extractor emitsa.operator+, the pattern dropped it before receiver-type inference could run. Widen the method segment to also acceptoperator+ an overload-symbol tail, C/C++ only. The symbol set is the C++ overloadable operators; an unbounded[^.]+would over-match, so it's enumerated.The receiver-type inference chain (
inferCppReceiverType→resolveMethodOnType, which validates the method exists on the inferred type) was already in place — only the extraction gap and the pattern gate stopped it.Scope
a.operator+(b),a.operator[](i),a.operator==(b), and the rest of the overloadable-operator set, in both.method()andClass::methodshapes.a + b, subscripta[i]— those need expression-level receiver type inference (C++: operator overloads via infix (a + b) / subscript (a[i]) get no call edge (needs receiver type inference) #1258).operator_nameactually exists in the subtree, and only ever emitsoperator-prefixed names (no ordinary call site produces those); the resolver widening is language-gated to C/C++.Test
Added to
__tests__/resolution.test.ts:resolves an explicit a.operator+(b) call to the operator+ method (#1247 case 1)— end-to-end: indexes aVecwithoperator+plus anadd(Vec, Vec)that callsa.operator+(b), and assertsaddis a caller of theoperator+method.Before the fix this emitted
calls:"a"and resolved to nothing; after, it links tooperator+.Full suite green: 2363 passed, 4 skipped, 0 failed (build +
vitest run).