fix(cpp): strip template args from out-of-line method receiver qualifiers (#1309)
template<typename T> T Box<T>::get() stored qualified_name Box<T>::get — the <T> qualifier never matched the class node indexed as Box, so the method didn't link to its class, while the inline form of the same method produced Box::get. ICU-shaped multi-line template parameter lists leaked whole <…> blocks (newlines included) into qualified_name, exceeding NAME_MAX for downstream consumers. extractCppReceiverType now applies stripCppTemplateArgs (the #1043 normalization for base-class refs) to the receiver qualifier. fmt re-index: template-arg-in-qualifier names 25 -> 4 (remaining are a FMT_BEGIN_EXPORT misparse artifact and gmock conversion-operator names, both distinct pre-existing shapes), node count byte-stable at 7,536. Fixes #1286 Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
e1f339f732
commit
4dd29ea5c1
@@ -4074,6 +4074,66 @@ class Both : public Base<char>, public Plain {};
|
||||
});
|
||||
});
|
||||
|
||||
describe('C++ out-of-line template method receivers (#1286)', () => {
|
||||
// `template<typename T> T Box<T>::get()` used to store qualified_name
|
||||
// `Box<T>::get` — the `<T>` qualifier never matched the class node indexed
|
||||
// as `Box`, and long multi-line parameter lists could push qualified_name
|
||||
// past NAME_MAX. Inline definitions of the same method produce `Box::get`,
|
||||
// so the out-of-line form must normalize to the identical name.
|
||||
it('strips the template parameter list from the receiver 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 result = extractFromSource('box.cpp', code);
|
||||
expect(result.errors).toHaveLength(0);
|
||||
const methods = result.nodes.filter((n) => n.kind === 'method');
|
||||
const qns = methods.map((n) => n.qualifiedName).sort();
|
||||
// Out-of-line definitions carry the SAME qualifier as the class node.
|
||||
expect(qns).toContain('Box::get');
|
||||
expect(qns).toContain('Box::set');
|
||||
expect(qns.find((q) => q?.includes('<'))).toBeUndefined();
|
||||
// Names themselves stay clean.
|
||||
expect(methods.map((n) => n.name).sort()).toEqual(expect.arrayContaining(['get', 'set']));
|
||||
});
|
||||
|
||||
it('multi-line template parameter lists cannot leak into qualified_name (NAME_MAX overflow shape)', () => {
|
||||
// The ICU capi_helper.h shape: enormous multi-line parameter names made
|
||||
// qualified_name 272 bytes (> NAME_MAX 255) including embedded newlines.
|
||||
const code = `template <typename CType,
|
||||
typename CPPType,
|
||||
int32_t kMagicValidationSentinelConstantForTheHelperTemplateClassInstanceGuardLong>
|
||||
class ApiHelper {
|
||||
public:
|
||||
CPPType* validate();
|
||||
};
|
||||
|
||||
template <typename CType,
|
||||
typename CPPType,
|
||||
int32_t kMagicValidationSentinelConstantForTheHelperTemplateClassInstanceGuardLong>
|
||||
CPPType* ApiHelper<CType,
|
||||
CPPType,
|
||||
kMagicValidationSentinelConstantForTheHelperTemplateClassInstanceGuardLong>::validate() {
|
||||
return nullptr;
|
||||
}
|
||||
`;
|
||||
const result = extractFromSource('capi_helper.h', code);
|
||||
const validate = result.nodes.find((n) => n.kind === 'method' && n.name === 'validate' && n.qualifiedName?.includes('::'));
|
||||
expect(validate).toBeDefined();
|
||||
expect(validate!.qualifiedName).toBe('ApiHelper::validate');
|
||||
expect(validate!.qualifiedName!.length).toBeLessThan(255);
|
||||
expect(validate!.qualifiedName).not.toMatch(/[<>\n]/);
|
||||
});
|
||||
});
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user