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
16 changes: 8 additions & 8 deletions codeflash/languages/java/gradle_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ def install_multi_module_deps(self, build_root: Path, test_module: str | None, e
logger.error("Gradle not found — cannot pre-install multi-module dependencies")
return False

cmd = [gradle, f":{test_module}:classes", "-x", "test", "--build-cache", "--no-daemon"]
cmd = [gradle, f":{test_module}:classes", "-x", "test", "--no-build-cache", "--no-daemon"]
cmd.extend(["--init-script", _get_skip_validation_init_script()])

logger.info("Pre-installing multi-module dependencies: %s (module: %s)", build_root, test_module)
Expand Down Expand Up @@ -504,9 +504,9 @@ def compile_tests(
return subprocess.CompletedProcess(args=["gradle"], returncode=-1, stdout="", stderr="Gradle not found")

if test_module:
cmd = [gradle, f":{test_module}:testClasses", "--no-daemon"]
cmd = [gradle, f":{test_module}:testClasses", "--no-build-cache", "--no-daemon"]
else:
cmd = [gradle, "testClasses", "--no-daemon"]
cmd = [gradle, "testClasses", "--no-build-cache", "--no-daemon"]
cmd.extend(["--init-script", _get_skip_validation_init_script()])

logger.debug("Compiling tests: %s in %s", " ".join(cmd), build_root)
Expand All @@ -528,9 +528,9 @@ def compile_source_only(
return subprocess.CompletedProcess(args=["gradle"], returncode=-1, stdout="", stderr="Gradle not found")

if test_module:
cmd = [gradle, f":{test_module}:classes", "--no-daemon"]
cmd = [gradle, f":{test_module}:classes", "--no-build-cache", "--no-daemon"]
else:
cmd = [gradle, "classes", "--no-daemon"]
cmd = [gradle, "classes", "--no-build-cache", "--no-daemon"]
cmd.extend(["--init-script", _get_skip_validation_init_script()])

logger.debug("Compiling source only: %s in %s", " ".join(cmd), build_root)
Expand Down Expand Up @@ -574,7 +574,7 @@ def _get_classpath_uncached(
else:
task = "codeflashPrintClasspath"

cmd = [gradle, "--init-script", init_script_path, task, "-q", "--no-daemon"]
cmd = [gradle, "--init-script", init_script_path, task, "-q", "--no-build-cache", "--no-daemon"]

logger.debug("Getting classpath: %s", " ".join(cmd))

Expand Down Expand Up @@ -725,7 +725,7 @@ def run_tests_via_build_tool(
with os.fdopen(init_fd, "w", encoding="utf-8") as f:
f.write(init_script_content)

cmd = [gradle, task, "--no-daemon", "--rerun", "--init-script", init_path]
cmd = [gradle, task, "--no-build-cache", "--no-daemon", "--rerun", "--init-script", init_path]
cmd.extend(["--init-script", _get_skip_validation_init_script()])

# --continue ensures Gradle keeps going even if some tests fail.
Expand Down Expand Up @@ -952,7 +952,7 @@ def get_test_run_command(self, project_root: Path, test_classes: list[str] | Non
raise ValueError(msg)

gradle = self.find_executable(project_root) or "gradle"
cmd = [gradle, "test", "--no-daemon"]
cmd = [gradle, "test", "--no-build-cache", "--no-daemon"]
if test_classes:
for cls in test_classes:
cmd.extend(["--tests", cls])
Expand Down
61 changes: 51 additions & 10 deletions codeflash/languages/java/instrumentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,17 +391,50 @@ def wrap_target_calls_with_treesitter(
line_char_start = call["_line_char_start"]

if precise_call_timing:
prefix_lines = [
f"{line_indent_str}Object {var_name} = null;",
# For embedded calls, the original line uses the captured variable inline
# (e.g., builder().model("x") becomes _cf_result.model("x")).
# Using `Object` loses the type and breaks method chaining (builder pattern).
# Fix: use `var` to capture with type inference inside the try block, and
# move the original line (with call replaced) INTO the try block so the
# `var`-typed variable is in scope. A separate Object variable handles
# serialization in the finally block.
#
# Generated structure:
# Object _cf_obj = null;
# try {
# var _cf_result = targetCall();
# _cf_obj = _cf_result;
# serialize(_cf_obj);
# <original line with call replaced by _cf_result>
# } finally { ... }
obj_var = f"_cf_obj{iter_id}_{call_counter}"
typed_capture = f"var {var_name} = {call['full_call']};"
obj_assign = f"{obj_var} = {var_name};"
typed_serialize = f"_cf_serializedResult{iter_id}_{call_counter} = com.codeflash.Serializer.serialize((Object) {var_name});"

# Step 1: Replace the call in the original line with the typed var
modified_line_text = body_text[line_char_start:]
# Adjust offsets relative to line start
rel_call_start = call_start - line_char_start
rel_call_end = call_end - line_char_start
modified_line_text_before_eol = modified_line_text.split("\n", 1)
orig_line_text = modified_line_text_before_eol[0]
# Replace the call within the original line
orig_line_with_var = orig_line_text[:rel_call_start] + var_name + orig_line_text[rel_call_end:]

pre_lines = [
f"{line_indent_str}Object {obj_var} = null;",
f"{line_indent_str}long _cf_end{iter_id}_{call_counter} = -1;",
f"{line_indent_str}long _cf_start{iter_id}_{call_counter} = 0;",
f"{line_indent_str}byte[] _cf_serializedResult{iter_id}_{call_counter} = null;",
f'{line_indent_str}System.out.println("!$######" + _cf_mod{iter_id} + ":" + _cf_cls{iter_id} + "." + _cf_test{iter_id} + ":" + _cf_fn{iter_id} + ":" + _cf_loop{iter_id} + ":{inv_id}" + "######$!");',
f"{line_indent_str}try {{",
f"{line_indent_str} {start_stmt}",
f"{line_indent_str} {capture_stmt_assign}",
f"{line_indent_str} {typed_capture}",
f"{line_indent_str} {end_stmt}",
f"{line_indent_str} {serialize_stmt}",
f"{line_indent_str} {obj_assign}",
f"{line_indent_str} {typed_serialize}",
f"{line_indent_str} {orig_line_with_var.strip()}",
]
finally_lines = _generate_sqlite_write_code(
iter_id,
Expand All @@ -412,15 +445,23 @@ def wrap_target_calls_with_treesitter(
test_method_name,
invocation_id=inv_id,
)
prefix_lines.extend(finally_lines)
pre_lines.extend(finally_lines)

# Replace the entire original line with the instrumented block
# Find the end of the original line
next_newline = body_text.find("\n", line_char_start)
if next_newline == -1:
next_newline = len(body_text)
replacement_text = "\n".join(pre_lines)
body_text = body_text[:line_char_start] + replacement_text + body_text[next_newline:]
else:
prefix_lines = [f"{line_indent_str}{capture_stmt_with_decl}", f"{line_indent_str}{serialize_stmt}"]

# Step 1: Replace the call with the variable (at higher offset, safe to do first)
body_text = body_text[:call_start] + var_with_cast + body_text[call_end:]
# Step 2: Insert prefix lines before the line containing the call (at lower offset)
prefix_text = "\n".join(prefix_lines) + "\n"
body_text = body_text[:line_char_start] + prefix_text + body_text[line_char_start:]
# Step 1: Replace the call with the variable (at higher offset, safe to do first)
body_text = body_text[:call_start] + var_with_cast + body_text[call_end:]
# Step 2: Insert prefix lines before the line containing the call (at lower offset)
prefix_text = "\n".join(prefix_lines) + "\n"
body_text = body_text[:line_char_start] + prefix_text + body_text[line_char_start:]

# Split back into lines, filtering out any lines that became empty from statement replacement
wrapped = [line for line in body_text.split("\n") if line.strip()]
Expand Down
1 change: 1 addition & 0 deletions codeflash/languages/java/maven_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"-Derrorprone.skip=true",
"-Dmaven.compiler.failOnWarning=false",
"-Dmaven.compiler.showWarnings=false",
"-Dmaven.build.cache.enabled=false",
]

# Cache for classpath strings — keyed on (maven_root, test_module).
Expand Down
7 changes: 4 additions & 3 deletions tests/test_languages/test_java/test_instrumentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,18 @@ def test_instrument_behavior_mode_simple(self, tmp_path: Path):
if (_cf_testIteration1 == null) _cf_testIteration1 = "0";
String _cf_test1 = "testAdd";
Calculator calc = new Calculator();
Object _cf_result1_1 = null;
Object _cf_obj1_1 = null;
long _cf_end1_1 = -1;
long _cf_start1_1 = 0;
byte[] _cf_serializedResult1_1 = null;
System.out.println("!$######" + _cf_mod1 + ":" + _cf_cls1 + "." + _cf_test1 + ":" + _cf_fn1 + ":" + _cf_loop1 + ":L11_1" + "######$!");
try {
_cf_start1_1 = System.nanoTime();
_cf_result1_1 = calc.add(2, 2);
var _cf_result1_1 = calc.add(2, 2);
_cf_end1_1 = System.nanoTime();
_cf_obj1_1 = _cf_result1_1;
_cf_serializedResult1_1 = com.codeflash.Serializer.serialize((Object) _cf_result1_1);
assertEquals(4, _cf_result1_1);
} finally {
long _cf_end1_1_finally = System.nanoTime();
long _cf_dur1_1 = (_cf_end1_1 != -1 ? _cf_end1_1 : _cf_end1_1_finally) - _cf_start1_1;
Expand Down Expand Up @@ -189,7 +191,6 @@ def test_instrument_behavior_mode_simple(self, tmp_path: Path):
}
}
}
assertEquals(4, _cf_result1_1);
}
}
"""
Expand Down
Loading