diff --git a/injector/src/main/java/edu/ucr/cs/riple/injector/Helper.java b/injector/src/main/java/edu/ucr/cs/riple/injector/Helper.java index a509ae61c..a39b4d20c 100644 --- a/injector/src/main/java/edu/ucr/cs/riple/injector/Helper.java +++ b/injector/src/main/java/edu/ucr/cs/riple/injector/Helper.java @@ -22,8 +22,10 @@ package edu.ucr.cs.riple.injector; +import com.github.javaparser.JavaToken; import com.github.javaparser.ParserConfiguration; import com.github.javaparser.Range; +import com.github.javaparser.TokenRange; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; @@ -608,7 +610,16 @@ public static Range findSimpleNameRangeInTypeName(Type type) { return ((ClassOrInterfaceType) type).getName().getRange().get(); } if (type instanceof ArrayType) { - return findSimpleNameRangeInTypeName(((ArrayType) type).getComponentType()); + Optional tokenRange = type.getTokenRange(); + if (tokenRange.isEmpty()) { + return null; + } + for (JavaToken javaToken : tokenRange.get()) { + if (javaToken.asString().equals("[")) { + return javaToken.getRange().orElse(null); + } + } + return null; } if (type instanceof PrimitiveType) { if (type.getRange().isEmpty()) { diff --git a/injector/src/main/java/edu/ucr/cs/riple/injector/changes/AddTypeUseMarkerAnnotation.java b/injector/src/main/java/edu/ucr/cs/riple/injector/changes/AddTypeUseMarkerAnnotation.java index 876962dcf..9c16aa8e8 100644 --- a/injector/src/main/java/edu/ucr/cs/riple/injector/changes/AddTypeUseMarkerAnnotation.java +++ b/injector/src/main/java/edu/ucr/cs/riple/injector/changes/AddTypeUseMarkerAnnotation.java @@ -108,6 +108,7 @@ public RemoveAnnotation getReverse() { @Nullable public AddTypeUseMarkerAnnotation toDeclaration() { // check if the annotation is on array declaration + // TODO check this for array. if (isOnLocalVariableArray() && typeIndex.contains(ImmutableList.of(0))) { return null; } diff --git a/injector/src/main/java/edu/ucr/cs/riple/injector/changes/TypeArgumentChangeVisitor.java b/injector/src/main/java/edu/ucr/cs/riple/injector/changes/TypeArgumentChangeVisitor.java index b4ef1632d..f1cc0cfa7 100644 --- a/injector/src/main/java/edu/ucr/cs/riple/injector/changes/TypeArgumentChangeVisitor.java +++ b/injector/src/main/java/edu/ucr/cs/riple/injector/changes/TypeArgumentChangeVisitor.java @@ -80,7 +80,20 @@ public Set visit(ClassOrInterfaceType type, TypeUseAnnotationChang @Override public Set visit(ArrayType type, TypeUseAnnotationChange change) { - return type.getComponentType().accept(this, change); + if (index.size() == 1 && index.getFirst() == 0) { + Modification onType = change.computeTextModificationOnType(type, annotationExpr); + if (onType != null) { + return Set.of(onType); + } + } + // if current index is 1, the process component type + if (!index.isEmpty()) { + boolean onComponentType = index.pollFirst() == 1; + if (onComponentType) { + return type.getComponentType().accept(this, change); + } + } + return Collections.emptySet(); } @Override diff --git a/injector/src/test/java/edu/ucr/cs/riple/injector/TypeUseAnnotationTest.java b/injector/src/test/java/edu/ucr/cs/riple/injector/TypeUseAnnotationTest.java index 3b22ee341..415b88b62 100644 --- a/injector/src/test/java/edu/ucr/cs/riple/injector/TypeUseAnnotationTest.java +++ b/injector/src/test/java/edu/ucr/cs/riple/injector/TypeUseAnnotationTest.java @@ -140,7 +140,7 @@ public void additionOnFullyQualifiedTypeNamesTest() { "import edu.ucr.custom.Nullable;", "public class Foo {", " java.lang.@Nullable Object bar;", - " java.util.@Nullable Map f0;", + " java.util.@Nullable Map f0;", " java.lang.@Nullable Object baz(java.lang.@Nullable Object param) {;", " java.lang.@Nullable Object localVar;", " return new Object();", @@ -175,7 +175,7 @@ public void deletionOnFullyQualifiedTypeNamesTest() { "import edu.ucr.custom.Nullable;", "public class Foo {", " java.lang.@Nullable Object bar;", - " java.util.@Nullable Map f0;", + " java.util.@Nullable Map f0;", " java.lang.@Nullable Object baz(java.lang.@Nullable Object param) {;", " java.lang.@Nullable Object localVar;", " return new Object();", @@ -186,7 +186,7 @@ public void deletionOnFullyQualifiedTypeNamesTest() { "import edu.ucr.custom.Nullable;", "public class Foo {", " java.lang.Object bar;", - " java.util.Map f0;", + " java.util.Map f0;", " java.lang.Object baz(java.lang.Object param) {;", " java.lang.Object localVar;", " return new Object();", @@ -222,7 +222,7 @@ public void additionOnArrayTest() { " public void foo() {", " java.util.Map f0;", " Map[] f1;", - " String[] f2;", + " int[] f2;", " }", "}") .expectOutput( @@ -230,9 +230,9 @@ public void additionOnArrayTest() { "import edu.ucr.custom.Nullable;", "public class Foo {", " public void foo() {", - " java.util.@Nullable Map f0;", - " @Nullable Map<@Nullable T, @Nullable T>[] f1;", - " @Nullable String[] f2;", + " java.util.@Nullable Map f0;", + " Map<@Nullable T, @Nullable T>@Nullable [] f1;", + " int@Nullable [] f2;", " }", "}") .addChanges( @@ -245,7 +245,7 @@ public void additionOnArrayTest() { new OnLocalVariable("Foo.java", "test.Foo", "foo()", "f1"), "edu.ucr.custom.Nullable", ImmutableList.of( - ImmutableList.of(0), ImmutableList.of(1, 0), ImmutableList.of(2, 0))), + ImmutableList.of(0), ImmutableList.of(1, 1, 0), ImmutableList.of(1, 2, 0))), new AddTypeUseMarkerAnnotation( new OnLocalVariable("Foo.java", "test.Foo", "foo()", "f2"), "edu.ucr.custom.Nullable")) @@ -261,14 +261,14 @@ public void deletionOnArrayTest() { "import edu.ucr.custom.Nullable;", "public class Foo {", " java.util.Map f0;", - " java.util.@Nullable Map<@Nullable String, @Nullable String[]> f1;", - " @Nullable Map[] f2;", + " java.util.@Nullable Map<@Nullable String, String@Nullable []> f1;", + " Map@Nullable [] f2;", "}") .expectOutput( "package test;", "import edu.ucr.custom.Nullable;", "public class Foo {", - " java.util.@Nullable Map<@Nullable String, @Nullable String[]> f0;", + " java.util.@Nullable Map<@Nullable String, String@Nullable []> f0;", " java.util.Map f1;", " Map[] f2;", "}") @@ -287,7 +287,7 @@ public void deletionOnArrayTest() { new OnField("Foo.java", "test.Foo", Set.of("f2")), "edu.ucr.custom.Nullable", ImmutableList.of( - ImmutableList.of(0), ImmutableList.of(1, 0), ImmutableList.of(2, 0)))) + ImmutableList.of(0), ImmutableList.of(1, 1, 0), ImmutableList.of(1, 2, 0)))) .start(); } @@ -409,7 +409,7 @@ public void deletionOnInitializerTest() { " @Nullable int f0 = 0;", " @Nullable Bar<@Nullable String, @Nullable Integer, @Nullable Baz<@Nullable String, @Nullable Integer>> f1 = new Bar<@Nullable String, @Nullable Integer, @Nullable Baz<@Nullable String, @Nullable Integer>>();", " @Nullable String f2 = \"FOO\";", - " @Nullable Bar<@Nullable String, @Nullable Integer[], @Nullable Baz<@Nullable String, @Nullable Integer>> f3 = new Bar<@Nullable String, @Nullable Integer[], @Nullable Baz<@Nullable String, @Nullable Integer>>();", + " @Nullable Bar<@Nullable String, Integer@Nullable [], @Nullable Baz<@Nullable String, @Nullable Integer>> f3 = new Bar<@Nullable String, Integer@Nullable [], @Nullable Baz<@Nullable String, @Nullable Integer>>();", " }", "}") .expectOutput( @@ -775,4 +775,50 @@ public void multipleInlineLocalVariableTest() { ImmutableList.of(ImmutableList.of(1, 0)))) .start(); } + + @Test + public void nullableArrayAdditionOnReference() { + injectorTestHelper + .addInput( + "Foo.java", + "package test;", + "import javax.annotation.Nullable;", + "public class Foo {", + " Object[] h = new Object[4];", + "}") + .expectOutput( + "package test;", + "import javax.annotation.Nullable;", + "public class Foo {", + " Object@Nullable [] h = new Object[4];", + "}") + .addChanges( + new AddTypeUseMarkerAnnotation( + new OnField("Foo.java", "test.Foo", Collections.singleton("h")), + "javax.annotation.Nullable")) + .start(); + } + + @Test + public void nullableArrayDeletionOnReference() { + injectorTestHelper + .addInput( + "Foo.java", + "package test;", + "import javax.annotation.Nullable;", + "public class Foo {", + " Object@Nullable [] h = new Object[4];", + "}") + .expectOutput( + "package test;", + "import javax.annotation.Nullable;", + "public class Foo {", + " Object[] h = new Object[4];", + "}") + .addChanges( + new RemoveTypeUseMarkerAnnotation( + new OnField("Foo.java", "test.Foo", Collections.singleton("h")), + "javax.annotation.Nullable")) + .start(); + } }