Skip to content

Commit

Permalink
feat: improve heuristic of EEA generator to determine non-null params
Browse files Browse the repository at this point in the history
  • Loading branch information
sebthom committed Jun 7, 2024
1 parent f9cb165 commit 5c5b3ae
Show file tree
Hide file tree
Showing 811 changed files with 2,181 additions and 2,150 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,26 @@ public String toString(final boolean omitComment) {
protected static final Pattern PATTERN_CAPTURE_NULL_ANNOTATION_OF_TYPENAMES = Pattern.compile(
"[TL]([01])[a-zA-Z_][a-zA-Z_0-9$\\/*]*[<;]");

/**
* see https://wiki.eclipse.org/JDT_Core/Null_Analysis/External_Annotations#Textual_encoding_of_signatures
*/
protected static String removeNullAnnotations(final String annotatedSignature) {
var strippedSignature = annotatedSignature //
.replace("[0", "[") //
.replace("[1", "[") //
.replace("-0", "-") //
.replace("-1", "-") //
.replace("+0", "+") //
.replace("+1", "+") //
.replace("*0", "*") //
.replace("<0", "<") //
.replace("<1", "<") //
.replace("*1", "*");

strippedSignature = replaceAll(strippedSignature, PATTERN_CAPTURE_NULL_ANNOTATION_OF_TYPENAMES, 1, match -> "");
return strippedSignature;
}

public final ClassMember classHeader;
public final List<ClassMember> superTypes = new ArrayList<>();

Expand Down Expand Up @@ -316,10 +336,10 @@ public static EEAFile load(final BufferedReader reader, final String path) throw
lineNumber++;
final var superTypeParamsAnnotated = ValueWithComment.parse(line);
if (!superTypeParamsOriginal.value.equals(superTypeParamsAnnotated.value) //
&& !superTypeParamsOriginal.value.equals(eeaFile.removeNullAnnotations(superTypeParamsAnnotated.value)))
&& !superTypeParamsOriginal.value.equals(removeNullAnnotations(superTypeParamsAnnotated.value)))
throw new IOException("Signature mismatch at " + path + ":" + lineNumber + "\n" //
+ " Original: " + superTypeParamsAnnotated + "\n" //
+ "Annotated Stripped: " + eeaFile.removeNullAnnotations(superTypeParamsAnnotated.value) + "\n" //
+ "Annotated Stripped: " + removeNullAnnotations(superTypeParamsAnnotated.value) + "\n" //
+ " Annotated: " + superTypeParamsAnnotated + "\n");
eeaFile.superTypes.add(new ClassMember(superType, superTypeParamsOriginal, superTypeParamsAnnotated));
} else {
Expand All @@ -339,7 +359,7 @@ public static EEAFile load(final BufferedReader reader, final String path) throw
throw new IOException("Illegal format for original signature at " + path + ":" + lineNumber);

final var originalSignature = ValueWithComment.parse(line);
if (!originalSignature.value.equals(eeaFile.removeNullAnnotations(originalSignature.value)))
if (!originalSignature.value.equals(removeNullAnnotations(originalSignature.value)))
throw new IOException("Original signature contains null annotations at " + path + ":" + lineNumber);

final var member = new ClassMember(memberName, originalSignature);
Expand All @@ -354,10 +374,10 @@ public static EEAFile load(final BufferedReader reader, final String path) throw
lineNumber++;
final var annotatedSignature = ValueWithComment.parse(line);
if (!originalSignature.value.equals(annotatedSignature.value) //
&& !originalSignature.value.equals(eeaFile.removeNullAnnotations(annotatedSignature.value)))
&& !originalSignature.value.equals(removeNullAnnotations(annotatedSignature.value)))
throw new IOException("Signature mismatch at " + path + ":" + lineNumber + "\n" //
+ " Original: " + originalSignature + "\n" //
+ "Annotated Stripped: " + eeaFile.removeNullAnnotations(annotatedSignature.value) + "\n" //
+ "Annotated Stripped: " + removeNullAnnotations(annotatedSignature.value) + "\n" //
+ " Annotated: " + annotatedSignature + "\n");
if (!originalSignature.value.equals(annotatedSignature.value) || annotatedSignature.hasComment()) {
member.annotatedSignature = annotatedSignature;
Expand Down Expand Up @@ -562,24 +582,6 @@ && contains(member.annotatedSignature.comment, MARKER_OVERRIDES)) {
return lines;
}

/**
* see https://wiki.eclipse.org/JDT_Core/Null_Analysis/External_Annotations#Textual_encoding_of_signatures
*/
protected String removeNullAnnotations(final String annotatedSignature) {
var strippedSignature = annotatedSignature //
.replace("[0", "[") //
.replace("[1", "[") //
.replace("-0", "-") //
.replace("-1", "-") //
.replace("+0", "+") //
.replace("+1", "+") //
.replace("*0", "*") //
.replace("*1", "*");

strippedSignature = replaceAll(strippedSignature, PATTERN_CAPTURE_NULL_ANNOTATION_OF_TYPENAMES, 1, match -> "");
return strippedSignature;
}

/**
* @return true if modifications where written to disk, false was already up-to-date
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,23 @@ protected static ValueWithComment computeAnnotatedSignature(final EEAFile.ClassM
// (Ljava/lang/String;)V -> (L1java/lang/String;)V
return new ValueWithComment(insert(member.originalSignature.value, 2, "1"), "");

// mark the parameter of single-parmeter methods as @NonNull
// with signature matching: void (add|remove)*Listener(*Listener)
if (!methodInfo.isStatic() // non-static
&& (methodInfo.getName().startsWith("add") || methodInfo.getName().startsWith("remove")) //
&& methodInfo.getName().endsWith("Listener") //
&& member.originalSignature.value.endsWith(")V") // returns void
&& methodInfo.getParameterInfo().length == 1 // only 1 parameter
&& methodInfo.getParameterInfo()[0].getTypeDescriptor().toString().endsWith("Listener"))
return new ValueWithComment( //
member.originalSignature.value.startsWith("(") //
// (Lcom/example/MyListener;)V -> (L1com/example/MyListener;)V
// (TT;)V -> (T1T;)V
? insert(member.originalSignature.value, 2, "1") //
// <T::Lcom/example/MyListener;>(TT;)V --> <1T::Lcom/example/MyListener;>(TT;)V
: insert(member.originalSignature.value, 1, "1"), //
"");

if (hasObjectReturnType(member)) { // returns non-void
if (hasNullableAnnotation(methodInfo.getAnnotationInfo()))
// ()Ljava/lang/String -> ()L0java/lang/String;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
package com.vegardit.no_npe.eea_generator;

import static com.vegardit.no_npe.eea_generator.EEAFile.*;
import static com.vegardit.no_npe.eea_generator.internal.MiscUtils.remap;
import static org.assertj.core.api.Assertions.*;

Expand Down Expand Up @@ -42,7 +43,7 @@ public static final class TestEntity2 {

@Test
void testEEAFile() throws IOException {
final var eeaFile = EEAFile.load(Path.of("src/test/resources/valid"), TestEntity.class.getName());
final var eeaFile = load(Path.of("src/test/resources/valid"), TestEntity.class.getName());

assertThat(eeaFile.classHeader.name.value).isEqualTo(TestEntity.class.getName());
assertThat(eeaFile.classHeader.name.comment).isEqualTo("# a class comment");
Expand Down Expand Up @@ -74,7 +75,7 @@ void testEEAFile() throws IOException {
void testWrongTypeHeader() {
final var wrongTypePath = Path.of("src/test/resources/invalid/" + WRONG_TYPE_NAME_WITH_SLASHES + ".eea");
assertThatThrownBy(() -> { //
EEAFile.load(wrongTypePath);
load(wrongTypePath);
}) //
.isInstanceOf(java.io.IOException.class) //
.hasMessage("Mismatch between file path of [" + wrongTypePath + "] and contained class name definition [" + TestEntity.class
Expand All @@ -93,11 +94,22 @@ void testApplyAnnotationsAndCommentsFrom() throws IOException {
assertThat(method.hasNullAnnotations()).isFalse();
assertThat(method.name.comment).isEmpty();

final var loadedEEAFile = EEAFile.load(Path.of("src/test/resources/valid"), computedEEAFile.classHeader.name.value);
final var loadedEEAFile = load(Path.of("src/test/resources/valid"), computedEEAFile.classHeader.name.value);
computedEEAFile.applyAnnotationsAndCommentsFrom(loadedEEAFile, false, false);
final var annotatedSignature = method.annotatedSignature;
assert annotatedSignature != null;
assertThat(annotatedSignature.value).isEqualTo("L1java/lang/String;");
assertThat(method.name.comment).isEqualTo("# a method comment");
}

@Test
void testRemoveNullAnnotations() {
assertThat(removeNullAnnotations("L0java/lang/Object;")).isEqualTo("Ljava/lang/Object;");
assertThat(removeNullAnnotations("L1java/lang/Class<*>;L1java/lang/Class<*>;)L1java/lang/invoke/MethodType;")).isEqualTo(
"Ljava/lang/Class<*>;Ljava/lang/Class<*>;)Ljava/lang/invoke/MethodType;");
assertThat(removeNullAnnotations("<T::Ljava/lang/annotation/Annotation;>(L1java/lang/Class<TT;>;)[1T1T;")).isEqualTo(
"<T::Ljava/lang/annotation/Annotation;>(Ljava/lang/Class<TT;>;)[TT;");
assertThat(removeNullAnnotations("<1T::Ljava/util/EventListener;>(TT;)V")).isEqualTo("<T::Ljava/util/EventListener;>(TT;)V");
assertThat(removeNullAnnotations("<T1:Ljava/lang/Object;>")).isEqualTo("<T1:Ljava/lang/Object;>"); // T1 is the name of the generic variable
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fromMap
(Lorg/apache/commons/configuration2/io/FileBased;Lorg/apache/commons/configuration2/io/FileHandler;)V
addFileHandlerListener
(Lorg/apache/commons/configuration2/io/FileHandlerListener;)V
(Lorg/apache/commons/configuration2/io/FileHandlerListener;)V
(L1org/apache/commons/configuration2/io/FileHandlerListener;)V
getBasePath
()Ljava/lang/String;
()Ljava/lang/String;
Expand Down Expand Up @@ -63,7 +63,7 @@ load
(Ljava/net/URL;)V
removeFileHandlerListener
(Lorg/apache/commons/configuration2/io/FileHandlerListener;)V
(Lorg/apache/commons/configuration2/io/FileHandlerListener;)V
(L1org/apache/commons/configuration2/io/FileHandlerListener;)V
save
(Ljava/io/File;)V
(Ljava/io/File;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class org/apache/commons/io/monitor/FileAlterationObserver
(Lorg/apache/commons/io/monitor/FileEntry;Ljava/io/FileFilter;Lorg/apache/commons/io/IOCase;)V
addListener
(Lorg/apache/commons/io/monitor/FileAlterationListener;)V
(Lorg/apache/commons/io/monitor/FileAlterationListener;)V
(L1org/apache/commons/io/monitor/FileAlterationListener;)V
getDirectory
()Ljava/io/File;
()Ljava/io/File;
Expand All @@ -35,7 +35,7 @@ getListeners
()Ljava/lang/Iterable<Lorg/apache/commons/io/monitor/FileAlterationListener;>;
removeListener
(Lorg/apache/commons/io/monitor/FileAlterationListener;)V
(Lorg/apache/commons/io/monitor/FileAlterationListener;)V
(L1org/apache/commons/io/monitor/FileAlterationListener;)V
toString
()Ljava/lang/String;
()L1java/lang/String; # @Inherited(java.lang.Object)
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ class org/apache/commons/lang3/AnnotationUtils

equals
(Ljava/lang/annotation/Annotation;Ljava/lang/annotation/Annotation;)Z
(Ljava/lang/annotation/Annotation;Ljava/lang/annotation/Annotation;)Z
(L0java/lang/annotation/Annotation;L0java/lang/annotation/Annotation;)Z
hashCode
(Ljava/lang/annotation/Annotation;)I
(Ljava/lang/annotation/Annotation;)I
(L1java/lang/annotation/Annotation;)I
isValidAnnotationMemberType
(Ljava/lang/Class<*>;)Z
(Ljava/lang/Class<*>;)Z
(L0java/lang/Class<*>;)Z
toString
(Ljava/lang/annotation/Annotation;)Ljava/lang/String;
(Ljava/lang/annotation/Annotation;)Ljava/lang/String;
(L1java/lang/annotation/Annotation;)L1java/lang/String;
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ PROPERTY_NAME

isOpen
(Lorg/apache/commons/lang3/concurrent/AbstractCircuitBreaker$State;)Z
(Lorg/apache/commons/lang3/concurrent/AbstractCircuitBreaker$State;)Z
(L1org/apache/commons/lang3/concurrent/AbstractCircuitBreaker$State;)Z

state
Ljava/util/concurrent/atomic/AtomicReference<Lorg/apache/commons/lang3/concurrent/AbstractCircuitBreaker$State;>;
Ljava/util/concurrent/atomic/AtomicReference<Lorg/apache/commons/lang3/concurrent/AbstractCircuitBreaker$State;>;
L1java/util/concurrent/atomic/AtomicReference<Lorg/apache/commons/lang3/concurrent/AbstractCircuitBreaker$State;>;

addChangeListener
(Ljava/beans/PropertyChangeListener;)V
(Ljava/beans/PropertyChangeListener;)V
(L1java/beans/PropertyChangeListener;)V
changeState
(Lorg/apache/commons/lang3/concurrent/AbstractCircuitBreaker$State;)V
(Lorg/apache/commons/lang3/concurrent/AbstractCircuitBreaker$State;)V
(L1org/apache/commons/lang3/concurrent/AbstractCircuitBreaker$State;)V
incrementAndCheckState
(TT;)Z
(TT;)Z
removeChangeListener
(Ljava/beans/PropertyChangeListener;)V
(Ljava/beans/PropertyChangeListener;)V
(L1java/beans/PropertyChangeListener;)V
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ class org/eclipse/core/commands/Category

addCategoryListener
(Lorg/eclipse/core/commands/ICategoryListener;)V
(Lorg/eclipse/core/commands/ICategoryListener;)V
(L1org/eclipse/core/commands/ICategoryListener;)V
define
(Ljava/lang/String;Ljava/lang/String;)V
(Ljava/lang/String;Ljava/lang/String;)V
removeCategoryListener
(Lorg/eclipse/core/commands/ICategoryListener;)V
(Lorg/eclipse/core/commands/ICategoryListener;)V
(L1org/eclipse/core/commands/ICategoryListener;)V
toString
()Ljava/lang/String;
()L1java/lang/String; # @Inherited(org.eclipse.core.commands.common.HandleObject)
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ DEBUG_HANDLERS_COMMAND_ID

addCommandListener
(Lorg/eclipse/core/commands/ICommandListener;)V
(Lorg/eclipse/core/commands/ICommandListener;)V
(L1org/eclipse/core/commands/ICommandListener;)V
addExecutionListener
(Lorg/eclipse/core/commands/IExecutionListener;)V
(Lorg/eclipse/core/commands/IExecutionListener;)V
(L1org/eclipse/core/commands/IExecutionListener;)V
addState
(Ljava/lang/String;Lorg/eclipse/core/commands/State;)V
(Ljava/lang/String;Lorg/eclipse/core/commands/State;)V
Expand Down Expand Up @@ -54,10 +54,10 @@ getReturnType
()Lorg/eclipse/core/commands/ParameterType;
removeCommandListener
(Lorg/eclipse/core/commands/ICommandListener;)V
(Lorg/eclipse/core/commands/ICommandListener;)V
(L1org/eclipse/core/commands/ICommandListener;)V
removeExecutionListener
(Lorg/eclipse/core/commands/IExecutionListener;)V
(Lorg/eclipse/core/commands/IExecutionListener;)V
(L1org/eclipse/core/commands/IExecutionListener;)V
removeState
(Ljava/lang/String;)V
(Ljava/lang/String;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ AUTOGENERATED_CATEGORY_ID

addCommandManagerListener
(Lorg/eclipse/core/commands/ICommandManagerListener;)V
(Lorg/eclipse/core/commands/ICommandManagerListener;)V
(L1org/eclipse/core/commands/ICommandManagerListener;)V
addExecutionListener
(Lorg/eclipse/core/commands/IExecutionListener;)V
(Lorg/eclipse/core/commands/IExecutionListener;)V
(L1org/eclipse/core/commands/IExecutionListener;)V
categoryChanged
(Lorg/eclipse/core/commands/CategoryEvent;)V
(L1org/eclipse/core/commands/CategoryEvent;)V # @Inherited(org.eclipse.core.commands.ICategoryListener)
Expand Down Expand Up @@ -79,10 +79,10 @@ parameterTypeChanged
(L1org/eclipse/core/commands/ParameterTypeEvent;)V # @Inherited(org.eclipse.core.commands.IParameterTypeListener)
removeCommandManagerListener
(Lorg/eclipse/core/commands/ICommandManagerListener;)V
(Lorg/eclipse/core/commands/ICommandManagerListener;)V
(L1org/eclipse/core/commands/ICommandManagerListener;)V
removeExecutionListener
(Lorg/eclipse/core/commands/IExecutionListener;)V
(Lorg/eclipse/core/commands/IExecutionListener;)V
(L1org/eclipse/core/commands/IExecutionListener;)V
setHandlersByCommandId
(Ljava/util/Map;)V
(Ljava/util/Map;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ class org/eclipse/core/commands/IExecutionListener

notHandled
(Ljava/lang/String;Lorg/eclipse/core/commands/NotHandledException;)V
(Ljava/lang/String;Lorg/eclipse/core/commands/NotHandledException;)V
(L1java/lang/String;L1org/eclipse/core/commands/NotHandledException;)V
postExecuteFailure
(Ljava/lang/String;Lorg/eclipse/core/commands/ExecutionException;)V
(Ljava/lang/String;Lorg/eclipse/core/commands/ExecutionException;)V
(L1java/lang/String;L1org/eclipse/core/commands/ExecutionException;)V
postExecuteSuccess
(Ljava/lang/String;Ljava/lang/Object;)V
(Ljava/lang/String;Ljava/lang/Object;)V
(L1java/lang/String;L0java/lang/Object;)V
preExecute
(Ljava/lang/String;Lorg/eclipse/core/commands/ExecutionEvent;)V
(Ljava/lang/String;Lorg/eclipse/core/commands/ExecutionEvent;)V
(L1java/lang/String;L1org/eclipse/core/commands/ExecutionEvent;)V
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ class org/eclipse/core/commands/IStateListener

handleStateChange
(Lorg/eclipse/core/commands/State;Ljava/lang/Object;)V
(Lorg/eclipse/core/commands/State;Ljava/lang/Object;)V
(L1org/eclipse/core/commands/State;L0java/lang/Object;)V
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class org/eclipse/core/commands/ParameterType

addListener
(Lorg/eclipse/core/commands/IParameterTypeListener;)V
(Lorg/eclipse/core/commands/IParameterTypeListener;)V
(L1org/eclipse/core/commands/IParameterTypeListener;)V
compareTo
(Ljava/lang/Object;)I
(Ljava/lang/Object;)I
Expand All @@ -17,7 +17,7 @@ isCompatible
(Ljava/lang/Object;)Z
removeListener
(Lorg/eclipse/core/commands/IParameterTypeListener;)V
(Lorg/eclipse/core/commands/IParameterTypeListener;)V
(L1org/eclipse/core/commands/IParameterTypeListener;)V
toString
()Ljava/lang/String;
()L1java/lang/String; # @Inherited(org.eclipse.core.commands.common.HandleObject)
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class org/eclipse/core/commands/State

addListener
(Lorg/eclipse/core/commands/IStateListener;)V
(Lorg/eclipse/core/commands/IStateListener;)V
(L1org/eclipse/core/commands/IStateListener;)V
fireStateChanged
(Ljava/lang/Object;)V
(Ljava/lang/Object;)V
Expand All @@ -14,7 +14,7 @@ getValue
()Ljava/lang/Object;
removeListener
(Lorg/eclipse/core/commands/IStateListener;)V
(Lorg/eclipse/core/commands/IStateListener;)V
(L1org/eclipse/core/commands/IStateListener;)V
setId
(Ljava/lang/String;)V
(Ljava/lang/String;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class org/eclipse/core/commands/contexts/Context

addContextListener
(Lorg/eclipse/core/commands/contexts/IContextListener;)V
(Lorg/eclipse/core/commands/contexts/IContextListener;)V
(L1org/eclipse/core/commands/contexts/IContextListener;)V
compareTo
(Ljava/lang/Object;)I
(Ljava/lang/Object;)I
Expand All @@ -14,7 +14,7 @@ getParentId
()Ljava/lang/String;
removeContextListener
(Lorg/eclipse/core/commands/contexts/IContextListener;)V
(Lorg/eclipse/core/commands/contexts/IContextListener;)V
(L1org/eclipse/core/commands/contexts/IContextListener;)V
toString
()Ljava/lang/String;
()L1java/lang/String; # @Inherited(org.eclipse.core.commands.common.HandleObject)
Loading

0 comments on commit 5c5b3ae

Please sign in to comment.