Skip to content

Commit 3895e35

Browse files
Leave out the From note after an unspecified method body on the receiver
- No note when a method of the analyzed code with no state refinement is called on the receiver before the failing call: the verifier takes it to keep the state, which its body may still change. - "says nothing" also needs the called method to give no state through a state refinement, as to = "running(_)" does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 1fb8297 commit 3895e35

1 file changed

Lines changed: 15 additions & 2 deletions

File tree

  • liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/object_checkers

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import spoon.reflect.declaration.CtClass;
4747
import spoon.reflect.declaration.CtElement;
4848
import spoon.reflect.declaration.CtExecutable;
49+
import spoon.reflect.declaration.CtMethod;
4950
import spoon.reflect.declaration.CtVariable;
5051
import spoon.reflect.visitor.filter.TypeFilter;
5152

@@ -161,7 +162,18 @@ private boolean mayBeAliased() {
161162
return true;
162163
return scope.getElements(new TypeFilter<>(CtVariableRead.class)).stream()
163164
.filter(use -> use.getVariable().getDeclaration() == variable && mayRunBefore(use, scope))
164-
.anyMatch(use -> escapes(use, scope));
165+
.anyMatch(use -> escapes(use, scope) || callsUnspecifiedBody(use));
166+
}
167+
168+
/**
169+
* Whether {@code use} is the receiver of a call to a method of the analyzed code with no state refinement: the
170+
* verifier takes it to keep the state, which its body may still change
171+
*/
172+
private boolean callsUnspecifiedBody(CtVariableRead<?> use) {
173+
return use.getParent()instanceof CtInvocation<?> call && call != invocation && call.getTarget() == use
174+
&& call.getExecutable().getDeclaration()instanceof CtMethod<?> method && method.getBody() != null
175+
&& method.getAnnotations().stream().noneMatch(a -> a.getAnnotationType().getQualifiedName()
176+
.equals("liquidjava.specification.StateRefinement"));
165177
}
166178

167179
/**
@@ -234,7 +246,8 @@ && implies(facts.get().substituteVariable(Keys.WILDCARD, assigned.getName()), fo
234246
: Optional.empty();
235247
Predicate returned = call.returned();
236248
// a set declared without a name has a generated one, which the message does not otherwise show
237-
boolean saysNothing = found.isEmpty()
249+
// a state refinement of the method may give the value its state, as `to = "running(_)"` does
250+
boolean saysNothing = found.isEmpty() && call.function().getAllStates().stream().noneMatch(ObjectState::hasTo)
238251
&& shown.stream().noneMatch(set -> Utils.getSimpleName(set.getName()).matches(Formats.STATE_SET_NAMES))
239252
&& setsOf(List.of(returned), ghostStates).stream().noneMatch(shown::contains)
240253
&& returned.getVariableNames().stream().allMatch(Keys.WILDCARD::equals)

0 commit comments

Comments
 (0)