Skip to content

Commit 9bb8e45

Browse files
committed
addressing the review
1 parent e995740 commit 9bb8e45

File tree

7 files changed

+64
-35
lines changed

7 files changed

+64
-35
lines changed

key.core/src/main/java/de/uka/ilkd/key/pp/FieldPrinter.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ protected static boolean isFieldConstant(Term fieldTerm, HeapLDT heapLDT) {
131131
protected static boolean isJavaFieldConstant(Term fieldTerm, HeapLDT heapLDT,
132132
Services services) {
133133
try {
134+
// the called method either returns a ProgramVariable or throws an exception
135+
// We are only interested in whether the method throws an exception or not, so we
136+
// ignore the return value.
134137
getJavaFieldConstant(fieldTerm, heapLDT, services);
135138
return true;
136139
} catch (RuntimeException e) {

key.core/src/main/java/de/uka/ilkd/key/proof/init/FinalFieldCodeValidator.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
import de.uka.ilkd.key.java.*;
1111
import de.uka.ilkd.key.java.abstraction.ClassType;
1212
import de.uka.ilkd.key.java.abstraction.KeYJavaType;
13+
import de.uka.ilkd.key.java.abstraction.Type;
1314
import de.uka.ilkd.key.java.expression.Assignment;
15+
import de.uka.ilkd.key.java.expression.operator.New;
1416
import de.uka.ilkd.key.java.reference.*;
1517
import de.uka.ilkd.key.logic.op.IProgramMethod;
1618
import de.uka.ilkd.key.logic.op.ProgramMethod;
@@ -139,8 +141,8 @@ private void validate(IProgramMethod method) {
139141
private void validateProgramElement(SyntaxElement element) {
140142
if (element instanceof MethodReference methodReference) {
141143
validateMethodReference(methodReference);
142-
} else if (element instanceof ConstructorReference constructorReference) {
143-
validateConstructorReference(constructorReference);
144+
} else if (element instanceof New _new) {
145+
validateNew(_new);
144146
} else if (element instanceof FieldReference fieldReference) {
145147
validateFieldReference(fieldReference);
146148
} else if (element instanceof Assignment assignment) {
@@ -165,18 +167,27 @@ private void validateChildren(SyntaxElement element) {
165167
/*
166168
* Constructor calls must not leak 'this' to the called constructor.
167169
*/
168-
private void validateConstructorReference(ConstructorReference methodReference) {
169-
// TODO We have to make sure that on non-static subclass is instantiated here
170+
private void validateNew(New _new) {
171+
172+
TypeReference typeRef = _new.getTypeReference();
173+
Type type = typeRef.getKeYJavaType().getJavaType();
174+
if (type instanceof ClassType classType && !classType.isStatic()) {
175+
// This also disallows things like "a.new B()" which would not like this. However,
176+
// KeY cannot deal with this anyway, so we can do the easy check here.
177+
throw new FinalViolationException(
178+
"Call to non-static inner class " + classType + " leaks 'this' to the constructor",
179+
_new);
180+
}
181+
170182
var hasThisArgument =
171-
methodReference.getArguments().stream().anyMatch(ThisReference.class::isInstance);
183+
_new.getArguments().stream().anyMatch(ThisReference.class::isInstance);
172184

173185
if (hasThisArgument) {
174186
throw new FinalViolationException(
175-
"Method call " + methodReference + " leaks 'this' to called method.",
176-
methodReference);
187+
"Method call " + _new + " leaks 'this' to called method.", _new);
177188
}
178189

179-
validateChildren(methodReference);
190+
validateChildren(_new);
180191
}
181192

182193
/*

key.core/src/main/java/de/uka/ilkd/key/proof/init/FinalFieldsPOExtension.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ public Term modifyPostTerm(AbstractOperationPO abstractPO, InitConfig proofConfi
5757
// We know this holds because of isPOSupported:
5858
FunctionalOperationContractPO fpo = (FunctionalOperationContractPO) abstractPO;
5959
IProgramMethod iconstructor = fpo.getProgramMethod();
60-
assert iconstructor instanceof ProgramMethod : "Contracts cannot have schema ";
60+
assert iconstructor instanceof ProgramMethod
61+
: "Expected a ProgramMethod not a schema variable, since we need the actual implementation";
6162
ProgramMethod constructor = (ProgramMethod) iconstructor;
6263

6364
FinalFieldCodeValidator.validateFinalFields(constructor, proofConfig);

key.core/src/main/resources/de/uka/ilkd/key/proof/rules/heap.key

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
// default value for a field
2323
alpha alpha::defaultValue;
2424

25-
// reading from final attributes (corr. to select for non-final fields)
25+
// reading from final attributes (corresponds to select for non-final fields)
2626
alpha alpha::final(Object, Field);
2727

2828
// fields

key.core/src/main/resources/de/uka/ilkd/key/proof/rules/javaRules.key

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3804,7 +3804,9 @@
38043804
\heuristics(simplify_prog, simplify_prog_subset)
38053805
\displayname "active_attribute_access"
38063806
};
3807+
}
38073808

3809+
\rules(programRules:Java, finalFields:onHeap) {
38083810
// TODO 2 variants with different taclet options
38093811
assignment_read_static_attribute {
38103812
\find(\modality{#allmodal}{.. #v0 = @(#sv); ...}\endmodality (post))
@@ -3819,7 +3821,9 @@
38193821
}
38203822
\heuristics(simplify_prog, simplify_prog_subset)
38213823
};
3824+
}
38223825

3826+
\rules(programRules:Java, finalFields:immutable) {
38233827
assignment_read_static_attribute_final {
38243828
\find(\modality{#allmodal}{.. #v0 = @(#sv); ...}\endmodality (post))
38253829
\sameUpdateLevel
@@ -3833,7 +3837,9 @@
38333837
}
38343838
\heuristics(simplify_prog, simplify_prog_subset)
38353839
};
3840+
}
38363841

3842+
\rules(programRules:Java) {
38373843
// constant case cannot occur as no static initilisation handling happens
38383844
assignment_read_static_attribute_with_variable_prefix {
38393845
\find(\modality{#allmodal}{.. #loc = @(#v.#sv); ...}\endmodality (post))

key.core/src/test/java/de/uka/ilkd/key/pp/FinalPrinterTest.java

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import java.io.File;
77
import java.net.URL;
88
import java.util.List;
9-
import java.util.stream.Stream;
109

1110
import de.uka.ilkd.key.java.Services;
1211
import de.uka.ilkd.key.logic.Choice;
@@ -18,8 +17,7 @@
1817
import org.junit.jupiter.api.AfterAll;
1918
import org.junit.jupiter.api.BeforeAll;
2019
import org.junit.jupiter.params.ParameterizedTest;
21-
import org.junit.jupiter.params.provider.Arguments;
22-
import org.junit.jupiter.params.provider.MethodSource;
20+
import org.junit.jupiter.params.provider.CsvSource;
2321

2422
import static org.junit.jupiter.api.Assertions.assertEquals;
2523
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -45,18 +43,15 @@ public static void tearDown() {
4543
io = null;
4644
}
4745

48-
public static Stream<Arguments> casesWithFinal() {
49-
return Stream.of(
50-
Arguments.of("int::select(heap, self, C::$f)", "self.f"),
51-
Arguments.of("int::select(heap, self, C::$finf)", "int::select(heap, self, C::$finf)"),
52-
Arguments.of("int::final(sub, Csub::$finf)", "sub.finf"),
53-
Arguments.of("int::final(sub, C::$finf)", "sub.(C::finf)"),
54-
Arguments.of("int::final(self, C::$finf)", "self.finf"),
55-
Arguments.of("int::final(sub, C::$finf)", "sub.(C::finf)"));
56-
}
57-
5846
@ParameterizedTest(name = "{0} => {1}")
59-
@MethodSource("casesWithFinal")
47+
@CsvSource(delimiter = ';', textBlock = """
48+
int::select(heap, self, C::$f); self.f
49+
int::select(heap, self, C::$finf); int::select(heap, self, C::$finf)
50+
int::final(sub, Csub::$finf); sub.finf
51+
int::final(sub, C::$finf); sub.(C::finf)
52+
int::final(self, C::$finf); self.finf
53+
int::final(sub, C::$finf); sub.(C::finf)
54+
""")
6055
public void testPPWithFinal(String termString, String expected) throws Exception {
6156
services.getProof().getSettings().getChoiceSettings()
6257
.updateWith(List.of(PrettyPrinterRoundtripTest.WITH_FINAL));
@@ -68,18 +63,14 @@ public void testPPWithFinal(String termString, String expected) throws Exception
6863
assertEquals(expected, printed);
6964
}
7065

71-
public static Stream<Arguments> casesWithoutFinal() {
72-
return Stream.of(
73-
Arguments.of("int::final(sub, Csub::$finf)", "sub.finf"),
74-
Arguments.of("int::final(sub, C::$finf)", "sub.(C::finf)"),
75-
Arguments.of("int::final(self, C::$finf)", "self.finf"),
76-
Arguments.of("int::select(heap, self, C::$f)", "self.f"),
77-
Arguments.of("int::select(heap, self, C::$finf)", "self.finf"));
78-
}
79-
80-
8166
@ParameterizedTest(name = "{0} => {1}")
82-
@MethodSource("casesWithoutFinal")
67+
@CsvSource(delimiter = ';', textBlock = """
68+
int::final(sub, Csub::$finf); sub.finf
69+
int::final(sub, C::$finf); sub.(C::finf)
70+
int::final(self, C::$finf); self.finf
71+
int::select(heap, self, C::$f); self.f
72+
int::select(heap, self, C::$finf); self.finf
73+
""")
8374
public void testPPWithoutFinal(String termString, String expected) throws Exception {
8475
services.getProof().getSettings().getChoiceSettings()
8576
.updateWith(List.of(PrettyPrinterRoundtripTest.WITHOUT_FINAL));

key.ui/src/main/resources/de/uka/ilkd/key/gui/help/choiceExplanations.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,5 +231,22 @@ Treatment of formulas and terms for welldefinedness checks:
231231
<entry key="wdChecks">
232232
Welldefinedness checks of JML specifications can be turned on/off. This includes class invariants, operation contracts, model fields as well as JML (annotation) statements as loop invariants and block contracts. The former ones are checked "on-the-fly", i.e., directly when they are applied in the code while proving an operation contract, since the context is needed.
233233
</entry>
234+
235+
<entry key="finalFields">
236+
Final fields can only be written to from within the constructor. This is a
237+
Java language feature. KeY can exploit this restriction by treating final fields
238+
as immutable. This can simplify the reasoning about the program significantly.
239+
But it is still possible to tread final fields as normal mutable fields to
240+
ensure backward compatibility. If constructor code is to be inlined, there
241+
can be cases where the immutable treatment is incomplete.
242+
243+
immutable:
244+
Final fields are treated as immutable entities.
245+
This is the default option.
246+
247+
onHeap:
248+
Final fields are treated like all Java fields.
249+
This is the original behaviour of KeY.
250+
</entry>
234251
</properties>
235252

0 commit comments

Comments
 (0)