Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0b96144
Only recreate Isabelle session files if path has actually changed
flo2702 Jul 14, 2026
291ba27
Removed double dbg msg
flo2702 Jul 14, 2026
14aca31
Fixes empty taclet option even if problem is loaded
unp1 Jul 15, 2026
8040348
fix for #3927: make examples loadable (JML modifiers before return type)
WolframPfeifer Jul 15, 2026
242d821
Add a command line parameter to clear GUI prefrences
unp1 Jul 17, 2026
df8f7c6
update the THIRD_PARTY_LICENSES.txt
wadoon Jul 17, 2026
d3f6301
Fix saving-loading when path contains symlink
unp1 Jul 17, 2026
024c559
Proof > Show All Active Settings > Active Taclet Options shows actual…
unp1 Jul 17, 2026
c0c0905
Fix taclet options not activated after change and reloading (closes i…
unp1 Jul 17, 2026
2109cc8
Fix that open most recent file was not enabled when starting KeY fres…
unp1 Jul 17, 2026
aa642e1
Minor robustness add-on for last commit
unp1 Jul 17, 2026
fbebeb0
Increas forked JVM memory: macOS has less memory on CI, so the defaul…
unp1 Jul 17, 2026
7bdccfb
add description to modules
wadoon Jul 18, 2026
b154729
KeY 3.0 logo (used in About KeY), extended copyright notice
WolframPfeifer Jul 20, 2026
724e817
update license date
WolframPfeifer Jul 20, 2026
bbc8cb6
updated readme file
WolframPfeifer Jul 20, 2026
15f0766
remove stack trace from log when no proof settings are found
WolframPfeifer Jul 20, 2026
b0413dd
Sync File and Save dialog (issue #3938)
unp1 Jul 22, 2026
56b1735
fix #3935
wadoon Jul 23, 2026
680a260
Suppress additional contract in FM24 example
Drodt Jul 23, 2026
43a8ec4
swap 'Apply' and 'Cancel' in TacletMatchDialog for consistency
WolframPfeifer Jul 23, 2026
beca258
follow up of #3935: fix loading of instantiations and copying of old …
WolframPfeifer Jul 23, 2026
e9c8700
shorten text in TacletMatchDialog tabs
WolframPfeifer Jul 23, 2026
dc85953
Sync file chooser before opening with last opened location
unp1 Jul 23, 2026
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
2 changes: 1 addition & 1 deletion LICENSE.TXT
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Copyright (C) 2001-2011 Universitaet Karlsruhe (TH), Germany
Universitaet Koblenz-Landau, Germany
Chalmers University of Technology, Sweden
Copyright (C) 2011-2019 Karlsruhe Institute of Technology, Germany
Copyright (C) 2011-2026 Karlsruhe Institute of Technology, Germany
Technical University Darmstadt, Germany
Chalmers University of Technology, Sweden

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

[![Tests](https://github.com/KeYProject/key/actions/workflows/tests.yml/badge.svg)](https://github.com/KeYProject/key/actions/workflows/tests.yml) [![CodeQuality](https://github.com/KeYProject/key/actions/workflows/code_quality.yml/badge.svg)](https://github.com/KeYProject/key/actions/workflows/code_quality.yml)

![Maven metadata URL](https://img.shields.io/maven-metadata/v?metadataUrl=https%3A%2F%2Fcentral.sonatype.com%2Frepository%2Fmaven-snapshots%2Forg%2Fkey-project%2Fkey.core%2Fmaven-metadata.xml&label=maven%20snapshots)
![Maven metadata URL](https://img.shields.io/maven-metadata/v?metadataUrl=https%3A%2F%2Frepo1.maven.org%2Fmaven2%2Forg%2Fkey-project%2Fkey.core%2Fmaven-metadata.xml&label=maven%20central)


Expand Down Expand Up @@ -29,7 +30,7 @@ Feel free to use the project templates to get started using KeY:

* Hardware: >=2 GB RAM
* Operating System: Linux/Unix, MacOSX, Windows
* Java 21 or newer
* Java 17 or newer
* Optionally, KeY can make use of the following binaries:
* SMT Solvers:
* [Z3](https://github.com/Z3Prover/z3#z3)
Expand Down
20 changes: 19 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,20 @@ plugins {

// Plugin for publishing via the new Nexus API
alias(libs.plugins.maven.publish) apply false

//alias(libs.plugins.license.report)
}

/* // required for generated the license report THIRD_PARTY_LICENSES.txt
licenseReport {
unionParentPomLicenses = false
outputDir = layout.buildDirectory.dir("licenses").get().asFile
projects = [project] + project.subprojects
configurations = ['runtimeClasspath']
excludeOwnGroup = true
excludeBoms = false
}
*/

// Configure this project for use inside IntelliJ:
idea {
Expand All @@ -46,6 +58,8 @@ subprojects {
apply plugin: "idea"
apply plugin: "eclipse"

// apply plugin: libs.plugins.license.report

apply plugin: "com.diffplug.spotless"
apply plugin: "org.checkerframework"
apply plugin: "com.vanniktech.maven.publish"
Expand Down Expand Up @@ -299,7 +313,11 @@ subprojects {

pom {
name = project.name
description = project.description
afterEvaluate {
description = project.description
assert (project.description != null && project.description != "") : "Description of modules are required at maven-central"
print(project.description)
}
url = 'https://key-project.org/'

licenses {
Expand Down
5 changes: 4 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8

# do not release automatically at Maven Central
mavenCentralAutomaticPublishing=false
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,4 @@ spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
checkerframework = { id = "org.checkerframework", version.ref = "checkerframework-gradle" }
maven-publish = { id = "com.vanniktech.maven.publish", version.ref = "maven-publish" }
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
license-report = { id = "com.github.jk1.dependency-license-report", version = "3.1.4" }
1 change: 1 addition & 0 deletions key.core.infflow/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
description = "Information-Flow / Non-interference calculus for Java using the KeY theorem prover"


dependencies {
Expand Down
3 changes: 3 additions & 0 deletions key.core.wd/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
description = "Well-defined calculus for JML specifciation and Java using the KeY theorem prover"


dependencies {
api(project(":key.core"))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.*;
import java.util.*;

import de.uka.ilkd.key.control.instantiation_model.TacletFindModel;
Expand All @@ -33,30 +32,44 @@ public class InstantiationFileHandler {

private static Map<String, List<List<String>>> hm;

/// Finds the current place to store used instantiation. If there was a version switch
/// Finds the current place to store used instantiations. If there was a version change
/// (the folder does not exist), this method tries to copy previous instantiations to
/// the new directory silently.
///
/// It is guaranteed, that the folder exists.
/// the new directory silently. However, if both old and new instantiations exist, they are not
/// merge, i.e. only the new ones are used currently.
private static Path getStoragePath() {
Path cur = PathConfig.currentPaths.keyConfigDir.resolve("instantiations");
if (Files.exists(cur)) {
/*
* At the moment, we do not merge when old and new instantiations are
* present. In the future, we could go one step further and try to merge.
*/
return cur;
}

Path prev = PathConfig.previousPaths.keyConfigDir.resolve("instantiations");
// create the directory for storing instantiations
try {
Files.createDirectories(cur);
} catch (IOException e) {
LOGGER.warn("Could not create the instantiations folder {}", cur, e);
}

// Check if instantiations from older key version exist. If so, try to copy them over.
Path prev = PathConfig.previousPaths.keyConfigDir.resolve("instantiations");
if (Files.exists(prev)) {
try (var files = Files.walk(prev)) {
files.forEach(path -> {
try {
Files.copy(path, cur.resolve(path.relativize(prev)));
} catch (IOException ignore) {
Path target = cur.resolve(prev.relativize(path));
// Do not overwrite existing file!
if (!Files.exists(target)) {
Files.copy(path, target);
}
} catch (IOException inner) {
LOGGER.warn("Could not copy instantiation file {}", path, inner);
}
});
} catch (IOException e) {
LOGGER.warn("Could not copy instantiation files from {} to {}", prev, cur, e);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return cur;
}
Expand All @@ -82,9 +95,9 @@ private static void createHashMap() {
hm = new TreeMap<>();
try (var stream = Files.list(INSTANTIATION_DIR)) {
// using a TreeMap here avoids non-determinsm introduce by the file system.
stream.forEach(file -> hm.put(file.toString(), null));
stream.forEach(file -> hm.put(file.getFileName().toString(), null));
} catch (IOException e) {
LOGGER.warn("Could not read the instantions folder {}", INSTANTIATION_DIR, e);
LOGGER.warn("Could not read the instantiations folder {}", INSTANTIATION_DIR, e);
}
}

Expand Down
15 changes: 15 additions & 0 deletions key.core/src/main/java/de/uka/ilkd/key/proof/init/InitConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public class InitConfig {

/** HashMap for quick lookups taclet name->taclet */
private Map<Name, Taclet> activatedTacletCache = null;
private boolean defaultsComputed;

/** the fileRepo which is responsible for consistency between source code and proof */
private FileRepo fileRepo;
Expand All @@ -104,6 +105,9 @@ public InitConfig(Services services) {
/// combines the found choices in KeY files, together with the current settings.
/// The namespace of choices has to be filled.
public void computeDefaults(ChoiceInformation ci) {
if (defaultsComputed) {
return;
}
var currentDefaultChoices =
ProofSettings.DEFAULT_SETTINGS.getChoiceSettings().getDefaultChoices();

Expand Down Expand Up @@ -145,6 +149,8 @@ public void computeDefaults(ChoiceInformation ci) {
}
settings.getChoiceSettings().setDefaultChoices(defaults);
}
activatedTacletCache = null;
defaultsComputed = true;
}

/**
Expand Down Expand Up @@ -203,6 +209,14 @@ public Map<Taclet, TacletBuilder<? extends Taclet>> getTaclet2Builder() {
}


/**
* @return an immutable mapping from a category to its default choice
*/
public @NonNull Map<String, Choice> getCategory2DefaultChoices() {
return Collections.unmodifiableMap(category2DefaultChoice);
}


/**
* sets the set of activated choices of this initial configuration. For categories without a
* specified choice the default choice contained in category2DefaultChoice is added.
Expand Down Expand Up @@ -448,6 +462,7 @@ public InitConfig copyWithServices(Services services) {
ic.header = header;
ic.justifInfo = justifInfo.copy();
ic.fileRepo = fileRepo; // TODO: copy instead? delete via dispose method?
ic.defaultsComputed = defaultsComputed;
return ic;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import de.uka.ilkd.key.logic.label.OriginTermLabelFactory;
import de.uka.ilkd.key.logic.op.*;
import de.uka.ilkd.key.logic.sort.GenericSort;
import de.uka.ilkd.key.nparser.ChoiceInformation;
import de.uka.ilkd.key.proof.Goal;
import de.uka.ilkd.key.proof.JavaModel;
import de.uka.ilkd.key.proof.Proof;
Expand Down Expand Up @@ -392,11 +393,14 @@ private void populateNamespaces(Proof proof) {
}
}

// what is the purpose of this method?
/**
* Updates the global settings the taclet options that declared in
* {@code optionDeclaration.key}.
* A proof created afterwards inherits these settings unless it overwrites it.
*/
private InitConfig determineEnvironment(ProofOblInput po, InitConfig initConfig) {
// TODO: what does this actually do?
ProofSettings.DEFAULT_SETTINGS.getChoiceSettings().updateChoices(initConfig.choiceNS(),
false);
initConfig.getCategory2DefaultChoices(), false);
return initConfig;
}

Expand Down Expand Up @@ -505,7 +509,7 @@ public InitConfig prepare(EnvInput envInput) throws ProofInputException {
var warnings = ic.getProfile()
.prepareInitConfig(ic, additionalProfileOptions);
addWarnings(warnings);

ic.computeDefaults(new ChoiceInformation());
return ic;
}

Expand Down
6 changes: 3 additions & 3 deletions key.core/src/main/java/de/uka/ilkd/key/proof/io/KeYFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public Path readBootClassPath() {
if (!bootClassPathFile.isAbsolute()) {
// convert to absolute by resolving against the parent path of the parsed file
Path parentDirectory = file.file().getParent();
bootClassPathFile = parentDirectory.resolve(bootClassPathFile);
bootClassPathFile = parentDirectory.resolve(bootClassPathFile).normalize();
}
if (!Files.isDirectory(bootClassPathFile)) {
// Report the missing directory at the \bootclasspath declaration in the .key file,
Expand Down Expand Up @@ -297,7 +297,7 @@ private static Location locationOrUndefined(ProblemInformation pi, String path)
} else {
var f = Paths.get(normalizeStoredPath(cp));
if (!f.isAbsolute()) {
f = parentDirectory.resolve(f);
f = parentDirectory.resolve(f).normalize();
}
if (!Files.exists(f)) {
// Point at the \classpath declaration in the .key file instead of letting the
Expand All @@ -321,7 +321,7 @@ public Path readJavaPath() throws ProofInputException {
if (!absFile.isAbsolute()) {
// convert to absolute by resolving against the parent path of the parsed file
Path parent = file.file().getParent();
absFile = parent.resolve(javaPath);
absFile = parent.resolve(javaPath).normalize();
}
if (!Files.exists(absFile)) {
throw new ProofInputException(String.format(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,12 @@ public void setChoiceCategories(Map<String, Set<String>> c2C) {
* updates <code>category2Choices</code> if new entries are found in <code>choiceNS</code> or if
* entries of <code>category2Choices</code> are no longer present in <code>choiceNS</code>
*
* @param choiceNS the choices declared by the loaded problem file
* @param defaults the default choice of each category
* @param remove remove entries not present in <code>choiceNS</code>
*/
public void updateChoices(Namespace<Choice> choiceNS, boolean remove) {
public void updateChoices(Namespace<Choice> choiceNS, Map<String, Choice> defaults,
boolean remove) {
// Translate the given namespace into a map of 'string -> list[string]'
HashMap<String, Set<String>> c2C = new LinkedHashMap<>();
for (Choice c : choiceNS.allElements()) {
Expand All @@ -118,11 +121,11 @@ public void updateChoices(Namespace<Choice> choiceNS, boolean remove) {
}
}

// ensure that default values are set if a key is present
var defaultTmp = new HashMap<>(category2Default);
for (var pair : category2Default.entrySet()) {
var s = pair.getKey();
var v = pair.getValue();
// if key is known then the default value should exist
if (category2Choices.containsKey(s)) {
if (!category2Choices.get(s).contains(v)) {
defaultTmp.put(s, category2Choices.get(s).iterator().next());
Expand All @@ -131,6 +134,16 @@ public void updateChoices(Namespace<Choice> choiceNS, boolean remove) {
defaultTmp.remove(s);
}
}

for (var category : category2Choices.keySet()) {
if (!defaultTmp.containsKey(category)) {
var declared = defaults.get(category);
if (declared != null) {
defaultTmp.put(category, declared.name().toString());
}
}
}

setDefaultChoices(defaultTmp);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ public void loadSettings() {
loadSettingsFromJSONStream(in);
}
} catch (Exception e) {
LOGGER.warn("No proof-settings could be loaded, using defaults", e);
LOGGER.warn("No proof settings could be loaded, using defaults");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ public interface KeYConstants {
KeYResourceManager.getManager().getVersion() + " (internal: " + INTERNAL_VERSION + ")";

String COPYRIGHT = UnicodeHelper.COPYRIGHT + " Copyright 2001"
+ UnicodeHelper.ENDASH + "2024 " + "Karlsruhe Institute of Technology, "
+ UnicodeHelper.ENDASH + "2026 " + "Karlsruhe Institute of Technology, "
+ "Chalmers University of Technology, and Technische Universit\u00e4t Darmstadt";
}
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,10 @@ public static ProofCollection automaticJavaDL() throws IOException {
* If the fork mode is not set to noFork, the launched subprocesses
* get the specified amount of heap memory.
*
* Heap memory for subprocesses (like 500m or 2G)
* Heap memory for subprocesses (like 500m or 3G)
*/
// forkMemory = 1000m
settings.setForkMemory("3g");


/*
* To run the forked JVM in debug mode, set the TCP port to listen to here.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ protected void reload(boolean verbose, Path proofFile, Proof loadedProof, boolea
if (settings.reloadEnabled() && (testProperty == TestProperty.PROVABLE) && success) {
// Save the available proof to a temporary file.
ProofSaver.saveToFile(proofFile, loadedProof);
loadedProof.dispose();
reloadProof(proofFile);
if (verbose) {
LOGGER.debug("... success: reloaded.");
Expand Down
2 changes: 2 additions & 0 deletions key.ncore.calculus/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
description = "Pattern Matchern New core KeY theorem prover"

repositories {
mavenCentral()
}
Expand Down
4 changes: 1 addition & 3 deletions key.ncore.matcher/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
repositories {
mavenCentral()
}
description = "Compiling Matching Algorithm of the KeY theorem prover"

dependencies {
api project(':key.util')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public interface List {

//@ public instance invariant \subset(\singleton(this.seq), footprint);
//@ public instance invariant \subset(\singleton(this.footprint), footprint);
//@ public accessible \inv: footprint;
//@ accessible \inv: footprint;

/*@ public normal_behaviour
@ requires 0 <= index && index < seq.length;
Expand Down
2 changes: 1 addition & 1 deletion key.ui/examples/newBook/Chapter_16/Sort/Sort.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public class Sort {
@ ensures (\forall int i; start <= i && i<a.length;a[\result] >= a[i]);
@ ensures start <= \result && \result < a.length;
@ */
int /*@ strictly_pure @*/ max(int start) {
/*@ strictly_pure @*/ int max(int start) {
int counter = start; int idx = start;
/*@ loop_invariant start<=counter && counter<=a.length
@ && start<=idx && idx<a.length && start<a.length
Expand Down
Loading
Loading