chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* repro_extraction.c — Reproduce-first cases for OPEN extraction-quality bugs.
|
||||
*
|
||||
* Each TEST() asserts the CORRECT behaviour and is RED until the bug is fixed.
|
||||
* Keep one TEST() per issue; name it repro_issue<N>_<slug> and lead with a
|
||||
* comment naming the issue, the root cause, and expected-vs-actual.
|
||||
*
|
||||
* Cluster (TIER A, in-process via cbm_extract_file):
|
||||
* #554 — C++ out-of-line method CALLS source = Module, not enclosing Method
|
||||
* (more added per wave: #495 #521 #382 #408 #523 #56 #333)
|
||||
*/
|
||||
#include "test_framework.h"
|
||||
#include "cbm.h"
|
||||
|
||||
/* Convenience: extract, return result (caller frees). Mirrors test_extraction.c. */
|
||||
static CBMFileResult *rx(const char *src, CBMLanguage lang, const char *proj, const char *path) {
|
||||
return cbm_extract_file(src, (int)strlen(src), lang, proj, path, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Find the first definition matching label+name (either may be NULL = wildcard). */
|
||||
static CBMDefinition *find_def(CBMFileResult *r, const char *label, const char *name) {
|
||||
for (int i = 0; i < r->defs.count; i++) {
|
||||
CBMDefinition *d = &r->defs.items[i];
|
||||
if (label && (!d->label || strcmp(d->label, label) != 0))
|
||||
continue;
|
||||
if (name && (!d->name || strcmp(d->name, name) != 0))
|
||||
continue;
|
||||
return d;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ───────────────────────────────────────────────────────────────────
|
||||
* #554 — C++ out-of-line method definitions: the CALLS edge source falls
|
||||
* back to the Module (file-level) instead of the enclosing Method.
|
||||
*
|
||||
* Root cause (#621 follow-up to #463/adc8304): for `void Foo::bar() { helper(); }`
|
||||
* the inner call's `enclosing_func_qn` drops the CLASS qualifier — it resolves to
|
||||
* the bare method name (e.g. "t.m.bar") instead of the method node's full
|
||||
* class-qualified QN (e.g. "t.m.Foo.bar"). The pre-existing guard in
|
||||
* test_extraction.c only checks `enclosing_func_qn != "t.m"` (module), which a
|
||||
* buggy "t.m.bar" PASSES — so it never caught the class-qualifier drop.
|
||||
*
|
||||
* Strong reproduction: tie the call's enclosing_func_qn to the METHOD DEFINITION's
|
||||
* own qualified_name (format-agnostic) AND require the class qualifier be present.
|
||||
* Expected: enclosing_func_qn == def(bar).qualified_name, and that QN names "Foo".
|
||||
* Actual (buggy): enclosing_func_qn loses "Foo" → mismatch → RED.
|
||||
* ─────────────────────────────────────────────────────────────────── */
|
||||
TEST(repro_issue554_cpp_out_of_line_method_class_qualified) {
|
||||
CBMFileResult *r = rx("struct Foo { void bar(); };\n"
|
||||
"int helper(int x) { return x; }\n"
|
||||
"void Foo::bar() { helper(1); }\n",
|
||||
CBM_LANG_CPP, "t", "m.cpp");
|
||||
ASSERT_NOT_NULL(r);
|
||||
ASSERT_FALSE(r->has_error);
|
||||
|
||||
/* The out-of-line method definition: its qualified_name is the ground truth
|
||||
* the inner CALLS edge must point at. */
|
||||
CBMDefinition *method = find_def(r, "Method", "bar");
|
||||
if (!method)
|
||||
method = find_def(r, NULL, "bar"); /* tolerate label variance */
|
||||
ASSERT_NOT_NULL(method);
|
||||
ASSERT_NOT_NULL(method->qualified_name);
|
||||
|
||||
/* The method node must carry the class qualifier — either embedded in the QN
|
||||
* or via parent_class. This is the heart of #554/#621. */
|
||||
int qn_has_class = strstr(method->qualified_name, "Foo") != NULL;
|
||||
int parent_has_class = method->parent_class && strstr(method->parent_class, "Foo") != NULL;
|
||||
ASSERT_TRUE(qn_has_class || parent_has_class);
|
||||
|
||||
/* The helper() call inside Foo::bar must attribute to the method node, i.e.
|
||||
* its enclosing_func_qn must EQUAL the method's qualified_name (class included),
|
||||
* not the bare method name and not the module. */
|
||||
int saw_helper = 0;
|
||||
for (int i = 0; i < r->calls.count; i++) {
|
||||
if (strcmp(r->calls.items[i].callee_name, "helper") == 0) {
|
||||
saw_helper = 1;
|
||||
const char *enc = r->calls.items[i].enclosing_func_qn;
|
||||
ASSERT_NOT_NULL(enc);
|
||||
ASSERT_STR_EQ(enc, method->qualified_name);
|
||||
ASSERT_TRUE(strstr(enc, "Foo") != NULL); /* class qualifier preserved */
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(saw_helper);
|
||||
|
||||
cbm_free_result(r);
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* ── Suite ──────────────────────────────────────────────────────── */
|
||||
SUITE(repro_extraction) {
|
||||
RUN_TEST(repro_issue554_cpp_out_of_line_method_class_qualified);
|
||||
}
|
||||
Reference in New Issue
Block a user