Skip to content

Commit 51666ee

Browse files
Write the state origin notes as Origin: line L, <call> <verb> <state>
- the call that last set the sets "makes" their state; - a call the receiver was assigned "returns" it, or "says nothing about" the sets; - the creation fact says the constructor "creates" the receiver with its state, not that it makes the current one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent bf683fa commit 51666ee

2 files changed

Lines changed: 12 additions & 11 deletions

File tree

‎liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/object_checkers/StateOrigin.java‎

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,9 @@ private Optional<String> lastSetNote(StateChange change, VariableInstance after,
237237
Optional<Predicate> facts = foundAbout(after, shownFound, changed);
238238
if (facts.isEmpty() || !implies(after.getRefinement(), facts.get()))
239239
return Optional.empty();
240-
return code(change.position()).map(code -> String.format("From: %s, last set at line %d: %s",
241-
display(facts.get(), after.getName()), change.position().getLine(), code));
240+
// the call last set these sets, so it is what makes them so
241+
return code(change.position()).map(code -> String.format("Origin: line %d, %s makes %s",
242+
change.position().getLine(), code, display(facts.get(), after.getName())));
242243
}
243244

244245
/**
@@ -251,14 +252,13 @@ private Optional<String> returnedNote(CallResult call, VariableInstance assigned
251252
Optional<String> code = code(call.position());
252253
if (code.isEmpty())
253254
return Optional.empty();
254-
String from = String.format("From: %s = %s, line %d, ", written, code.get(), call.position().getLine());
255+
String origin = String.format("Origin: line %d, %s ", call.position().getLine(), code.get());
255256
Optional<Predicate> facts = factsOn(call.returned(), Keys.WILDCARD, shown);
256257
Optional<Predicate> found = foundAbout(assigned, shownFound, shown);
257258
if (facts.isPresent())
258259
return found.isPresent()
259260
&& implies(facts.get().substituteVariable(Keys.WILDCARD, assigned.getName()), found.get())
260-
? Optional.of(from + "which returns " + display(facts.get(), Keys.WILDCARD))
261-
: Optional.empty();
261+
? Optional.of(origin + "returns " + display(facts.get(), Keys.WILDCARD)) : Optional.empty();
262262
Predicate returned = call.returned();
263263
// a set declared without a name has a generated one, which the message does not otherwise show
264264
// a state refinement of the method may give the value its state, as `to = "running(_)"` does
@@ -269,7 +269,7 @@ && setsOf(List.of(returned), ghostStates).stream().noneMatch(shown::contains)
269269
&& !hasAlias(returned.getExpression());
270270
String sets = shown.stream().map(set -> Utils.getSimpleName(set.getName()) + "(" + written + ")").sorted()
271271
.collect(Collectors.joining(", "));
272-
return saysNothing ? Optional.of(from + "which says nothing about " + sets) : Optional.empty();
272+
return saysNothing ? Optional.of(origin + "says nothing about " + sets) : Optional.empty();
273273
}
274274

275275
/**
@@ -278,7 +278,7 @@ && setsOf(List.of(returned), ghostStates).stream().noneMatch(shown::contains)
278278
* constructor only, given when the walk back to the call that last set the state broke, e.g. at a join of branches
279279
*/
280280
private Optional<String> creationNote(VariableInstance unknown, Predicate shownFound) throws LJError {
281-
DebugLog.warn("From note: no known call gives " + unknown.getName() + " its state, e.g. a join of branches");
281+
DebugLog.warn("Origin note: no known call gives " + unknown.getName() + " its state, e.g. a join of branches");
282282
if (!(invocation instanceof CtInvocation<?> call && call.getTarget()instanceof CtVariableRead<?> read
283283
&& read.getVariable().getDeclaration()instanceof CtLocalVariable<?> local
284284
&& local.getDefaultExpression()instanceof CtConstructorCall<?> constructor
@@ -292,8 +292,9 @@ private Optional<String> creationNote(VariableInstance unknown, Predicate shownF
292292
if (facts.isEmpty() || found.isEmpty() || code.isEmpty()
293293
|| !implies(found.get(), facts.get().substituteVariable(Keys.THIS, unknown.getName())))
294294
return Optional.empty();
295-
return Optional.of(String.format("From: %s is created at line %d by %s, which makes it %s", written,
296-
created.position().getLine(), code.get(), display(facts.get(), Keys.THIS)));
295+
// not "makes": a later call may have set the state again, which found no longer tells
296+
return Optional.of(String.format("Origin: line %d, %s creates %s with %s", created.position().getLine(),
297+
code.get(), written, display(facts.get(), Keys.THIS)));
297298
}
298299

299300
/**

‎liquidjava-verifier/src/test/java/liquidjava/api/tests/TestOriginNotes.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ void unrefinedParameterIsNamedWithItsMethod() {
2424

2525
@Test
2626
void stateIsTracedToTheCallThatLastSetTheSetThatIsWrong() {
27-
assertEquals(List.of("From: lockState(d) == locked, last set at line 27: d.lock()"),
27+
assertEquals(List.of("Origin: line 27, d.lock() makes lockState(d) == locked"),
2828
verify("ErrorStateHintMultipleSets.java").getMessageNotes());
2929
}
3030

3131
@Test
3232
void stateIsTracedToTheReturnRefinementOfTheCallAssigned() {
33-
assertEquals(List.of("From: task = FromReturnedTask.create(), line 27, which returns phase(task) == idle"),
33+
assertEquals(List.of("Origin: line 27, FromReturnedTask.create() returns phase(task) == idle"),
3434
verify("ErrorStateFromReturnedValue.java").getMessageNotes());
3535
}
3636

0 commit comments

Comments
 (0)