Repository navigation
Java impact: type initializers, library-run members, field initializer after a comment - #1880
Merged
Merged
Conversation
A call written in a field initializer has no method around it, so the engine names the type as its caller, and a static or instance block is a <clinit> / <init_block> callable. Nothing calls either, so the upward walk stopped there: a factory whose `INSTANCE = new Factory()` throws breaks every test that touches the factory, and none of them was selected. impact.dl now hops from such an initializer (a type reached as a caller, or a <clinit> / <init_block>) to whoever uses the type in a way that runs it: a call to one of its members, a construction of a subtype, a read or write of one of its fields. The hop is taken only where the walk arrives at the type as a caller, never from a type or field target's own seed. Test routes through it carry a new rung, `at load`, ranked beside `at import`. The SQL fast path declines a closure that reaches such an initializer. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
`static final F X = // why
new F() { ... };` — the Java field extractor took the node right after `=` as the
initializer, and a comment is a named node in tree-sitter, so the whole initializer was
dropped: its calls, and an anonymous class it creates together with that class's methods.
A try-with-resources declaration had the same read. Both now skip comments, as a local
variable's initializer already did.
The comment-invariance twins gain a field initializer, a field holding an anonymous class
and a resource declaration; the case checks that a test reaching the anonymous class's
method through its interface is selected, beside the same shape with no comment.
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
A method query is handed the field and field-access facts empty (KIND_SKIPS: only a field or type target was thought to reach them), so the `at load` hop's field clause derived nothing and a test that touches the initialized type only by reading one of its static fields (`Factory.INSTANCE_NULL.lookup(...)`) was dropped. Both relations are now loaded for the kinds that walk the closure; every other rule that joins them also needs a relation that stays skipped for those kinds, so nothing else changes. The case gains that shape. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…lds it `equals`, `hashCode` and `toString` are run by a HashMap key, a StringBuilder, String.format, an assertion; an override of a library method (`iterator` of an Iterable, `size` of a Collection, `close`) by the for-each loop, the collection, try-with-resources. The call is written on a library receiver or not at all, and Object's members are deliberately not fanned to client overrides by the engine, so a change to one had no caller and selected no test. The protocol hop Python already has (whoever constructs the type runs its protocol members) now has Java clauses: a member named equals / hashCode / toString, or one that overrides a library method, is reached by the callers of the type's constructors and of its subtypes' constructors. Still taken only from the change itself, under the `protocol` rung. The SQL fast path declines such a target. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Java
impact --testsmisses measured against a behavioural oracle on 12 Java (Maven, JUnit 4/5) repositories, 50 sampled methods each, every one broken on entry and the suite run (truth = test files that newly fail vs a per-test baseline). Dependencies and the JDK are staged as libraries. 8 repositories were used for tuning, 4 held out and scored once at the end.Fixes
impact.dlload_hop, rungat load). A call written in a field initializer has no enclosing method, so the engine names the TYPE as its caller; a static / instance block is a<clinit>/<init_block>callable. Nothing calls either, so the upward walk stopped there: a private constructor called only fromINSTANCE = new Factory()selected 0 of 17 failing test files. The hop now goes from such an initializer (a type reached as a caller, never a type/field target's own seed) to whoever uses the type: a call to one of its members, a construction of a subtype, a read or write of one of its fields. The SQL fast path declines such a closure.KIND_SKIPShands a method query emptyfield/faccessfacts, so the field clause derived nothing (silently). Both are now loaded for method / param / var; every other rule joining them also needs a relation that stays skipped for those kinds.static final F X = // why+ newline +new F() { ... };— the field extractor took the node after=as the initializer, and a comment is a named node, so the whole initializer (and an anonymous class it creates, with its methods) was dropped. Try-with-resources had the same read. Both now skip comments, as local variables already did.protocolrung).equals/hashCode/toString, and an override of a library method (iteratorof an Iterable,sizeof a collection), are run by a HashMap, a StringBuilder, a for-each loop — never a written call on a client receiver, and the engine does not fan Object members on purpose. The protocol hop Python already has (whoever constructs the type) gains Java clauses: constructors of the type and its subtypes. Seed-only, as for Python.Each fix has a case under
tests/cases/java/that fails on the base and passes here, with a control that must not change:type-initializer-runs-for-its-users(+ a type no test touches),field-initializer-after-a-comment(+ the same shape with no comment),library-runs-the-members-it-is-given(+ a type no test constructs). The parser comment-invariance twins gain the three initializer shapes (31 vs 36 rows before, equal after).Numbers (base = integration tip)
An answer that errored counts as an empty selection (fix 3's subject had one mutant whose answer errored on the base: 71 failing files).
No subject loses recall. Per subject on tune, recall gains of +0.25, +0.15, +0.12 come from fixes 1–2, 3–4 and 1 respectively.
path(mutation pairs) 0.849 → 0.853, runtime direct callers 0.754 → 0.754 (585 targets), runtime A→C paths 399/442 unchanged, context recall@5 0.568 unchanged.Rung precision on tune:
at load0.46 (n=67),protocol0.10 (n=898, the weakest rung, kept belowone of a set).Cost, warm, interleaved A B A B on two subjects: index 24.5/30.3 s → 28.8/25.7 s and 43.4/41.1 s → 42.1/42.2 s (noise); 20 impact queries 16.4/17.4 s → 22.0/19.4 s and 74.6/71.5 s → 78.9/76.1 s (+6 to +25%, the field facts now loaded for a method query).
Suites
tests/run.py: java 343/343, typescript 269/269, javascript 307/307, python 306/306. Java engine suite with--oracle(JDK 25): 79 passed, 0 failed, on base and on the parser change; torture SKIPs on this machine (its golden is pinned to another platform IR).Still open (fewer than two repositories, or precision only)
assertThat(x.primitiveGetter()).isEqualTo(..): a call argument returning a primitive keeps every overload, so the chained assertion stays unresolved (three repositories; feedsby namerows)super()to a base no-arg constructor is not an edgepathdoes not take the at-load hop