Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4c36ba7
introducing infrastructure for final values w/o select.
mattulbrich Jul 6, 2024
11539db
adding taclets for wellformedness of final fields
mattulbrich Jul 6, 2024
8ebaa61
soundness bugfix for final values
mattulbrich Jul 6, 2024
d4f7ec0
introducing a taclet option for the new final field mechanism
mattulbrich Jul 6, 2024
79a50da
more general way to respect taclet options for final fields
mattulbrich Jul 6, 2024
bbafd0f
adapt rule for new syntax
mattulbrich Jul 6, 2024
d928eb0
Add pretty printing for final fields
mattulbrich Jul 6, 2024
82e1aad
set statements may also assign to final fields
mattulbrich Jul 6, 2024
44d8634
spotlessing ...
mattulbrich Jul 7, 2024
80c9112
Merge remote-tracking branch 'origin/main' into newFinalHeaps
mattulbrich Aug 25, 2024
ea6e9ca
towards final heaps with static analysis
mattulbrich Aug 27, 2024
e46b239
final field code validator and tests
mattulbrich Dec 10, 2024
9bae13f
cleaning up towards PR
mattulbrich Dec 10, 2024
0c991b0
documentation, towards PR
mattulbrich Dec 10, 2024
ae9ea9b
spotlessing
mattulbrich Dec 10, 2024
c647495
mostly fixing the prettyprinting and parsing problem
mattulbrich Dec 10, 2024
aa749dd
test cases for pp and parsing, mainly wrt. final fields
mattulbrich Dec 13, 2024
c3a28ef
repairing failing test cases
mattulbrich Dec 13, 2024
3af8775
more automation for finals in constructors
mattulbrich Dec 13, 2024
7c81700
repairing test cases
mattulbrich Dec 13, 2024
491cfca
Merge remote-tracking branch 'origin/main' into newFinalHeaps
mattulbrich Dec 13, 2024
f88dd46
Merge remote-tracking branch 'origin/main' into newFinalHeaps
mattulbrich Dec 20, 2024
dad8aca
adding two rules for final fields.
mattulbrich Dec 20, 2024
d99efd2
applying spotless
mattulbrich Dec 20, 2024
da84fda
making non-final fields in interfaces possible
mattulbrich Dec 21, 2024
3e8fbbd
changing one rule for final fields
mattulbrich Jan 20, 2025
27f1584
enabling static final fields
mattulbrich Jan 20, 2025
e921c72
make information flow examples use traditional final treatment.
mattulbrich Feb 22, 2025
e137c77
Merge remote-tracking branch 'origin/main' into newFinalHeaps
mattulbrich Feb 23, 2025
2f599d3
cleaning up code for upcoming review.
mattulbrich Feb 23, 2025
e995740
taking static final fields into account for createdness proofs.
mattulbrich Feb 26, 2025
9bb8e45
addressing the review
mattulbrich Feb 28, 2025
fe0954a
adding missing rule for final static fields
mattulbrich Mar 1, 2025
d35ef21
repairing the check of inner class constructor calls and updating tes…
mattulbrich Mar 3, 2025
aa0f53e
improving error feedback (though the info is not present anyway)
mattulbrich Mar 5, 2025
c14cabc
Merge branch 'main' into newFinalHeaps
WolframPfeifer Mar 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import de.uka.ilkd.key.logic.TermFactory;
import de.uka.ilkd.key.logic.label.FormulaTermLabel;
import de.uka.ilkd.key.logic.label.TermLabel;
import de.uka.ilkd.key.logic.op.ProgramVariable;
import de.uka.ilkd.key.proof.init.AbstractOperationPO;
import de.uka.ilkd.key.proof.init.InitConfig;
import de.uka.ilkd.key.proof.init.POExtension;
Expand Down Expand Up @@ -35,7 +36,9 @@ public boolean isPOSupported(ProofOblInput po) {
* {@inheritDoc}
*/
@Override
public Term modifyPostTerm(InitConfig proofConfig, Services services, Term postTerm) {
public Term modifyPostTerm(AbstractOperationPO abstractOperationPO, InitConfig proofConfig,
Services services, ProgramVariable selfTerm,
Term postTerm) {
if (SymbolicExecutionJavaProfile.isTruthValueEvaluationEnabled(proofConfig)) {
return labelPostTerm(services, postTerm);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ public interface Variable extends ProgramModelElement {
*/
boolean isFinal();

/**
* Checks if this variable is a model entity.
*
* @return <CODE>true</CODE> if this variable is a model entity, <CODE>false</CODE> otherwise.
*/
public boolean isModel();

/**
* Returns the type of this variable.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public String getProgramName() {
* Test whether the declaration is static.
*/
public boolean isStatic() {
return ((ProgramVariable) var).isStatic();
return ((ProgramVariable) programVar).isStatic();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import de.uka.ilkd.key.java.visitor.Visitor;
import de.uka.ilkd.key.logic.ProgramElementName;
import de.uka.ilkd.key.logic.op.IProgramVariable;
import de.uka.ilkd.key.logic.op.ProgramVariable;
import de.uka.ilkd.key.rule.MatchConditions;

import org.key_project.util.ExtList;
Expand Down Expand Up @@ -46,33 +47,33 @@ public class VariableSpecification extends JavaNonTerminalProgramElement
*/
protected final Type type;

protected final IProgramVariable var;
protected final IProgramVariable programVar;

public VariableSpecification() {
this(null, 0, null, null, null);
}

public VariableSpecification(IProgramVariable var) {
this(var, var.getKeYJavaType());
public VariableSpecification(IProgramVariable programVar) {
this(programVar, programVar.getKeYJavaType());
}

public VariableSpecification(IProgramVariable var, Type type) {
this(var, 0, null, type, null);
public VariableSpecification(IProgramVariable programVar, Type type) {
this(programVar, 0, null, type, null);
}


public VariableSpecification(IProgramVariable var, Expression init, Type type) {
this(var, 0, init, type, null);
public VariableSpecification(IProgramVariable programVar, Expression init, Type type) {
this(programVar, 0, init, type, null);
}

public VariableSpecification(IProgramVariable var, int dim, Expression init, Type type) {
this(var, dim, init, type, PositionInfo.UNDEFINED);
public VariableSpecification(IProgramVariable programVar, int dim, Expression init, Type type) {
this(programVar, dim, init, type, PositionInfo.UNDEFINED);
}

public VariableSpecification(IProgramVariable var, int dim, Expression init, Type type,
public VariableSpecification(IProgramVariable programVar, int dim, Expression init, Type type,
PositionInfo pi) {
super(pi);
this.var = var;
this.programVar = programVar;
this.initializer = init;
this.dimensions = dim;
this.type = type;
Expand All @@ -86,9 +87,10 @@ public VariableSpecification(IProgramVariable var, int dim, Expression init, Typ
* (as initializer of the variable) a Comment
* @param dim the dimension of this type
*/
public VariableSpecification(ExtList children, IProgramVariable var, int dim, Type type) {
public VariableSpecification(ExtList children, IProgramVariable programVar, int dim,
Type type) {
super(children);
this.var = var;
this.programVar = programVar;
initializer = children.get(Expression.class);
dimensions = dim;
this.type = type;
Expand All @@ -102,7 +104,7 @@ public VariableSpecification(ExtList children, IProgramVariable var, int dim, Ty
*/
public int getChildCount() {
int result = 0;
if (var != null) {
if (programVar != null) {
result++;
}
if (initializer != null) {
Expand All @@ -119,9 +121,9 @@ public int getChildCount() {
* @throws ArrayIndexOutOfBoundsException if <tt>index</tt> is out of bounds
*/
public ProgramElement getChildAt(int index) {
if (var != null) {
if (programVar != null) {
if (index == 0) {
return var;
return programVar;
}
index--;
}
Expand Down Expand Up @@ -169,7 +171,7 @@ public Expression getExpressionAt(int index) {
* @return the string.
*/
public final String getName() {
return (var == null) ? null : var.name().toString();
return (programVar == null) ? null : programVar.name().toString();
}

/**
Expand All @@ -178,10 +180,10 @@ public final String getName() {
* @return the name.
*/
public ProgramElementName getProgramElementName() {
if (var.name() instanceof ProgramElementName) {
return (ProgramElementName) var.name();
if (programVar.name() instanceof ProgramElementName) {
return (ProgramElementName) programVar.name();
} else {
return new ProgramElementName(var.name().toString()); // only with SVs
return new ProgramElementName(programVar.name().toString()); // only with SVs
}
}

Expand All @@ -192,7 +194,7 @@ public ProgramElementName getProgramElementName() {
* @return the program variable.
*/
public IProgramVariable getProgramVariable() {
return var;
return programVar;
}


Expand Down Expand Up @@ -220,8 +222,19 @@ public boolean hasInitializer() {
}

public boolean isFinal() {
LOGGER.warn("Method in Variable Specification not implemented!");
return false;
if (programVar instanceof ProgramVariable pv) {
return pv.isFinal();
}
// This used to return always false.
throw new UnsupportedOperationException("Cannot determine finality of " + programVar);
}

public boolean isModel() {
if (programVar instanceof ProgramVariable pv) {
return pv.isModel();
}
// This used to return always false.
throw new UnsupportedOperationException("Cannot determine finality of " + programVar);
}


Expand All @@ -235,15 +248,15 @@ public String getFullName() {

@Override
public SourceElement getFirstElement() {
return var;
return programVar;
}

@Override
public SourceElement getLastElement() {
if (initializer != null) {
return initializer.getLastElement();
} else {
return var;
return programVar;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ private void transformFieldDecl(TextualJMLFieldDecl decl, Comment[] originalComm
public boolean isStatic() {
return false;
}

@Override
public boolean isFinal() {
return ((FieldDeclaration) old).getModifiers()
.contains(JMLModifier.FINAL);
}
};
fieldDecl.setStartPosition(old.getStartPosition());
fieldDecl.setEndPosition(old.getEndPosition());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/* This file is part of KeY - https://key-project.org
* KeY is licensed under the GNU General Public License Version 2
* SPDX-License-Identifier: GPL-2.0-only */
package de.uka.ilkd.key.ldt;

import de.uka.ilkd.key.proof.init.InitConfig;
import de.uka.ilkd.key.settings.ProofSettings;

import org.jspecify.annotations.NonNull;


/**
* A little helper class to resolve the settings for treatment of final fields.
*
* During the generation of {@link de.uka.ilkd.key.proof.init.ProofOblInput}s, we need to know
* which final-treatment is activated. Also during translation from JML to JavaDL this is needed.
* Unfortunately, the settings are not directly available everywhere, so there is a mechanism to
* remember the setting while it is available in a thread-local variable. This class provides a
* simple interface to access this boolean variable.
*
* The alternative would be to make the settings available at more spots ...
*
* @author Mattias Ulbrich
*/
public class FinalHeapResolution {

private static final ThreadLocal<Boolean> finalEnabledVariable = new ThreadLocal<>();
private static final String SETTING = "finalFields";
private static final String IMMUTABLE_OPTION = SETTING + ":immutable";

/**
* Returns whether final fields are treated different from normal fields as immutable data.
*
* If initConfig does not have settings yet, the default settings are used.
*
* @param initConfig the configuration to read the settings from
* @return true if final fields are treated as immutable
*/
public static boolean isFinalEnabled(@NonNull InitConfig initConfig) {
ProofSettings settings = initConfig.getSettings();
if (settings == null) {
settings = new ProofSettings(ProofSettings.DEFAULT_SETTINGS);
}
return isFinalEnabled(settings);
}

/**
* Returns whether final fields are treated different from normal fields as immutable data.
*
* @param settings the settings to read the settings from
* @return true if final fields are treated as immutable
*/
public static boolean isFinalEnabled(@NonNull ProofSettings settings) {
return settings.getChoiceSettings().getDefaultChoices().get(SETTING)
.equals(IMMUTABLE_OPTION);
}

/**
* Remembers if final fields are treated differently from normal fields as immutable flag
* in a thread-local variable that can be recalled later using {@link #recallIsFinalEnabled()}.
*
* @param initConfig the configuration to read the settings from
*/
public static void rememberIfFinalEnabled(InitConfig initConfig) {
finalEnabledVariable.set(isFinalEnabled(initConfig));
}

/**
* Recall a previously stored status regarding the treatment of final fields.
* See {@link #rememberIfFinalEnabled(InitConfig)}.
*
* @return true if final fields are treated as immutable (as recorded earlier)
* @throws IllegalStateException if the variable has not been set before
*/

public static boolean recallIsFinalEnabled() {
Boolean bool = finalEnabledVariable.get();
if (bool == null) {
throw new IllegalStateException("Unset final enabled variable");
}
return bool.booleanValue();
}
}
29 changes: 28 additions & 1 deletion key.core/src/main/java/de/uka/ilkd/key/ldt/HeapLDT.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.key_project.util.collection.ImmutableList;
import org.key_project.util.collection.ImmutableSLList;

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;


Expand All @@ -41,6 +42,7 @@ public final class HeapLDT extends LDT {

public static final Name SELECT_NAME = new Name("select");
public static final Name STORE_NAME = new Name("store");
public static final Name FINAL_NAME = new Name("final");
public static final Name BASE_HEAP_NAME = new Name("heap");
public static final Name SAVED_HEAP_NAME = new Name("savedHeap");
public static final Name PERMISSION_HEAP_NAME = new Name("permissions");
Expand All @@ -54,6 +56,7 @@ public final class HeapLDT extends LDT {

// select/store
private final SortDependingFunction select;
private final SortDependingFunction finalFunction;
private final JFunction store;
private final JFunction create;
private final JFunction anon;
Expand Down Expand Up @@ -96,7 +99,8 @@ public HeapLDT(TermServices services) {

fieldSort = sorts.lookup(new Name("Field"));
select = addSortDependingFunction(services, SELECT_NAME.toString());
store = addFunction(services, "store");
finalFunction = addSortDependingFunction(services, FINAL_NAME.toString());
store = addFunction(services, STORE_NAME.toString());
create = addFunction(services, "create");
anon = addFunction(services, "anon");
memset = addFunction(services, "memset");
Expand Down Expand Up @@ -233,6 +237,29 @@ public SortDependingFunction getSelect(Sort instanceSort, TermServices services)
return select.getInstanceFor(instanceSort, services);
}

/**
* Returns the function symbol to access final fields for the given instance sort.
*
* @param instanceSort the sort of the value to be read
* @param services the services to find/create the sort-depending function
* @return the function symbol to access final fields for the given instance sort
*/
public @NonNull SortDependingFunction getFinal(@NonNull Sort instanceSort,
@NonNull Services services) {
return finalFunction.getInstanceFor(instanceSort, services);
}

/**
* Check if the given operator is an instance of the "final" function to access final fields.
*
* @param op the operator to check
* @return true if the operator is an instance of the "X::final" srot-depending function
*/
public boolean isFinalOp(Operator op) {
return op instanceof SortDependingFunction
&& ((SortDependingFunction) op).isSimilar(finalFunction);
}


/**
* If the passed operator is an instance of "select", this method returns the sort of the
Expand Down
Loading
Loading