diff --git a/pom.xml b/pom.xml
index 2a4337eb1aa..f120f62e3ca 100644
--- a/pom.xml
+++ b/pom.xml
@@ -99,6 +99,11 @@
commons-compress
1.23.0
+
+ org.jspecify
+ jspecify
+ 0.3.0
+
com.google.guava
diff --git a/qodana.yaml b/qodana.yaml
index d0043b7e59c..a86568c5ff0 100644
--- a/qodana.yaml
+++ b/qodana.yaml
@@ -11,7 +11,8 @@ include:
- name: DoubleBraceInitialization
- name: EqualsAndHashcode
- name: JavaLangImport
- - name: MissortedModifiers
+ # Disabled for annotations applied to type
+ #- name: MissortedModifiers
- name: NestedAssignment
- name: NonShortCircuitBoolean
- name: RedundantFieldInitialization
diff --git a/src/main/java/spoon/OutputType.java b/src/main/java/spoon/OutputType.java
index ede4e7bb98a..79ac0a17426 100644
--- a/src/main/java/spoon/OutputType.java
+++ b/src/main/java/spoon/OutputType.java
@@ -9,6 +9,8 @@
import java.util.Locale;
+import org.jspecify.annotations.Nullable;
+
/**
* Types of output.
*/
@@ -42,7 +44,7 @@ public String toString() {
*
* @see Launcher#printUsage()
*/
- public static OutputType fromString(String string) {
+ public static @Nullable OutputType fromString(String string) {
for (OutputType outputType : OutputType.values()) {
if (outputType.toString().equals(string)) {
return outputType;
diff --git a/src/main/java/spoon/compiler/Environment.java b/src/main/java/spoon/compiler/Environment.java
index db3d2b23d1b..0e58a8020c5 100644
--- a/src/main/java/spoon/compiler/Environment.java
+++ b/src/main/java/spoon/compiler/Environment.java
@@ -27,6 +27,8 @@
import java.nio.charset.Charset;
import java.util.function.Supplier;
+import org.jspecify.annotations.Nullable;
+
/**
* This interface represents the environment in which Spoon is launched -
* accessible through {@link spoon.reflect.factory.Factory#getEnvironment()}. Its
@@ -103,7 +105,7 @@ public interface Environment {
* @param processorName fully qualified name of a processor
* @return properties for the processor, or {@code null} if there is no processor by that name
*/
- ProcessorProperties getProcessorProperties(String processorName);
+ @Nullable ProcessorProperties getProcessorProperties(String processorName);
/**
* Sets the properties for a given processor.
diff --git a/src/main/java/spoon/metamodel/Metamodel.java b/src/main/java/spoon/metamodel/Metamodel.java
index fd32cc448b3..c42c92b99b1 100644
--- a/src/main/java/spoon/metamodel/Metamodel.java
+++ b/src/main/java/spoon/metamodel/Metamodel.java
@@ -18,6 +18,9 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+
+import org.jspecify.annotations.Nullable;
+
import spoon.Launcher;
import spoon.SpoonException;
import spoon.reflect.annotations.PropertyGetter;
@@ -346,7 +349,7 @@ private static String getConceptName(String simpleName) {
* @param iface the interface of spoon model element
* @return {@link CtClass} of Spoon model which implements the spoon model interface. null if there is no implementation.
*/
- public static CtClass> getImplementationOfInterface(CtInterface> iface) {
+ public static @Nullable CtClass> getImplementationOfInterface(CtInterface> iface) {
String impl = replaceApiToImplPackage(iface.getQualifiedName()) + CLASS_SUFFIX;
return (CtClass>) getType(impl, iface);
}
@@ -355,7 +358,7 @@ public static CtClass> getImplementationOfInterface(CtInterface> iface) {
* @param impl the implementation class of a Spoon element
* @return {@link CtInterface} of Spoon model which represents API of the spoon model class. null if there is no implementation.
*/
- public static CtInterface> getInterfaceOfImplementation(CtClass> impl) {
+ public static @Nullable CtInterface> getInterfaceOfImplementation(CtClass> impl) {
String iface = impl.getQualifiedName();
if (!iface.endsWith(CLASS_SUFFIX) || !iface.startsWith("spoon.support.reflect.")) {
throw new SpoonException("Unexpected spoon model implementation class: " + impl.getQualifiedName());
diff --git a/src/main/java/spoon/metamodel/MetamodelProperty.java b/src/main/java/spoon/metamodel/MetamodelProperty.java
index 76e83da330a..963ffb5868d 100644
--- a/src/main/java/spoon/metamodel/MetamodelProperty.java
+++ b/src/main/java/spoon/metamodel/MetamodelProperty.java
@@ -21,6 +21,8 @@
import java.util.Map;
import java.util.Set;
+import org.jspecify.annotations.Nullable;
+
import spoon.SpoonException;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtMethod;
@@ -435,7 +437,7 @@ private enum MatchLevel {
* @param realType
* @return new expectedType or null if it is not matching
*/
- private MatchLevel getMatchLevel(CtTypeReference> expectedType, CtTypeReference> realType) {
+ private @Nullable MatchLevel getMatchLevel(CtTypeReference> expectedType, CtTypeReference> realType) {
if (expectedType.equals(realType)) {
return MatchLevel.EQUALS;
}
diff --git a/src/main/java/spoon/pattern/internal/DefaultGenerator.java b/src/main/java/spoon/pattern/internal/DefaultGenerator.java
index d0020882900..56b7faaa1bc 100644
--- a/src/main/java/spoon/pattern/internal/DefaultGenerator.java
+++ b/src/main/java/spoon/pattern/internal/DefaultGenerator.java
@@ -34,6 +34,8 @@
import java.util.List;
import java.util.Map;
+import org.jspecify.annotations.Nullable;
+
/**
* Drives generation process
*/
@@ -55,7 +57,7 @@ public DefaultGenerator(Factory factory, ListOfNodes nodes) {
*
* @return a generate value or null
*/
- public T generateSingleTarget(RootNode node, ImmutableMap parameters, Class expectedType) {
+ public @Nullable T generateSingleTarget(RootNode node, ImmutableMap parameters, Class expectedType) {
ResultHolder.Single result = new ResultHolder.Single<>(expectedType);
generateTargets(node, result, parameters);
return result.getResult();
diff --git a/src/main/java/spoon/pattern/internal/matcher/TobeMatched.java b/src/main/java/spoon/pattern/internal/matcher/TobeMatched.java
index e6b7c52ca9a..ea5dcb1e1bb 100644
--- a/src/main/java/spoon/pattern/internal/matcher/TobeMatched.java
+++ b/src/main/java/spoon/pattern/internal/matcher/TobeMatched.java
@@ -16,6 +16,9 @@
import java.util.Objects;
import java.util.Set;
import java.util.function.BiFunction;
+
+import org.jspecify.annotations.Nullable;
+
import spoon.SpoonException;
import spoon.reflect.meta.ContainerKind;
import spoon.support.util.ImmutableMap;
@@ -173,7 +176,7 @@ public TobeMatched copyAndSetParams(ImmutableMap newParams) {
* @param matcher a matching algorithm
* @return {@link TobeMatched} with List of remaining (to be matched) targets or null if there is no match
*/
- public TobeMatched matchNext(BiFunction