Skip to content
Open
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
29 changes: 29 additions & 0 deletions __tests__/extraction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4074,6 +4074,35 @@ class Both : public Base<char>, public Plain {};
});
});

describe('C++ out-of-line template method qualifier (#1286)', () => {
// An out-of-line template method definition
// (`template<typename T> T Box<T>::get()`) recorded its class qualifier as the
// full instantiation `Box<T>`, so the method's qualifiedName was `Box<T>::get`.
// That never name-matched the class node indexed as `Box`, and long/multi-line
// template params could push the qualifiedName past the 255-byte filename
// limit. The `<…>` args are stripped so the qualifier is the bare `Box`,
// exactly like #1043 did for templated base classes. Inline method bodies were
// already unaffected.
it('strips template args from an out-of-line template method qualifier', () => {
const code = `
template <typename T>
class Box { public: T get() const; void set(T v); private: T value; };

template <typename T> T Box<T>::get() const { return value; }
template <typename T> void Box<T>::set(T v) { value = v; }
`;
const nodes = extractFromSource('box.cpp', code).nodes;
const get = nodes.find((n) => n.name === 'get');
const set = nodes.find((n) => n.name === 'set');

// Qualifier is the bare class, not the `Box<T>` instantiation.
expect(get?.qualifiedName).toBe('Box::get');
expect(set?.qualifiedName).toBe('Box::set');
// No node still carries angle brackets in its qualified name.
expect(nodes.find((n) => n.qualifiedName?.includes('<'))).toBeUndefined();
});
});

describe('C++ stack-allocation construction (#1035)', () => {
// `Calculator calc(0)` (direct-init) and `Widget w{1, 2}` (brace-init) carry
// the constructor args directly on the declarator — no call/new node — so
Expand Down
9 changes: 8 additions & 1 deletion src/extraction/languages/c-cpp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,14 @@ function extractCppReceiverType(node: SyntaxNode, source: string): string | unde
if (!declarator) return undefined;
const qid = findDeclaratorQualifiedId(declarator);
if (!qid) return undefined;
const parts = getNodeText(qid, source).trim().split('::').filter(Boolean);
// Strip template arguments before splitting on `::` so an out-of-line template
// method definition (`template<typename T> T Box<T>::get()`) yields the bare
// class `Box`, not `Box<T>` — matching the class node indexed as `Box`, the
// same reason #1043 stripped them from templated base-class references. Doing it
// before the split also tolerates `::` inside the args (`Box<std::string>::get`).
const parts = stripCppTemplateArgs(getNodeText(qid, source).trim())
.split('::')
.filter(Boolean);
return parts.length > 1 ? parts.slice(0, -1).join('::') : undefined;
}

Expand Down