mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
1488 lines
81 KiB
C
1488 lines
81 KiB
C
/*
|
|
* test_matrix_known_classes.c — Matrix-fill probe: apply every identified
|
|
* bug-class across ALL applicable languages and fill the coverage gap left
|
|
* by the existing suites (test_lang_contract.c, test_edge_structural.c,
|
|
* test_lsp_resolution_probe.c).
|
|
*
|
|
* LEGEND
|
|
* green=guard — asserts the CORRECT outcome; PASSES when the feature works.
|
|
* red=bug — legacy aggregate assertion in unmodified cases.
|
|
* RQ cases — exact source obligations: required calls, named missing-edge
|
|
* quality gaps, and forbidden unsupported target bindings.
|
|
*
|
|
* BUG CLASSES PROBED
|
|
* C1 — CONSTRUCTOR / instantiation (new T() / T{} / T() / T::new())
|
|
* C2 — OPERATOR OVERLOADING (a+b / a[i] / a==b → CALLS/USAGE to op fn)
|
|
* C3 — DECORATES via decorators/annotations/attributes/macros
|
|
* C4 — ASYNC/AWAIT calls (call through async context → CALLS)
|
|
* C5 — GENERIC/TEMPLATED call (call a method through generic type param)
|
|
* C6 — STATIC / CLASS-METHOD call (grammar-only langs: Scala/Swift/Ruby)
|
|
* C7 — INHERITED-METHOD call (grammar-only langs: Scala/Swift/Ruby)
|
|
*
|
|
* SUITE: matrix_known_classes
|
|
* Registered in the canonical test runner; named quality gaps are gating data.
|
|
*/
|
|
|
|
#include "../src/foundation/compat.h"
|
|
#include "test_framework.h"
|
|
#include "test_helpers.h"
|
|
#include "resolver_quality.h"
|
|
#include "cbm.h"
|
|
#include <mcp/mcp.h>
|
|
#include <store/store.h>
|
|
#include <pipeline/pipeline.h>
|
|
#include <foundation/log.h>
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#if !defined(_WIN32)
|
|
#include <sys/wait.h>
|
|
#endif
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════
|
|
* Harness (MKC_ prefix — avoids link collisions with other suites).
|
|
* Mirrors the pattern from test_edge_structural.c and test_lsp_resolution_probe.c.
|
|
* ══════════════════════════════════════════════════════════════════════ */
|
|
|
|
typedef struct {
|
|
char tmpdir[256];
|
|
char dbpath[512];
|
|
char *project;
|
|
cbm_mcp_server_t *srv;
|
|
} MKC_Proj;
|
|
|
|
typedef struct {
|
|
const char *name;
|
|
const char *content;
|
|
} MKC_File;
|
|
|
|
static void mkc_to_fwd_slashes(char *p) {
|
|
for (; *p; p++) {
|
|
if (*p == '\\')
|
|
*p = '/';
|
|
}
|
|
}
|
|
|
|
static cbm_store_t *mkc_open_indexed(MKC_Proj *lp) {
|
|
lp->project = cbm_project_name_from_path(lp->tmpdir);
|
|
if (!lp->project)
|
|
return NULL;
|
|
const char *home = getenv("HOME");
|
|
if (!home)
|
|
home = "/tmp";
|
|
char cache_dir[512];
|
|
snprintf(cache_dir, sizeof(cache_dir), "%s/.cache/codebase-memory-mcp", home);
|
|
cbm_mkdir(cache_dir);
|
|
snprintf(lp->dbpath, sizeof(lp->dbpath), "%s/%s.db", cache_dir, lp->project);
|
|
unlink(lp->dbpath);
|
|
lp->srv = cbm_mcp_server_new(NULL);
|
|
if (!lp->srv)
|
|
return NULL;
|
|
char args[700];
|
|
snprintf(args, sizeof(args), "{\"repo_path\":\"%s\"}", lp->tmpdir);
|
|
char *resp = cbm_mcp_handle_tool(lp->srv, "index_repository", args);
|
|
if (resp)
|
|
free(resp);
|
|
return cbm_store_open_path(lp->dbpath);
|
|
}
|
|
|
|
static cbm_store_t *mkc_index(MKC_Proj *lp, const MKC_File *files, int nfiles) {
|
|
memset(lp, 0, sizeof(*lp));
|
|
snprintf(lp->tmpdir, sizeof(lp->tmpdir), "/tmp/cbm_mkc_XXXXXX");
|
|
if (!cbm_mkdtemp(lp->tmpdir))
|
|
return NULL;
|
|
mkc_to_fwd_slashes(lp->tmpdir);
|
|
for (int i = 0; i < nfiles; i++) {
|
|
char path[700];
|
|
snprintf(path, sizeof(path), "%s/%s", lp->tmpdir, files[i].name);
|
|
char *slash = strrchr(path, '/');
|
|
if (slash && slash > path + strlen(lp->tmpdir)) {
|
|
*slash = '\0';
|
|
cbm_mkdir_p(path, 0755);
|
|
*slash = '/';
|
|
}
|
|
FILE *f = cbm_fopen(path, "wb");
|
|
if (!f)
|
|
return NULL;
|
|
fputs(files[i].content, f);
|
|
fclose(f);
|
|
}
|
|
return mkc_open_indexed(lp);
|
|
}
|
|
|
|
static void mkc_cleanup(MKC_Proj *lp, cbm_store_t *store) {
|
|
if (store)
|
|
cbm_store_close(store);
|
|
if (lp->srv) {
|
|
cbm_mcp_server_free(lp->srv);
|
|
lp->srv = NULL;
|
|
}
|
|
free(lp->project);
|
|
lp->project = NULL;
|
|
th_rmtree(lp->tmpdir);
|
|
unlink(lp->dbpath);
|
|
char wal[600], shm[600];
|
|
snprintf(wal, sizeof(wal), "%s-wal", lp->dbpath);
|
|
snprintf(shm, sizeof(shm), "%s-shm", lp->dbpath);
|
|
unlink(wal);
|
|
unlink(shm);
|
|
}
|
|
|
|
/* Each obligation below is authored from its fixture, independently of emitted
|
|
* rows. Missing edges remain quality debt; invented targets fail the oracle.
|
|
* A class stands for a constructor that has no node of its own: a primary constructor
|
|
* in the class header, a synthesized apply, or a Swift init. The evidence marks it as a
|
|
* class call. Unknown receiver sites are forbidden. */
|
|
typedef struct {
|
|
const char *test, *caller, *needle, *target, *declaration, *label;
|
|
int line;
|
|
unsigned occurrence;
|
|
bool required;
|
|
} MKC_Golden;
|
|
static const MKC_Golden mkc_goldens[] = {
|
|
{"mkc_c1_scala_constructor_new", "make", "new Widget(n)", "Widget",
|
|
"class Widget(val name: String) {", "Class", 1, 0, true},
|
|
{"mkc_c1_scala_case_class_apply", "origin", "Point(0.0, 0.0)", "Point",
|
|
"case class Point(x: Double, y: Double) {", "Class", 1, 0, true},
|
|
{"mkc_c1_scala_case_class_apply", "origin", "Point(0.0, 0.0).dist()", "dist",
|
|
" def dist(): Double = math.sqrt(x*x + y*y)", "Method", 2, 0, true},
|
|
{"mkc_c1_swift_initializer", "make", "Widget(name: n)", "Widget", "class Widget {", "Class", 1, 0,
|
|
true},
|
|
{"mkc_c1_ruby_type_new", "make", "Widget.new(name)", "initialize", " def initialize(name)",
|
|
"Method", 2, 0, true},
|
|
{"mkc_c1_rust_new_samefile", "run", "Point::new(3.0, 4.0)", "new",
|
|
" pub fn new(x: f64, y: f64) -> Self { Point { x, y } }", "Method", 4, 0, true},
|
|
{"mkc_c1_rust_new_samefile", "run", "p.dist()", "dist",
|
|
" pub fn dist(&self) -> f64 { (self.x * self.x + self.y * self.y).sqrt() }", "Method", 5, 0,
|
|
true},
|
|
{"mkc_c2_cpp_operator_plus", "run", "a + b", "operator+",
|
|
" Vec2 operator+(const Vec2 &o) const { return Vec2(x+o.x, y+o.y); }", "Method", 4, 0,
|
|
false},
|
|
{"mkc_c2_cpp_operator_plus", "run", "c.dot(b)", "dot",
|
|
" float dot(const Vec2 &o) const { return x*o.x + y*o.y; }", "Method", 5, 0, true},
|
|
{"mkc_c2_cpp_operator_plus", "operator+", "Vec2(x+o.x, y+o.y)", "Vec2",
|
|
" Vec2(float x, float y): x(x), y(y){}", "Method", 3, 0, false},
|
|
{"mkc_c2_cpp_operator_subscript", "run", "a[2]", "operator[]",
|
|
" int& operator[](int i) { return data[i]; }", "Method", 3, 0, false},
|
|
{"mkc_c2_python_dunder_add", "__add__", "Vec(self.x + other.x, self.y + other.y)", "__init__",
|
|
" def __init__(self, x, y):", "Method", 2, 0, false},
|
|
{"mkc_c2_python_dunder_add", "__add__", "Vec(self.x + other.x, self.y + other.y)", "Vec",
|
|
"class Vec:", "Class", 1, 0, true},
|
|
{"mkc_c2_python_dunder_getitem", "run", "s[0]", "__getitem__",
|
|
" def __getitem__(self, i):", "Method", 5, 0, false},
|
|
{"mkc_c2_rust_add_trait", "run", "a + b", "add", " fn add(self, rhs: Self) -> Self {",
|
|
"Method", 8, 0, false},
|
|
{"mkc_c2_kotlin_operator_plus", "run", "a + b", "plus",
|
|
" operator fun plus(other: Vec2): Vec2 =", "Method", 2, 0, true},
|
|
{"mkc_c2_csharp_operator_plus", "Run", "a + b", "operator+",
|
|
" public static Vec2 operator+(Vec2 a, Vec2 b) {", "Method", 5, 0, false},
|
|
{"mkc_c2_csharp_operator_plus", "Run", "(a + b).Dot(b)", "Dot",
|
|
" public float Dot(Vec2 o) { return X*o.X + Y*o.Y; }", "Method", 8, 0, false},
|
|
{"mkc_c2_csharp_operator_plus", "operator+", "new Vec2(a.X + b.X, a.Y + b.Y)", "Vec2",
|
|
" public Vec2(float x, float y) { X = x; Y = y; }", "Method", 4, 0, true},
|
|
{"mkc_c2_scala_symbolic_method", "run", "a + b", "+",
|
|
" def +(other: Vec2): Vec2 = Vec2(x + other.x, y + other.y)", "Method", 2, 0, true},
|
|
{"mkc_c2_scala_symbolic_method", "run", "(a + b).dot(b)", "dot",
|
|
" def dot(other: Vec2): Double = x * other.x + y * other.y", "Method", 3, 0, true},
|
|
{"mkc_c2_ruby_operator_plus", "+", "Vec2.new(@x + other.x, @y + other.y)", "initialize",
|
|
" def initialize(x, y)", "Method", 3, 0, true},
|
|
{"mkc_c4_typescript_async_await", "getData", "fetch(url)", "fetch",
|
|
"async function fetch(url: string): Promise<string> {", "Function", 1, 0, true},
|
|
{"mkc_c4_typescript_async_await", "run", "getData(url)", "getData",
|
|
"async function getData(url: string): Promise<string> {", "Function", 5, 0, true},
|
|
{"mkc_c4_csharp_async_await", "GetDataAsync", "FetchAsync(url)", "FetchAsync",
|
|
" public async Task<string> FetchAsync(string url) {", "Method", 5, 0, true},
|
|
{"mkc_c4_csharp_async_await", "RunAsync", "GetDataAsync(\"http://example.com\")",
|
|
"GetDataAsync", " public async Task<string> GetDataAsync(string url) {", "Method", 9, 0,
|
|
true},
|
|
{"mkc_c4_rust_await", "get_data", "fetch(url)", "fetch",
|
|
"async fn fetch(url: &str) -> String {", "Function", 1, 0, true},
|
|
{"mkc_c4_rust_await", "run", "get_data(url)", "get_data",
|
|
"async fn get_data(url: &str) -> String {", "Function", 5, 0, true},
|
|
{"mkc_c4_kotlin_suspend_call", "getData", "fetchData(url)", "fetchData",
|
|
"suspend fun fetchData(url: String): String {", "Function", 1, 0, true},
|
|
{"mkc_c4_kotlin_suspend_call", "run", "getData(url)", "getData",
|
|
"suspend fun getData(url: String): String {", "Function", 5, 0, true},
|
|
{"mkc_c4_swift_async_await", "getData", "fetch(url: url)", "fetch",
|
|
"func fetch(url: String) async -> String {", "Function", 1, 0, true},
|
|
{"mkc_c4_swift_async_await", "run", "getData(url: url)", "getData",
|
|
"func getData(url: String) async -> String {", "Function", 5, 0, true},
|
|
{"mkc_c5_scala_generic_call", "run", "first(ns)", "first",
|
|
"def first[T](xs: List[T]): Option[T] =", "Function", 1, 0, true},
|
|
{"mkc_c5_swift_generic_call", "run", "maxOf(a, b)", "maxOf",
|
|
"func maxOf<T: Comparable>(_ a: T, _ b: T) -> T {", "Function", 1, 0, true},
|
|
{"mkc_c5_ruby_duck_typed_call", "run", "first(items)", "first", "def first(collection)",
|
|
"Function", 1, 0, true},
|
|
{"mkc_c6_scala_companion_object", "run", "Config.default()", "default",
|
|
" def default(): Config = new Config(false)", "Method", 4, 0, true},
|
|
{"mkc_c6_swift_static_method", "run", "MathHelper.clamp(n, 0, 100)", "clamp",
|
|
" static func clamp(_ v: Int, _ lo: Int, _ hi: Int) -> Int {", "Method", 2, 0, true},
|
|
{"mkc_c6_ruby_class_method", "run", "Config.version", "version", " def self.version", "Method",
|
|
2, 0, true},
|
|
{"mkc_c6_scala_singleton_object", "run", "Logger.log(msg)", "log",
|
|
" def log(msg: String): Unit = println(msg)", "Method", 2, 0, true},
|
|
{"mkc_c7_scala_inherited_method", "run", "d.describe()", "describe",
|
|
" def describe(): String = \"animal\"", "Method", 2, 0, true},
|
|
{"mkc_c7_swift_inherited_method", "run", "d.describe()", "describe",
|
|
" func describe() -> String { return \"animal\" }", "Method", 2, 0, true},
|
|
{"mkc_c7_ruby_inherited_method", "run", "describe()", "describe", " def describe", "Method", 2,
|
|
0, true},
|
|
{"mkc_c7_scala_super_call", "describe", "super.describe()", "Base.describe",
|
|
" def describe(): String = \"base\"", "Method", 2, 0, true},
|
|
{"mkc_c7_scala_super_call", "run", "c.describe()", "Child.describe",
|
|
" override def describe(): String = \"child: \" + super.describe()", "Method", 6, 0, true},
|
|
{"mkc_c8_java_constructor_samefile", "make", "new Widget(name)", "Widget",
|
|
" public Widget(String name) { this.name = name; }", "Method", 5, 0, true},
|
|
{"mkc_c8_java_constructor_samefile", "run", "make(name)", "make",
|
|
" public Widget make(String name) { return new Widget(name); }", "Method", 10, 0, true},
|
|
{"mkc_c8_java_constructor_samefile", "run", "make(name).label()", "label",
|
|
" public String label() { return name; }", "Method", 6, 0, true},
|
|
{"mkc_c8_csharp_constructor_samefile", "Make", "new Widget(name)", "Widget",
|
|
" public Widget(string name) { Name = name; }", "Method", 4, 0, true},
|
|
{"mkc_c8_csharp_constructor_samefile", "Run", "Make(name)", "Make",
|
|
" public Widget Make(string name) { return new Widget(name); }", "Method", 9, 0, true},
|
|
{"mkc_c8_csharp_constructor_samefile", "Run", "Make(name).Label()", "Label",
|
|
" public string Label() { return Name; }", "Method", 5, 0, true},
|
|
{"mkc_c8_php_constructor_samefile", "make", "new Widget($name)", "__construct",
|
|
" public function __construct($name) { $this->name = $name; }", "Method", 4, 0, true},
|
|
{"mkc_c8_php_constructor_samefile", "run", "$this->make($name)", "make",
|
|
" public function make($name) { return new Widget($name); }", "Method", 9, 0, true},
|
|
{"mkc_c8_php_constructor_samefile", "run", "$this->make($name)->label()", "label",
|
|
" public function label() { return $this->name; }", "Method", 5, 0, false},
|
|
{"mkc_c8_typescript_constructor_samefile", "make", "new Widget(name)", "constructor",
|
|
" constructor(public name: string) {}", "Method", 2, 0, true},
|
|
{"mkc_c8_typescript_constructor_samefile", "run", "this.make(name)", "make",
|
|
" make(name: string): Widget { return new Widget(name); }", "Method", 7, 0, true},
|
|
{"mkc_c8_typescript_constructor_samefile", "run", "this.make(name).label()", "label",
|
|
" label(): string { return this.name; }", "Method", 3, 0, true},
|
|
{"mkc_c8_kotlin_constructor_samefile", "make", "Widget(name)", "Widget",
|
|
"class Widget(val name: String) {", "Class", 1, 0, true},
|
|
{"mkc_c8_kotlin_constructor_samefile", "run", "make(name)", "make",
|
|
"fun make(name: String): Widget = Widget(name)", "Function", 5, 0, true},
|
|
{"mkc_c8_kotlin_constructor_samefile", "run", "make(name).label()", "label",
|
|
" fun label(): String = name", "Method", 2, 0, true},
|
|
};
|
|
/* The harness audits a known target under every role. A class named in a signature is
|
|
* referenced there, in these languages as USAGE and as USES_TYPE, apart from the call. */
|
|
typedef struct {
|
|
const char *test, *caller, *needle, *relation, *target, *declaration;
|
|
int line;
|
|
unsigned occurrence;
|
|
} MKC_TypeMention;
|
|
static const MKC_TypeMention mkc_type_mentions[] = {
|
|
{"mkc_c1_scala_constructor_new", "make", "Widget", "USAGE", "Widget",
|
|
"class Widget(val name: String) {", 1, 1},
|
|
{"mkc_c1_scala_constructor_new", "make", "Widget", "USES_TYPE", "Widget",
|
|
"class Widget(val name: String) {", 1, 1},
|
|
{"mkc_c1_swift_initializer", "make", "Widget", "USAGE", "Widget", "class Widget {", 1, 1},
|
|
{"mkc_c1_swift_initializer", "make", "Widget", "USES_TYPE", "Widget", "class Widget {", 1, 1},
|
|
{"mkc_c8_kotlin_constructor_samefile", "make", "Widget", "USAGE", "Widget",
|
|
"class Widget(val name: String) {", 1, 1},
|
|
{"mkc_c8_kotlin_constructor_samefile", "make", "Widget", "USES_TYPE", "Widget",
|
|
"class Widget(val name: String) {", 1, 1},
|
|
};
|
|
typedef struct {
|
|
const char *test, *caller, *needle;
|
|
unsigned occurrence;
|
|
} MKC_Forbidden;
|
|
static const MKC_Forbidden mkc_forbidden[] = {
|
|
{"mkc_c2_python_dunder_add", "run", "a + b", 0},
|
|
{"mkc_c2_ruby_operator_plus", "run", "a + b", 0},
|
|
{"mkc_c2_ruby_operator_plus", "run", "(a + b).dot(b)", 0},
|
|
};
|
|
|
|
static bool mkc_quality(const MKC_File *original, int count, const char *test) {
|
|
if (!strncmp(test, "test_", 5))
|
|
test += 5;
|
|
if (count != 1)
|
|
return false;
|
|
/* The same production harness must retain a nonzero exact-call control. */
|
|
const MKC_File files[] = {original[0],
|
|
{"quality_control.py",
|
|
"def exact_target():\n return 1\n"
|
|
"def exact_caller():\n return exact_target()\n"}};
|
|
const RQ_Source sources[] = {{.path = files[0].name, .text = files[0].content},
|
|
{.path = files[1].name, .text = files[1].content}};
|
|
RQ_Expected expected[8] = {{.case_id = "required-local-control",
|
|
.site = {.file = "quality_control.py",
|
|
.caller = "exact_caller",
|
|
.needle = "exact_target()",
|
|
.occurrence_index = 1},
|
|
.relation = "CALLS",
|
|
.target = {.file = "quality_control.py",
|
|
.suffix = "quality_control.exact_target",
|
|
.label = "Function",
|
|
.declaration_line = 1,
|
|
.declaration_text = "def exact_target():"},
|
|
.mode = RQ_REQUIRED}};
|
|
RQ_Forbidden invalid[3] = {0};
|
|
char ids[8][100];
|
|
size_t n = 1, nf = 0, required = 1;
|
|
for (size_t i = 0; i < sizeof(mkc_goldens) / sizeof(mkc_goldens[0]); i++) {
|
|
const MKC_Golden *g = mkc_goldens + i;
|
|
if (strcmp(test, g->test))
|
|
continue;
|
|
if (n == sizeof(expected) / sizeof(expected[0]))
|
|
return false;
|
|
snprintf(ids[n], sizeof(ids[n]), "%s-%zu", test, n);
|
|
expected[n] = (RQ_Expected){
|
|
.case_id = ids[n],
|
|
.site = {.file = original[0].name,
|
|
.caller = g->caller,
|
|
.needle = g->needle,
|
|
.occurrence_index = g->occurrence},
|
|
.relation = "CALLS",
|
|
.target = {.file = original[0].name,
|
|
.suffix = g->target,
|
|
.label = g->label,
|
|
.declaration_line = g->line,
|
|
.declaration_text = g->declaration},
|
|
.mode = g->required ? RQ_REQUIRED : RQ_KNOWN_GAP,
|
|
.gap_id = g->target ? "source-call-binding-proof-missing"
|
|
: "callable-identity-not-materialized",
|
|
.why = g->target
|
|
? "This source-authored call requires a complete language binding and "
|
|
"receiver/overload proof to its exact callable declaration."
|
|
: "The genuine call has no faithful callable graph identity.",
|
|
.tried = "The original v69 production harness failed its aggregate call floor. "
|
|
"Preserved fixture bytes and replaced that floor with exact source "
|
|
"occurrences/declarations. Direct make calls remain required source "
|
|
"obligations; an old aggregate count does not establish exact admission."};
|
|
/* The expression names the class and invokes its initialization
|
|
* protocol. Keep the unresolved __init__ dispatch as a separate
|
|
* obligation alongside the proved class binding. */
|
|
if (!strcmp(test, "mkc_c2_python_dunder_add"))
|
|
expected[n].dispatch_group = "python-class-initialization";
|
|
required += g->required;
|
|
n++;
|
|
}
|
|
for (size_t i = 0; i < sizeof(mkc_type_mentions) / sizeof(mkc_type_mentions[0]); i++) {
|
|
const MKC_TypeMention *g = mkc_type_mentions + i;
|
|
if (strcmp(test, g->test))
|
|
continue;
|
|
if (n == sizeof(expected) / sizeof(expected[0]))
|
|
return false;
|
|
snprintf(ids[n], sizeof(ids[n]), "%s-%zu", test, n);
|
|
expected[n] = (RQ_Expected){.case_id = ids[n],
|
|
.site = {.file = original[0].name,
|
|
.caller = g->caller,
|
|
.needle = g->needle,
|
|
.occurrence_index = g->occurrence},
|
|
.relation = g->relation,
|
|
.target = {.file = original[0].name,
|
|
.suffix = g->target,
|
|
.label = "Class",
|
|
.declaration_line = g->line,
|
|
.declaration_text = g->declaration},
|
|
.mode = RQ_REQUIRED};
|
|
required++;
|
|
n++;
|
|
}
|
|
for (size_t i = 0; i < sizeof(mkc_forbidden) / sizeof(mkc_forbidden[0]); i++) {
|
|
const MKC_Forbidden *g = mkc_forbidden + i;
|
|
if (strcmp(test, g->test))
|
|
continue;
|
|
if (nf == sizeof(invalid) / sizeof(invalid[0]))
|
|
return false;
|
|
invalid[nf++] = (RQ_Forbidden){.case_id = g->needle,
|
|
.site = {.file = original[0].name,
|
|
.caller = g->caller,
|
|
.needle = g->needle,
|
|
.occurrence_index = g->occurrence},
|
|
.relation = "CALLS",
|
|
.any_target = true};
|
|
}
|
|
if (n == 1 && nf == 0)
|
|
return false;
|
|
MKC_Proj project;
|
|
cbm_store_t *store = mkc_index(&project, files, 2);
|
|
RQ_Report report = {0};
|
|
bool ok = store && rq_check_project_declarations(store, project.project, test, sources, 2,
|
|
expected, n, invalid, nf, &report, stderr);
|
|
mkc_cleanup(&project, store);
|
|
return ok && report.genuine == n && report.found == required && report.missing == n - required;
|
|
}
|
|
|
|
static const char *MKC_ALL_EDGE_TYPES[] = {"CALLS", "DEFINES", "DEFINES_METHOD", "IMPORTS",
|
|
"INHERITS", "IMPLEMENTS", "USAGE", "DECORATES",
|
|
"HANDLES", "HTTP_CALLS", "ASYNC_CALLS", "OVERRIDE",
|
|
"TESTS", "TESTS_FILE", "DATA_FLOWS", NULL};
|
|
|
|
static void mkc_diag(cbm_store_t *store, const char *project, const char *label) {
|
|
if (!store) {
|
|
fprintf(stderr, " [MKC] %s: no graph DB\n", label);
|
|
return;
|
|
}
|
|
char line[512] = {0};
|
|
for (int i = 0; MKC_ALL_EDGE_TYPES[i]; i++) {
|
|
int c = cbm_store_count_edges_by_type(store, project, MKC_ALL_EDGE_TYPES[i]);
|
|
if (c > 0 && strlen(line) < sizeof(line) - 40) {
|
|
char one[48];
|
|
snprintf(one, sizeof(one), "%s=%d ", MKC_ALL_EDGE_TYPES[i], c);
|
|
strncat(line, one, sizeof(line) - strlen(line) - 1);
|
|
}
|
|
}
|
|
fprintf(stderr, " [MKC] %s edges=[%s]\n", label, line[0] ? line : "(none)");
|
|
}
|
|
|
|
/* Index files, assert edge_type appears >= floor times.
|
|
* is_green=1: this is a green guard (regression if it fails).
|
|
* is_green=0: this is a red reproduction (correct outcome asserted; fails until fixed). */
|
|
static int mkc_edge(const MKC_File *files, int nfiles, const char *edge_type, int floor,
|
|
const char *label, int is_green) {
|
|
MKC_Proj lp;
|
|
cbm_store_t *store = mkc_index(&lp, files, nfiles);
|
|
int got = store ? cbm_store_count_edges_by_type(store, lp.project, edge_type) : -1;
|
|
if (got < floor) {
|
|
fprintf(stderr, " [MKC] %s FAIL %s=%d expected>=%d %s\n", label, edge_type, got, floor,
|
|
is_green ? "(GREEN regression)" : "(RED reproduction — bug)");
|
|
mkc_diag(store, lp.project, label);
|
|
} else if (!is_green) {
|
|
fprintf(stderr,
|
|
" [MKC] %s UNEXPECTED PASS %s=%d "
|
|
"(bug may be fixed — promote to GREEN)\n",
|
|
label, edge_type, got);
|
|
}
|
|
mkc_cleanup(&lp, store);
|
|
return got >= floor;
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════════
|
|
* ═══ CLASS C1: CONSTRUCTOR / INSTANTIATION ═══════════════════════════════
|
|
*
|
|
* A constructor call (new T() / T() / T{} / T::new() / Class.new) should
|
|
* produce a CALLS edge to the constructor/init method (or at minimum a USAGE
|
|
* edge to the type). The existing lsp_resolution_probe.c covers S3 for
|
|
* Go/C/C++/Rust/Python/TypeScript/Java/Kotlin/C#/PHP at the cross-file level.
|
|
*
|
|
* This matrix-fill adds:
|
|
* - Scala (new Widget() / case-class apply) — same-file
|
|
* - Swift (Type() initializer) — same-file
|
|
* - Ruby (Type.new) — same-file
|
|
* - C++ operator-new with non-trivial constructor — same-file (additional shape)
|
|
* - Rust struct literal T { } in same-file (avoids the :: resolution bug)
|
|
* ══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
/* c1 scala constructor new: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c1_scala_constructor_new) {
|
|
static const MKC_File f[] = {{"Widget.scala", "class Widget(val name: String) {\n"
|
|
" def label(): String = name\n"
|
|
"}\n\n"
|
|
"def make(n: String): Widget = new Widget(n)\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c1 scala case class apply: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c1_scala_case_class_apply) {
|
|
static const MKC_File f[] = {{"Point.scala",
|
|
"case class Point(x: Double, y: Double) {\n"
|
|
" def dist(): Double = math.sqrt(x*x + y*y)\n"
|
|
"}\n\n"
|
|
"def origin(): Double = Point(0.0, 0.0).dist()\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c1 swift initializer: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c1_swift_initializer) {
|
|
static const MKC_File f[] = {{"Widget.swift", "class Widget {\n"
|
|
" let name: String\n"
|
|
" init(name: String) { self.name = name }\n"
|
|
" func label() -> String { return name }\n"
|
|
"}\n\n"
|
|
"func make(n: String) -> Widget {\n"
|
|
" return Widget(name: n)\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c1 ruby type new: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c1_ruby_type_new) {
|
|
static const MKC_File f[] = {{"widget.rb", "class Widget\n"
|
|
" def initialize(name)\n"
|
|
" @name = name\n"
|
|
" end\n\n"
|
|
" def label\n"
|
|
" @name\n"
|
|
" end\n"
|
|
"end\n\n"
|
|
"def make(name)\n"
|
|
" Widget.new(name)\n"
|
|
"end\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* C1-E: C++ — same-file constructor call (no cross-file complication).
|
|
* green=guard: C++ `Counter c(0)` / `Counter c{0}` — lsp_cross (cpp_mode)
|
|
* handles this when both definition and call site are in the same file.
|
|
* This supplements lrp_cpp_s3_constructor (which uses two files) with a
|
|
* single-file shape where forward-declaration ambiguity is absent. */
|
|
TEST(mkc_c1_cpp_constructor_samefile) {
|
|
static const MKC_File f[] = {{"counter.cpp", "class Counter {\npublic:\n"
|
|
" int n;\n"
|
|
" Counter(int start) : n(start) {}\n"
|
|
" int val() const { return n; }\n};\n\n"
|
|
"int run(int start) {\n"
|
|
" Counter c(start);\n"
|
|
" return c.val();\n"
|
|
"}\n"}};
|
|
/* green=guard: constructor + method call both in one file; lsp_cross should
|
|
* resolve both. If this fails it is a C++ same-file constructor regression. */
|
|
ASSERT_TRUE(mkc_edge(f, 1, "CALLS", 1, "c1/cpp/constructor_samefile", 1));
|
|
PASS();
|
|
}
|
|
|
|
/* c1 rust new samefile: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c1_rust_new_samefile) {
|
|
static const MKC_File f[] = {
|
|
{"point.rs",
|
|
"pub struct Point { pub x: f64, pub y: f64 }\n\n"
|
|
"impl Point {\n"
|
|
" pub fn new(x: f64, y: f64) -> Self { Point { x, y } }\n"
|
|
" pub fn dist(&self) -> f64 { (self.x * self.x + self.y * self.y).sqrt() }\n"
|
|
"}\n\n"
|
|
"pub fn run() -> f64 {\n"
|
|
" let p = Point::new(3.0, 4.0);\n"
|
|
" p.dist()\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════════
|
|
* ═══ CLASS C2: OPERATOR OVERLOADING ══════════════════════════════════════
|
|
*
|
|
* When a language desugars `a + b` → `a.operator+(b)` or `a.__add__(b)`,
|
|
* the pipeline should emit a CALLS edge to that operator method.
|
|
*
|
|
* Languages: C++, Python, Rust (Add trait), Kotlin (operator fun),
|
|
* C# (operator), Scala (symbolic def), Ruby (def +),
|
|
* Swift (static func +)
|
|
* ══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
/* c2 cpp operator plus: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c2_cpp_operator_plus) {
|
|
static const MKC_File f[] = {
|
|
{"vec.cpp", "struct Vec2 {\n float x, y;\n Vec2(float x, float y): x(x), y(y){}\n"
|
|
" Vec2 operator+(const Vec2 &o) const { return Vec2(x+o.x, y+o.y); }\n"
|
|
" float dot(const Vec2 &o) const { return x*o.x + y*o.y; }\n};\n\n"
|
|
"float run(Vec2 a, Vec2 b) {\n"
|
|
" Vec2 c = a + b;\n" /* operator+ call */
|
|
" return c.dot(b);\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c2 cpp operator subscript: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c2_cpp_operator_subscript) {
|
|
static const MKC_File f[] = {{"arr.cpp", "struct IntArr {\n int data[8];\n"
|
|
" int& operator[](int i) { return data[i]; }\n"
|
|
"};\n\n"
|
|
"int run(IntArr &a) {\n"
|
|
" return a[2];\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c2 python dunder add: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c2_python_dunder_add) {
|
|
static const MKC_File f[] = {
|
|
{"vec.py",
|
|
"class Vec:\n"
|
|
" def __init__(self, x, y):\n self.x, self.y = x, y\n\n"
|
|
" def __add__(self, other):\n return Vec(self.x + other.x, self.y + other.y)\n\n"
|
|
" def __eq__(self, other):\n return self.x == other.x and self.y == other.y\n\n"
|
|
"def run(a, b):\n"
|
|
" return a + b\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c2 python dunder getitem: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c2_python_dunder_getitem) {
|
|
static const MKC_File f[] = {{"seq.py",
|
|
"class Seq:\n"
|
|
" def __init__(self, data):\n self._d = data\n\n"
|
|
" def __getitem__(self, i):\n return self._d[i]\n\n"
|
|
"def run(s: Seq):\n"
|
|
" return s[0]\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c2 rust add trait: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c2_rust_add_trait) {
|
|
static const MKC_File f[] = {{"vec.rs",
|
|
"use std::ops::Add;\n\n"
|
|
"#[derive(Clone, Copy)]\n"
|
|
"pub struct Vec2 { pub x: f32, pub y: f32 }\n\n"
|
|
"impl Add for Vec2 {\n"
|
|
" type Output = Self;\n"
|
|
" fn add(self, rhs: Self) -> Self {\n"
|
|
" Vec2 { x: self.x + rhs.x, y: self.y + rhs.y }\n"
|
|
" }\n"
|
|
"}\n\n"
|
|
"pub fn run(a: Vec2, b: Vec2) -> Vec2 {\n"
|
|
" a + b\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c2 kotlin operator plus: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c2_kotlin_operator_plus) {
|
|
static const MKC_File f[] = {{"vec.kt",
|
|
"data class Vec2(val x: Float, val y: Float) {\n"
|
|
" operator fun plus(other: Vec2): Vec2 =\n"
|
|
" Vec2(x + other.x, y + other.y)\n"
|
|
" operator fun get(i: Int): Float = if (i == 0) x else y\n"
|
|
"}\n\n"
|
|
"fun run(a: Vec2, b: Vec2): Vec2 = a + b\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c2 csharp operator plus: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c2_csharp_operator_plus) {
|
|
static const MKC_File f[] = {{"Vec.cs",
|
|
"namespace App {\n"
|
|
" struct Vec2 {\n"
|
|
" public float X, Y;\n"
|
|
" public Vec2(float x, float y) { X = x; Y = y; }\n"
|
|
" public static Vec2 operator+(Vec2 a, Vec2 b) {\n"
|
|
" return new Vec2(a.X + b.X, a.Y + b.Y);\n"
|
|
" }\n"
|
|
" public float Dot(Vec2 o) { return X*o.X + Y*o.Y; }\n"
|
|
" }\n"
|
|
" class Math {\n"
|
|
" public static float Run(Vec2 a, Vec2 b) {\n"
|
|
" return (a + b).Dot(b);\n"
|
|
" }\n"
|
|
" }\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* A C# operator's body has its own node, also when the operator is overloaded or spelled
|
|
* with a space or a word. A call in it belongs to that operator, never to the file. */
|
|
TEST(mkc_c2_csharp_operator_overloads) {
|
|
static const char source[] =
|
|
"namespace App {\n"
|
|
" struct Vec2 {\n"
|
|
" public float X;\n"
|
|
" public Vec2(float x) { X = x; }\n"
|
|
" public static Vec2 operator+(Vec2 a, Vec2 b) { return new Vec2(a.X + b.X); }\n"
|
|
" public static Vec2 operator+(Vec2 a, float b) { return new Vec2(a.X + b); }\n"
|
|
" public static Vec2 operator -(Vec2 a, Vec2 b) { return new Vec2(a.X - b.X); }\n"
|
|
" public static bool operator true(Vec2 a) { return Check(a); }\n"
|
|
" static bool Check(Vec2 a) { return true; }\n"
|
|
" }\n"
|
|
"}\n";
|
|
const MKC_File files[] = {{"Vec.cs", source}};
|
|
const RQ_Source sources[] = {{.path = "Vec.cs", .text = source}};
|
|
const RQ_Target ctor = {.file = "Vec.cs",
|
|
.suffix = "Vec2.Vec2",
|
|
.label = "Method",
|
|
.declaration_line = 4,
|
|
.declaration_text = " public Vec2(float x) { X = x; }"};
|
|
const RQ_Target check = {.file = "Vec.cs",
|
|
.suffix = "Vec2.Check",
|
|
.label = "Method",
|
|
.declaration_line = 9,
|
|
.declaration_text =
|
|
" static bool Check(Vec2 a) { return true; }"};
|
|
const RQ_Expected expected[] = {
|
|
{.case_id = "first-plus",
|
|
.site = {.file = "Vec.cs",
|
|
.caller = "Vec2.operator+",
|
|
.needle = "new Vec2(a.X + b.X)",
|
|
.caller_variant_start_line = 5,
|
|
.caller_variant_end_line = 5,
|
|
.caller_variant_declaration = " public static Vec2 operator+(Vec2 a, Vec2 "
|
|
"b) { return new Vec2(a.X + b.X); }"},
|
|
.relation = "CALLS",
|
|
.target = ctor,
|
|
.mode = RQ_REQUIRED},
|
|
{.case_id = "second-plus",
|
|
.site = {.file = "Vec.cs",
|
|
.caller = "Vec2.operator+",
|
|
.needle = "new Vec2(a.X + b)",
|
|
.caller_variant_start_line = 6,
|
|
.caller_variant_end_line = 6,
|
|
.caller_variant_declaration = " public static Vec2 operator+(Vec2 a, float "
|
|
"b) { return new Vec2(a.X + b); }"},
|
|
.relation = "CALLS",
|
|
.target = ctor,
|
|
.mode = RQ_REQUIRED},
|
|
{.case_id = "minus",
|
|
.site = {.file = "Vec.cs", .caller = "Vec2.operator-", .needle = "new Vec2(a.X - b.X)"},
|
|
.relation = "CALLS",
|
|
.target = ctor,
|
|
.mode = RQ_REQUIRED},
|
|
{.case_id = "word",
|
|
.site = {.file = "Vec.cs", .caller = "Vec2.operator true", .needle = "Check(a)"},
|
|
.relation = "CALLS",
|
|
.target = check,
|
|
.mode = RQ_REQUIRED}};
|
|
MKC_Proj project;
|
|
cbm_store_t *store = mkc_index(&project, files, 1);
|
|
RQ_Report report = {0};
|
|
bool ok = store && rq_check_project_declarations(store, project.project, __func__, sources, 1,
|
|
expected, 4, NULL, 0, &report, stderr);
|
|
mkc_cleanup(&project, store);
|
|
ASSERT_TRUE(ok);
|
|
ASSERT_EQ(report.found, 4);
|
|
PASS();
|
|
}
|
|
|
|
/* c2 scala symbolic method: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c2_scala_symbolic_method) {
|
|
static const MKC_File f[] = {{"vec.scala",
|
|
"case class Vec2(x: Double, y: Double) {\n"
|
|
" def +(other: Vec2): Vec2 = Vec2(x + other.x, y + other.y)\n"
|
|
" def dot(other: Vec2): Double = x * other.x + y * other.y\n"
|
|
"}\n\n"
|
|
"def run(a: Vec2, b: Vec2): Double = (a + b).dot(b)\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c2 ruby operator plus: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c2_ruby_operator_plus) {
|
|
static const MKC_File f[] = {
|
|
{"vec.rb", "class Vec2\n"
|
|
" attr_reader :x, :y\n"
|
|
" def initialize(x, y)\n @x, @y = x, y\n end\n\n"
|
|
" def +(other)\n Vec2.new(@x + other.x, @y + other.y)\n end\n\n"
|
|
" def dot(other)\n @x * other.x + @y * other.y\n end\n"
|
|
"end\n\n"
|
|
"def run(a, b)\n"
|
|
" (a + b).dot(b)\n"
|
|
"end\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════════
|
|
* ═══ CLASS C3: DECORATES — annotations / attributes / macros ═════════════
|
|
*
|
|
* Languages / forms NOT yet covered by test_edge_structural.c:
|
|
* - Rust #[derive(...)] and #[cfg(...)] macro attributes
|
|
* - PHP 8 #[Attribute] syntax
|
|
* - Swift @propertyWrapper / @available
|
|
* - Scala @annotation.tailrec / @deprecated
|
|
* - Ruby no native decorators (N/A — excluded)
|
|
* - Python same-file already green in test_lang_contract.c; cross-file in
|
|
* test_edge_structural.c. Add a class-level decorator here.
|
|
*
|
|
* Note: test_edge_structural.c already covers Java, Kotlin, C# annotations
|
|
* (all expected RED). This section adds Rust/PHP/Swift/Scala.
|
|
* ══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
/* C3-A: Rust — #[derive(...)] attribute macro.
|
|
* red=bug: Rust `#[derive(Debug, Clone)]` is an attribute_item node in the
|
|
* grammar. The pipeline models decorators for Python/TS via `decorators[]`
|
|
* in the def struct, but there is no Rust branch that maps attribute_item
|
|
* to a DECORATES edge.
|
|
* Root cause: extract_defs.c has no Rust attribute/decorator extraction.
|
|
* Fix: add a Rust path in extract_defs.c that reads attribute_item children
|
|
* and populates def.decorators[]. */
|
|
TEST(mkc_c3_rust_derive_attribute) {
|
|
static const MKC_File f[] = {{"model.rs", "fn debug_marker() {}\n\n"
|
|
"#[derive(Debug, Clone)]\n"
|
|
"pub struct Point {\n"
|
|
" pub x: f64,\n"
|
|
" pub y: f64,\n"
|
|
"}\n\n"
|
|
"#[derive(Debug)]\n"
|
|
"pub struct Color(pub u8, pub u8, pub u8);\n"}};
|
|
/* REAL BUG: #[derive(Debug)] should produce a DECORATES edge. extract_defs.c
|
|
* has no Rust attribute_item → decorators[] path, so Rust attribute/derive
|
|
* macros are never modeled → DECORATES=0. [KNOWN class 13] */
|
|
ASSERT_TRUE(mkc_edge(f, 1, "DECORATES", 1, "c3/rust/derive_attribute", 0));
|
|
PASS();
|
|
}
|
|
|
|
/* C3-B: Rust — custom function attribute (locally defined proc-macro simulation).
|
|
* red=bug: Even a simple fn-level attribute `#[my_attr]` applied to a function
|
|
* where `my_attr` is defined in the same file is not modeled as DECORATES.
|
|
* Same root cause as C3-A. */
|
|
TEST(mkc_c3_rust_fn_attribute) {
|
|
static const MKC_File f[] = {
|
|
{"service.rs", "/* hypothetical local marker — real proc-macros live in separate crates,\n"
|
|
" * but we just want to check if ANY attribute is modeled as DECORATES */\n"
|
|
"pub fn log_call() {}\n\n"
|
|
"#[allow(dead_code)]\n"
|
|
"pub fn helper(x: i32) -> i32 { x + 1 }\n\n"
|
|
"#[allow(dead_code)]\n"
|
|
"pub fn run(y: i32) -> i32 { helper(y) }\n"}};
|
|
/* REAL BUG: #[allow(dead_code)] should produce a DECORATES edge. Same root
|
|
* cause as c3/rust/derive_attribute — extract_defs.c has no Rust
|
|
* attribute_item → decorators[] path → DECORATES=0. [KNOWN class 13] */
|
|
ASSERT_TRUE(mkc_edge(f, 1, "DECORATES", 1, "c3/rust/fn_attribute", 0));
|
|
PASS();
|
|
}
|
|
|
|
/* C3-C: PHP 8 — #[Attribute] syntax (modern PHP attributes).
|
|
* red=bug: PHP 8 `#[Route("/users")]` attribute on a function is a new grammar
|
|
* node (attribute_group / attribute) distinct from PHP docblock annotations.
|
|
* The PHP extractor may not yet populate decorators[] for the new #[...] syntax.
|
|
* Root cause: extract_defs.c PHP path handles @docblock annotations but may
|
|
* not handle PHP 8 attribute_group nodes. */
|
|
TEST(mkc_c3_php8_attribute) {
|
|
static const MKC_File f[] = {{"routes.php",
|
|
"<?php\n"
|
|
"function Route(string $path): callable {\n"
|
|
" return function() use ($path) { return $path; };\n"
|
|
"}\n\n"
|
|
"#[Route('/users')]\n"
|
|
"function listUsers(): array {\n"
|
|
" return [];\n"
|
|
"}\n\n"
|
|
"#[Route('/items')]\n"
|
|
"function listItems(): array {\n"
|
|
" return [];\n"
|
|
"}\n"}};
|
|
/* REAL BUG: #[Route(...)] should DECORATES listUsers->Route. extract_defs.c
|
|
* handles PHP @docblock annotations but not PHP 8 attribute_group / attribute
|
|
* nodes → DECORATES=0. [KNOWN class 13] */
|
|
ASSERT_TRUE(mkc_edge(f, 1, "DECORATES", 1, "c3/php8/attribute", 0));
|
|
PASS();
|
|
}
|
|
|
|
/* C3-D: Swift — @available / @discardableResult attribute.
|
|
* red=bug: Swift attributes like `@available(macOS 12, *)` and
|
|
* `@discardableResult` are attribute nodes in the tree-sitter-swift grammar.
|
|
* The pipeline has no Swift decorator extraction branch.
|
|
* Root cause: extract_defs.c has no Swift attribute_item → decorators[] path. */
|
|
TEST(mkc_c3_swift_attribute) {
|
|
static const MKC_File f[] = {{"service.swift", "func available() -> Bool { return true }\n\n"
|
|
"@discardableResult\n"
|
|
"func compute(x: Int) -> Int {\n"
|
|
" return x * 2\n"
|
|
"}\n\n"
|
|
"@discardableResult\n"
|
|
"func run(n: Int) -> Int {\n"
|
|
" return compute(n)\n"
|
|
"}\n"}};
|
|
/* REAL BUG: @discardableResult should produce a DECORATES edge. extract_defs.c
|
|
* has no Swift attribute → decorators[] path, so Swift attributes are never
|
|
* modeled → DECORATES=0. [KNOWN class 13] */
|
|
ASSERT_TRUE(mkc_edge(f, 1, "DECORATES", 1, "c3/swift/attribute", 0));
|
|
PASS();
|
|
}
|
|
|
|
/* C3-E: Scala — @annotation on a method.
|
|
* red=bug: Scala `@deprecated` / `@tailrec` annotations are annotation nodes.
|
|
* The generic extractor may or may not capture them as DECORATES edges.
|
|
* Root cause: extract_defs.c Scala path likely does not handle annotation nodes. */
|
|
TEST(mkc_c3_scala_annotation) {
|
|
static const MKC_File f[] = {{"algo.scala", "import scala.annotation.tailrec\n\n"
|
|
"@deprecated(\"use newHelper\", \"2.0\")\n"
|
|
"def helper(x: Int): Int = x + 1\n\n"
|
|
"@tailrec\n"
|
|
"def loop(n: Int, acc: Int): Int =\n"
|
|
" if (n <= 0) acc else loop(n - 1, acc + n)\n"}};
|
|
/* REAL BUG: @deprecated should produce a DECORATES edge. extract_defs.c has
|
|
* no Scala annotation → decorators[] path, so Scala annotations are never
|
|
* modeled → DECORATES=0. [KNOWN class 13] */
|
|
ASSERT_TRUE(mkc_edge(f, 1, "DECORATES", 1, "c3/scala/annotation", 0));
|
|
PASS();
|
|
}
|
|
|
|
/* C3-F: Python — class-level decorator (not just function-level).
|
|
* green=guard: test_lang_contract.c P6 covers function-level decorators.
|
|
* This adds a CLASS-level decorator to confirm the extractor handles
|
|
* decorated class definitions (not just functions). */
|
|
TEST(mkc_c3_python_class_decorator) {
|
|
static const MKC_File f[] = {{"service.py",
|
|
"def singleton(cls):\n"
|
|
" instances = {}\n"
|
|
" def get(*a, **kw):\n"
|
|
" if cls not in instances:\n"
|
|
" instances[cls] = cls(*a, **kw)\n"
|
|
" return instances[cls]\n"
|
|
" return get\n\n\n"
|
|
"@singleton\n"
|
|
"class Config:\n"
|
|
" def __init__(self):\n self.debug = False\n\n\n"
|
|
"@singleton\n"
|
|
"class Cache:\n"
|
|
" def __init__(self):\n self.data = {}\n"}};
|
|
/* green=guard: @singleton on a class should DECORATES Config->singleton.
|
|
* Python class-level decorator extraction should work the same as function-level
|
|
* (both are `decorated_definition` nodes in tree-sitter-python). */
|
|
ASSERT_TRUE(mkc_edge(f, 1, "DECORATES", 1, "c3/python/class_decorator", 1));
|
|
PASS();
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════════
|
|
* ═══ CLASS C4: ASYNC/AWAIT CALLS ═════════════════════════════════════════
|
|
*
|
|
* An `await expr` or async function call should still produce a CALLS edge
|
|
* to the callee. The async/await syntax wraps the call but must not hide it
|
|
* from the extractor.
|
|
*
|
|
* Languages: Python (async def / await), TypeScript (async/await),
|
|
* C# (async Task / await), Rust (.await expr),
|
|
* Kotlin (suspend fun / coroutine launch),
|
|
* Swift (async/await — Swift 5.5+)
|
|
* ══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
/* C4-A: Python — async/await function call.
|
|
* green=guard: Python `await fetch(url)` — the `await` expression wraps a
|
|
* regular `call` node whose function field is `fetch`. Python's call_types
|
|
* include `call`, so the `call` inside `await` is still extracted.
|
|
* The extractor should find the inner call regardless of the await wrapper. */
|
|
TEST(mkc_c4_python_async_await) {
|
|
static const MKC_File f[] = {{"client.py", "async def fetch(url: str) -> str:\n"
|
|
" return url\n\n\n"
|
|
"async def get_data(url: str) -> str:\n"
|
|
" result = await fetch(url)\n"
|
|
" return result\n\n\n"
|
|
"async def run(urls):\n"
|
|
" for url in urls:\n"
|
|
" data = await get_data(url)\n"
|
|
" print(data)\n"}};
|
|
/* green=guard: await fetch(url) inner call should CALLS get_data->fetch.
|
|
* await is transparent to the call extractor for Python. */
|
|
ASSERT_TRUE(mkc_edge(f, 1, "CALLS", 1, "c4/python/async_await", 1));
|
|
PASS();
|
|
}
|
|
|
|
/* c4 typescript async await: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c4_typescript_async_await) {
|
|
static const MKC_File f[] = {{"client.ts",
|
|
"async function fetch(url: string): Promise<string> {\n"
|
|
" return url;\n"
|
|
"}\n\n"
|
|
"async function getData(url: string): Promise<string> {\n"
|
|
" return await fetch(url);\n"
|
|
"}\n\n"
|
|
"async function run(urls: string[]): Promise<void> {\n"
|
|
" for (const url of urls) {\n"
|
|
" const data = await getData(url);\n"
|
|
" console.log(data);\n"
|
|
" }\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c4 csharp async await: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c4_csharp_async_await) {
|
|
static const MKC_File f[] = {
|
|
{"Client.cs", "using System.Threading.Tasks;\n\n"
|
|
"namespace App {\n"
|
|
" class Client {\n"
|
|
" public async Task<string> FetchAsync(string url) {\n"
|
|
" return url;\n"
|
|
" }\n\n"
|
|
" public async Task<string> GetDataAsync(string url) {\n"
|
|
" return await FetchAsync(url);\n"
|
|
" }\n\n"
|
|
" public async Task RunAsync() {\n"
|
|
" string data = await GetDataAsync(\"http://example.com\");\n"
|
|
" }\n"
|
|
" }\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c4 rust await: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c4_rust_await) {
|
|
static const MKC_File f[] = {{"client.rs", "async fn fetch(url: &str) -> String {\n"
|
|
" url.to_string()\n"
|
|
"}\n\n"
|
|
"async fn get_data(url: &str) -> String {\n"
|
|
" fetch(url).await\n"
|
|
"}\n\n"
|
|
"async fn run(urls: &[&str]) {\n"
|
|
" for url in urls {\n"
|
|
" let _data = get_data(url).await;\n"
|
|
" }\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c4 kotlin suspend call: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c4_kotlin_suspend_call) {
|
|
static const MKC_File f[] = {{"client.kt", "suspend fun fetchData(url: String): String {\n"
|
|
" return url\n"
|
|
"}\n\n"
|
|
"suspend fun getData(url: String): String {\n"
|
|
" return fetchData(url)\n"
|
|
"}\n\n"
|
|
"suspend fun run(urls: List<String>) {\n"
|
|
" for (url in urls) {\n"
|
|
" val data = getData(url)\n"
|
|
" println(data)\n"
|
|
" }\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c4 swift async await: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c4_swift_async_await) {
|
|
static const MKC_File f[] = {{"client.swift", "func fetch(url: String) async -> String {\n"
|
|
" return url\n"
|
|
"}\n\n"
|
|
"func getData(url: String) async -> String {\n"
|
|
" return await fetch(url: url)\n"
|
|
"}\n\n"
|
|
"func run(urls: [String]) async {\n"
|
|
" for url in urls {\n"
|
|
" let data = await getData(url: url)\n"
|
|
" print(data)\n"
|
|
" }\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════════
|
|
* ═══ CLASS C5: GENERIC / TEMPLATED METHOD CALLS ═══════════════════════════
|
|
*
|
|
* Calling a method through a generic type parameter. The existing
|
|
* lsp_resolution_probe.c covers S7 (generic call) for all 9 hybrid langs.
|
|
*
|
|
* Matrix-fill adds: Scala, Swift, Ruby (duck-typed, no generics per se).
|
|
* ══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
/* c5 scala generic call: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c5_scala_generic_call) {
|
|
static const MKC_File f[] = {{"algo.scala",
|
|
"def first[T](xs: List[T]): Option[T] =\n"
|
|
" if (xs.isEmpty) None else Some(xs.head)\n\n"
|
|
"def run(ns: List[Int]): Option[Int] = first(ns)\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c5 swift generic call: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c5_swift_generic_call) {
|
|
static const MKC_File f[] = {{"algo.swift", "func maxOf<T: Comparable>(_ a: T, _ b: T) -> T {\n"
|
|
" return a > b ? a : b\n"
|
|
"}\n\n"
|
|
"func run(a: Int, b: Int) -> Int {\n"
|
|
" return maxOf(a, b)\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c5 ruby duck typed call: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c5_ruby_duck_typed_call) {
|
|
static const MKC_File f[] = {{"algo.rb", "def first(collection)\n"
|
|
" collection.empty? ? nil : collection.first\n"
|
|
"end\n\n"
|
|
"def run(items)\n"
|
|
" first(items)\n"
|
|
"end\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════════
|
|
* ═══ CLASS C6: STATIC / CLASS-METHOD CALLS (grammar-only langs) ══════════
|
|
*
|
|
* The existing suites cover static calls for Go/C/C++/Python/TS/Java/Kotlin/
|
|
* C#/PHP/Rust. Matrix-fill adds: Scala companion-object, Swift static/class
|
|
* methods, Ruby self.method (class methods).
|
|
* ══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
/* c6 scala companion object: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c6_scala_companion_object) {
|
|
static const MKC_File f[] = {{"config.scala", "class Config(val debug: Boolean)\n\n"
|
|
"object Config {\n"
|
|
" def default(): Config = new Config(false)\n"
|
|
" def debug(): Config = new Config(true)\n"
|
|
"}\n\n"
|
|
"def run(): Config = Config.default()\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c6 swift static method: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c6_swift_static_method) {
|
|
static const MKC_File f[] = {{"mathhelper.swift",
|
|
"class MathHelper {\n"
|
|
" static func clamp(_ v: Int, _ lo: Int, _ hi: Int) -> Int {\n"
|
|
" return v < lo ? lo : v > hi ? hi : v\n"
|
|
" }\n"
|
|
" static func square(_ x: Int) -> Int { return x * x }\n"
|
|
"}\n\n"
|
|
"func run(n: Int) -> Int {\n"
|
|
" return MathHelper.clamp(n, 0, 100)\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c6 ruby class method: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c6_ruby_class_method) {
|
|
static const MKC_File f[] = {{"config.rb", "class Config\n"
|
|
" def self.version\n"
|
|
" '1.0'\n"
|
|
" end\n\n"
|
|
" def self.default\n"
|
|
" new\n"
|
|
" end\n"
|
|
"end\n\n"
|
|
"def run\n"
|
|
" Config.version\n"
|
|
"end\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c6 scala singleton object: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c6_scala_singleton_object) {
|
|
static const MKC_File f[] = {{"logger.scala",
|
|
"object Logger {\n"
|
|
" def log(msg: String): Unit = println(msg)\n"
|
|
" def warn(msg: String): Unit = println(\"WARN: \" + msg)\n"
|
|
"}\n\n"
|
|
"def run(msg: String): Unit = Logger.log(msg)\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════════
|
|
* ═══ CLASS C7: INHERITED-METHOD CALL (grammar-only langs) ════════════════
|
|
*
|
|
* Existing suites cover inherited-method calls for all 9 hybrid langs.
|
|
* Matrix-fill adds: Scala, Swift, Ruby.
|
|
* ══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
/* c7 scala inherited method: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c7_scala_inherited_method) {
|
|
static const MKC_File f[] = {{"zoo.scala", "class Animal {\n"
|
|
" def describe(): String = \"animal\"\n"
|
|
" def speak(): String = \"...\"\n"
|
|
"}\n\n"
|
|
"class Dog extends Animal {\n"
|
|
" override def speak(): String = \"woof\"\n"
|
|
"}\n\n"
|
|
"def run(d: Dog): String = d.describe()\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c7 swift inherited method: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c7_swift_inherited_method) {
|
|
static const MKC_File f[] = {{"zoo.swift",
|
|
"class Animal {\n"
|
|
" func describe() -> String { return \"animal\" }\n"
|
|
" func speak() -> String { return \"...\" }\n"
|
|
"}\n\n"
|
|
"class Dog: Animal {\n"
|
|
" override func speak() -> String { return \"woof\" }\n"
|
|
"}\n\n"
|
|
"func run(d: Dog) -> String {\n"
|
|
" return d.describe()\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c7 ruby inherited method: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c7_ruby_inherited_method) {
|
|
static const MKC_File f[] = {
|
|
{"zoo.rb",
|
|
"class Animal\n"
|
|
" def describe\n 'animal'\n end\n\n"
|
|
" def speak\n '...'\n end\n"
|
|
"end\n\n"
|
|
"class Dog < Animal\n"
|
|
" def speak\n 'woof'\n end\n\n"
|
|
" def run\n"
|
|
" describe()\n" /* inherited method call — explicit () makes it a `call` node */
|
|
" end\n"
|
|
"end\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c7 scala super call: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c7_scala_super_call) {
|
|
static const MKC_File f[] = {
|
|
{"zoo2.scala", "class Base {\n"
|
|
" def describe(): String = \"base\"\n"
|
|
"}\n\n"
|
|
"class Child extends Base {\n"
|
|
" override def describe(): String = \"child: \" + super.describe()\n"
|
|
"}\n\n"
|
|
"def run(c: Child): String = c.describe()\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════════
|
|
* ═══ CLASS C8: ADDITIONAL CONSTRUCTOR SHAPES (same-file cross-check) ════
|
|
*
|
|
* These cases probe constructor CALLS in languages where the cross-file
|
|
* lsp_probe already documents failures, but we want a same-file variant to
|
|
* determine if the failure is specifically cross-file (lsp_cross not wired)
|
|
* or also same-file (call_types missing the construction expression).
|
|
* ══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
/* c8 java constructor samefile: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c8_java_constructor_samefile) {
|
|
static const MKC_File f[] = {
|
|
{"Factory.java", "package app;\n\n"
|
|
"class Widget {\n"
|
|
" private String name;\n"
|
|
" public Widget(String name) { this.name = name; }\n"
|
|
" public String label() { return name; }\n"
|
|
"}\n\n"
|
|
"class Factory {\n"
|
|
" public Widget make(String name) { return new Widget(name); }\n"
|
|
" public String run(String name) { return make(name).label(); }\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c8 csharp constructor samefile: exact source calls are required obligations or named quality
|
|
* gaps; unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c8_csharp_constructor_samefile) {
|
|
static const MKC_File f[] = {
|
|
{"Service.cs", "namespace App {\n"
|
|
" class Widget {\n"
|
|
" public string Name;\n"
|
|
" public Widget(string name) { Name = name; }\n"
|
|
" public string Label() { return Name; }\n"
|
|
" }\n\n"
|
|
" class Service {\n"
|
|
" public Widget Make(string name) { return new Widget(name); }\n"
|
|
" public string Run(string name) { return Make(name).Label(); }\n"
|
|
" }\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c8 php constructor samefile: exact source calls are required obligations or named quality gaps;
|
|
* unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c8_php_constructor_samefile) {
|
|
static const MKC_File f[] = {
|
|
{"factory.php", "<?php\n"
|
|
"class Widget {\n"
|
|
" public $name;\n"
|
|
" public function __construct($name) { $this->name = $name; }\n"
|
|
" public function label() { return $this->name; }\n"
|
|
"}\n\n"
|
|
"class Factory {\n"
|
|
" public function make($name) { return new Widget($name); }\n"
|
|
" public function run($name) { return $this->make($name)->label(); }\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c8 typescript constructor samefile: exact source calls are required obligations or named quality
|
|
* gaps; unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c8_typescript_constructor_samefile) {
|
|
static const MKC_File f[] = {
|
|
{"service.ts", "class Widget {\n"
|
|
" constructor(public name: string) {}\n"
|
|
" label(): string { return this.name; }\n"
|
|
"}\n\n"
|
|
"class Service {\n"
|
|
" make(name: string): Widget { return new Widget(name); }\n"
|
|
" run(name: string): string { return this.make(name).label(); }\n"
|
|
"}\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* c8 kotlin constructor samefile: exact source calls are required obligations or named quality
|
|
* gaps; unknown receiver sites cannot bind to a same-named project method. */
|
|
TEST(mkc_c8_kotlin_constructor_samefile) {
|
|
static const MKC_File f[] = {{"app.kt",
|
|
"class Widget(val name: String) {\n"
|
|
" fun label(): String = name\n"
|
|
"}\n\n"
|
|
"fun make(name: String): Widget = Widget(name)\n"
|
|
"fun run(name: String): String = make(name).label()\n"}};
|
|
/* Exact source obligations and unsupported-binding gaps are tracked above. */
|
|
ASSERT_TRUE(mkc_quality(f, 1, __func__));
|
|
PASS();
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════════
|
|
* SUITE registration
|
|
* ══════════════════════════════════════════════════════════════════════════ */
|
|
|
|
SUITE(matrix_known_classes) {
|
|
|
|
/* ── CLASS C1: CONSTRUCTOR / INSTANTIATION ─────────────────────────── */
|
|
/* C1-A/B: Scala new + case class apply — red=bug */
|
|
RUN_TEST(mkc_c1_scala_constructor_new);
|
|
RUN_TEST(mkc_c1_scala_case_class_apply);
|
|
/* C1-C: Swift initializer — red=bug */
|
|
RUN_TEST(mkc_c1_swift_initializer);
|
|
/* C1-D: Ruby Type.new — red=bug */
|
|
RUN_TEST(mkc_c1_ruby_type_new);
|
|
/* C1-E: C++ same-file constructor — green=guard */
|
|
RUN_TEST(mkc_c1_cpp_constructor_samefile);
|
|
/* C1-F: Rust same-file Point::new — red=bug (:: resolver gap) */
|
|
RUN_TEST(mkc_c1_rust_new_samefile);
|
|
|
|
/* ── CLASS C2: OPERATOR OVERLOADING ────────────────────────────────── */
|
|
/* C2-A/B: C++ operator+/[] — red=bug */
|
|
RUN_TEST(mkc_c2_cpp_operator_plus);
|
|
RUN_TEST(mkc_c2_cpp_operator_subscript);
|
|
/* C2-C/D: Python __add__/__getitem__ — red=bug */
|
|
RUN_TEST(mkc_c2_python_dunder_add);
|
|
RUN_TEST(mkc_c2_python_dunder_getitem);
|
|
/* C2-E: Rust Add trait — red=bug */
|
|
RUN_TEST(mkc_c2_rust_add_trait);
|
|
/* C2-F: Kotlin operator fun plus — red=bug */
|
|
RUN_TEST(mkc_c2_kotlin_operator_plus);
|
|
/* C2-G: C# operator+ — red=bug */
|
|
RUN_TEST(mkc_c2_csharp_operator_plus);
|
|
RUN_TEST(mkc_c2_csharp_operator_overloads);
|
|
/* C2-H: Scala symbolic method — uncertain/red=bug */
|
|
RUN_TEST(mkc_c2_scala_symbolic_method);
|
|
/* C2-I: Ruby def + — uncertain/red=bug */
|
|
RUN_TEST(mkc_c2_ruby_operator_plus);
|
|
|
|
/* ── CLASS C3: DECORATES ─────────────────────────────────────────── */
|
|
/* C3-A/B: Rust #[derive] / #[allow] — red=bug */
|
|
RUN_TEST(mkc_c3_rust_derive_attribute);
|
|
RUN_TEST(mkc_c3_rust_fn_attribute);
|
|
/* C3-C: PHP 8 #[Attribute] — red=bug */
|
|
RUN_TEST(mkc_c3_php8_attribute);
|
|
/* C3-D: Swift @discardableResult — red=bug */
|
|
RUN_TEST(mkc_c3_swift_attribute);
|
|
/* C3-E: Scala @deprecated/@tailrec — red=bug */
|
|
RUN_TEST(mkc_c3_scala_annotation);
|
|
/* C3-F: Python class-level decorator — green=guard */
|
|
RUN_TEST(mkc_c3_python_class_decorator);
|
|
|
|
/* ── CLASS C4: ASYNC/AWAIT CALLS ─────────────────────────────────── */
|
|
/* C4-A/B: Python / TypeScript async — green=guard */
|
|
RUN_TEST(mkc_c4_python_async_await);
|
|
RUN_TEST(mkc_c4_typescript_async_await);
|
|
/* C4-C: C# async Task — uncertain/red=bug */
|
|
RUN_TEST(mkc_c4_csharp_async_await);
|
|
/* C4-D: Rust .await — red=bug */
|
|
RUN_TEST(mkc_c4_rust_await);
|
|
/* C4-E: Kotlin suspend — green=guard (uncertain) */
|
|
RUN_TEST(mkc_c4_kotlin_suspend_call);
|
|
/* C4-F: Swift async/await — uncertain/red=bug */
|
|
RUN_TEST(mkc_c4_swift_async_await);
|
|
|
|
/* ── CLASS C5: GENERIC / TEMPLATED CALLS ─────────────────────────── */
|
|
/* C5-A/B: Scala + Swift generic — uncertain */
|
|
RUN_TEST(mkc_c5_scala_generic_call);
|
|
RUN_TEST(mkc_c5_swift_generic_call);
|
|
/* C5-C: Ruby duck-typed — green=guard */
|
|
RUN_TEST(mkc_c5_ruby_duck_typed_call);
|
|
|
|
/* ── CLASS C6: STATIC / CLASS-METHOD CALLS ──────────────────────── */
|
|
/* C6-A/B/C: Scala companion / Swift static / Ruby self.method */
|
|
RUN_TEST(mkc_c6_scala_companion_object);
|
|
RUN_TEST(mkc_c6_swift_static_method);
|
|
RUN_TEST(mkc_c6_ruby_class_method);
|
|
/* C6-D: Scala singleton object — green=guard */
|
|
RUN_TEST(mkc_c6_scala_singleton_object);
|
|
|
|
/* ── CLASS C7: INHERITED-METHOD CALLS ───────────────────────────── */
|
|
/* C7-A: Scala inherited method — uncertain */
|
|
RUN_TEST(mkc_c7_scala_inherited_method);
|
|
/* C7-B: Swift inherited method — uncertain */
|
|
RUN_TEST(mkc_c7_swift_inherited_method);
|
|
/* C7-C: Ruby inherited method — green=guard */
|
|
RUN_TEST(mkc_c7_ruby_inherited_method);
|
|
/* C7-D: Scala super call — uncertain */
|
|
RUN_TEST(mkc_c7_scala_super_call);
|
|
|
|
/* ── CLASS C8: CONSTRUCTOR SAME-FILE CROSS-CHECK ────────────────── */
|
|
/* All red=bug: isolates extraction-layer constructor gaps */
|
|
RUN_TEST(mkc_c8_java_constructor_samefile);
|
|
RUN_TEST(mkc_c8_csharp_constructor_samefile);
|
|
RUN_TEST(mkc_c8_php_constructor_samefile);
|
|
RUN_TEST(mkc_c8_typescript_constructor_samefile);
|
|
RUN_TEST(mkc_c8_kotlin_constructor_samefile);
|
|
}
|