Skip to content

Commit ddead1b

Browse files
renames and add if null
1 parent 0687906 commit ddead1b

3 files changed

Lines changed: 27 additions & 4 deletions

File tree

liquidjava-example/src/main/java/testSuite/classes/resultset_forward_correct/ResultSetTests.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,13 @@ float readAverage(Connection conn) throws SQLException {
6363
}
6464
}
6565

66-
float readAverage2(Connection conn) throws SQLException {
66+
float readAverageStoredCondition(Connection conn) throws SQLException {
6767
Statement parentstmt = conn.createStatement();
6868
ResultSet parentMessage =
6969
parentstmt.executeQuery("SELECT SUM(IMPORTANCE) AS IMPAVG FROM MAIL");
70-
// FIX (from accepted answer): parentMessage.next();
71-
// VIOLATION: cursor is before the first row; getFloat() with no next().
70+
// Regression for issue #241: next()'s result is stored in a boolean before the `if`.
71+
// The transition (_ ? onRow : endRows) must still flow through `b`, so the guarded
72+
// getFloat() is on a row (onRow) and verifies — exactly as the inline readAverage above.
7273
boolean b = parentMessage.next();
7374
if( b ) {
7475
float avgsum = parentMessage.getFloat("IMPAVG");

liquidjava-example/src/main/java/testSuite/classes/resultset_forward_error/ResultSetTests.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,18 @@ float readAverage(Connection conn) throws SQLException {
6868
return avgsum;
6969
}
7070

71-
// Branch-sensitive: legal in the then-branch (onRow), illegal in the else-branch (endRows).
71+
// Issue #241 soundness: storing next()'s result in a boolean must NOT make getFloat()
72+
// unconditionally legal. With no guard the state is `next ? onRow : endRows`, so onRow is
73+
// not guaranteed and getFloat() must still be rejected.
74+
float readAverageStoredNoGuard(Connection conn) throws SQLException {
75+
Statement parentstmt = conn.createStatement();
76+
ResultSet parentMessage = parentstmt.executeQuery("SELECT SUM(IMPORTANCE) AS IMPAVG FROM MAIL");
77+
boolean b = parentMessage.next();
78+
float avgsum = parentMessage.getFloat("IMPAVG"); // State Refinement Error
79+
return avgsum;
80+
}
81+
82+
// Issue #241 branch-sensitivity: legal in the then-branch (onRow), illegal in the else-branch (endRows).
7283
float readAverageVarElse(Connection conn) throws SQLException {
7384
Statement parentstmt = conn.createStatement();
7485
ResultSet parentMessage = parentstmt.executeQuery("SELECT SUM(IMPORTANCE) AS IMPAVG FROM MAIL");

liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/RefinementTypeChecker.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,10 @@ private <T> boolean tryStaticFinalConstantRefinement(CtFieldRead<T> fieldRead) {
321321
public <T> void visitCtVariableRead(CtVariableRead<T> variableRead) {
322322
super.visitCtVariableRead(variableRead);
323323
CtVariable<T> varDecl = variableRead.getVariable().getDeclaration();
324+
// Some CtVariableRead forms have no resolvable declaration (e.g. accesses to symbols outside the
325+
// model); with no name there is no context entry to attach, so leave the metadata as-is.
326+
if (varDecl == null)
327+
return;
324328
getPutVariableMetadata(variableRead, varDecl.getSimpleName());
325329
}
326330

@@ -539,8 +543,15 @@ private Predicate getAssignmentRefinement(String name, CtExpression<?> assignmen
539543

540544
private Predicate getExpressionRefinements(CtExpression<?> element) throws LJError {
541545
if (element instanceof CtFieldRead<?>) {
546+
// CtFieldRead is a subtype of CtVariableRead and MUST be matched first: field reads (including
547+
// the array pseudo-field `.length`, whose declaration is null) are handled by visitCtFieldRead
548+
// during the surrounding scan, so here we just read the metadata it already set.
542549
return getRefinement(element);
543550
} else if (element instanceof CtVariableRead<?> varRead) {
551+
// Visit the read so its metadata becomes `_ == <last instance>`, linking the variable to the
552+
// instance that carries its refinement (e.g. a stored method result). Without this, `if (b)`
553+
// looks refinement-free and is treated as uninformative, dropping the typestate that b's
554+
// defining call established (#241).
544555
visitCtVariableRead(varRead);
545556
return getRefinement(element);
546557
} else if (element instanceof CtBinaryOperator<?>) {

0 commit comments

Comments
 (0)