Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
26ecc72
add -rc to the version
wadoon Jul 14, 2026
ecb15e9
change the tag in the weekly deployer
wadoon Jul 14, 2026
c7e163d
Remove proof-tree node border
flo2702 Jul 14, 2026
608cad8
Only recreate Isabelle session files if path has actually changed
flo2702 Jul 14, 2026
4998e21
Only recreate Isabelle session files if path has actually changed (#3…
flo2702 Jul 14, 2026
1796d15
Removed double dbg msg
flo2702 Jul 14, 2026
f7695ce
Removed double dbg msg (#3930)
flo2702 Jul 14, 2026
459732f
Fixes empty taclet option even if problem is loaded
unp1 Jul 15, 2026
56541d4
fix for #3927: make examples loadable (JML modifiers before return type)
WolframPfeifer Jul 15, 2026
2474948
Add a command line parameter to clear GUI prefrences
unp1 Jul 17, 2026
9187d13
update the THIRD_PARTY_LICENSES.txt
wadoon Jul 17, 2026
798bd67
Fix saving-loading when path contains symlink
unp1 Jul 17, 2026
5aa26d3
Proof > Show All Active Settings > Active Taclet Options shows actual…
unp1 Jul 17, 2026
46a9749
Fix taclet options not activated after change and reloading (closes i…
unp1 Jul 17, 2026
2414e3c
Fix that open most recent file was not enabled when starting KeY fres…
unp1 Jul 17, 2026
c78d577
Minor robustness add-on for last commit
unp1 Jul 17, 2026
4b2b7f9
Increas forked JVM memory: macOS has less memory on CI, so the defaul…
unp1 Jul 17, 2026
fbc20f5
add description to modules
wadoon Jul 18, 2026
8be0d33
KeY 3.0 logo (used in About KeY), extended copyright notice
WolframPfeifer Jul 20, 2026
93384fe
update license date
WolframPfeifer Jul 20, 2026
17e5e13
updated readme file
WolframPfeifer Jul 20, 2026
f4a01c1
remove stack trace from log when no proof settings are found
WolframPfeifer Jul 20, 2026
5edbab5
Add FM 2024 Tutorial tests (#3933)
Drodt Jul 22, 2026
4f04a40
Add FM24 Tutorial to Example dialog (and fix typo) (#3936)
Drodt Jul 22, 2026
914e8f7
Sync File and Save dialog (issue #3938)
unp1 Jul 22, 2026
c764715
fix #3935
wadoon Jul 23, 2026
420c634
Suppress additional contract in FM24 example
Drodt Jul 23, 2026
86d318f
Merge branch 'prereleases/KeY-3.0.0-rc' of https://github.com/KeYProj…
Drodt Jul 23, 2026
8be7f5a
swap 'Apply' and 'Cancel' in TacletMatchDialog for consistency
WolframPfeifer Jul 23, 2026
b35333f
follow up of #3935: fix loading of instantiations and copying of old …
WolframPfeifer Jul 23, 2026
3c42927
shorten text in TacletMatchDialog tabs
WolframPfeifer Jul 23, 2026
e0b55ee
Sync file chooser before opening with last opened location
unp1 Jul 23, 2026
89522a5
finalizing release
WolframPfeifer 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
8 changes: 4 additions & 4 deletions .github/workflows/nightlydeploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,17 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release delete nightly --yes --cleanup-tag
gh release delete KEY-3.0.0-rc --yes --cleanup-tag


- name: Create nightly release
id: create_release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create --generate-notes --title "Nightly Release" \
--prerelease --notes-start-tag KEY-2.12.3 \
nightly key.ui/build/libs/key-*-exe.jar key-javadoc.tar.xz
gh release create --generate-notes --title "KeY-3.0.0" \
--notes-start-tag KEY-2.12.3 \
KeY-3.0.0 key.ui/build/libs/key-*-exe.jar key-javadoc.tar.xz


- name: Upload to MAVEN CENTRAL SNAPSHOT repository
Expand Down
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
25 changes: 11 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,22 @@
![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)


This repository is the home of the interactive theorem prover KeY for formal verification and analysis of Java programs. KeY comes as a standalone GUI application, which allows you to verify the functional correctness of Java programs with respect to formal specifications formulated in the Java Modeling Language JML. Moreover, KeY can also be used as a library e.g. for symbolic program execution, first order reasoning, or test case generation.
This repository is the home of the interactive theorem prover KeY for formal verification and analysis of Java programs.
KeY comes as a standalone GUI application, which allows you to verify the functional correctness of Java programs with
respect to formal specifications formulated in the Java Modeling Language JML. Moreover, KeY can also be used as a
library e.g. for symbolic program execution, first order reasoning, or test case generation.

For more information, refer to

* [The KeY homepage](https://key-project.org)
* [The KeY book](https://www.key-project.org/thebook2/)
* [The KeY developer documentation](https://keyproject.github.io/key-docs/)
* [The KeY documentation pages](https://keyproject.github.io/key-docs/)
* KeY's success stories:
* [Severe bug discovered in JDK sorting routine (TimSort)](http://www.envisage-project.eu/proving-android-java-and-python-sorting-algorithm-is-broken-and-how-to-fix-it/),
* [Verification of `java.util.IdentityHashMap`](https://doi.org/10.1007/978-3-031-07727-2_4),
* [Google Award for analysing a bug in `LinkedList`](https://www.key-project.org/2023/07/23/cwi-researchers-win-google-award-for-finding-a-bug-in-javas-linkedlist-using-key/)

The current version of KeY is 2.12.2, licensed under GPL v2.

The current version of KeY is 3.0, licensed under GPL v2.

Feel free to use the project templates to get started using KeY:
* [For Verification Projects](https://github.com/KeYProject/verification-project-template)
Expand All @@ -30,7 +32,7 @@ Feel free to use the project templates to get started using KeY:

* Hardware: >=2 GB RAM
* Operating System: Linux/Unix, MacOSX, Windows
* Java 17 or newer
* Java 21 or newer
* Optionally, KeY can make use of the following binaries:
* SMT Solvers:
* [Z3](https://github.com/Z3Prover/z3#z3)
Expand Down Expand Up @@ -87,17 +89,10 @@ Assuming you are in the directory of this README file, you can create a runnable

# Developing KeY

* Quality is automatically assessed using [SonarQube](https://sonarqube.org) on each pull request.
The results of the assessments (pass/fail) can be inspected in the checks section of the PR.

The rules and quality gate are maintained by Alexander Weigl
<weigl@kit.edu> currently.

* More guideline and documentation for the KeY development can be found under
Guidelines and documentation for the KeY development can be found under
[key-docs](https://keyproject.github.io/key-docs/devel/).



# Issues and Bug Reports

* For bug reports, please use the [issue tracker](https://github.com/KeYProject/key/issues) or send a mail to support@key-project.org.
Expand All @@ -106,7 +101,9 @@ Assuming you are in the directory of this README file, you can create a runnable

# Contributing to KeY

Feel free to submit [pull requests](https://github.com/KeYProject/key/pulls) via GitHub. Pull requests are assessed using automatic tests, formatting and static source checkers, as well as a manual review by one of the developers. More guidelines and documentation for the KeY development can be found under [key-docs](https://keyproject.github.io/key-docs/devel/).
Feel free to submit [pull requests](https://github.com/KeYProject/key/pulls) via GitHub. Pull requests are assessed
using automatic tests, formatting and static source checkers, as well as a manual review by one of the developers. More
guidelines and documentation for the KeY development can be found under [key-docs](https://keyproject.github.io/key-docs/devel/).



Expand Down
23 changes: 21 additions & 2 deletions 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 @@ -35,7 +47,7 @@ static def getDate() {
}

// The $BUILD_NUMBER is an environment variable set by Jenkins.
def build = System.env.BUILD_NUMBER == null ? "-dev" : "-${System.env.BUILD_NUMBER}"
def build = System.env.BUILD_NUMBER == null ? "" : "-${System.env.BUILD_NUMBER}"

group = "org.key-project"
version = "3.0.0$build"
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 All @@ -62,6 +76,7 @@ subprojects {
repositories {
mavenCentral()
//maven { url = "https://git.key-project.org/api/v4/projects/35/packages/maven/" }
//maven { url = "https://central.sonatype.com/repository/maven-snapshots/" }
}

dependencies {
Expand Down Expand Up @@ -293,7 +308,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
3 changes: 2 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ stringtemplate = "4.3.4"

# Java parsing and analysis
javapoet = "1.13.0"
javaparser = "3.28.0-K13.5"
javaparser = "3.28.0-K13.6"
truth = "1.4.5"

# UI and CLI
Expand Down 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 @@ -381,11 +382,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 @@ -494,7 +498,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
Loading
Loading