Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions key.core/src/main/antlr4/JavaKeYLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ ISARRAY:'\\isArray';
ISARRAYLENGTH:'\\isArrayLength';
ISCONSTANT: '\\isConstant';
ISENUMTYPE:'\\isEnumType';
ISENUMCONST:'\\isEnumConst';
ISINDUCTVAR:'\\isInductVar';
ISLOCALVARIABLE : '\\isLocalVariable';
ISOBSERVER : '\\isObserver';
Expand Down
1 change: 1 addition & 0 deletions key.core/src/main/antlr4/JavaKeYParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ varexpId: // weigl, 2021-03-12: This will be later just an arbitrary identifier.
| SIMPLIFY_IF_THEN_ELSE_UPDATE
| CONTAINS_ASSIGNMENT
| ISENUMTYPE
| ISENUMCONST
| ISTHISREFERENCE
| STATICMETHODREFERENCE
| ISREFERENCEARRAY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,57 +3,70 @@
* SPDX-License-Identifier: GPL-2.0-only */
package de.uka.ilkd.key.java.ast.declaration;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import de.uka.ilkd.key.java.ast.abstraction.KeYJavaType;
import de.uka.ilkd.key.java.ast.abstraction.Type;
import de.uka.ilkd.key.logic.JavaDLFieldNames;
import de.uka.ilkd.key.logic.ProgramElementName;
import de.uka.ilkd.key.logic.op.IProgramVariable;
import de.uka.ilkd.key.logic.op.ProgramVariable;

import org.key_project.util.ExtList;
import org.key_project.util.collection.ImmutableList;
import org.key_project.util.collection.ImmutableSLList;

import com.github.javaparser.ast.body.EnumConstantDeclaration;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/**
* This class is used for wrapping an enum into a standard class type.
*
* <p>
* In addition the programvariables that represent enum constants are memorized. Thus this class is
* In addition, the programvariables that represent enum constants are memorized. Thus this class is
* able to have queries on the enum constants.
*
* mulbrich: Update 2025 (a mere 19 years later):
* Updated from the old heap model to the new one.
*
* @author mulbrich
* @since 2006-12-10
* @since 2006-12-10, updated 2025-10-24 by MU
*/

@NullMarked
public class EnumClassDeclaration extends ClassDeclaration {
public record EnumEntry(String name, int ordinal, IProgramVariable variable) {
}

/**
* store the program variables which represent the enum constants
* in a lookup map from name to (ordinal index, program variable)
*/
private final List<IProgramVariable> constants = new ArrayList<>();
private final ImmutableList<EnumEntry> constants;

/**
* create a new EnumClassDeclaration that describes an enum defintion. It merely wraps a
* ClassDeclaration but has memory about which fields have been declared as enum constants.
*
* @param children
* children in the ast (members)
* @param fullName
* of the class/enum
* @param isLibrary
* see class constructor
* @param children children in the ast (members)
* @param fullName of the class/enum
* @param isLibrary see class constructor
* @param enumConstantDeclarations the declarations for the enum constants
*/
// TODO javaparser
public EnumClassDeclaration(
ExtList children, ProgramElementName fullName, boolean isLibrary
/* , List<EnumConstantDeclaration> enumConstantDeclarations */) {
ExtList children, ProgramElementName fullName, boolean isLibrary,
List<EnumConstantDeclaration> enumConstantDeclarations) {
super(children, fullName, isLibrary);

// for (EnumConstantDeclaration ecd : enumConstantDeclarations) {
// String constName = ecd.getEnumConstantSpecification().getName();
// constants.add(findAttr(constName));
// }
ImmutableList<EnumEntry> seq = ImmutableSLList.nil();
int ordinal = 0;
for (EnumConstantDeclaration ecd : enumConstantDeclarations) {
String constName = ecd.getNameAsString();
seq = seq.prepend(new EnumEntry(constName, ordinal, findAttr(constName)));
ordinal++;
}

constants = seq;
}

/*
Expand All @@ -64,11 +77,12 @@ public EnumClassDeclaration(
*
*/
private IProgramVariable findAttr(String fieldName) {
String completeName = getFullName() + JavaDLFieldNames.SEPARATOR + fieldName;
// TODO String completeName = getFullName() + JavaDLFieldNames.SEPARATOR + fieldName;
String completeName = getFullName() + "::" + fieldName;
for (int i = 0; i < members.size(); i++) {
if (members.get(i) instanceof FieldDeclaration fd) {
FieldSpecification fs = fd.getFieldSpecifications().get(0);
if (fs.getName().equals(completeName)) {
if (Objects.equals(fs.getName(), completeName)) {
return fs.getProgramVariable();
}
}
Expand All @@ -81,12 +95,7 @@ private IProgramVariable findAttr(String fieldName) {
* is pv a enum constant of THIS enum?
*/
private boolean isLocalEnumConstant(IProgramVariable pv) {
for (IProgramVariable cnst : constants) {
if (cnst.equals(pv)) {
return true;
}
}
return false;
return constants.stream().anyMatch(it -> it.variable.equals(pv));
}

/**
Expand All @@ -98,7 +107,7 @@ private boolean isLocalEnumConstant(IProgramVariable pv) {
*/
private int localIndexOf(ProgramVariable pv) {
for (int i = 0; i < constants.size(); i++) {
if (constants.get(i).equals(pv)) {
if (constants.get(i).variable.equals(pv)) {
return i;
}
}
Expand Down Expand Up @@ -142,4 +151,15 @@ public static int indexOf(ProgramVariable attribute) {
}
}


/**
* get the constant with the given name, including its ordinal index.
*
* @param fieldName the name of the enum constant
* @return a pair of (index, program variable) of the enum constant with the given name or null
* if there is no such constant
*/
public @Nullable EnumEntry getConstant(String fieldName) {
return constants.stream().filter(it -> it.name == fieldName).findAny().orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ private boolean applyManipulator(boolean negated, Object[] args,
manipulator.apply(peekTBuilder(), args, parameters, negated);
return true;
} catch (Throwable e) {
LOGGER.debug("Unexpected exception while producing variable condition", e);
return false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@

import org.key_project.prover.rules.VariableCondition;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ConstructorBasedBuilder extends AbstractConditionBuilder {

private static final Logger LOGGER = LoggerFactory.getLogger(ConstructorBasedBuilder.class);
private final Class<? extends VariableCondition> clazz;
private final boolean negationSupported;

Expand Down Expand Up @@ -54,8 +59,14 @@ public VariableCondition build(Object[] arguments, List<String> parameters, bool
return (VariableCondition) constructor.newInstance(args);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException
| IllegalArgumentException ignored) {
LOGGER.debug("Constructor " + constructor
+ " does not match the given arguments for VariableCondition " + clazz
+ ". Trying next constructor.");
}
}
throw new RuntimeException();

throw new RuntimeException(
"No matching constructor found for VariableCondition " + clazz + " with args "
+ Arrays.toString(args));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ public void apply(TacletBuilder<?> tb, Object[] arguments, List<String> paramete
public static final AbstractConditionBuilder FINAL =
new ConstructorBasedBuilder("final", FinalReferenceCondition.class, SV);
public static final AbstractConditionBuilder ENUM_CONST =
new ConstructorBasedBuilder("isEnumConst", EnumConstantCondition.class, SV);
new ConstructorBasedBuilder("isEnumConst", EnumConstantCondition.class, SORT, SV);
public static final AbstractConditionBuilder LOCAL_VARIABLE =
new ConstructorBasedBuilder("isLocalVariable", LocalVariableCondition.class, SV);
public static final AbstractConditionBuilder ARRAY_LENGTH =
Expand Down Expand Up @@ -260,8 +260,8 @@ public VariableCondition build(Object[] arguments, List<String> parameters,
return new TypeCondition((TypeResolver) arguments[0], !negated, non_null);
}
};
public static final AbstractConditionBuilder ENUM_TYPE =
new ConstructorBasedBuilder("reference", EnumTypeCondition.class, SV, SV, SV);
// public static final AbstractConditionBuilder ENUM_TYPE =
// new ConstructorBasedBuilder("reference", EnumTypeCondition.class, SV, SV, SV);
public static final AbstractConditionBuilder CONTAINS_ASSIGNMENT =
new ConstructorBasedBuilder("containsAssignment", ContainsAssignmentCondition.class, SV);
public static final AbstractConditionBuilder FIELD_TYPE =
Expand Down Expand Up @@ -377,7 +377,7 @@ public IsLabeledCondition build(Object[] arguments, List<String> parameters,
FREE_3, FREE_4, FINAL_TYPE,
FREE_5, NEW_TYPE_OF, NEW_DEPENDING_ON, FREE_LABEL_IN_VARIABLE, DIFFERENT, FINAL,
ENUM_CONST, LOCAL_VARIABLE, ARRAY_LENGTH, ARRAY, REFERENCE_ARRAY, MAY_EXPAND_METHOD_2,
MAY_EXPAND_METHOD_3, STATIC_METHOD, THIS_REFERENCE, REFERENCE, ENUM_TYPE,
MAY_EXPAND_METHOD_3, STATIC_METHOD, THIS_REFERENCE, REFERENCE, /* ENUM_TYPE, */
Comment thread
wadoon marked this conversation as resolved.
CONTAINS_ASSIGNMENT, FIELD_TYPE, STATIC_REFERENCE, DIFFERENT_FIELDS, SAME_OBSERVER,
applyUpdateOnRigid, DROP_EFFECTLESS_ELEMENTARIES, SIMPLIFY_ITE_UPDATE, SUBFORMULAS,
STATIC_FIELD, MODEL_FIELD, SUBFORMULA, DROP_EFFECTLESS_STORES, EQUAL_UNIQUE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,41 @@


import de.uka.ilkd.key.java.Services;
import de.uka.ilkd.key.java.ast.abstraction.KeYJavaType;
import de.uka.ilkd.key.java.ast.declaration.EnumClassDeclaration;
import de.uka.ilkd.key.java.ast.reference.FieldReference;
import de.uka.ilkd.key.logic.JTerm;
import de.uka.ilkd.key.logic.op.ProgramVariable;
import de.uka.ilkd.key.logic.sort.GenericSort;
import de.uka.ilkd.key.rule.VariableConditionAdapter;
import de.uka.ilkd.key.rule.inst.SVInstantiations;

import org.key_project.logic.SyntaxElement;
import org.key_project.logic.Term;
import org.key_project.logic.op.Function;
import org.key_project.logic.op.Operator;
import org.key_project.logic.op.sv.SchemaVariable;
import org.key_project.logic.sort.Sort;


/**
* ensures that the given instantiation for the schemavariable denotes a constant of an enum type.
* ensures that the given instantiation for the schema-variable denotes a constant of an enum type.
*
* @author mulbrich
* @since 2006-12-04
* @version 2006-12-11
* @version 2025-10-24 Refactored for the "new" heap model.
*/
public final class EnumConstantCondition extends VariableConditionAdapter {

private final SchemaVariable reference;
private final GenericSort typeReference;

/**
* the static reference condition checks if a suggested instantiation for a schema variable
* denotes a reference to an enum constant.
*/
public EnumConstantCondition(SchemaVariable reference) {
public EnumConstantCondition(GenericSort typeReference, SchemaVariable reference) {
this.reference = reference;
this.typeReference = typeReference;
}


Expand All @@ -41,27 +48,50 @@ public boolean check(SchemaVariable var, SyntaxElement subst, SVInstantiations s
Services services) {

if (var == reference) {
// new ObjectInspector(var).setVisible(true);
// new ObjectInspector(subst).setVisible(true);
ProgramVariable progvar;

if (subst instanceof FieldReference) {
progvar = ((FieldReference) subst).getProgramVariable();
} else if (subst instanceof JTerm && ((JTerm) subst).op() instanceof ProgramVariable) {
progvar = (ProgramVariable) ((JTerm) subst).op();
} else {
// try to find the enum constant field
EnumClassDeclaration.EnumEntry field = resolveEnumFieldConstant(subst, services);
if (field == null)
return false;
}

return EnumClassDeclaration.isEnumConstant(progvar);

// if there is such a field, check that its type is the right enum type
KeYJavaType containerType = ((ProgramVariable) field.variable()).getContainerType();
Sort typeInst = svInst.getGenericSortInstantiations().getInstantiation(typeReference);
return containerType.getSort() == typeInst;
}

return true;
}

// also used in EnumConstantValue
public static EnumClassDeclaration.EnumEntry resolveEnumFieldConstant(Object obj,
Services services) {
if (obj instanceof Term term) {
Operator op = term.op();
if (op instanceof Function func && func.isUnique()
&& func.sort() == services.getTypeConverter().getHeapLDT().getFieldSort()
&& func.name().toString().contains("::")) {
String funcName = func.name().toString();
int colon = funcName.indexOf("::$");
if (colon == -1) {
return null;
}
String sortName = funcName.substring(0, colon);
String fieldName = funcName.substring(colon + 3);
KeYJavaType kjt = services.getJavaInfo().getKeYJavaType(sortName);
if (kjt == null || !(kjt.getJavaType() instanceof EnumClassDeclaration ecd)) {
return null;
}

return ecd.getConstant(fieldName);
}
}
return null;
}



@Override
public String toString() {
return "\\enumConstant(" + reference + ")";
return "\\isEnumConst(" + typeReference + ", " + reference + ")";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@
/**
* This variable condition checks if a type is an enum type.
*
* @deprecated As of 2025, this varcond is no longer needed, its functionality is currently
* handled by {@link EnumConstantCondition} that checks type and constant field in one
* varcond.
* Should be removed soon.
*
* @author mulbrich
* @since 2006-12-14
*/
@Deprecated
public final class EnumTypeCondition extends VariableConditionAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(EnumTypeCondition.class);

Expand Down
Loading
Loading