fix(cpp): extract out-of-line member definitions - #577
Merged
Conversation
A definition written outside its declaring scope — `void ns::Cls::run() {}`
in the .cpp for a header's class — declares itself with a
qualified_identifier, a shape no function_definition pattern admitted. The
definition emitted no node at all, and every call in its body went with it:
a deferred call needs an enclosing function range to attach to. In a
translation unit whose class lives in a header, that is the whole file.
Admit a qualified declarator in each function_definition pattern and read
the qualifier structurally. The trailing segment decides the shape: a type
owner yields a method keyed on the owner (member_of the class when this
file declares it, so `A::run` and `B::run` no longer collide), and an
all-namespace qualifier yields a free function carrying the qualifier as
scope_ns. Destructors, operators, pointer and reference returns, and
out-of-line template members reach the same walk.
Folds cppQualifiedCallName and lastIdentifier into that one walk — a
qualified callee and a qualified declarator are the same shape. lastIdentifier
scanned direct children only, so once a name nested it returned the first
segment rather than the last (`ns::Cls::bar` gave `ns`).
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.
Summary
Found while reviewing #576. That PR made
std::chrono::duration_cast(x)andboost::asio::post(ex)emit call edges at any qualification depth — but in a typical translation unit those calls sit in out-of-line member bodies, and those definitions extract as nothing at all.void ns::Cls::run() {}declares itself with aqualified_identifier, which nofunction_definitionpattern inqCppAlladmitted (every one requireddeclarator: (identifier)). No method node was emitted, and every call in the body went with it — a deferred call needs an enclosing function range to attach to. Probed againstmainbefore this change, a.cppwhose class lives in a header extracts only the file node and itsimportsedge:Changes
function_definitionpattern now admits[(identifier) (qualified_identifier)]in the declarator slot.emitOutOfLineMemberreads the qualifier structurally and lets the trailing segment decide the shape:demo.cpp::Cls.run),member_ofthe class when this file declares it. Keying on the owner is what keepsvoid A::run()andvoid B::run()in one file from colliding on a single ID and dropping the second.scope_ns, sincevoid ns::helper() {}is not a member. A class/struct emitted from this file is proof of a type; otherwise the same Capitalized-name heuristicisCapitalizedCppTypealready uses decides.template <typename T> void Holder<T>::put(T)) reach the same walk.cppQualifiedCallName(added by fix(cpp): emit nested qualified call edges #576) andlastIdentifierinto that single walk — a qualified callee and a qualified declarator are the same shape.lastIdentifierscanned direct children only, so once a name nested it returned the first segment rather than the last:ns::Cls::bargavens. One consequence of the shared walk is that a qualified operator call (ns::operator+(a, b)) now emits an edge instead of being dropped; covered by a test.Testing
go test ./internal/parser/languages -run Cpp -count=1— all pass, including 7 new cases (depth 2/3/4 members, same-name members in one file, namespace-qualified free function, local-classmember_of, destructor/operator/template member, qualified operator call, and a regression case pinning free functions and inline methods unchanged).go test -race ./internal/parser/languages -count=1go test ./internal/parser/... ./internal/resolver/... ./internal/indexer/... ./internal/semantic/lsp/... ./internal/search/rerank/... -count=1— the packages carrying C++ fixtures outside the extractor.go build ./...,go vet ./internal/parser/languages,golangci-lint run ./internal/parser/languages/...(0 issues),git diff --check.