Skip to content

Fix crashes on enum methods, varargs calls and calls on a call result - #420

Merged
CatarinaGamboa merged 3 commits into
mainfrom
fix/enum-methods-external-checker
Oct 24, 2026
Merged

CatarinaGamboa merged 3 commits into
mainfrom
fix/enum-methods-external-checker

Conversation

@CatarinaGamboa

Copy link
Copy Markdown
Collaborator

Three crashes on ordinary Java code, met together in one real class (JabRef's EditAction). One commit each.

1. An enum with a method crashes the verifier

enum Action { UNDO, REDO; String getText() { return name(); } }
NullPointerException: Cannot invoke "String.endsWith(String)" because "qualifiedName" is null
  at ExternalRefinementTypeChecker.visitCtMethod

ExternalRefinementTypeChecker skips classes and records (user code) but not enums, so it visits the enum's methods with no external target. Fix: a no-op visitCtEnum, as for records.

2. A varargs call with more arguments than parameters

void debug(String format, Object... args) {}
logger.debug("{} and {}", a, b);   // IndexOutOfBoundsException: Index 2 out of bounds for length 2

mapInvocation and checkParameters index the parameters by argument position. Fix: both use only the arguments bound one to one to parameters; the ones collected into the varargs array are left out (an array parameter's refinement is not checked per element anyway).

3. A call on the result of a call without a return refinement

holder.get().close();
// Argument Mismatch Error: Argument '#holder_14' and its respective parameter of ghost 'Door.state1'
// types are incompatible: expected Door, got Holder

When get() has no return refinement, its TARGET metadata is still its own receiver (holder), and prepareInvocationTarget used it as the receiver of close(). Fix: a call whose TARGET is not its return value (RETURN_VAR_NAME) gives a fresh receiver of the call's type, in an unknown state, created once per call (Keys.RECEIVER, as for constructor calls). Now: found true but expected open(#fresh).

Tests

  • CorrectEnumWithMethod: crashed before.
  • CorrectVarargsCall (more, fewer and an explicit array) and ErrorVarargsCall (a refined fixed parameter before the varargs is still checked): crashed before.
  • CorrectCallResultReceiver (a call with no precondition on a call result) and ErrorCallResultReceiver (reported as a state error, not an argument mismatch).
  • mvn test: 463 tests, 0 failures.

Found on a real fixed bug: JabRef's Edit command calling undo()/redo() without canUndo()/canRedo() (PR JabRef/jabref#9777). We also checked 53 exercises built from real OSS bugs on main (69895fa) and with these changes: the results are identical.

🤖 Generated with Claude Code

CatarinaGamboa and others added 3 commits October 24, 2026 23:36
ExternalRefinementTypeChecker skips classes and records (user code) but
walked into enums, whose methods have no external target: any program
declaring an enum with a method crashed with a NullPointerException
("qualifiedName" is null).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mapInvocation and checkParameters indexed the parameters by argument
position, so a varargs call with more arguments than parameters (e.g.
logger.debug("{} {}", a, b)) failed with IndexOutOfBoundsException. The
arguments collected into the varargs array are left out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In a.get().m(), when get() has no return refinement its TARGET metadata
is its own receiver (a), not the value it returns, and m() was checked
against a: "Argument Mismatch Error ... expected Door, got Holder". The
receiver is now a fresh value of get()'s type, in an unknown state,
created once per call.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@CatarinaGamboa
CatarinaGamboa force-pushed the fix/enum-methods-external-checker branch from d3f6745 to de56949 Compare October 24, 2026 22:39
@CatarinaGamboa
CatarinaGamboa merged commit b3a4e4a into main Oct 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant