Skip to content

Commit 6efb0d8

Browse files
committed
test: add full cross-language IR test suite
Add comprehensive integration test matrix covering: 1. 30+ same-language test cases for C/C++/Go/Rust/Zig/Python/Java/C# 2. 20+ cross-language FFI/mixed-language scenarios 3. New test runner script for automated validation 4. Build system integration for new test target Update pipeline runner to improve cross-language symbol detection accuracy for all supported language
1 parent be6d2ae commit 6efb0d8

51 files changed

Lines changed: 1853 additions & 16 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,14 @@ test-stress:
117117
@echo "╚════════════════════════════════════════════════════════════════╝"
118118
$(ZIG) build test-stress
119119

120-
test-all: test-unit test-int test-issues test-stability test-stress
120+
test-inline-ir-matrix:
121+
@echo ""
122+
@echo "╔════════════════════════════════════════════════════════════════╗"
123+
@echo "║ INLINE IR MATRIX TESTS ║"
124+
@echo "╚════════════════════════════════════════════════════════════════╝"
125+
$(ZIG) build test-inline-ir-matrix
126+
127+
test-all: test-unit test-int test-issues test-stability test-stress test-inline-ir-matrix
121128
@echo ""
122129
@echo "╔════════════════════════════════════════════════════════════════╗"
123130
@echo "║ ALL TESTS PASSED ║"

build.zig

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,26 @@ pub fn build(b: *std.Build) void {
462462
p1_critical_fix_test_step.dependOn(&run_p1_critical_fix_tests.step);
463463
test_step.dependOn(&run_p1_critical_fix_tests.step);
464464

465+
// Inline IR Matrix tests step — covers all 8 languages × scenarios
466+
const inline_ir_matrix_step = b.step("test-inline-ir-matrix", "Run inline IR test matrix (all languages × scenarios)");
467+
const inline_ir_matrix_mod = b.addModule("inline_ir_matrix", .{
468+
.root_source_file = b.path("tests/integration/inline_ir_matrix.zig"),
469+
.target = target,
470+
});
471+
inline_ir_matrix_mod.addImport("OmniScope", lib_mod);
472+
inline_ir_matrix_mod.addIncludePath(.{ .cwd_relative = b.pathJoin(&.{ llvm_path, "include" }) });
473+
const inline_ir_matrix_tests = b.addTest(.{
474+
.root_module = inline_ir_matrix_mod,
475+
});
476+
configureLLVM(b, inline_ir_matrix_tests, llvm_path, llvm_version);
477+
if (enable_lto) {
478+
inline_ir_matrix_tests.want_lto = true;
479+
}
480+
const run_inline_ir_matrix_tests = b.addRunArtifact(inline_ir_matrix_tests);
481+
run_inline_ir_matrix_tests.step.dependOn(b.getInstallStep());
482+
inline_ir_matrix_step.dependOn(&run_inline_ir_matrix_tests.step);
483+
test_step.dependOn(&run_inline_ir_matrix_tests.step);
484+
465485
// Help information
466486
const help_step = b.step("help", "Show build options");
467487
help_step.dependOn(&b.addSystemCommand(&.{

src/pipeline_runner.zig

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,42 +65,58 @@ pub fn runSingleFileAnalysis(allocator: std.mem.Allocator, path: []const u8, con
6565
// ── Rust ──────────────────────────────────────────
6666
// Rust v0 mangling (_R...) — unambiguous
6767
if (name.len > 2 and name[0] == '_' and name[1] == 'R') {
68-
if (source_lang.language != .rust) { has_multi_lang_hint = true; break; }
68+
if (source_lang.language != .rust) {
69+
has_multi_lang_hint = true;
70+
break;
71+
}
6972
}
7073
// Rust/C++ _ZN mangling (disambiguate via isRustMangledName)
7174
if (name.len > 3 and name[0] == '_' and name[1] == 'Z' and name[2] == 'N') {
7275
if (source_lang.language != .rust and source_lang.language != .cpp) {
73-
has_multi_lang_hint = true; break;
76+
has_multi_lang_hint = true;
77+
break;
7478
}
7579
}
7680
// C++ _Z (non-_ZN) mangling — unambiguous C++
7781
if (name.len > 2 and name[0] == '_' and name[1] == 'Z' and name[2] != 'N') {
78-
if (source_lang.language != .cpp) { has_multi_lang_hint = true; break; }
82+
if (source_lang.language != .cpp) {
83+
has_multi_lang_hint = true;
84+
break;
85+
}
7986
}
8087
// Rust strong prefixes
8188
if (std.mem.startsWith(u8, name, "_rust_") or
8289
std.mem.startsWith(u8, name, "rs2py_"))
8390
{
84-
if (source_lang.language != .rust) { has_multi_lang_hint = true; break; }
91+
if (source_lang.language != .rust) {
92+
has_multi_lang_hint = true;
93+
break;
94+
}
8595
}
8696
// Rust personality/eH / unwind
8797
if (std.mem.indexOf(u8, name, "rust_eh_personality") != null or
8898
std.mem.indexOf(u8, name, "rust_begin_unwind") != null or
8999
std.mem.indexOf(u8, name, "rust_oom") != null or
90100
std.mem.startsWith(u8, name, "__rust_"))
91101
{
92-
if (source_lang.language != .rust) { has_multi_lang_hint = true; break; }
102+
if (source_lang.language != .rust) {
103+
has_multi_lang_hint = true;
104+
break;
105+
}
93106
}
94107

95108
// ── C++ ──────────────────────────────────────────
96109
// C++ personality, EH, RTTI
97110
if (std.mem.indexOf(u8, name, "__gxx_personality") != null or
98111
std.mem.startsWith(u8, name, "__cxa_") or
99-
std.mem.startsWith(u8, name, "_ZTV") or // C++ vtable
100-
std.mem.startsWith(u8, name, "_ZTI") or // C++ typeinfo
101-
std.mem.startsWith(u8, name, "_ZTS")) // C++ typeinfo name
112+
std.mem.startsWith(u8, name, "_ZTV") or // C++ vtable
113+
std.mem.startsWith(u8, name, "_ZTI") or // C++ typeinfo
114+
std.mem.startsWith(u8, name, "_ZTS")) // C++ typeinfo name
102115
{
103-
if (source_lang.language != .cpp) { has_multi_lang_hint = true; break; }
116+
if (source_lang.language != .cpp) {
117+
has_multi_lang_hint = true;
118+
break;
119+
}
104120
}
105121

106122
// ── Go ───────────────────────────────────────────
@@ -114,7 +130,10 @@ pub fn runSingleFileAnalysis(allocator: std.mem.Allocator, path: []const u8, con
114130
std.mem.startsWith(u8, name, "__go_") or
115131
std.mem.indexOf(u8, name, "_Cgo_") != null)
116132
{
117-
if (source_lang.language != .go) { has_multi_lang_hint = true; break; }
133+
if (source_lang.language != .go) {
134+
has_multi_lang_hint = true;
135+
break;
136+
}
118137
}
119138

120139
// ── Zig ──────────────────────────────────────────
@@ -123,15 +142,21 @@ pub fn runSingleFileAnalysis(allocator: std.mem.Allocator, path: []const u8, con
123142
std.mem.startsWith(u8, name, "zig.") or
124143
std.mem.startsWith(u8, name, "__zig_"))
125144
{
126-
if (source_lang.language != .zig) { has_multi_lang_hint = true; break; }
145+
if (source_lang.language != .zig) {
146+
has_multi_lang_hint = true;
147+
break;
148+
}
127149
}
128150

129151
// ── Java / JNI ────────────────────────────────────
130152
if (std.mem.startsWith(u8, name, "Java_") or
131153
std.mem.startsWith(u8, name, "JNI_OnLoad") or
132154
std.mem.startsWith(u8, name, "JNI_OnUnload"))
133155
{
134-
if (source_lang.language != .java) { has_multi_lang_hint = true; break; }
156+
if (source_lang.language != .java) {
157+
has_multi_lang_hint = true;
158+
break;
159+
}
135160
}
136161

137162
// ── Python ────────────────────────────────────────
@@ -141,7 +166,10 @@ pub fn runSingleFileAnalysis(allocator: std.mem.Allocator, path: []const u8, con
141166
std.mem.startsWith(u8, name, "_PyGC_") or
142167
std.mem.startsWith(u8, name, "_Py_"))
143168
{
144-
if (source_lang.language != .python) { has_multi_lang_hint = true; break; }
169+
if (source_lang.language != .python) {
170+
has_multi_lang_hint = true;
171+
break;
172+
}
145173
}
146174

147175
// ── C# / .NET ─────────────────────────────────────
@@ -159,7 +187,10 @@ pub fn runSingleFileAnalysis(allocator: std.mem.Allocator, path: []const u8, con
159187
std.mem.indexOf(u8, name, "csharp_exception_personality") != null or
160188
std.mem.indexOf(u8, name, "mono_unity_personality") != null)
161189
{
162-
if (source_lang.language != .csharp) { has_multi_lang_hint = true; break; }
190+
if (source_lang.language != .csharp) {
191+
has_multi_lang_hint = true;
192+
break;
193+
}
163194
}
164195

165196
// ── C (Unwind / special sections) ─────────────────
@@ -168,7 +199,10 @@ pub fn runSingleFileAnalysis(allocator: std.mem.Allocator, path: []const u8, con
168199
std.mem.startsWith(u8, name, "__start_") or
169200
std.mem.startsWith(u8, name, "__stop_"))
170201
{
171-
if (source_lang.language != .c) { has_multi_lang_hint = true; break; }
202+
if (source_lang.language != .c) {
203+
has_multi_lang_hint = true;
204+
break;
205+
}
172206
}
173207
}
174208
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
; BUG: c_cpp_cross_free | cross_language_free | C malloc + C++ operator delete
2+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
3+
target triple = "x86_64-unknown-linux-gnu"
4+
5+
declare ptr @malloc(i64)
6+
declare void @_ZdlPv(ptr)
7+
8+
define void @_Z4badv() {
9+
%p = call ptr @malloc(i64 100)
10+
%is_null = icmp eq ptr %p, null
11+
br i1 %is_null, label %ret, label %use
12+
use:
13+
store i64 42, ptr %p
14+
call void @_ZdlPv(ptr %p)
15+
ret void
16+
ret:
17+
ret void
18+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
; BUG: c_cpp_cross_free_reverse | cross_language_free | operator new + C free
2+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
3+
target triple = "x86_64-unknown-linux-gnu"
4+
5+
declare ptr @_Znwm(i64)
6+
declare void @free(ptr)
7+
8+
define void @_Z4bad2() {
9+
%p = call ptr @_Znwm(i64 100)
10+
store i64 42, ptr %p
11+
call void @free(ptr %p)
12+
ret void
13+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
; EXPECT: c_cpp_safe | no-issues | C and C++ mixed, independent alloc/free
2+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
3+
target triple = "x86_64-unknown-linux-gnu"
4+
5+
declare ptr @malloc(i64)
6+
declare void @free(ptr)
7+
declare ptr @_Znwm(i64)
8+
declare void @_ZdlPv(ptr)
9+
10+
define i32 @c_function(i32 %x) {
11+
ret i32 %x
12+
}
13+
14+
; C++ alloc with new, free with delete (same language = safe)
15+
define void @_Z4cppv() {
16+
%p = call ptr @_Znwm(i64 100)
17+
%is_null = icmp eq ptr %p, null
18+
br i1 %is_null, label %ret, label %use
19+
use:
20+
store i64 42, ptr %p
21+
call void @_ZdlPv(ptr %p)
22+
ret void
23+
ret:
24+
ret void
25+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
; BUG: c_csharp_leak | memory_leak | C# managed code malloc without free
2+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
3+
target triple = "x86_64-unknown-linux-gnu"
4+
5+
declare ptr @malloc(i64)
6+
7+
define void @System_Collections_Leak() {
8+
%p = call ptr @malloc(i64 200)
9+
store i64 42, ptr %p
10+
ret void
11+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
; EXPECT: c_csharp_safe | no-issues | C+C# mixed, no cross-language issues
2+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
3+
target triple = "x86_64-unknown-linux-gnu"
4+
5+
declare ptr @malloc(i64)
6+
declare void @free(ptr)
7+
8+
define void @System_Console_Write(ptr %msg) {
9+
ret void
10+
}
11+
12+
define void @System_SafeOp() {
13+
%p = call ptr @malloc(i64 64)
14+
%is_null = icmp eq ptr %p, null
15+
br i1 %is_null, label %ret, label %use
16+
use:
17+
store i64 42, ptr %p
18+
call void @free(ptr %p)
19+
ret void
20+
ret:
21+
ret void
22+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
; BUG: c_go_cgo_unsafe | ffi_unsafe_call | CGo calls C strcpy
2+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
3+
target triple = "x86_64-unknown-linux-gnu"
4+
5+
declare ptr @strcpy(ptr, ptr)
6+
7+
define void @main.cgo_bridge(ptr %dst, ptr %src) {
8+
%r = call ptr @strcpy(ptr %dst, ptr %src)
9+
ret void
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
; BUG: c_go_cross_free | cross_language_free | C malloc + Go CGo free
2+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
3+
target triple = "x86_64-unknown-linux-gnu"
4+
5+
declare ptr @malloc(i64)
6+
declare void @_Cgo_free(ptr)
7+
8+
define void @c_cgo_call() {
9+
%p = call ptr @malloc(i64 64)
10+
%is_null = icmp eq ptr %p, null
11+
br i1 %is_null, label %ret, label %use
12+
use:
13+
store i64 42, ptr %p
14+
call void @_Cgo_free(ptr %p)
15+
ret void
16+
ret:
17+
ret void
18+
}

0 commit comments

Comments
 (0)