From dcb52e527002e214817b23a9497408634c68357e Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sat, 12 Aug 2023 15:57:41 -0700 Subject: [PATCH 01/16] WIP --- gradle/dependencies.gradle | 2 +- .../nullaway/dataflow/AccessPathNullnessPropagation.java | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 481be0dc74..10e059ac7f 100755 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -40,7 +40,7 @@ if (project.hasProperty("epApiVersion")) { def versions = [ asm : "9.3", - checkerFramework : "3.26.0", + checkerFramework : "3.37.0", // for comparisons in other parts of the build errorProneLatest : latestErrorProneVersion, // The version of Error Prone used to check NullAway's code. diff --git a/nullaway/src/main/java/com/uber/nullaway/dataflow/AccessPathNullnessPropagation.java b/nullaway/src/main/java/com/uber/nullaway/dataflow/AccessPathNullnessPropagation.java index 60b80399fc..00d72cda8f 100644 --- a/nullaway/src/main/java/com/uber/nullaway/dataflow/AccessPathNullnessPropagation.java +++ b/nullaway/src/main/java/com/uber/nullaway/dataflow/AccessPathNullnessPropagation.java @@ -113,7 +113,6 @@ import org.checkerframework.nullaway.dataflow.cfg.node.ReturnNode; import org.checkerframework.nullaway.dataflow.cfg.node.ShortLiteralNode; import org.checkerframework.nullaway.dataflow.cfg.node.SignedRightShiftNode; -import org.checkerframework.nullaway.dataflow.cfg.node.StringConcatenateAssignmentNode; import org.checkerframework.nullaway.dataflow.cfg.node.StringConcatenateNode; import org.checkerframework.nullaway.dataflow.cfg.node.StringConversionNode; import org.checkerframework.nullaway.dataflow.cfg.node.StringLiteralNode; @@ -376,13 +375,6 @@ public TransferResult visitBitwiseXor( return noStoreChanges(NONNULL, input); } - @Override - public TransferResult visitStringConcatenateAssignment( - StringConcatenateAssignmentNode stringConcatenateAssignmentNode, - TransferInput input) { - return noStoreChanges(NULLABLE, input); - } - @Override public TransferResult visitLessThan( LessThanNode lessThanNode, TransferInput input) { From 527f74931f0bafc2248f674aba0e11d876548df8 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Fri, 25 Aug 2023 18:12:21 -0700 Subject: [PATCH 02/16] WIP --- build.gradle | 1 + gradle/dependencies.gradle | 2 +- .../nullaway/dataflow/AccessPathNullnessPropagation.java | 8 ++++++++ .../uber/nullaway/dataflow/cfg/NullAwayCFGBuilder.java | 2 +- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index db827fa246..956ca9478b 100644 --- a/build.gradle +++ b/build.gradle @@ -102,6 +102,7 @@ subprojects { project -> repositories { mavenCentral() google() + mavenLocal() } // For some reason, spotless complains when applied to the jar-infer folder itself, even diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 226d962ae5..76eba3b73b 100755 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -40,7 +40,7 @@ if (project.hasProperty("epApiVersion")) { def versions = [ asm : "9.3", - checkerFramework : "3.37.0", + checkerFramework : "3.37.1-SNAPSHOT", // for comparisons in other parts of the build errorProneLatest : latestErrorProneVersion, // The version of Error Prone used to check NullAway's code. diff --git a/nullaway/src/main/java/com/uber/nullaway/dataflow/AccessPathNullnessPropagation.java b/nullaway/src/main/java/com/uber/nullaway/dataflow/AccessPathNullnessPropagation.java index 00d72cda8f..6681d69797 100644 --- a/nullaway/src/main/java/com/uber/nullaway/dataflow/AccessPathNullnessPropagation.java +++ b/nullaway/src/main/java/com/uber/nullaway/dataflow/AccessPathNullnessPropagation.java @@ -75,6 +75,7 @@ import org.checkerframework.nullaway.dataflow.cfg.node.DoubleLiteralNode; import org.checkerframework.nullaway.dataflow.cfg.node.EqualToNode; import org.checkerframework.nullaway.dataflow.cfg.node.ExplicitThisNode; +import org.checkerframework.nullaway.dataflow.cfg.node.ExpressionStatementNode; import org.checkerframework.nullaway.dataflow.cfg.node.FieldAccessNode; import org.checkerframework.nullaway.dataflow.cfg.node.FloatLiteralNode; import org.checkerframework.nullaway.dataflow.cfg.node.FloatingDivisionNode; @@ -1077,6 +1078,13 @@ public TransferResult visitClassDeclaration( return noStoreChanges(NULLABLE, input); } + @Override + public TransferResult visitExpressionStatement( + ExpressionStatementNode expressionStatementNode, + TransferInput input) { + return noStoreChanges(NULLABLE, input); + } + @Override public TransferResult visitPackageName( PackageNameNode packageNameNode, TransferInput input) { diff --git a/nullaway/src/main/java/com/uber/nullaway/dataflow/cfg/NullAwayCFGBuilder.java b/nullaway/src/main/java/com/uber/nullaway/dataflow/cfg/NullAwayCFGBuilder.java index bf5070866d..2f955b7b51 100644 --- a/nullaway/src/main/java/com/uber/nullaway/dataflow/cfg/NullAwayCFGBuilder.java +++ b/nullaway/src/main/java/com/uber/nullaway/dataflow/cfg/NullAwayCFGBuilder.java @@ -187,7 +187,7 @@ public R accept(TreeVisitor visitor, D data) { } }, booleanExpressionNode, - this.getProcessingEnvironment().getTypeUtils()), + this.env.getTypeUtils()), errorType); exNode.setTerminatesExecution(true); this.addLabelForNextNode(endPrecondition); From 8acfb89530ac34d13b005b12aaa382d1d57c01bf Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Fri, 25 Aug 2023 19:42:17 -0700 Subject: [PATCH 03/16] WIP --- nullaway/build.gradle | 31 +++++++++++++++++++ .../main/java/com/uber/nullaway/NullAway.java | 24 +++++++++----- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/nullaway/build.gradle b/nullaway/build.gradle index 5b6346f4a9..77aecd0a56 100644 --- a/nullaway/build.gradle +++ b/nullaway/build.gradle @@ -141,6 +141,37 @@ def jdk8Test = tasks.register("testJdk8", Test) { jvmArgs "-Xbootclasspath/p:${configurations.errorproneJavac.asPath}" } +// Create a task to test on JDK 8 +def jdk21Test = tasks.register("testJdk21", Test) { + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(21) + } + + description = "Runs the test suite on JDK 21" + group = LifecycleBasePlugin.VERIFICATION_GROUP + + // Copy inputs from normal Test task. + def testTask = tasks.getByName("test") + classpath = testTask.classpath + testClassesDirs = testTask.testClassesDirs + maxHeapSize = "1024m" + // to expose necessary JDK types on JDK 16+; see https://errorprone.info/docs/installation#java-9-and-newer + jvmArgs += [ + "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", + "--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", + "--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED", + // Accessed by Lombok tests + "--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED", + ] +} + tasks.named('check').configure { dependsOn(jdk8Test) } diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index bfed0af259..0490256810 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -475,7 +475,7 @@ public Description matchAssignment(AssignmentTree tree, VisitorState state) { doUnboxingCheck(state, tree.getExpression()); } // generics check - if (lhsType != null && lhsType.getTypeArguments().length() > 0) { + if (lhsType != null && lhsType.getTypeArguments().length() > 0 && config.isJSpecifyMode()) { GenericsChecks.checkTypeParameterNullnessForAssignability(tree, this, state); } @@ -693,7 +693,9 @@ public Description matchParameterizedType(ParameterizedTypeTree tree, VisitorSta if (!withinAnnotatedCode(state)) { return Description.NO_MATCH; } - GenericsChecks.checkInstantiationForParameterizedTypedTree(tree, state, this, config); + if (config.isJSpecifyMode()) { + GenericsChecks.checkInstantiationForParameterizedTypedTree(tree, state, this, config); + } return Description.NO_MATCH; } @@ -869,8 +871,10 @@ private Description checkReturnExpression( state, methodSymbol); } - GenericsChecks.checkTypeParameterNullnessForFunctionReturnType( - retExpr, methodSymbol, this, state); + if (config.isJSpecifyMode()) { + GenericsChecks.checkTypeParameterNullnessForFunctionReturnType( + retExpr, methodSymbol, this, state); + } return Description.NO_MATCH; } @@ -1365,7 +1369,7 @@ public Description matchVariable(VariableTree tree, VisitorState state) { return Description.NO_MATCH; } VarSymbol symbol = ASTHelpers.getSymbol(tree); - if (tree.getInitializer() != null) { + if (tree.getInitializer() != null && config.isJSpecifyMode()) { GenericsChecks.checkTypeParameterNullnessForAssignability(tree, this, state); } @@ -1518,7 +1522,9 @@ public Description matchUnary(UnaryTree tree, VisitorState state) { public Description matchConditionalExpression( ConditionalExpressionTree tree, VisitorState state) { if (withinAnnotatedCode(state)) { - GenericsChecks.checkTypeParameterNullnessForConditionalExpression(tree, this, state); + if (config.isJSpecifyMode()) { + GenericsChecks.checkTypeParameterNullnessForConditionalExpression(tree, this, state); + } doUnboxingCheck(state, tree.getCondition()); } return Description.NO_MATCH; @@ -1649,8 +1655,10 @@ private Description handleInvocation( : Nullness.NONNULL); } } - GenericsChecks.compareGenericTypeParameterNullabilityForCall( - formalParams, actualParams, methodSymbol.isVarArgs(), this, state); + if (config.isJSpecifyMode()) { + GenericsChecks.compareGenericTypeParameterNullabilityForCall( + formalParams, actualParams, methodSymbol.isVarArgs(), this, state); + } } // Allow handlers to override the list of non-null argument positions From 1102fd797ba3c95f718b1147f954b354e1be0fe3 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sat, 26 Aug 2023 14:25:14 -0700 Subject: [PATCH 04/16] WIP --- .../com/uber/nullaway/GenericsChecks.java | 31 +++++++++++++++++-- .../java/com/uber/nullaway/PreJDK21Util.java | 12 +++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 nullaway/src/main/java/com/uber/nullaway/PreJDK21Util.java diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index bd1be2a876..4590a94628 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -26,6 +26,9 @@ import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.TypeMetadata; import com.sun.tools.javac.code.Types; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -452,8 +455,14 @@ private static Type.ClassType typeWithPreservedAnnotations( new Attribute.TypeCompound( nullableType, com.sun.tools.javac.util.List.nil(), null))) : com.sun.tools.javac.util.List.nil(); - TypeMetadata typeMetadata = - new TypeMetadata(new TypeMetadata.Annotations(nullableAnnotationCompound)); + // TypeMetadata typeMetadata = + // new TypeMetadata(new TypeMetadata.Annotations(nullableAnnotationCompound)); + TypeMetadata typeMetadata = null; + try { + typeMetadata = (TypeMetadata) typeMetadataHandle.invoke(nullableAnnotationCompound); + } catch (Throwable e) { + throw new RuntimeException(e); + } Type currentTypeArgType = castToNonNull(ASTHelpers.getType(curTypeArg)); if (currentTypeArgType.getTypeArguments().size() > 0) { // nested generic type; recursively preserve its nullability type argument annotations @@ -916,4 +925,22 @@ public String visitType(Type t, Void s) { return t.toString(); } }; + + static final MethodHandle typeMetadataHandle; + + static { + try { + typeMetadataHandle = createHandle(); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private static MethodHandle createHandle() throws NoSuchMethodException, IllegalAccessException { + MethodHandles.Lookup lookup = MethodHandles.publicLookup(); + MethodType mt = MethodType.methodType(TypeMetadata.class, com.sun.tools.javac.util.List.class); + return lookup.findStatic(PreJDK21Util.class, "createTypeMetadata", mt); + } } diff --git a/nullaway/src/main/java/com/uber/nullaway/PreJDK21Util.java b/nullaway/src/main/java/com/uber/nullaway/PreJDK21Util.java new file mode 100644 index 0000000000..8252ccbde7 --- /dev/null +++ b/nullaway/src/main/java/com/uber/nullaway/PreJDK21Util.java @@ -0,0 +1,12 @@ +package com.uber.nullaway; + +import com.sun.tools.javac.code.Attribute; +import com.sun.tools.javac.code.TypeMetadata; + +public class PreJDK21Util { + + public static TypeMetadata createTypeMetadata( + com.sun.tools.javac.util.List attrs) { + return new TypeMetadata(new TypeMetadata.Annotations(attrs)); + } +} From 62434ccb9947309d7dffdff4947ce37fb9c8e18a Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sun, 27 Aug 2023 16:01:16 -0700 Subject: [PATCH 05/16] WIP --- .../com/uber/nullaway/GenericsChecks.java | 72 ++++++++++++++----- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 4590a94628..748b0c91ee 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -26,6 +26,7 @@ import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.TypeMetadata; import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.util.ListBuffer; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -457,12 +458,7 @@ private static Type.ClassType typeWithPreservedAnnotations( : com.sun.tools.javac.util.List.nil(); // TypeMetadata typeMetadata = // new TypeMetadata(new TypeMetadata.Annotations(nullableAnnotationCompound)); - TypeMetadata typeMetadata = null; - try { - typeMetadata = (TypeMetadata) typeMetadataHandle.invoke(nullableAnnotationCompound); - } catch (Throwable e) { - throw new RuntimeException(e); - } + TypeMetadata typeMetadata = tmBuilder.create(nullableAnnotationCompound); Type currentTypeArgType = castToNonNull(ASTHelpers.getType(curTypeArg)); if (currentTypeArgType.getTypeArguments().size() > 0) { // nested generic type; recursively preserve its nullability type argument annotations @@ -926,21 +922,61 @@ public String visitType(Type t, Void s) { } }; - static final MethodHandle typeMetadataHandle; + private interface TypeMetadataBuilder { + TypeMetadata create(com.sun.tools.javac.util.List attrs); + } + + private static class JDK17AndEarlierTypeMetadataBuilder implements TypeMetadataBuilder { - static { - try { - typeMetadataHandle = createHandle(); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); + @Override + public TypeMetadata create(com.sun.tools.javac.util.List attrs) { + return new TypeMetadata(new TypeMetadata.Annotations(attrs)); } } - private static MethodHandle createHandle() throws NoSuchMethodException, IllegalAccessException { - MethodHandles.Lookup lookup = MethodHandles.publicLookup(); - MethodType mt = MethodType.methodType(TypeMetadata.class, com.sun.tools.javac.util.List.class); - return lookup.findStatic(PreJDK21Util.class, "createTypeMetadata", mt); + private static class JDK21TypeMetadataBuilder implements TypeMetadataBuilder { + + private static final MethodHandle typeMetadataHandle = createHandle(); + + private static MethodHandle createHandle() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodType mt = MethodType.methodType(void.class, com.sun.tools.javac.util.ListBuffer.class); + try { + return lookup.findConstructor(TypeMetadata.Annotations.class, mt); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @Override + public TypeMetadata create(com.sun.tools.javac.util.List attrs) { + ListBuffer b = new ListBuffer<>(); + b.appendList(attrs); + try { + return (TypeMetadata) typeMetadataHandle.invoke(b); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } + + private static final TypeMetadataBuilder tmBuilder = + getVersion() >= 21 + ? new JDK21TypeMetadataBuilder() + : new JDK17AndEarlierTypeMetadataBuilder(); + + private static int getVersion() { + String version = System.getProperty("java.version"); + if (version.startsWith("1.")) { + version = version.substring(2, 3); + } else { + int dot = version.indexOf("."); + if (dot != -1) { + version = version.substring(0, dot); + } + } + return Integer.parseInt(version); } } From 121e735557581a6c44cc5ccdee9d5e1ce9e16553 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Mon, 13 Nov 2023 14:14:17 -0800 Subject: [PATCH 06/16] remove unused class --- .../main/java/com/uber/nullaway/PreJDK21Util.java | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 nullaway/src/main/java/com/uber/nullaway/PreJDK21Util.java diff --git a/nullaway/src/main/java/com/uber/nullaway/PreJDK21Util.java b/nullaway/src/main/java/com/uber/nullaway/PreJDK21Util.java deleted file mode 100644 index 8252ccbde7..0000000000 --- a/nullaway/src/main/java/com/uber/nullaway/PreJDK21Util.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.uber.nullaway; - -import com.sun.tools.javac.code.Attribute; -import com.sun.tools.javac.code.TypeMetadata; - -public class PreJDK21Util { - - public static TypeMetadata createTypeMetadata( - com.sun.tools.javac.util.List attrs) { - return new TypeMetadata(new TypeMetadata.Annotations(attrs)); - } -} From ce338a61f32b3a2269ec1ac934937ff5a53ad446 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Mon, 13 Nov 2023 15:59:17 -0800 Subject: [PATCH 07/16] run the generics tests --- nullaway/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nullaway/build.gradle b/nullaway/build.gradle index 90ac062418..d341070f80 100644 --- a/nullaway/build.gradle +++ b/nullaway/build.gradle @@ -128,7 +128,7 @@ tasks.named('testJdk21', Test).configure { filter { // JSpecify Generics tests do not yet pass on JDK 21 // See https://github.com/uber/NullAway/issues/827 - excludeTestsMatching "com.uber.nullaway.NullAwayJSpecifyGenericsTests" + //excludeTestsMatching "com.uber.nullaway.NullAwayJSpecifyGenericsTests" } } From ef844c80a1ad82d0699e4082748dfe995c49f6a2 Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Sat, 25 Nov 2023 14:12:57 -0800 Subject: [PATCH 08/16] adding logic for using addMetadata and dropMetadata through methodHandle --- .../PreservedAnnotationTreeVisitor.java | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java index 84dc4e7b84..dfb3fe6774 100644 --- a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java +++ b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java @@ -80,7 +80,7 @@ public Type visitParameterizedType(ParameterizedTypeTree tree, Void p) { : com.sun.tools.javac.util.List.nil(); TypeMetadata typeMetadata = tmBuilder.create(nullableAnnotationCompound); Type currentTypeArgType = curTypeArg.accept(this, null); - Type newTypeArgType = currentTypeArgType.cloneWithMetadata(typeMetadata); + Type newTypeArgType = tmBuilder.cloneTypeWithMetaData(currentTypeArgType, typeMetadata); newTypeArgs.add(newTypeArgType); } Type.ClassType finalType = @@ -97,6 +97,8 @@ protected Type defaultAction(Tree node, Void unused) { private interface TypeMetadataBuilder { TypeMetadata create(com.sun.tools.javac.util.List attrs); + + Type cloneTypeWithMetaData(Type typeToBeCloned, TypeMetadata metaData); } private static class JDK17AndEarlierTypeMetadataBuilder implements TypeMetadataBuilder { @@ -105,11 +107,18 @@ private static class JDK17AndEarlierTypeMetadataBuilder implements TypeMetadataB public TypeMetadata create(com.sun.tools.javac.util.List attrs) { return new TypeMetadata(new TypeMetadata.Annotations(attrs)); } + + @Override + public Type cloneTypeWithMetaData(Type typeToBeCloned, TypeMetadata metaData) { + return typeToBeCloned.cloneWithMetadata(metaData); + } } private static class JDK21TypeMetadataBuilder implements TypeMetadataBuilder { private static final MethodHandle typeMetadataHandle = createHandle(); + private static final MethodHandle cloneAddMetadataHandle = createAddMethodHandle(); + private static final MethodHandle cloneDropMetadataHandle = createDropMethodHandle(); private static MethodHandle createHandle() { MethodHandles.Lookup lookup = MethodHandles.lookup(); @@ -123,6 +132,30 @@ private static MethodHandle createHandle() { } } + private static MethodHandle createAddMethodHandle() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodType mt = MethodType.methodType(Type.class, TypeMetadata.class); + try { + return lookup.findVirtual(com.sun.tools.javac.code.Type.class, "addMetadata", mt); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private static MethodHandle createDropMethodHandle() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodType mt = MethodType.methodType(Type.class, Class.class); + try { + return lookup.findVirtual(com.sun.tools.javac.code.Type.class, "dropMetadata", mt); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + @Override public TypeMetadata create(com.sun.tools.javac.util.List attrs) { ListBuffer b = new ListBuffer<>(); @@ -133,6 +166,23 @@ public TypeMetadata create(com.sun.tools.javac.util.List throw new RuntimeException(e); } } + + @Override + public Type cloneTypeWithMetaData(Type typeToBeCloned, TypeMetadata metaData) { + try { + Type clonedType = null; + if (metaData.getClass().getComponentType() != null) { + clonedType = (Type) cloneAddMetadataHandle.invoke(typeToBeCloned, metaData); + } else { + Type clonedTypeDrop = + (Type) cloneDropMetadataHandle.invoke(typeToBeCloned, metaData.getClass()); + clonedType = (Type) cloneAddMetadataHandle.invoke(clonedTypeDrop, metaData); + } + return clonedType; + } catch (Throwable e) { + throw new RuntimeException(e); + } + } } private static final TypeMetadataBuilder tmBuilder = From 79bc5790292b41e43b01dff30ef83be81fa78b14 Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Sun, 26 Nov 2023 00:16:39 -0800 Subject: [PATCH 09/16] cleaning up unnecessary condition and adding a comment --- .../generics/PreservedAnnotationTreeVisitor.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java index dfb3fe6774..aabc35ee67 100644 --- a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java +++ b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java @@ -170,15 +170,11 @@ public TypeMetadata create(com.sun.tools.javac.util.List @Override public Type cloneTypeWithMetaData(Type typeToBeCloned, TypeMetadata metaData) { try { - Type clonedType = null; - if (metaData.getClass().getComponentType() != null) { - clonedType = (Type) cloneAddMetadataHandle.invoke(typeToBeCloned, metaData); - } else { - Type clonedTypeDrop = - (Type) cloneDropMetadataHandle.invoke(typeToBeCloned, metaData.getClass()); - clonedType = (Type) cloneAddMetadataHandle.invoke(clonedTypeDrop, metaData); - } - return clonedType; + // In Jdk21 addMetadata works if there is no metadata associated with the type, so we create + // a copy without the existing metadata first and then add it + Type clonedTypeWithoutMetadata = + (Type) cloneDropMetadataHandle.invoke(typeToBeCloned, metaData.getClass()); + return (Type) cloneAddMetadataHandle.invoke(clonedTypeWithoutMetadata, metaData); } catch (Throwable e) { throw new RuntimeException(e); } From ee143b177a0dafb8e009cff10f9b987b6a5c36bf Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Sun, 26 Nov 2023 01:25:40 -0800 Subject: [PATCH 10/16] creating a common method for creating virtual method handle to re-use for both add and drop metadata --- .../PreservedAnnotationTreeVisitor.java | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java index aabc35ee67..e9c5595deb 100644 --- a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java +++ b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java @@ -117,8 +117,10 @@ public Type cloneTypeWithMetaData(Type typeToBeCloned, TypeMetadata metaData) { private static class JDK21TypeMetadataBuilder implements TypeMetadataBuilder { private static final MethodHandle typeMetadataHandle = createHandle(); - private static final MethodHandle cloneAddMetadataHandle = createAddMethodHandle(); - private static final MethodHandle cloneDropMetadataHandle = createDropMethodHandle(); + private static final MethodHandle cloneAddMetadataHandle = + createVirtualMethodHandle(Type.class, TypeMetadata.class, Type.class, "addMetadata"); + private static final MethodHandle cloneDropMetadataHandle = + createVirtualMethodHandle(Type.class, Class.class, Type.class, "dropMetadata"); private static MethodHandle createHandle() { MethodHandles.Lookup lookup = MethodHandles.lookup(); @@ -132,23 +134,12 @@ private static MethodHandle createHandle() { } } - private static MethodHandle createAddMethodHandle() { + private static MethodHandle createVirtualMethodHandle( + Class retTypeClass, Class paramTypeClass, Class refClass, String methodName) { MethodHandles.Lookup lookup = MethodHandles.lookup(); - MethodType mt = MethodType.methodType(Type.class, TypeMetadata.class); + MethodType mt = MethodType.methodType(retTypeClass, paramTypeClass); try { - return lookup.findVirtual(com.sun.tools.javac.code.Type.class, "addMetadata", mt); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - private static MethodHandle createDropMethodHandle() { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - MethodType mt = MethodType.methodType(Type.class, Class.class); - try { - return lookup.findVirtual(com.sun.tools.javac.code.Type.class, "dropMetadata", mt); + return lookup.findVirtual(refClass, methodName, mt); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { From 62500ed9774dcc52e62e17bfc8325dba550ad11e Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Mon, 27 Nov 2023 16:01:11 -0800 Subject: [PATCH 11/16] method names and other minor updates, updating build.gradle to remove unnecessary code --- nullaway/build.gradle | 8 -------- .../PreservedAnnotationTreeVisitor.java | 18 +++++++++--------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/nullaway/build.gradle b/nullaway/build.gradle index d341070f80..829917f026 100644 --- a/nullaway/build.gradle +++ b/nullaway/build.gradle @@ -124,14 +124,6 @@ tasks.named('check').configure { dependsOn(jdk8Test) } -tasks.named('testJdk21', Test).configure { - filter { - // JSpecify Generics tests do not yet pass on JDK 21 - // See https://github.com/uber/NullAway/issues/827 - //excludeTestsMatching "com.uber.nullaway.NullAwayJSpecifyGenericsTests" - } -} - // Create a task to build NullAway with NullAway checking enabled tasks.register('buildWithNullAway', JavaCompile) { onlyIf { diff --git a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java index e9c5595deb..e039750612 100644 --- a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java +++ b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java @@ -80,7 +80,7 @@ public Type visitParameterizedType(ParameterizedTypeTree tree, Void p) { : com.sun.tools.javac.util.List.nil(); TypeMetadata typeMetadata = tmBuilder.create(nullableAnnotationCompound); Type currentTypeArgType = curTypeArg.accept(this, null); - Type newTypeArgType = tmBuilder.cloneTypeWithMetaData(currentTypeArgType, typeMetadata); + Type newTypeArgType = tmBuilder.cloneTypeWithMetadata(currentTypeArgType, typeMetadata); newTypeArgs.add(newTypeArgType); } Type.ClassType finalType = @@ -98,7 +98,7 @@ protected Type defaultAction(Tree node, Void unused) { private interface TypeMetadataBuilder { TypeMetadata create(com.sun.tools.javac.util.List attrs); - Type cloneTypeWithMetaData(Type typeToBeCloned, TypeMetadata metaData); + Type cloneTypeWithMetadata(Type typeToBeCloned, TypeMetadata metaData); } private static class JDK17AndEarlierTypeMetadataBuilder implements TypeMetadataBuilder { @@ -109,17 +109,17 @@ public TypeMetadata create(com.sun.tools.javac.util.List } @Override - public Type cloneTypeWithMetaData(Type typeToBeCloned, TypeMetadata metaData) { - return typeToBeCloned.cloneWithMetadata(metaData); + public Type cloneTypeWithMetadata(Type typeToBeCloned, TypeMetadata metadata) { + return typeToBeCloned.cloneWithMetadata(metadata); } } private static class JDK21TypeMetadataBuilder implements TypeMetadataBuilder { private static final MethodHandle typeMetadataHandle = createHandle(); - private static final MethodHandle cloneAddMetadataHandle = + private static final MethodHandle addMetadataHandle = createVirtualMethodHandle(Type.class, TypeMetadata.class, Type.class, "addMetadata"); - private static final MethodHandle cloneDropMetadataHandle = + private static final MethodHandle dropMetadataHandle = createVirtualMethodHandle(Type.class, Class.class, Type.class, "dropMetadata"); private static MethodHandle createHandle() { @@ -159,13 +159,13 @@ public TypeMetadata create(com.sun.tools.javac.util.List } @Override - public Type cloneTypeWithMetaData(Type typeToBeCloned, TypeMetadata metaData) { + public Type cloneTypeWithMetadata(Type typeToBeCloned, TypeMetadata metadata) { try { // In Jdk21 addMetadata works if there is no metadata associated with the type, so we create // a copy without the existing metadata first and then add it Type clonedTypeWithoutMetadata = - (Type) cloneDropMetadataHandle.invoke(typeToBeCloned, metaData.getClass()); - return (Type) cloneAddMetadataHandle.invoke(clonedTypeWithoutMetadata, metaData); + (Type) dropMetadataHandle.invoke(typeToBeCloned, metadata.getClass()); + return (Type) addMetadataHandle.invoke(clonedTypeWithoutMetadata, metadata); } catch (Throwable e) { throw new RuntimeException(e); } From 417f88814d3b3be188913d2992640ec47d3d19f6 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Tue, 28 Nov 2023 14:47:36 -0800 Subject: [PATCH 12/16] Hacky way to collect test coverage for testJdk21 tasks --- .../nullaway.java-test-conventions.gradle | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle b/buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle index 07f8f2690e..8f7c31ffb3 100644 --- a/buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle +++ b/buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle @@ -44,22 +44,6 @@ configurations.create('transitiveSourcesElements') { } } -// Share the coverage data to be aggregated for the whole product -configurations.create('coverageDataElements') { - visible = false - canBeResolved = false - canBeConsumed = true - extendsFrom(configurations.implementation) - attributes { - attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_RUNTIME)) - attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.DOCUMENTATION)) - attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, 'jacoco-coverage-data')) - } - // This will cause the test task to run if the coverage data is requested by the aggregation task - outgoing.artifact(tasks.named("test").map { task -> - task.extensions.getByType(JacocoTaskExtension).destinationFile - }) -} test { maxHeapSize = "1024m" @@ -118,3 +102,21 @@ def testJdk21 = tasks.register("testJdk21", Test) { tasks.named('check').configure { dependsOn testJdk21 } + + +// Share the coverage data to be aggregated for the whole product +configurations.create('coverageDataElements') { + visible = false + canBeResolved = false + canBeConsumed = true + extendsFrom(configurations.implementation) + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_RUNTIME)) + attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.DOCUMENTATION)) + attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, 'jacoco-coverage-data')) + } + // This will cause the test tasks to run if the coverage data is requested by the aggregation task + tasks.withType(Test).forEach {task -> + outgoing.artifact(tasks.named(task.name).map { t -> t.extensions.getByType(JacocoTaskExtension).destinationFile }) + } +} From b0bf1ba0b5a415bba548168dd2cd68647204a620 Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Thu, 30 Nov 2023 21:55:12 -0800 Subject: [PATCH 13/16] Adding Java docs --- .../PreservedAnnotationTreeVisitor.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java index e039750612..efba65079e 100644 --- a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java +++ b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java @@ -95,12 +95,20 @@ protected Type defaultAction(Tree node, Void unused) { return castToNonNull(ASTHelpers.getType(node)); } + /** + * Provides abstraction for using Type and TypeMetadata library methods for different Jdk version + * implementations. + */ private interface TypeMetadataBuilder { TypeMetadata create(com.sun.tools.javac.util.List attrs); Type cloneTypeWithMetadata(Type typeToBeCloned, TypeMetadata metaData); } + /** + * Provides implementations for methods under TypeMetadataBuilder compatible with Jdk 17 and + * earlier versions. + */ private static class JDK17AndEarlierTypeMetadataBuilder implements TypeMetadataBuilder { @Override @@ -108,12 +116,24 @@ public TypeMetadata create(com.sun.tools.javac.util.List return new TypeMetadata(new TypeMetadata.Annotations(attrs)); } + /** + * Clones the given type with the specified Metadata for getting the right Nullability. + * + * @param typeToBeCloned The Type we want to clone with the required Nullability Metadata + * @param metadata The required Nullability metadata which is lost from the type + * @return Type after it has been cloned by applying the required Nullability metadata + */ @Override public Type cloneTypeWithMetadata(Type typeToBeCloned, TypeMetadata metadata) { return typeToBeCloned.cloneWithMetadata(metadata); } } + /** + * Provides implementations for methods under TypeMetadataBuilder compatible with the updates made + * to the library methods for Jdk 21. The implementation calls the logic specific to Jdk 21 + * indirectly using MethodHandles since we still need the code to compile on earlier versions. + */ private static class JDK21TypeMetadataBuilder implements TypeMetadataBuilder { private static final MethodHandle typeMetadataHandle = createHandle(); @@ -134,6 +154,15 @@ private static MethodHandle createHandle() { } } + /** + * Used to get a MethodHandle for a virtual method from the specified class + * + * @param retTypeClass Class to indicate the return type of the desired method + * @param paramTypeClass Class to indicate the parameter type of the desired method + * @param refClass Class within which the desired method is contained + * @param methodName Name of the desired method + * @return The appropriate MethodHandle for the virtual method + */ private static MethodHandle createVirtualMethodHandle( Class retTypeClass, Class paramTypeClass, Class refClass, String methodName) { MethodHandles.Lookup lookup = MethodHandles.lookup(); @@ -158,6 +187,14 @@ public TypeMetadata create(com.sun.tools.javac.util.List } } + /** + * Calls dropMetadata and addMetadata using MethodHandles for Jdk21 Implementation which + * deprecated the cloneWithMetadata method. + * + * @param typeToBeCloned The Type we want to clone with the required Nullability metadata + * @param metadata The required Nullability metadata + * @return Cloned Type with the necessary Nullability metadata + */ @Override public Type cloneTypeWithMetadata(Type typeToBeCloned, TypeMetadata metadata) { try { From 4c6ef166e3f56a902b267584113a75cb5067572d Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Fri, 1 Dec 2023 08:57:09 -0800 Subject: [PATCH 14/16] tweaks --- .../nullaway.java-test-conventions.gradle | 2 ++ .../PreservedAnnotationTreeVisitor.java | 30 ++++++++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle b/buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle index 8f7c31ffb3..6a0e6415fd 100644 --- a/buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle +++ b/buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle @@ -117,6 +117,8 @@ configurations.create('coverageDataElements') { } // This will cause the test tasks to run if the coverage data is requested by the aggregation task tasks.withType(Test).forEach {task -> + // tasks.named(task.name) is a hack to introduce the right task dependence in Gradle. We will fix this + // correctly when addressing https://github.com/uber/NullAway/issues/871 outgoing.artifact(tasks.named(task.name).map { t -> t.extensions.getByType(JacocoTaskExtension).destinationFile }) } } diff --git a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java index efba65079e..9401beb7bf 100644 --- a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java +++ b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java @@ -78,9 +78,10 @@ public Type visitParameterizedType(ParameterizedTypeTree tree, Void p) { new Attribute.TypeCompound( nullableType, com.sun.tools.javac.util.List.nil(), null))) : com.sun.tools.javac.util.List.nil(); - TypeMetadata typeMetadata = tmBuilder.create(nullableAnnotationCompound); + TypeMetadata typeMetadata = TYPE_METADATA_BUILDER.create(nullableAnnotationCompound); Type currentTypeArgType = curTypeArg.accept(this, null); - Type newTypeArgType = tmBuilder.cloneTypeWithMetadata(currentTypeArgType, typeMetadata); + Type newTypeArgType = + TYPE_METADATA_BUILDER.cloneTypeWithMetadata(currentTypeArgType, typeMetadata); newTypeArgs.add(newTypeArgType); } Type.ClassType finalType = @@ -96,8 +97,8 @@ protected Type defaultAction(Tree node, Void unused) { } /** - * Provides abstraction for using Type and TypeMetadata library methods for different Jdk version - * implementations. + * Abstracts over the different APIs for building {@link TypeMetadata} objects in different JDK + * versions. */ private interface TypeMetadataBuilder { TypeMetadata create(com.sun.tools.javac.util.List attrs); @@ -106,7 +107,7 @@ private interface TypeMetadataBuilder { } /** - * Provides implementations for methods under TypeMetadataBuilder compatible with Jdk 17 and + * Provides implementations for methods under TypeMetadataBuilder compatible with JDK 17 and * earlier versions. */ private static class JDK17AndEarlierTypeMetadataBuilder implements TypeMetadataBuilder { @@ -117,7 +118,8 @@ public TypeMetadata create(com.sun.tools.javac.util.List } /** - * Clones the given type with the specified Metadata for getting the right Nullability. + * Clones the given type with the specified Metadata for getting the right nullability + * annotations. * * @param typeToBeCloned The Type we want to clone with the required Nullability Metadata * @param metadata The required Nullability metadata which is lost from the type @@ -188,8 +190,8 @@ public TypeMetadata create(com.sun.tools.javac.util.List } /** - * Calls dropMetadata and addMetadata using MethodHandles for Jdk21 Implementation which - * deprecated the cloneWithMetadata method. + * Calls dropMetadata and addMetadata using MethodHandles for JDK 21, which removed the previous + * cloneWithMetadata method. * * @param typeToBeCloned The Type we want to clone with the required Nullability metadata * @param metadata The required Nullability metadata @@ -198,8 +200,8 @@ public TypeMetadata create(com.sun.tools.javac.util.List @Override public Type cloneTypeWithMetadata(Type typeToBeCloned, TypeMetadata metadata) { try { - // In Jdk21 addMetadata works if there is no metadata associated with the type, so we create - // a copy without the existing metadata first and then add it + // In JDK 21 addMetadata works if there is no metadata associated with the type, so we + // create a copy without the existing metadata first and then add it Type clonedTypeWithoutMetadata = (Type) dropMetadataHandle.invoke(typeToBeCloned, metadata.getClass()); return (Type) addMetadataHandle.invoke(clonedTypeWithoutMetadata, metadata); @@ -209,11 +211,17 @@ public Type cloneTypeWithMetadata(Type typeToBeCloned, TypeMetadata metadata) { } } - private static final TypeMetadataBuilder tmBuilder = + /** The TypeMetadataBuilder to be used for the current JDK version. */ + private static final TypeMetadataBuilder TYPE_METADATA_BUILDER = getVersion() >= 21 ? new JDK21TypeMetadataBuilder() : new JDK17AndEarlierTypeMetadataBuilder(); + /** + * Utility method to get the current JDK version, that works on Java 8 and above. + * + * @return the current JDK version + */ private static int getVersion() { String version = System.getProperty("java.version"); if (version.startsWith("1.")) { From 708a49457eb759a14d8241017a88de9404a9f4d5 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Fri, 1 Dec 2023 08:58:16 -0800 Subject: [PATCH 15/16] tweak --- .../uber/nullaway/generics/PreservedAnnotationTreeVisitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java index 9401beb7bf..89bed181ca 100644 --- a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java +++ b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java @@ -133,7 +133,7 @@ public Type cloneTypeWithMetadata(Type typeToBeCloned, TypeMetadata metadata) { /** * Provides implementations for methods under TypeMetadataBuilder compatible with the updates made - * to the library methods for Jdk 21. The implementation calls the logic specific to Jdk 21 + * to the library methods for Jdk 21. The implementation calls the logic specific to JDK 21 * indirectly using MethodHandles since we still need the code to compile on earlier versions. */ private static class JDK21TypeMetadataBuilder implements TypeMetadataBuilder { From ac250edca3cfffc326061c22198732a7fc5f9cc9 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 10 Jan 2024 08:14:34 -0800 Subject: [PATCH 16/16] add a TODO to remove method --- .../uber/nullaway/generics/PreservedAnnotationTreeVisitor.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java index 89bed181ca..822fcf193c 100644 --- a/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java +++ b/nullaway/src/main/java/com/uber/nullaway/generics/PreservedAnnotationTreeVisitor.java @@ -220,6 +220,8 @@ public Type cloneTypeWithMetadata(Type typeToBeCloned, TypeMetadata metadata) { /** * Utility method to get the current JDK version, that works on Java 8 and above. * + *

TODO remove this method once we drop support for Java 8 + * * @return the current JDK version */ private static int getVersion() {