Skip to content

Commit b99d9b6

Browse files
authored
Fix finalFields default in FinalHeapResolution.isFinalEnabled (#3895)
2 parents 62aed4c + 55242fa commit b99d9b6

2 files changed

Lines changed: 69 additions & 1 deletion

File tree

key.core/src/main/java/de/uka/ilkd/key/ldt/FinalHeapResolution.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,17 @@ public static boolean isFinalEnabled(InitConfig initConfig) {
4848
* @return true if final fields are treated as immutable
4949
*/
5050
public static boolean isFinalEnabled(ProofSettings settings) {
51+
// When the finalFields choice is absent from the settings (e.g. a freshly
52+
// created environment, or settings that predate this option), the taclet base
53+
// still activates the *declaration default* of the category. That default is
54+
// the first option listed in optionsDeclarations.key, which is "immutable"
55+
// (see ChoiceFinder#visitChoice, which uses choices.getFirst()). Falling back
56+
// to onHeap here would contradict the rules actually applied during symbolic
57+
// execution and produce an inconsistent mix of final(o, f) and
58+
// select(heap, o, f) for the very same field. The fallback must therefore
59+
// match the declaration default.
5160
return settings.getChoiceSettings().getDefaultChoices()
52-
.getOrDefault(SETTING, "")
61+
.getOrDefault(SETTING, IMMUTABLE_OPTION)
5362
.equals(IMMUTABLE_OPTION);
5463
}
5564

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/* This file is part of KeY - https://key-project.org
2+
* KeY is licensed under the GNU General Public License Version 2
3+
* SPDX-License-Identifier: GPL-2.0-only */
4+
package de.uka.ilkd.key.ldt;
5+
6+
import java.util.TreeMap;
7+
8+
import de.uka.ilkd.key.settings.ProofSettings;
9+
10+
import org.junit.jupiter.api.Test;
11+
12+
import static org.junit.jupiter.api.Assertions.assertFalse;
13+
import static org.junit.jupiter.api.Assertions.assertTrue;
14+
15+
/**
16+
* Tests for {@link FinalHeapResolution#isFinalEnabled(ProofSettings)}.
17+
*
18+
* <p>
19+
* In particular this pins down that an <em>absent</em> {@code finalFields} choice is resolved to
20+
* the declaration default {@code immutable} (the first option in the category, see
21+
* {@code optionsDeclarations.key} and {@code ChoiceFinder#visitChoice}). If it were resolved to
22+
* {@code onHeap} instead, the setting would disagree with the taclets that symbolic execution
23+
* actually applies, and reads of a final field would appear both as {@code final(o, f)} (from the
24+
* taclet base) and as {@code select(heap, o, f)} (from JML translation), which blocks otherwise
25+
* closable proofs.
26+
* </p>
27+
*/
28+
class FinalHeapResolutionTest {
29+
30+
private static final String FINAL_FIELDS = "finalFields";
31+
32+
private static ProofSettings settingsWith(String finalFieldsValue) {
33+
ProofSettings settings = new ProofSettings(ProofSettings.DEFAULT_SETTINGS);
34+
var choices = new TreeMap<>(settings.getChoiceSettings().getDefaultChoices());
35+
if (finalFieldsValue == null) {
36+
choices.remove(FINAL_FIELDS);
37+
} else {
38+
choices.put(FINAL_FIELDS, finalFieldsValue);
39+
}
40+
settings.getChoiceSettings().setDefaultChoices(choices);
41+
return settings;
42+
}
43+
44+
@Test
45+
void absentChoiceDefaultsToImmutable() {
46+
assertTrue(FinalHeapResolution.isFinalEnabled(settingsWith(null)),
47+
"an absent finalFields choice must resolve to the declaration default 'immutable'");
48+
}
49+
50+
@Test
51+
void explicitImmutableIsEnabled() {
52+
assertTrue(FinalHeapResolution.isFinalEnabled(settingsWith("finalFields:immutable")));
53+
}
54+
55+
@Test
56+
void explicitOnHeapIsDisabled() {
57+
assertFalse(FinalHeapResolution.isFinalEnabled(settingsWith("finalFields:onHeap")));
58+
}
59+
}

0 commit comments

Comments
 (0)