From f306db23cbdb9e6883524d4838c36686e79c5ab7 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Tue, 13 Sep 2022 12:12:27 -0700 Subject: [PATCH 001/184] an initial test case --- .../NullAwayJSpecifyGenericsTests.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java new file mode 100644 index 0000000000..f9e050b36f --- /dev/null +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -0,0 +1,33 @@ +package com.uber.nullaway; + +import org.junit.Test; + +public class NullAwayJSpecifyGenericsTests extends NullAwayTestsBase { + + @Test + public void basicTypeParamSubtyping() { + defaultCompilationHelper + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.nullness.Nullable;", + "class Test {", + " static class NonNullTypeParam {}", + " static class NullableTypeParam {}", + " static void testOkNonNull(NonNullTypeParam t) {", + " NonNullTypeParam t2 = new NonNullTypeParam();", + " }", + " // BUG: Diagnostic contains: XXX", + " static void testBadNonNull(NonNullTypeParam<@Nullable String> t) {", + " // 2 reports here?", + " // BUG: Diagnostic contains: XXX", + " NonNullTypeParam<@Nullable String> t2 = new NonNullTypeParam<@Nullable String>();", + " }", + " static void testOkNullable(NullableTypeParam t1, NullableTypeParam<@Nullable String> t2) {", + " NullableTypeParam t3 = new NullableTypeParam();", + " NullableTypeParam<@Nullable String> t4 = new NullableTypeParam<@Nullable String>();", + " }", + "}") + .doTest(); + } +} From 16654f7bac916bded25d1405f7796edfbde56a0b Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Tue, 27 Sep 2022 16:48:05 -0700 Subject: [PATCH 002/184] sample code --- .../main/java/com/uber/nullaway/NullAway.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 132733bea7..0daba56f57 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -81,6 +81,7 @@ import com.sun.source.tree.WhileLoopTree; import com.sun.source.util.TreePath; import com.sun.source.util.Trees; +import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Type; @@ -611,6 +612,13 @@ public Description matchMethod(MethodTree tree, VisitorState state) { // package) Symbol.MethodSymbol methodSymbol = ASTHelpers.getSymbol(tree); handler.onMatchMethod(this, tree, state, methodSymbol); + // check parameter types + for (VariableTree varTree : tree.getParameters()) { + Type paramType = ASTHelpers.getType(varTree); + if (paramType.getTypeArguments().length() > 0) { // it's a generic type instantiation + checkInstantiatedType(paramType, state); + } + } boolean isOverriding = ASTHelpers.hasAnnotation(methodSymbol, Override.class, state); boolean exhaustiveOverride = config.exhaustiveOverride(); if (isOverriding || !exhaustiveOverride) { @@ -623,6 +631,35 @@ public Description matchMethod(MethodTree tree, VisitorState state) { return Description.NO_MATCH; } + // check that type is a valid instantiation of its generic type + @SuppressWarnings("UnusedVariable") + private void checkInstantiatedType(Type type, VisitorState state) { + // typeArguments used in the instantiated type (like for Foo, this gets + // [String,Integer]) + com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); + System.err.println(typeArguments); + // base type that is being instantiated (like for Foo, this will get the + // declared type Foo) + Type baseType = type.tsym.type; + // type arguments for base type + com.sun.tools.javac.util.List baseTypeArguments = baseType.getTypeArguments(); + System.err.println(baseTypeArguments); + for (Type baseTypeArg : baseTypeArguments) { + // to get the upper bound of a type (like for Foo, returns + // @Nullable Object) + Type upperBound = baseTypeArg.getUpperBound(); + System.err.println(upperBound); + // to get annotations on a type (like for @Nullable Object, returns [@Nullable]) + com.sun.tools.javac.util.List annotationMirrors = + upperBound.getAnnotationMirrors(); + System.err.println(annotationMirrors); + // checks if @Nullable is in a stream of annotations + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + System.err.println(hasNullableAnnotation); + } + } + @Override public Description matchSwitch(SwitchTree tree, VisitorState state) { if (!withinAnnotatedCode(state)) { From 7f9418b4b4dc02ead25729b7ad4cf65b7f7e2637 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 29 Sep 2022 03:27:24 -0700 Subject: [PATCH 003/184] add-generics-checks --- .../main/java/com/uber/nullaway/NullAway.java | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 0daba56f57..67142f76af 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -171,8 +171,7 @@ public class NullAway extends BugChecker BugChecker.IdentifierTreeMatcher, BugChecker.MemberReferenceTreeMatcher, BugChecker.CompoundAssignmentTreeMatcher, - BugChecker.SwitchTreeMatcher, - BugChecker.TypeCastTreeMatcher { + BugChecker.SwitchTreeMatcher { static final String INITIALIZATION_CHECK_NAME = "NullAway.Init"; static final String OPTIONAL_CHECK_NAME = "NullAway.Optional"; @@ -616,7 +615,12 @@ public Description matchMethod(MethodTree tree, VisitorState state) { for (VariableTree varTree : tree.getParameters()) { Type paramType = ASTHelpers.getType(varTree); if (paramType.getTypeArguments().length() > 0) { // it's a generic type instantiation - checkInstantiatedType(paramType, state); + Description description = checkInstantiatedType(paramType, state, varTree); + if (description + != Description.NO_MATCH) { // there is an invalid instantiation, some error is generated + return description; + } + // if the instantiation is invalid for the generic type generate an error } } boolean isOverriding = ASTHelpers.hasAnnotation(methodSymbol, Override.class, state); @@ -630,10 +634,12 @@ public Description matchMethod(MethodTree tree, VisitorState state) { } return Description.NO_MATCH; } - + private Description invalidInstantiationError(VariableTree tree, VisitorState state) { + return errorBuilder.createErrorDescription("XXX", buildDescription(tree), state, tree); + } // check that type is a valid instantiation of its generic type @SuppressWarnings("UnusedVariable") - private void checkInstantiatedType(Type type, VisitorState state) { + private Description checkInstantiatedType(Type type, VisitorState state, VariableTree tree) { // typeArguments used in the instantiated type (like for Foo, this gets // [String,Integer]) com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); @@ -656,8 +662,13 @@ private void checkInstantiatedType(Type type, VisitorState state) { // checks if @Nullable is in a stream of annotations boolean hasNullableAnnotation = Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + if (hasNullableAnnotation) { + return invalidInstantiationError(tree, state); + } System.err.println(hasNullableAnnotation); } + + return Description.NO_MATCH; } @Override @@ -690,16 +701,6 @@ public Description matchSwitch(SwitchTree tree, VisitorState state) { return Description.NO_MATCH; } - @Override - public Description matchTypeCast(TypeCastTree tree, VisitorState state) { - Type castExprType = ASTHelpers.getType(tree); - if (castExprType != null && castExprType.isPrimitive()) { - // casting to a primitive type performs unboxing - return doUnboxingCheck(state, tree.getExpression()); - } - return Description.NO_MATCH; - } - /** * checks that an overriding method does not override a {@code @Nullable} parameter with a * {@code @NonNull} parameter From 441ab7cab47b91e9078ada61e9d58866ca4c864a Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 30 Sep 2022 02:08:46 -0700 Subject: [PATCH 004/184] first-case-of-generics-support --- .../main/java/com/uber/nullaway/NullAway.java | 69 +++++++++++-------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 67142f76af..4019133c4b 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -93,6 +93,7 @@ import com.uber.nullaway.handlers.Handler; import com.uber.nullaway.handlers.Handlers; import java.util.ArrayList; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -615,12 +616,7 @@ public Description matchMethod(MethodTree tree, VisitorState state) { for (VariableTree varTree : tree.getParameters()) { Type paramType = ASTHelpers.getType(varTree); if (paramType.getTypeArguments().length() > 0) { // it's a generic type instantiation - Description description = checkInstantiatedType(paramType, state, varTree); - if (description - != Description.NO_MATCH) { // there is an invalid instantiation, some error is generated - return description; - } - // if the instantiation is invalid for the generic type generate an error + checkInstantiatedType(paramType, state, varTree); } } boolean isOverriding = ASTHelpers.hasAnnotation(methodSymbol, Override.class, state); @@ -634,41 +630,54 @@ public Description matchMethod(MethodTree tree, VisitorState state) { } return Description.NO_MATCH; } - private Description invalidInstantiationError(VariableTree tree, VisitorState state) { - return errorBuilder.createErrorDescription("XXX", buildDescription(tree), state, tree); + + private void invalidInstantiationError(VariableTree tree, VisitorState state) { + ErrorMessage errorMessage = new ErrorMessage(MessageTypes.PASS_NULLABLE, "XXX"); + VarSymbol symbol = ASTHelpers.getSymbol(tree); + System.out.println(errorMessage); + state.reportMatch( + errorBuilder.createErrorDescriptionForNullAssignment( + errorMessage, tree, buildDescription(tree), state, symbol)); } // check that type is a valid instantiation of its generic type @SuppressWarnings("UnusedVariable") - private Description checkInstantiatedType(Type type, VisitorState state, VariableTree tree) { + private void checkInstantiatedType(Type type, VisitorState state, VariableTree tree) { // typeArguments used in the instantiated type (like for Foo, this gets // [String,Integer]) + com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); - System.err.println(typeArguments); - // base type that is being instantiated (like for Foo, this will get the - // declared type Foo) + HashSet typeArgsWithNullableAnnotations = new HashSet(); + int index = 0; + for (Type typArgument : typeArguments) { + + Type upperBound = typArgument.getUpperBound(); + if (upperBound == null) { + typeArgsWithNullableAnnotations.add(index); + } + index++; + } + Type baseType = type.tsym.type; - // type arguments for base type com.sun.tools.javac.util.List baseTypeArguments = baseType.getTypeArguments(); - System.err.println(baseTypeArguments); + index = 0; for (Type baseTypeArg : baseTypeArguments) { - // to get the upper bound of a type (like for Foo, returns - // @Nullable Object) - Type upperBound = baseTypeArg.getUpperBound(); - System.err.println(upperBound); - // to get annotations on a type (like for @Nullable Object, returns [@Nullable]) - com.sun.tools.javac.util.List annotationMirrors = - upperBound.getAnnotationMirrors(); - System.err.println(annotationMirrors); - // checks if @Nullable is in a stream of annotations - boolean hasNullableAnnotation = - Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - if (hasNullableAnnotation) { - return invalidInstantiationError(tree, state); + // if type argument at current index has @Nullable annotation base type argument at that index + // should also have + // the @Nullable annotation. check for the annotation + if (typeArgsWithNullableAnnotations.contains(index)) { + Type upperBound = baseTypeArg.getUpperBound(); + com.sun.tools.javac.util.List annotationMirrors = + upperBound.getAnnotationMirrors(); + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + // if base type argument does not have @Nullable annotation then the instantiation is + // invalid + if (!hasNullableAnnotation) { + invalidInstantiationError(tree, state); + } } - System.err.println(hasNullableAnnotation); + index++; } - - return Description.NO_MATCH; } @Override From 4a9c86dab3aaedb95a5a5b703701970a48e9c723 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 30 Sep 2022 02:24:09 -0700 Subject: [PATCH 005/184] first-case-of-generics-support --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 4019133c4b..004cd3d09b 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -634,13 +634,12 @@ public Description matchMethod(MethodTree tree, VisitorState state) { private void invalidInstantiationError(VariableTree tree, VisitorState state) { ErrorMessage errorMessage = new ErrorMessage(MessageTypes.PASS_NULLABLE, "XXX"); VarSymbol symbol = ASTHelpers.getSymbol(tree); - System.out.println(errorMessage); + System.err.println(errorMessage.message + "" + symbol); state.reportMatch( errorBuilder.createErrorDescriptionForNullAssignment( errorMessage, tree, buildDescription(tree), state, symbol)); } // check that type is a valid instantiation of its generic type - @SuppressWarnings("UnusedVariable") private void checkInstantiatedType(Type type, VisitorState state, VariableTree tree) { // typeArguments used in the instantiated type (like for Foo, this gets // [String,Integer]) From 01377b6a70b8570d8d1fd984429f01190df9e6b4 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Fri, 30 Sep 2022 08:46:00 -0700 Subject: [PATCH 006/184] restore bad deletion --- .../src/main/java/com/uber/nullaway/NullAway.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 004cd3d09b..2058947f6f 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -172,7 +172,8 @@ public class NullAway extends BugChecker BugChecker.IdentifierTreeMatcher, BugChecker.MemberReferenceTreeMatcher, BugChecker.CompoundAssignmentTreeMatcher, - BugChecker.SwitchTreeMatcher { + BugChecker.SwitchTreeMatcher, + BugChecker.TypeCastTreeMatcher { static final String INITIALIZATION_CHECK_NAME = "NullAway.Init"; static final String OPTIONAL_CHECK_NAME = "NullAway.Optional"; @@ -709,6 +710,16 @@ public Description matchSwitch(SwitchTree tree, VisitorState state) { return Description.NO_MATCH; } + @Override + public Description matchTypeCast(TypeCastTree tree, VisitorState state) { + Type castExprType = ASTHelpers.getType(tree); + if (castExprType != null && castExprType.isPrimitive()) { + // casting to a primitive type performs unboxing + return doUnboxingCheck(state, tree.getExpression()); + } + return Description.NO_MATCH; + } + /** * checks that an overriding method does not override a {@code @Nullable} parameter with a * {@code @NonNull} parameter From 359dcc84c504c9f5db39a52313436a41210cc397 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 30 Sep 2022 15:11:05 -0700 Subject: [PATCH 007/184] add-generics-spport-task-1-updates --- .../src/main/java/com/uber/nullaway/NullAway.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 2058947f6f..63e859158d 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -646,13 +646,16 @@ private void checkInstantiatedType(Type type, VisitorState state, VariableTree t // [String,Integer]) com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); - HashSet typeArgsWithNullableAnnotations = new HashSet(); + HashSet nullableTypeArguments = new HashSet(); int index = 0; for (Type typArgument : typeArguments) { - Type upperBound = typArgument.getUpperBound(); - if (upperBound == null) { - typeArgsWithNullableAnnotations.add(index); + com.sun.tools.javac.util.List annotationMirrors = + typArgument.getAnnotationMirrors(); + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + if (hasNullableAnnotation) { + nullableTypeArguments.add(index); } index++; } @@ -661,10 +664,12 @@ private void checkInstantiatedType(Type type, VisitorState state, VariableTree t com.sun.tools.javac.util.List baseTypeArguments = baseType.getTypeArguments(); index = 0; for (Type baseTypeArg : baseTypeArguments) { + // if type argument at current index has @Nullable annotation base type argument at that index // should also have // the @Nullable annotation. check for the annotation - if (typeArgsWithNullableAnnotations.contains(index)) { + if (nullableTypeArguments.contains(index)) { + Type upperBound = baseTypeArg.getUpperBound(); com.sun.tools.javac.util.List annotationMirrors = upperBound.getAnnotationMirrors(); From 731bf3d221ec275a9708f6ddd18ce54e6f8e94db Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 30 Sep 2022 15:34:31 -0700 Subject: [PATCH 008/184] add-generics-spport-task-1-updates --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 63e859158d..06d241fc5b 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -633,12 +633,11 @@ public Description matchMethod(MethodTree tree, VisitorState state) { } private void invalidInstantiationError(VariableTree tree, VisitorState state) { - ErrorMessage errorMessage = new ErrorMessage(MessageTypes.PASS_NULLABLE, "XXX"); - VarSymbol symbol = ASTHelpers.getSymbol(tree); - System.err.println(errorMessage.message + "" + symbol); + ErrorMessage errorMessage = new ErrorMessage(MessageTypes.ANNOTATION_VALUE_INVALID, "XXX"); + // System.err.println(errorMessage.message + "" + symbol); state.reportMatch( errorBuilder.createErrorDescriptionForNullAssignment( - errorMessage, tree, buildDescription(tree), state, symbol)); + errorMessage, null, buildDescription(tree), state, null)); } // check that type is a valid instantiation of its generic type private void checkInstantiatedType(Type type, VisitorState state, VariableTree tree) { @@ -656,6 +655,7 @@ private void checkInstantiatedType(Type type, VisitorState state, VariableTree t Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); if (hasNullableAnnotation) { nullableTypeArguments.add(index); + // System.out.println(typArgument + "--" + index); } index++; } @@ -675,6 +675,7 @@ private void checkInstantiatedType(Type type, VisitorState state, VariableTree t upperBound.getAnnotationMirrors(); boolean hasNullableAnnotation = Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + System.out.println(hasNullableAnnotation + " " + index); // if base type argument does not have @Nullable annotation then the instantiation is // invalid if (!hasNullableAnnotation) { From b9b82397b63b79f7ff0475fd28d4fbfde9a755fc Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 30 Sep 2022 15:43:15 -0700 Subject: [PATCH 009/184] add-generics-spport-task-1-updates --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 06d241fc5b..eb8194e42b 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -633,7 +633,7 @@ public Description matchMethod(MethodTree tree, VisitorState state) { } private void invalidInstantiationError(VariableTree tree, VisitorState state) { - ErrorMessage errorMessage = new ErrorMessage(MessageTypes.ANNOTATION_VALUE_INVALID, "XXX"); + ErrorMessage errorMessage = new ErrorMessage(MessageTypes.ASSIGN_FIELD_NULLABLE, "XXX"); // System.err.println(errorMessage.message + "" + symbol); state.reportMatch( errorBuilder.createErrorDescriptionForNullAssignment( From fb1beb9a7448d6dd32999fd0995ec14cdfa97f4d Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sat, 1 Oct 2022 22:57:16 -0700 Subject: [PATCH 010/184] add generics check for variables --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index eb8194e42b..83a6de89d6 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -1377,6 +1377,11 @@ public Description matchVariable(VariableTree tree, VisitorState state) { if (!withinAnnotatedCode(state)) { return Description.NO_MATCH; } + // Check if the variable is generic + Type variableType = ASTHelpers.getType(tree); + if (variableType.getTypeArguments().length() > 0) { // it's a generic type instantiation + checkInstantiatedType(variableType, state, tree); + } VarSymbol symbol = ASTHelpers.getSymbol(tree); if (symbol.type.isPrimitive() && tree.getInitializer() != null) { return doUnboxingCheck(state, tree.getInitializer()); From 90d471d0d0b351018a784372b56e2e55b1e025e4 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Mon, 3 Oct 2022 13:29:50 -0700 Subject: [PATCH 011/184] tweak error message --- .../src/main/java/com/uber/nullaway/ErrorMessage.java | 1 + nullaway/src/main/java/com/uber/nullaway/NullAway.java | 9 ++++++--- .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/ErrorMessage.java b/nullaway/src/main/java/com/uber/nullaway/ErrorMessage.java index b559901d61..753f49431b 100644 --- a/nullaway/src/main/java/com/uber/nullaway/ErrorMessage.java +++ b/nullaway/src/main/java/com/uber/nullaway/ErrorMessage.java @@ -52,6 +52,7 @@ public enum MessageTypes { PRECONDITION_NOT_SATISFIED, WRONG_OVERRIDE_POSTCONDITION, WRONG_OVERRIDE_PRECONDITION, + TYPE_PARAMETER_CANNOT_BE_NULLABLE, } public String getMessage() { diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 83a6de89d6..1be55f90e7 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -633,12 +633,15 @@ public Description matchMethod(MethodTree tree, VisitorState state) { } private void invalidInstantiationError(VariableTree tree, VisitorState state) { - ErrorMessage errorMessage = new ErrorMessage(MessageTypes.ASSIGN_FIELD_NULLABLE, "XXX"); + ErrorMessage errorMessage = + new ErrorMessage( + MessageTypes.TYPE_PARAMETER_CANNOT_BE_NULLABLE, + "Generic type parameter cannot be @Nullable"); // System.err.println(errorMessage.message + "" + symbol); state.reportMatch( - errorBuilder.createErrorDescriptionForNullAssignment( - errorMessage, null, buildDescription(tree), state, null)); + errorBuilder.createErrorDescription(errorMessage, buildDescription(tree), state, null)); } + // check that type is a valid instantiation of its generic type private void checkInstantiatedType(Type type, VisitorState state, VariableTree tree) { // typeArguments used in the instantiated type (like for Foo, this gets diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index f9e050b36f..4aab894b77 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -17,10 +17,10 @@ public void basicTypeParamSubtyping() { " static void testOkNonNull(NonNullTypeParam t) {", " NonNullTypeParam t2 = new NonNullTypeParam();", " }", - " // BUG: Diagnostic contains: XXX", + " // BUG: Diagnostic contains: Generic type parameter", " static void testBadNonNull(NonNullTypeParam<@Nullable String> t) {", " // 2 reports here?", - " // BUG: Diagnostic contains: XXX", + " // BUG: Diagnostic contains: Generic type parameter", " NonNullTypeParam<@Nullable String> t2 = new NonNullTypeParam<@Nullable String>();", " }", " static void testOkNullable(NullableTypeParam t1, NullableTypeParam<@Nullable String> t2) {", From 98f7fa63f7456ff16e419285adfa9fd08660d00f Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Mon, 3 Oct 2022 13:35:32 -0700 Subject: [PATCH 012/184] more tests --- .../uber/nullaway/NullAwayJSpecifyGenericsTests.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 4aab894b77..b1e76686d6 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -5,7 +5,7 @@ public class NullAwayJSpecifyGenericsTests extends NullAwayTestsBase { @Test - public void basicTypeParamSubtyping() { + public void basicTypeParamInstantiation() { defaultCompilationHelper .addSourceLines( "Test.java", @@ -19,14 +19,19 @@ public void basicTypeParamSubtyping() { " }", " // BUG: Diagnostic contains: Generic type parameter", " static void testBadNonNull(NonNullTypeParam<@Nullable String> t) {", - " // 2 reports here?", " // BUG: Diagnostic contains: Generic type parameter", - " NonNullTypeParam<@Nullable String> t2 = new NonNullTypeParam<@Nullable String>();", + " NonNullTypeParam<@Nullable String> t2 = null;", + " // BUG: Diagnostic contains: Generic type parameter", + " t2 = new NonNullTypeParam<@Nullable String>();", + " // BUG: Diagnostic contains: Generic type parameter", + " testBadNonNull(new NonNullTypeParam<@Nullable String>());", " }", " static void testOkNullable(NullableTypeParam t1, NullableTypeParam<@Nullable String> t2) {", " NullableTypeParam t3 = new NullableTypeParam();", " NullableTypeParam<@Nullable String> t4 = new NullableTypeParam<@Nullable String>();", " }", + " // BUG: Diagnostic contains: Generic type parameter", + " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", "}") .doTest(); } From 53ddad7472465312949890aef17fb9d91b65764e Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 3 Oct 2022 13:48:26 -0700 Subject: [PATCH 013/184] code cleanup.remove print statements --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 1be55f90e7..88202ee7a4 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -637,7 +637,6 @@ private void invalidInstantiationError(VariableTree tree, VisitorState state) { new ErrorMessage( MessageTypes.TYPE_PARAMETER_CANNOT_BE_NULLABLE, "Generic type parameter cannot be @Nullable"); - // System.err.println(errorMessage.message + "" + symbol); state.reportMatch( errorBuilder.createErrorDescription(errorMessage, buildDescription(tree), state, null)); } @@ -651,14 +650,12 @@ private void checkInstantiatedType(Type type, VisitorState state, VariableTree t HashSet nullableTypeArguments = new HashSet(); int index = 0; for (Type typArgument : typeArguments) { - com.sun.tools.javac.util.List annotationMirrors = typArgument.getAnnotationMirrors(); boolean hasNullableAnnotation = Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); if (hasNullableAnnotation) { nullableTypeArguments.add(index); - // System.out.println(typArgument + "--" + index); } index++; } @@ -678,7 +675,6 @@ private void checkInstantiatedType(Type type, VisitorState state, VariableTree t upperBound.getAnnotationMirrors(); boolean hasNullableAnnotation = Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - System.out.println(hasNullableAnnotation + " " + index); // if base type argument does not have @Nullable annotation then the instantiation is // invalid if (!hasNullableAnnotation) { From 7daa52b84908c73f7f65c8fd9f5a1ed154c002a1 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 3 Oct 2022 14:30:45 -0700 Subject: [PATCH 014/184] Add temporary check to consider unannoted base type --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 88202ee7a4..4404880d10 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -645,7 +645,11 @@ private void invalidInstantiationError(VariableTree tree, VisitorState state) { private void checkInstantiatedType(Type type, VisitorState state, VariableTree tree) { // typeArguments used in the instantiated type (like for Foo, this gets // [String,Integer]) - + // if base type is unannotated do not check for generics + // temporary check to handle testMapComputeIfAbsent + if (codeAnnotationInfo.isSymbolUnannotated(type.tsym, config)) { + return; + } com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); HashSet nullableTypeArguments = new HashSet(); int index = 0; From cd01ff99cbe7946dec7ea08a9266096b732438bc Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 3 Oct 2022 21:52:59 -0700 Subject: [PATCH 015/184] minor code changes --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 4404880d10..04378db475 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -632,7 +632,7 @@ public Description matchMethod(MethodTree tree, VisitorState state) { return Description.NO_MATCH; } - private void invalidInstantiationError(VariableTree tree, VisitorState state) { + private void invalidInstantiationError(Tree tree, VisitorState state) { ErrorMessage errorMessage = new ErrorMessage( MessageTypes.TYPE_PARAMETER_CANNOT_BE_NULLABLE, @@ -642,7 +642,7 @@ private void invalidInstantiationError(VariableTree tree, VisitorState state) { } // check that type is a valid instantiation of its generic type - private void checkInstantiatedType(Type type, VisitorState state, VariableTree tree) { + private void checkInstantiatedType(Type type, VisitorState state, Tree tree) { // typeArguments used in the instantiated type (like for Foo, this gets // [String,Integer]) // if base type is unannotated do not check for generics From 202d5dba47b53c9c256e527603472ff9ac420c11 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 6 Oct 2022 14:43:30 -0700 Subject: [PATCH 016/184] add generics check for new class - check if the class is generic --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 04378db475..89c537629d 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -414,6 +414,11 @@ public Description matchNewClass(NewClassTree tree, VisitorState state) { // see https://github.com/uber/NullAway/issues/102 methodSymbol = getSymbolOfSuperConstructor(methodSymbol, state); } + // check if the class is generic + Type classType = ASTHelpers.getType(tree); + if (classType.getTypeArguments().length() > 0) { + checkInstantiatedType(classType, state, tree); + } return handleInvocation(tree, state, methodSymbol, actualParams); } From 39989494bf1b5d210dcf85a339d5db4ac7c9a123 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 6 Oct 2022 23:57:57 -0700 Subject: [PATCH 017/184] add generics check for new class - check for the type arguments --- .../main/java/com/uber/nullaway/NullAway.java | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 89c537629d..0514c1c70c 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -69,6 +69,7 @@ import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.MethodTree; import com.sun.source.tree.NewClassTree; +import com.sun.source.tree.ParameterizedTypeTree; import com.sun.source.tree.ParenthesizedTree; import com.sun.source.tree.ReturnTree; import com.sun.source.tree.StatementTree; @@ -397,6 +398,7 @@ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState } @Override + @SuppressWarnings("UnusedVariable") public Description matchNewClass(NewClassTree tree, VisitorState state) { if (!withinAnnotatedCode(state)) { return Description.NO_MATCH; @@ -417,11 +419,34 @@ public Description matchNewClass(NewClassTree tree, VisitorState state) { // check if the class is generic Type classType = ASTHelpers.getType(tree); if (classType.getTypeArguments().length() > 0) { - checkInstantiatedType(classType, state, tree); + ParameterizedTypeTree parameterizedTypeTree = (ParameterizedTypeTree) tree.getIdentifier(); + checkInstantiationForParameterizedTypedTree(parameterizedTypeTree, state); } return handleInvocation(tree, state, methodSymbol, actualParams); } - + /** Generics checks for parameterized typed trees * */ + @SuppressWarnings("UnusedVariable") + public void checkInstantiationForParameterizedTypedTree( + ParameterizedTypeTree tree, VisitorState state) { + List typeArguments = tree.getTypeArguments(); + HashSet nullableTypeArguments = new HashSet(); + for (int i = 0; i < typeArguments.size(); i++) { + boolean hasNullableAnnotation = false; + if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { + JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); + for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { + Attribute.Compound attribute = annotation.attribute; + hasNullableAnnotation = + hasNullableAnnotation + || attribute.toString().equals("@org.jspecify.nullness.Nullable"); + if (hasNullableAnnotation) { + nullableTypeArguments.add(i); + break; + } + } + } + } + } /** * Updates the {@link EnclosingEnvironmentNullness} with an entry for lambda or anonymous class, * capturing nullability info for locals just before the declaration of the entity @@ -655,6 +680,7 @@ private void checkInstantiatedType(Type type, VisitorState state, Tree tree) { if (codeAnnotationInfo.isSymbolUnannotated(type.tsym, config)) { return; } + com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); HashSet nullableTypeArguments = new HashSet(); int index = 0; From fc8b99fc5556432468b4d249cf516ae34273f0de Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 15:26:23 -0700 Subject: [PATCH 018/184] generics check for new class --- .../main/java/com/uber/nullaway/NullAway.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 0514c1c70c..8f5d4f10fa 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -88,6 +88,7 @@ import com.sun.tools.javac.code.Type; import com.sun.tools.javac.processing.JavacProcessingEnvironment; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCTypeApply; import com.uber.nullaway.ErrorMessage.MessageTypes; import com.uber.nullaway.dataflow.AccessPathNullnessAnalysis; import com.uber.nullaway.dataflow.EnclosingEnvironmentNullness; @@ -398,7 +399,6 @@ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState } @Override - @SuppressWarnings("UnusedVariable") public Description matchNewClass(NewClassTree tree, VisitorState state) { if (!withinAnnotatedCode(state)) { return Description.NO_MATCH; @@ -425,7 +425,7 @@ public Description matchNewClass(NewClassTree tree, VisitorState state) { return handleInvocation(tree, state, methodSymbol, actualParams); } /** Generics checks for parameterized typed trees * */ - @SuppressWarnings("UnusedVariable") + @SuppressWarnings("ModifiedButNotUsed") public void checkInstantiationForParameterizedTypedTree( ParameterizedTypeTree tree, VisitorState state) { List typeArguments = tree.getTypeArguments(); @@ -446,6 +446,22 @@ public void checkInstantiationForParameterizedTypedTree( } } } + JCTypeApply baseTypeTree = (JCTypeApply) tree; + Type t = baseTypeTree.type; + Type.ClassType classTyp = (Type.ClassType) t; + if (classTyp.tsym.getMetadata() != null) { + List baseTypeAttributes = + classTyp.tsym.getMetadata().getTypeAttributes(); + for (int i = 0; i < baseTypeAttributes.size(); i++) { + nullableTypeArguments.remove(baseTypeAttributes.get(i).position.parameter_index); + } + } + + if (!nullableTypeArguments + .isEmpty()) { // there exist @nullable annotated parameters in the constructor call that do + // not have corresponding @nullable annotations in the declaration + invalidInstantiationError(tree, state); + } } /** * Updates the {@link EnclosingEnvironmentNullness} with an entry for lambda or anonymous class, From 64259099d95801d045b2e16d5543918dbeca22cd Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 16:07:33 -0700 Subject: [PATCH 019/184] generics check for extended class --- .../src/main/java/com/uber/nullaway/NullAway.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 8f5d4f10fa..9847a015cd 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -459,7 +459,7 @@ public void checkInstantiationForParameterizedTypedTree( if (!nullableTypeArguments .isEmpty()) { // there exist @nullable annotated parameters in the constructor call that do - // not have corresponding @nullable annotations in the declaration + // not have corresponding @nullable annotations in the declaration invalidInstantiationError(tree, state); } } @@ -1530,6 +1530,15 @@ public Description matchClass(ClassTree tree, VisitorState state) { } checkFieldInitialization(tree, state); } + JCTree.JCClassDecl classTree = (JCTree.JCClassDecl) tree; + // check if the class extends any interface/Class + if (classTree.extending != null) { + Type extendedClassType = classTree.extending.type; + // check if the extended class is generic + if (extendedClassType.getTypeArguments().length() > 0) { + checkInstantiatedType(extendedClassType, state, classTree); + } + } return Description.NO_MATCH; } From bae84dc061125dd133482a2a5864ad1a1768ba1f Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 16:23:45 -0700 Subject: [PATCH 020/184] generics check for new class --- .../main/java/com/uber/nullaway/NullAway.java | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 9847a015cd..159c27fedd 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -430,6 +430,16 @@ public void checkInstantiationForParameterizedTypedTree( ParameterizedTypeTree tree, VisitorState state) { List typeArguments = tree.getTypeArguments(); HashSet nullableTypeArguments = new HashSet(); + JCTypeApply baseTypeTree = (JCTypeApply) tree; + Type t = baseTypeTree.type; + Type.ClassType classTyp = (Type.ClassType) t; + if (classTyp.tsym.getMetadata() != null) { + List baseTypeAttributes = + classTyp.tsym.getMetadata().getTypeAttributes(); + for (int i = 0; i < baseTypeAttributes.size(); i++) { + nullableTypeArguments.add(baseTypeAttributes.get(i).position.parameter_index); + } + } for (int i = 0; i < typeArguments.size(); i++) { boolean hasNullableAnnotation = false; if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { @@ -440,28 +450,16 @@ public void checkInstantiationForParameterizedTypedTree( hasNullableAnnotation || attribute.toString().equals("@org.jspecify.nullness.Nullable"); if (hasNullableAnnotation) { - nullableTypeArguments.add(i); break; } } } - } - JCTypeApply baseTypeTree = (JCTypeApply) tree; - Type t = baseTypeTree.type; - Type.ClassType classTyp = (Type.ClassType) t; - if (classTyp.tsym.getMetadata() != null) { - List baseTypeAttributes = - classTyp.tsym.getMetadata().getTypeAttributes(); - for (int i = 0; i < baseTypeAttributes.size(); i++) { - nullableTypeArguments.remove(baseTypeAttributes.get(i).position.parameter_index); + if (hasNullableAnnotation) { + if (!nullableTypeArguments.contains(i)) { + invalidInstantiationError(tree, state); + } } } - - if (!nullableTypeArguments - .isEmpty()) { // there exist @nullable annotated parameters in the constructor call that do - // not have corresponding @nullable annotations in the declaration - invalidInstantiationError(tree, state); - } } /** * Updates the {@link EnclosingEnvironmentNullness} with an entry for lambda or anonymous class, From 4aba42c29dd75fd4a0a53cc296ca54b95f4176df Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 16:35:07 -0700 Subject: [PATCH 021/184] generics check for new class - minor changes for error message --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 159c27fedd..8b0a18fdb8 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -456,7 +456,7 @@ public void checkInstantiationForParameterizedTypedTree( } if (hasNullableAnnotation) { if (!nullableTypeArguments.contains(i)) { - invalidInstantiationError(tree, state); + invalidInstantiationError(typeArguments.get(i), state); } } } From bca4f24128ed24aaacb39b6d4cbb42740d38720a Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 16:49:20 -0700 Subject: [PATCH 022/184] generics check for interface implementation --- .../src/main/java/com/uber/nullaway/NullAway.java | 13 ++++++++++++- .../nullaway/NullAwayJSpecifyGenericsTests.java | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 8b0a18fdb8..f1b3bdb646 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -1529,7 +1529,7 @@ public Description matchClass(ClassTree tree, VisitorState state) { checkFieldInitialization(tree, state); } JCTree.JCClassDecl classTree = (JCTree.JCClassDecl) tree; - // check if the class extends any interface/Class + // check if the class extends any class if (classTree.extending != null) { Type extendedClassType = classTree.extending.type; // check if the extended class is generic @@ -1537,6 +1537,17 @@ public Description matchClass(ClassTree tree, VisitorState state) { checkInstantiatedType(extendedClassType, state, classTree); } } + // check if the class implements any interface + List interfaces = classTree.implementing; + if (interfaces.size() > 0) { + for (int i = 0; i < interfaces.size(); i++) { + Type implementedInterfaceType = interfaces.get(i).type; + // check if the interface is generic + if (implementedInterfaceType.getTypeArguments().size() > 0) { + checkInstantiatedType(implementedInterfaceType, state, classTree); + } + } + } return Description.NO_MATCH; } diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index b1e76686d6..f83d0b3523 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -14,6 +14,7 @@ public void basicTypeParamInstantiation() { "class Test {", " static class NonNullTypeParam {}", " static class NullableTypeParam {}", + " static interface NonNullTypeParamInterface{}", " static void testOkNonNull(NonNullTypeParam t) {", " NonNullTypeParam t2 = new NonNullTypeParam();", " }", @@ -32,6 +33,8 @@ public void basicTypeParamInstantiation() { " }", " // BUG: Diagnostic contains: Generic type parameter", " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", + " // BUG: Diagnostic contains: Generic type parameter", + " static class InvalidInterfaceImplementation implements NonNullTypeParamInterface<@Nullable String> {}", "}") .doTest(); } From 99e8bf98938bc9c23771aab372ffedf32a4ffa92 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 16:56:44 -0700 Subject: [PATCH 023/184] minor identation changes From a0caac860cf37f2ec1e58ff7a7ab28a4c3bce6bc Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 19:39:35 -0700 Subject: [PATCH 024/184] nullability checks for build failures --- .../main/java/com/uber/nullaway/NullAway.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index f1b3bdb646..daeee1615c 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -418,9 +418,11 @@ public Description matchNewClass(NewClassTree tree, VisitorState state) { } // check if the class is generic Type classType = ASTHelpers.getType(tree); - if (classType.getTypeArguments().length() > 0) { - ParameterizedTypeTree parameterizedTypeTree = (ParameterizedTypeTree) tree.getIdentifier(); - checkInstantiationForParameterizedTypedTree(parameterizedTypeTree, state); + if (classType != null) { + if (classType.getTypeArguments().length() > 0) { + ParameterizedTypeTree parameterizedTypeTree = (ParameterizedTypeTree) tree.getIdentifier(); + checkInstantiationForParameterizedTypedTree(parameterizedTypeTree, state); + } } return handleInvocation(tree, state, methodSymbol, actualParams); } @@ -660,8 +662,10 @@ public Description matchMethod(MethodTree tree, VisitorState state) { // check parameter types for (VariableTree varTree : tree.getParameters()) { Type paramType = ASTHelpers.getType(varTree); - if (paramType.getTypeArguments().length() > 0) { // it's a generic type instantiation - checkInstantiatedType(paramType, state, varTree); + if (paramType != null) { + if (paramType.getTypeArguments().length() > 0) { // it's a generic type instantiation + checkInstantiatedType(paramType, state, varTree); + } } } boolean isOverriding = ASTHelpers.hasAnnotation(methodSymbol, Override.class, state); @@ -1427,9 +1431,12 @@ public Description matchVariable(VariableTree tree, VisitorState state) { } // Check if the variable is generic Type variableType = ASTHelpers.getType(tree); - if (variableType.getTypeArguments().length() > 0) { // it's a generic type instantiation - checkInstantiatedType(variableType, state, tree); + if (variableType != null) { + if (variableType.getTypeArguments().length() > 0) { // it's a generic type instantiation + checkInstantiatedType(variableType, state, tree); + } } + VarSymbol symbol = ASTHelpers.getSymbol(tree); if (symbol.type.isPrimitive() && tree.getInitializer() != null) { return doUnboxingCheck(state, tree.getInitializer()); From 5b9d91853d2a80d9fc78aaee2be788c07429f53f Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 19:47:45 -0700 Subject: [PATCH 025/184] Add Test: generics check for subclasses --- .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index f83d0b3523..405470b995 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -35,6 +35,11 @@ public void basicTypeParamInstantiation() { " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", " // BUG: Diagnostic contains: Generic type parameter", " static class InvalidInterfaceImplementation implements NonNullTypeParamInterface<@Nullable String> {}", + " static class SuperClassForValidSubclass {", + " static class ValidSubclass extends NullableTypeParam<@Nullable String> {}", + " // BUG: Diagnostic contains: Generic type parameter", + " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", + " }", "}") .doTest(); } From 4cb51d998ed192892d02908fa62535ea361d751a Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 20:06:09 -0700 Subject: [PATCH 026/184] restructure generics tests --- .../NullAwayJSpecifyGenericsTests.java | 76 +++++++++++++++++-- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 405470b995..6d25160ce4 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -15,15 +15,35 @@ public void basicTypeParamInstantiation() { " static class NonNullTypeParam {}", " static class NullableTypeParam {}", " static interface NonNullTypeParamInterface{}", - " static void testOkNonNull(NonNullTypeParam t) {", - " NonNullTypeParam t2 = new NonNullTypeParam();", - " }", " // BUG: Diagnostic contains: Generic type parameter", " static void testBadNonNull(NonNullTypeParam<@Nullable String> t) {", " // BUG: Diagnostic contains: Generic type parameter", " NonNullTypeParam<@Nullable String> t2 = null;", + " }", + " // BUG: Diagnostic contains: Generic type parameter", + " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", + " // BUG: Diagnostic contains: Generic type parameter", + " static class InvalidInterfaceImplementation implements NonNullTypeParamInterface<@Nullable String> {}", + "}") + .doTest(); + } + + @Test + public void ConstructorTypeParamInstantiation() { + defaultCompilationHelper + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.nullness.Nullable;", + "class Test {", + " static class NonNullTypeParam {}", + " static class NullableTypeParam {}", + " static void testOkNonNull(NonNullTypeParam t) {", + " NonNullTypeParam t2 = new NonNullTypeParam();", + " }", + " static void testBadNonNull(NonNullTypeParam t) {", " // BUG: Diagnostic contains: Generic type parameter", - " t2 = new NonNullTypeParam<@Nullable String>();", + " NonNullTypeParam t2 = new NonNullTypeParam<@Nullable String>();", " // BUG: Diagnostic contains: Generic type parameter", " testBadNonNull(new NonNullTypeParam<@Nullable String>());", " }", @@ -31,10 +51,35 @@ public void basicTypeParamInstantiation() { " NullableTypeParam t3 = new NullableTypeParam();", " NullableTypeParam<@Nullable String> t4 = new NullableTypeParam<@Nullable String>();", " }", + "}") + .doTest(); + } + + @Test + public void ExtendedClassTypeParamInstantiation() { + defaultCompilationHelper + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.nullness.Nullable;", + "class Test {", + " static class NonNullTypeParam {}", " // BUG: Diagnostic contains: Generic type parameter", " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", - " // BUG: Diagnostic contains: Generic type parameter", - " static class InvalidInterfaceImplementation implements NonNullTypeParamInterface<@Nullable String> {}", + "}") + .doTest(); + } + + @Test + public void SubClassTypeParamInstantiation() { + defaultCompilationHelper + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.nullness.Nullable;", + "class Test {", + " static class NonNullTypeParam {}", + " static class NullableTypeParam {}", " static class SuperClassForValidSubclass {", " static class ValidSubclass extends NullableTypeParam<@Nullable String> {}", " // BUG: Diagnostic contains: Generic type parameter", @@ -43,4 +88,23 @@ public void basicTypeParamInstantiation() { "}") .doTest(); } + + @Test + public void InterfaceImplementationTypeParamInstantiation() { + defaultCompilationHelper + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.nullness.Nullable;", + "class Test {", + " static class NonNullTypeParam {}", + " static class NullableTypeParam {}", + " static interface NonNullTypeParamInterface{}", + " static interface NullableTypeParamInterface{}", + " // BUG: Diagnostic contains: Generic type parameter", + " static class InvalidInterfaceImplementation implements NonNullTypeParamInterface<@Nullable String> {}", + " static class ValidInterfaceImplementation implements NullableTypeParamInterface {}", + "}") + .doTest(); + } } From 2e4a2ef3239ec9602454acce74d3442cdb8ca2b7 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 20:08:42 -0700 Subject: [PATCH 027/184] restructure generics tests --- .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 6d25160ce4..8b4f419997 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -14,16 +14,11 @@ public void basicTypeParamInstantiation() { "class Test {", " static class NonNullTypeParam {}", " static class NullableTypeParam {}", - " static interface NonNullTypeParamInterface{}", " // BUG: Diagnostic contains: Generic type parameter", " static void testBadNonNull(NonNullTypeParam<@Nullable String> t) {", " // BUG: Diagnostic contains: Generic type parameter", " NonNullTypeParam<@Nullable String> t2 = null;", " }", - " // BUG: Diagnostic contains: Generic type parameter", - " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", - " // BUG: Diagnostic contains: Generic type parameter", - " static class InvalidInterfaceImplementation implements NonNullTypeParamInterface<@Nullable String> {}", "}") .doTest(); } From b1668e9e7ba03036c7aaed7c201424417a28368b Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 20:15:17 -0700 Subject: [PATCH 028/184] Add tests --- .../java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 8b4f419997..eecbfcdb2c 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -59,8 +59,11 @@ public void ExtendedClassTypeParamInstantiation() { "import org.jspecify.nullness.Nullable;", "class Test {", " static class NonNullTypeParam {}", + " static class MixedTypeParam {}", " // BUG: Diagnostic contains: Generic type parameter", " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", + " // BUG: Diagnostic contains: Generic type parameter", + " static class PartiallyInvalidSubclass extends MixedTypeParam<@Nullable String, String, String, String> {}", "}") .doTest(); } From 9c8b3ae42be38fdcfed47a56bc824f8efc64b017 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 20:15:53 -0700 Subject: [PATCH 029/184] restructure code From 97e088b1f9770c1218c8b6ecef1965638a34d1f9 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 20:16:17 -0700 Subject: [PATCH 030/184] restructure code From 036febfd08e80290bc725cf8c7efebde596c1c3c Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 10 Oct 2022 20:57:27 -0700 Subject: [PATCH 031/184] restructure code --- .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index eecbfcdb2c..1adc9ceccf 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -24,7 +24,7 @@ public void basicTypeParamInstantiation() { } @Test - public void ConstructorTypeParamInstantiation() { + public void constructorTypeParamInstantiation() { defaultCompilationHelper .addSourceLines( "Test.java", @@ -51,7 +51,7 @@ public void ConstructorTypeParamInstantiation() { } @Test - public void ExtendedClassTypeParamInstantiation() { + public void extendedClassTypeParamInstantiation() { defaultCompilationHelper .addSourceLines( "Test.java", @@ -69,7 +69,7 @@ public void ExtendedClassTypeParamInstantiation() { } @Test - public void SubClassTypeParamInstantiation() { + public void subClassTypeParamInstantiation() { defaultCompilationHelper .addSourceLines( "Test.java", @@ -88,7 +88,7 @@ public void SubClassTypeParamInstantiation() { } @Test - public void InterfaceImplementationTypeParamInstantiation() { + public void interfaceImplementationTypeParamInstantiation() { defaultCompilationHelper .addSourceLines( "Test.java", From 00ad702221ae20c09810b804fbeec078d9fd7888 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Tue, 11 Oct 2022 10:13:15 -0700 Subject: [PATCH 032/184] add jspecify mode flag --- .../src/main/java/com/uber/nullaway/AbstractConfig.java | 7 +++++++ nullaway/src/main/java/com/uber/nullaway/Config.java | 3 +++ .../main/java/com/uber/nullaway/DummyOptionsConfig.java | 5 +++++ .../java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java | 2 ++ 4 files changed, 17 insertions(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/AbstractConfig.java b/nullaway/src/main/java/com/uber/nullaway/AbstractConfig.java index c12b34c38b..01bb17777a 100644 --- a/nullaway/src/main/java/com/uber/nullaway/AbstractConfig.java +++ b/nullaway/src/main/java/com/uber/nullaway/AbstractConfig.java @@ -83,6 +83,8 @@ public abstract class AbstractConfig implements Config { protected boolean acknowledgeAndroidRecent; + protected boolean jspecifyMode; + protected ImmutableSet knownInitializers; protected ImmutableSet excludedClassAnnotations; @@ -339,4 +341,9 @@ public String getErrorURL() { public boolean acknowledgeAndroidRecent() { return acknowledgeAndroidRecent; } + + @Override + public boolean isJSpecifyMode() { + return jspecifyMode; + } } diff --git a/nullaway/src/main/java/com/uber/nullaway/Config.java b/nullaway/src/main/java/com/uber/nullaway/Config.java index f727093135..83f3f7e002 100644 --- a/nullaway/src/main/java/com/uber/nullaway/Config.java +++ b/nullaway/src/main/java/com/uber/nullaway/Config.java @@ -292,4 +292,7 @@ public interface Config { * similarly for {@code @RecentlyNonNull} */ boolean acknowledgeAndroidRecent(); + + /** Should new checks based on JSpecify (like checks for generic types) be enabled? */ + boolean isJSpecifyMode(); } diff --git a/nullaway/src/main/java/com/uber/nullaway/DummyOptionsConfig.java b/nullaway/src/main/java/com/uber/nullaway/DummyOptionsConfig.java index 9fcfb5436d..62e90ece71 100644 --- a/nullaway/src/main/java/com/uber/nullaway/DummyOptionsConfig.java +++ b/nullaway/src/main/java/com/uber/nullaway/DummyOptionsConfig.java @@ -215,4 +215,9 @@ public String getErrorURL() { public boolean acknowledgeAndroidRecent() { throw new IllegalStateException(ERROR_MESSAGE); } + + @Override + public boolean isJSpecifyMode() { + throw new IllegalStateException(ERROR_MESSAGE); + } } diff --git a/nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java b/nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java index 2d461cc897..41f256d4bd 100644 --- a/nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java +++ b/nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java @@ -53,6 +53,7 @@ final class ErrorProneCLIFlagsConfig extends AbstractConfig { EP_FL_NAMESPACE + ":CustomGeneratedCodeAnnotations"; static final String FL_GENERATED_UNANNOTATED = EP_FL_NAMESPACE + ":TreatGeneratedAsUnannotated"; static final String FL_ACKNOWLEDGE_ANDROID_RECENT = EP_FL_NAMESPACE + ":AcknowledgeAndroidRecent"; + static final String FL_JSPECIFY_MODE = EP_FL_NAMESPACE + ":JSpecifyMode"; static final String FL_EXCLUDED_FIELD_ANNOT = EP_FL_NAMESPACE + ":ExcludedFieldAnnotations"; static final String FL_INITIALIZER_ANNOT = EP_FL_NAMESPACE + ":CustomInitializerAnnotations"; static final String FL_NULLABLE_ANNOT = EP_FL_NAMESPACE + ":CustomNullableAnnotations"; @@ -188,6 +189,7 @@ final class ErrorProneCLIFlagsConfig extends AbstractConfig { flags.getBoolean(FL_HANDLE_TEST_ASSERTION_LIBRARIES).orElse(false); treatGeneratedAsUnannotated = flags.getBoolean(FL_GENERATED_UNANNOTATED).orElse(false); acknowledgeAndroidRecent = flags.getBoolean(FL_ACKNOWLEDGE_ANDROID_RECENT).orElse(false); + jspecifyMode = flags.getBoolean(FL_JSPECIFY_MODE).orElse(false); assertsEnabled = flags.getBoolean(FL_ASSERTS_ENABLED).orElse(false); fieldAnnotPattern = getPackagePattern( From 31a0e4dcc4292cbb839573c9ff0304d934fcba0c Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Tue, 11 Oct 2022 10:24:19 -0700 Subject: [PATCH 033/184] check jspecify flag --- .../main/java/com/uber/nullaway/NullAway.java | 58 +++++++++++-------- .../NullAwayJSpecifyGenericsTests.java | 18 ++++-- 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index daeee1615c..5b9b0bebcd 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -417,9 +417,9 @@ public Description matchNewClass(NewClassTree tree, VisitorState state) { methodSymbol = getSymbolOfSuperConstructor(methodSymbol, state); } // check if the class is generic - Type classType = ASTHelpers.getType(tree); - if (classType != null) { - if (classType.getTypeArguments().length() > 0) { + if (config.isJSpecifyMode()) { + Type classType = ASTHelpers.getType(tree); + if (classType != null && classType.getTypeArguments().length() > 0) { ParameterizedTypeTree parameterizedTypeTree = (ParameterizedTypeTree) tree.getIdentifier(); checkInstantiationForParameterizedTypedTree(parameterizedTypeTree, state); } @@ -430,6 +430,9 @@ public Description matchNewClass(NewClassTree tree, VisitorState state) { @SuppressWarnings("ModifiedButNotUsed") public void checkInstantiationForParameterizedTypedTree( ParameterizedTypeTree tree, VisitorState state) { + if (!config.isJSpecifyMode()) { + throw new IllegalStateException("should only check type instantiations in JSpecify mode"); + } List typeArguments = tree.getTypeArguments(); HashSet nullableTypeArguments = new HashSet(); JCTypeApply baseTypeTree = (JCTypeApply) tree; @@ -660,10 +663,10 @@ public Description matchMethod(MethodTree tree, VisitorState state) { Symbol.MethodSymbol methodSymbol = ASTHelpers.getSymbol(tree); handler.onMatchMethod(this, tree, state, methodSymbol); // check parameter types - for (VariableTree varTree : tree.getParameters()) { - Type paramType = ASTHelpers.getType(varTree); - if (paramType != null) { - if (paramType.getTypeArguments().length() > 0) { // it's a generic type instantiation + if (config.isJSpecifyMode()) { + for (VariableTree varTree : tree.getParameters()) { + Type paramType = ASTHelpers.getType(varTree); + if (paramType != null && paramType.getTypeArguments().length() > 0) { checkInstantiatedType(paramType, state, varTree); } } @@ -691,6 +694,9 @@ private void invalidInstantiationError(Tree tree, VisitorState state) { // check that type is a valid instantiation of its generic type private void checkInstantiatedType(Type type, VisitorState state, Tree tree) { + if (!config.isJSpecifyMode()) { + throw new IllegalStateException("should only check instantiated types in JSpecify mode"); + } // typeArguments used in the instantiated type (like for Foo, this gets // [String,Integer]) // if base type is unannotated do not check for generics @@ -1430,9 +1436,9 @@ public Description matchVariable(VariableTree tree, VisitorState state) { return Description.NO_MATCH; } // Check if the variable is generic - Type variableType = ASTHelpers.getType(tree); - if (variableType != null) { - if (variableType.getTypeArguments().length() > 0) { // it's a generic type instantiation + if (config.isJSpecifyMode()) { + Type variableType = ASTHelpers.getType(tree); + if (variableType != null && variableType.getTypeArguments().length() > 0) { checkInstantiatedType(variableType, state, tree); } } @@ -1536,22 +1542,24 @@ public Description matchClass(ClassTree tree, VisitorState state) { checkFieldInitialization(tree, state); } JCTree.JCClassDecl classTree = (JCTree.JCClassDecl) tree; - // check if the class extends any class - if (classTree.extending != null) { - Type extendedClassType = classTree.extending.type; - // check if the extended class is generic - if (extendedClassType.getTypeArguments().length() > 0) { - checkInstantiatedType(extendedClassType, state, classTree); + if (config.isJSpecifyMode()) { + // check if the class extends any class + if (classTree.extending != null) { + Type extendedClassType = classTree.extending.type; + // check if the extended class is generic + if (extendedClassType.getTypeArguments().length() > 0) { + checkInstantiatedType(extendedClassType, state, classTree); + } } - } - // check if the class implements any interface - List interfaces = classTree.implementing; - if (interfaces.size() > 0) { - for (int i = 0; i < interfaces.size(); i++) { - Type implementedInterfaceType = interfaces.get(i).type; - // check if the interface is generic - if (implementedInterfaceType.getTypeArguments().size() > 0) { - checkInstantiatedType(implementedInterfaceType, state, classTree); + // check if the class implements any interface + List interfaces = classTree.implementing; + if (interfaces.size() > 0) { + for (int i = 0; i < interfaces.size(); i++) { + Type implementedInterfaceType = interfaces.get(i).type; + // check if the interface is generic + if (implementedInterfaceType.getTypeArguments().size() > 0) { + checkInstantiatedType(implementedInterfaceType, state, classTree); + } } } } diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 1adc9ceccf..1b78fbc2d4 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -1,12 +1,14 @@ package com.uber.nullaway; +import com.google.errorprone.CompilationTestHelper; +import java.util.Arrays; import org.junit.Test; public class NullAwayJSpecifyGenericsTests extends NullAwayTestsBase { @Test public void basicTypeParamInstantiation() { - defaultCompilationHelper + makeHelper() .addSourceLines( "Test.java", "package com.uber;", @@ -25,7 +27,7 @@ public void basicTypeParamInstantiation() { @Test public void constructorTypeParamInstantiation() { - defaultCompilationHelper + makeHelper() .addSourceLines( "Test.java", "package com.uber;", @@ -52,7 +54,7 @@ public void constructorTypeParamInstantiation() { @Test public void extendedClassTypeParamInstantiation() { - defaultCompilationHelper + makeHelper() .addSourceLines( "Test.java", "package com.uber;", @@ -70,7 +72,7 @@ public void extendedClassTypeParamInstantiation() { @Test public void subClassTypeParamInstantiation() { - defaultCompilationHelper + makeHelper() .addSourceLines( "Test.java", "package com.uber;", @@ -89,7 +91,7 @@ public void subClassTypeParamInstantiation() { @Test public void interfaceImplementationTypeParamInstantiation() { - defaultCompilationHelper + makeHelper() .addSourceLines( "Test.java", "package com.uber;", @@ -105,4 +107,10 @@ public void interfaceImplementationTypeParamInstantiation() { "}") .doTest(); } + + private CompilationTestHelper makeHelper() { + return makeTestHelperWithArgs( + Arrays.asList( + "-XepOpt:NullAway:AnnotatedPackages=com.uber", "-XepOpt:NullAway:JSpecifyMode=true")); + } } From fe66b4af8339ae4e9d9fcc6d32692b36b105d0ff Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Tue, 11 Oct 2022 13:23:21 -0700 Subject: [PATCH 034/184] add test case for nested type parameter instantiation --- .../NullAwayJSpecifyGenericsTests.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 1b78fbc2d4..2a70ba5d48 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -108,6 +108,29 @@ public void interfaceImplementationTypeParamInstantiation() { .doTest(); } + @Test + public void nestedTypeParams() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.nullness.Nullable;", + "class Test {", + " static class NonNullTypeParam {}", + " static class NullableTypeParam {}", + " // BUG: Diagnostic contains: Generic type parameter", + " static void testBadNonNull(NullableTypeParam> t) {", + " // BUG: Diagnostic contains: Generic type parameter", + " NullableTypeParam>> t2 = null;", + " // BUG: Diagnostic contains: Generic type parameter", + " t2 = new NullableTypeParam>>();", + " // this is fine", + " NullableTypeParam>> t3 = null;", + " }", + "}") + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( Arrays.asList( From 89ca225ce97e6339aebf4508015e41fba73b5c82 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 13 Oct 2022 00:45:00 -0700 Subject: [PATCH 035/184] nested type --- .../main/java/com/uber/nullaway/NullAway.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 5b9b0bebcd..bdcc79cd0e 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -426,6 +426,7 @@ public Description matchNewClass(NewClassTree tree, VisitorState state) { } return handleInvocation(tree, state, methodSymbol, actualParams); } + /** Generics checks for parameterized typed trees * */ @SuppressWarnings("ModifiedButNotUsed") public void checkInstantiationForParameterizedTypedTree( @@ -667,7 +668,8 @@ public Description matchMethod(MethodTree tree, VisitorState state) { for (VariableTree varTree : tree.getParameters()) { Type paramType = ASTHelpers.getType(varTree); if (paramType != null && paramType.getTypeArguments().length() > 0) { - checkInstantiatedType(paramType, state, varTree); + checkNestedParameterInstantiation(paramType, state, varTree); + // checkInstantiatedType(paramType, state, varTree); } } } @@ -1430,6 +1432,16 @@ private boolean okToReadBeforeInitialized(TreePath path, VisitorState state) { return false; } + public void checkNestedParameterInstantiation(Type type, VisitorState state, Tree tree) { + checkInstantiatedType(type, state, tree); + List typeArguments = type.getTypeArguments(); + for (Type typeArgument : typeArguments) { + if (typeArgument.getTypeArguments().length() > 0) { + checkNestedParameterInstantiation(typeArgument, state, tree); + } + } + } + @Override public Description matchVariable(VariableTree tree, VisitorState state) { if (!withinAnnotatedCode(state)) { @@ -1439,10 +1451,12 @@ public Description matchVariable(VariableTree tree, VisitorState state) { if (config.isJSpecifyMode()) { Type variableType = ASTHelpers.getType(tree); if (variableType != null && variableType.getTypeArguments().length() > 0) { - checkInstantiatedType(variableType, state, tree); + checkNestedParameterInstantiation(variableType, state, tree); } } + // is nested variable + VarSymbol symbol = ASTHelpers.getSymbol(tree); if (symbol.type.isPrimitive() && tree.getInitializer() != null) { return doUnboxingCheck(state, tree.getInitializer()); @@ -1548,7 +1562,8 @@ public Description matchClass(ClassTree tree, VisitorState state) { Type extendedClassType = classTree.extending.type; // check if the extended class is generic if (extendedClassType.getTypeArguments().length() > 0) { - checkInstantiatedType(extendedClassType, state, classTree); + checkNestedParameterInstantiation(extendedClassType, state, tree); + // checkInstantiatedType(extendedClassType, state, classTree); } } // check if the class implements any interface From 8ba736bc4a6363cf7edda1057781d3ad769cbecb Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 13 Oct 2022 11:39:22 -0700 Subject: [PATCH 036/184] nested generics type check for new class --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index bdcc79cd0e..0adb77c21c 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -448,6 +448,16 @@ public void checkInstantiationForParameterizedTypedTree( } for (int i = 0; i < typeArguments.size(); i++) { boolean hasNullableAnnotation = false; + if (typeArguments.get(i).getClass().equals(JCTypeApply.class)) { + ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = + (ParameterizedTypeTree) typeArguments.get(i); + Type argumentType = ASTHelpers.getType(parameterizedTypeTreeForTypeArgument); + if (argumentType != null + && argumentType.getTypeArguments() != null + && argumentType.getTypeArguments().length() > 0) { // Nested generics + checkInstantiationForParameterizedTypedTree(parameterizedTypeTreeForTypeArgument, state); + } + } if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { From fa627be2ef2827136e8070d131488b4a21b15958 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 13 Oct 2022 21:33:07 -0700 Subject: [PATCH 037/184] Add test - generics check for function return type --- .../NullAwayJSpecifyGenericsTests.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 2a70ba5d48..ae315d600b 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -131,6 +131,27 @@ public void nestedTypeParams() { .doTest(); } + @Test + public void returnTypeParamInstantiation() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.nullness.Nullable;", + "class Test {", + " static class NonNullTypeParam {}", + " static class NullableTypeParam {}", + " // BUG: Diagnostic contains: Generic type parameter", + " static NonNullTypeParam<@Nullable String> testBadNonNull(NonNullTypeParam t) {", + " return t;", + " }", + " static NullableTypeParam<@Nullable String> testOKNull(Nullable<@Nullable String> t) {", + " return t;", + " }", + "}") + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( Arrays.asList( From 5745cf78c8dda2b9bf91c7ca814247564524ad2f Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 13 Oct 2022 22:14:08 -0700 Subject: [PATCH 038/184] Add - generics check for function return type --- .../src/main/java/com/uber/nullaway/NullAway.java | 15 ++++++++++++++- .../nullaway/NullAwayJSpecifyGenericsTests.java | 4 ++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 0adb77c21c..9de8fd926b 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -679,10 +679,23 @@ public Description matchMethod(MethodTree tree, VisitorState state) { Type paramType = ASTHelpers.getType(varTree); if (paramType != null && paramType.getTypeArguments().length() > 0) { checkNestedParameterInstantiation(paramType, state, varTree); - // checkInstantiatedType(paramType, state, varTree); } } } + + // generics check for function return type + Tree returnTypeTree = tree.getReturnType(); + if (config.isJSpecifyMode()) { + if (tree.getReturnType() != null) { + Type returnType = ASTHelpers.getType(returnTypeTree); + if (returnType != null + && returnType.getTypeArguments() != null + && returnType.getTypeArguments().length() > 0) { // generics check + checkNestedParameterInstantiation(returnType, state, returnTypeTree); + } + } + } + boolean isOverriding = ASTHelpers.hasAnnotation(methodSymbol, Override.class, state); boolean exhaustiveOverride = config.exhaustiveOverride(); if (isOverriding || !exhaustiveOverride) { diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index ae315d600b..0f81a430d0 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -145,8 +145,8 @@ public void returnTypeParamInstantiation() { " static NonNullTypeParam<@Nullable String> testBadNonNull(NonNullTypeParam t) {", " return t;", " }", - " static NullableTypeParam<@Nullable String> testOKNull(Nullable<@Nullable String> t) {", - " return t;", + " static NullableTypeParam<@Nullable String> testOKNull() {", + " return new NullableTypeParam<@Nullable String>();", " }", "}") .doTest(); From 15186293b8e562c91219f7e60c30deb552da4edb Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 17 Oct 2022 18:23:39 -0700 Subject: [PATCH 039/184] code cleaning - generics check --- .../java/com/uber/nullaway/GenericsCheck.java | 144 ++++++++++++++++++ .../main/java/com/uber/nullaway/NullAway.java | 142 ++--------------- 2 files changed, 155 insertions(+), 131 deletions(-) create mode 100644 nullaway/src/main/java/com/uber/nullaway/GenericsCheck.java diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsCheck.java b/nullaway/src/main/java/com/uber/nullaway/GenericsCheck.java new file mode 100644 index 0000000000..970b26e92a --- /dev/null +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsCheck.java @@ -0,0 +1,144 @@ +package com.uber.nullaway; + +import com.google.common.collect.ImmutableSet; +import com.google.errorprone.VisitorState; +import com.google.errorprone.util.ASTHelpers; +import com.sun.source.tree.ParameterizedTypeTree; +import com.sun.source.tree.Tree; +import com.sun.tools.javac.code.Attribute; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.tree.JCTree; +import java.util.HashSet; +import java.util.List; + +public class GenericsCheck { + + // check that type is a valid instantiation of its generic type + public static void checkInstantiatedType( + Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { + CodeAnnotationInfo codeAnnotationInfo = CodeAnnotationInfo.instance(state.context); + if (!config.isJSpecifyMode()) { + throw new IllegalStateException("should only check instantiated types in JSpecify mode"); + } + // typeArguments used in the instantiated type (like for Foo, this gets + // [String,Integer]) + // if base type is unannotated do not check for generics + // temporary check to handle testMapComputeIfAbsent + if (codeAnnotationInfo.isSymbolUnannotated(type.tsym, config)) { + return; + } + + com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); + HashSet nullableTypeArguments = new HashSet(); + int index = 0; + for (Type typArgument : typeArguments) { + com.sun.tools.javac.util.List annotationMirrors = + typArgument.getAnnotationMirrors(); + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + if (hasNullableAnnotation) { + nullableTypeArguments.add(index); + } + index++; + } + + Type baseType = type.tsym.type; + com.sun.tools.javac.util.List baseTypeArguments = baseType.getTypeArguments(); + index = 0; + for (Type baseTypeArg : baseTypeArguments) { + + // if type argument at current index has @Nullable annotation base type argument at that index + // should also have + // the @Nullable annotation. check for the annotation + if (nullableTypeArguments.contains(index)) { + + Type upperBound = baseTypeArg.getUpperBound(); + com.sun.tools.javac.util.List annotationMirrors = + upperBound.getAnnotationMirrors(); + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + // if base type argument does not have @Nullable annotation then the instantiation is + // invalid + if (!hasNullableAnnotation) { + GenericsCheck.invalidInstantiationError(tree, state, analysis, config); + } + } + index++; + } + } + + /** Generics checks for parameterized typed trees * */ + @SuppressWarnings("ModifiedButNotUsed") + public static void checkInstantiationForParameterizedTypedTree( + ParameterizedTypeTree tree, VisitorState state, NullAway analysis, Config config) { + if (!config.isJSpecifyMode()) { + throw new IllegalStateException("should only check type instantiations in JSpecify mode"); + } + List typeArguments = tree.getTypeArguments(); + HashSet nullableTypeArguments = new HashSet(); + JCTree.JCTypeApply baseTypeTree = (JCTree.JCTypeApply) tree; + Type t = baseTypeTree.type; + Type.ClassType classTyp = (Type.ClassType) t; + if (classTyp.tsym.getMetadata() != null) { + List baseTypeAttributes = + classTyp.tsym.getMetadata().getTypeAttributes(); + for (int i = 0; i < baseTypeAttributes.size(); i++) { + nullableTypeArguments.add(baseTypeAttributes.get(i).position.parameter_index); + } + } + for (int i = 0; i < typeArguments.size(); i++) { + boolean hasNullableAnnotation = false; + if (typeArguments.get(i).getClass().equals(JCTree.JCTypeApply.class)) { + ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = + (ParameterizedTypeTree) typeArguments.get(i); + Type argumentType = ASTHelpers.getType(parameterizedTypeTreeForTypeArgument); + if (argumentType != null + && argumentType.getTypeArguments() != null + && argumentType.getTypeArguments().length() > 0) { // Nested generics + checkInstantiationForParameterizedTypedTree( + parameterizedTypeTreeForTypeArgument, state, analysis, config); + } + } + if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { + JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); + for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { + Attribute.Compound attribute = annotation.attribute; + hasNullableAnnotation = + hasNullableAnnotation + || attribute.toString().equals("@org.jspecify.nullness.Nullable"); + if (hasNullableAnnotation) { + break; + } + } + } + if (hasNullableAnnotation) { + if (!nullableTypeArguments.contains(i)) { + GenericsCheck.invalidInstantiationError(typeArguments.get(i), state, analysis, config); + } + } + } + } + + private static void invalidInstantiationError( + Tree tree, VisitorState state, NullAway analysis, Config config) { + ErrorBuilder errorBuilder = new ErrorBuilder(config, "", ImmutableSet.of()); + ErrorMessage errorMessage = + new ErrorMessage( + ErrorMessage.MessageTypes.TYPE_PARAMETER_CANNOT_BE_NULLABLE, + "Generic type parameter cannot be @Nullable"); + state.reportMatch( + errorBuilder.createErrorDescription( + errorMessage, analysis.buildDescription(tree), state, null)); + } + + public static void checkNestedParameterInstantiation( + Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { + GenericsCheck.checkInstantiatedType(type, state, tree, analysis, config); + List typeArguments = type.getTypeArguments(); + for (Type typeArgument : typeArguments) { + if (typeArgument.getTypeArguments().length() > 0) { + checkNestedParameterInstantiation(typeArgument, state, tree, analysis, config); + } + } + } +} diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 9de8fd926b..59544edea3 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -82,20 +82,17 @@ import com.sun.source.tree.WhileLoopTree; import com.sun.source.util.TreePath; import com.sun.source.util.Trees; -import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.processing.JavacProcessingEnvironment; import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.JCTypeApply; import com.uber.nullaway.ErrorMessage.MessageTypes; import com.uber.nullaway.dataflow.AccessPathNullnessAnalysis; import com.uber.nullaway.dataflow.EnclosingEnvironmentNullness; import com.uber.nullaway.handlers.Handler; import com.uber.nullaway.handlers.Handlers; import java.util.ArrayList; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -421,62 +418,13 @@ public Description matchNewClass(NewClassTree tree, VisitorState state) { Type classType = ASTHelpers.getType(tree); if (classType != null && classType.getTypeArguments().length() > 0) { ParameterizedTypeTree parameterizedTypeTree = (ParameterizedTypeTree) tree.getIdentifier(); - checkInstantiationForParameterizedTypedTree(parameterizedTypeTree, state); + GenericsCheck.checkInstantiationForParameterizedTypedTree( + parameterizedTypeTree, state, this, config); } } return handleInvocation(tree, state, methodSymbol, actualParams); } - /** Generics checks for parameterized typed trees * */ - @SuppressWarnings("ModifiedButNotUsed") - public void checkInstantiationForParameterizedTypedTree( - ParameterizedTypeTree tree, VisitorState state) { - if (!config.isJSpecifyMode()) { - throw new IllegalStateException("should only check type instantiations in JSpecify mode"); - } - List typeArguments = tree.getTypeArguments(); - HashSet nullableTypeArguments = new HashSet(); - JCTypeApply baseTypeTree = (JCTypeApply) tree; - Type t = baseTypeTree.type; - Type.ClassType classTyp = (Type.ClassType) t; - if (classTyp.tsym.getMetadata() != null) { - List baseTypeAttributes = - classTyp.tsym.getMetadata().getTypeAttributes(); - for (int i = 0; i < baseTypeAttributes.size(); i++) { - nullableTypeArguments.add(baseTypeAttributes.get(i).position.parameter_index); - } - } - for (int i = 0; i < typeArguments.size(); i++) { - boolean hasNullableAnnotation = false; - if (typeArguments.get(i).getClass().equals(JCTypeApply.class)) { - ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = - (ParameterizedTypeTree) typeArguments.get(i); - Type argumentType = ASTHelpers.getType(parameterizedTypeTreeForTypeArgument); - if (argumentType != null - && argumentType.getTypeArguments() != null - && argumentType.getTypeArguments().length() > 0) { // Nested generics - checkInstantiationForParameterizedTypedTree(parameterizedTypeTreeForTypeArgument, state); - } - } - if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { - JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); - for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { - Attribute.Compound attribute = annotation.attribute; - hasNullableAnnotation = - hasNullableAnnotation - || attribute.toString().equals("@org.jspecify.nullness.Nullable"); - if (hasNullableAnnotation) { - break; - } - } - } - if (hasNullableAnnotation) { - if (!nullableTypeArguments.contains(i)) { - invalidInstantiationError(typeArguments.get(i), state); - } - } - } - } /** * Updates the {@link EnclosingEnvironmentNullness} with an entry for lambda or anonymous class, * capturing nullability info for locals just before the declaration of the entity @@ -678,7 +626,7 @@ public Description matchMethod(MethodTree tree, VisitorState state) { for (VariableTree varTree : tree.getParameters()) { Type paramType = ASTHelpers.getType(varTree); if (paramType != null && paramType.getTypeArguments().length() > 0) { - checkNestedParameterInstantiation(paramType, state, varTree); + GenericsCheck.checkNestedParameterInstantiation(paramType, state, varTree, this, config); } } } @@ -691,7 +639,8 @@ public Description matchMethod(MethodTree tree, VisitorState state) { if (returnType != null && returnType.getTypeArguments() != null && returnType.getTypeArguments().length() > 0) { // generics check - checkNestedParameterInstantiation(returnType, state, returnTypeTree); + GenericsCheck.checkNestedParameterInstantiation( + returnType, state, returnTypeTree, this, config); } } } @@ -708,67 +657,6 @@ public Description matchMethod(MethodTree tree, VisitorState state) { return Description.NO_MATCH; } - private void invalidInstantiationError(Tree tree, VisitorState state) { - ErrorMessage errorMessage = - new ErrorMessage( - MessageTypes.TYPE_PARAMETER_CANNOT_BE_NULLABLE, - "Generic type parameter cannot be @Nullable"); - state.reportMatch( - errorBuilder.createErrorDescription(errorMessage, buildDescription(tree), state, null)); - } - - // check that type is a valid instantiation of its generic type - private void checkInstantiatedType(Type type, VisitorState state, Tree tree) { - if (!config.isJSpecifyMode()) { - throw new IllegalStateException("should only check instantiated types in JSpecify mode"); - } - // typeArguments used in the instantiated type (like for Foo, this gets - // [String,Integer]) - // if base type is unannotated do not check for generics - // temporary check to handle testMapComputeIfAbsent - if (codeAnnotationInfo.isSymbolUnannotated(type.tsym, config)) { - return; - } - - com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); - HashSet nullableTypeArguments = new HashSet(); - int index = 0; - for (Type typArgument : typeArguments) { - com.sun.tools.javac.util.List annotationMirrors = - typArgument.getAnnotationMirrors(); - boolean hasNullableAnnotation = - Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - if (hasNullableAnnotation) { - nullableTypeArguments.add(index); - } - index++; - } - - Type baseType = type.tsym.type; - com.sun.tools.javac.util.List baseTypeArguments = baseType.getTypeArguments(); - index = 0; - for (Type baseTypeArg : baseTypeArguments) { - - // if type argument at current index has @Nullable annotation base type argument at that index - // should also have - // the @Nullable annotation. check for the annotation - if (nullableTypeArguments.contains(index)) { - - Type upperBound = baseTypeArg.getUpperBound(); - com.sun.tools.javac.util.List annotationMirrors = - upperBound.getAnnotationMirrors(); - boolean hasNullableAnnotation = - Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - // if base type argument does not have @Nullable annotation then the instantiation is - // invalid - if (!hasNullableAnnotation) { - invalidInstantiationError(tree, state); - } - } - index++; - } - } - @Override public Description matchSwitch(SwitchTree tree, VisitorState state) { if (!withinAnnotatedCode(state)) { @@ -1455,16 +1343,6 @@ private boolean okToReadBeforeInitialized(TreePath path, VisitorState state) { return false; } - public void checkNestedParameterInstantiation(Type type, VisitorState state, Tree tree) { - checkInstantiatedType(type, state, tree); - List typeArguments = type.getTypeArguments(); - for (Type typeArgument : typeArguments) { - if (typeArgument.getTypeArguments().length() > 0) { - checkNestedParameterInstantiation(typeArgument, state, tree); - } - } - } - @Override public Description matchVariable(VariableTree tree, VisitorState state) { if (!withinAnnotatedCode(state)) { @@ -1474,7 +1352,7 @@ public Description matchVariable(VariableTree tree, VisitorState state) { if (config.isJSpecifyMode()) { Type variableType = ASTHelpers.getType(tree); if (variableType != null && variableType.getTypeArguments().length() > 0) { - checkNestedParameterInstantiation(variableType, state, tree); + GenericsCheck.checkNestedParameterInstantiation(variableType, state, tree, this, config); } } @@ -1585,8 +1463,9 @@ public Description matchClass(ClassTree tree, VisitorState state) { Type extendedClassType = classTree.extending.type; // check if the extended class is generic if (extendedClassType.getTypeArguments().length() > 0) { - checkNestedParameterInstantiation(extendedClassType, state, tree); - // checkInstantiatedType(extendedClassType, state, classTree); + + GenericsCheck.checkNestedParameterInstantiation( + extendedClassType, state, tree, this, config); } } // check if the class implements any interface @@ -1596,7 +1475,8 @@ public Description matchClass(ClassTree tree, VisitorState state) { Type implementedInterfaceType = interfaces.get(i).type; // check if the interface is generic if (implementedInterfaceType.getTypeArguments().size() > 0) { - checkInstantiatedType(implementedInterfaceType, state, classTree); + GenericsCheck.checkInstantiatedType( + implementedInterfaceType, state, classTree, this, config); } } } From b25ba392bb51298901a4e81302fe2b1e4531c272 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 17 Oct 2022 18:26:10 -0700 Subject: [PATCH 040/184] code cleaning - generics check --- .../java/com/uber/nullaway/GenericsCheck.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsCheck.java b/nullaway/src/main/java/com/uber/nullaway/GenericsCheck.java index 970b26e92a..40691b773e 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsCheck.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsCheck.java @@ -15,7 +15,7 @@ public class GenericsCheck { // check that type is a valid instantiation of its generic type public static void checkInstantiatedType( - Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { + Type type, VisitorState state, Tree tree, NullAway currentState, Config config) { CodeAnnotationInfo codeAnnotationInfo = CodeAnnotationInfo.instance(state.context); if (!config.isJSpecifyMode()) { throw new IllegalStateException("should only check instantiated types in JSpecify mode"); @@ -60,7 +60,7 @@ public static void checkInstantiatedType( // if base type argument does not have @Nullable annotation then the instantiation is // invalid if (!hasNullableAnnotation) { - GenericsCheck.invalidInstantiationError(tree, state, analysis, config); + GenericsCheck.invalidInstantiationError(tree, state, currentState, config); } } index++; @@ -70,7 +70,7 @@ public static void checkInstantiatedType( /** Generics checks for parameterized typed trees * */ @SuppressWarnings("ModifiedButNotUsed") public static void checkInstantiationForParameterizedTypedTree( - ParameterizedTypeTree tree, VisitorState state, NullAway analysis, Config config) { + ParameterizedTypeTree tree, VisitorState state, NullAway currentState, Config config) { if (!config.isJSpecifyMode()) { throw new IllegalStateException("should only check type instantiations in JSpecify mode"); } @@ -96,7 +96,7 @@ public static void checkInstantiationForParameterizedTypedTree( && argumentType.getTypeArguments() != null && argumentType.getTypeArguments().length() > 0) { // Nested generics checkInstantiationForParameterizedTypedTree( - parameterizedTypeTreeForTypeArgument, state, analysis, config); + parameterizedTypeTreeForTypeArgument, state, currentState, config); } } if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { @@ -113,14 +113,15 @@ public static void checkInstantiationForParameterizedTypedTree( } if (hasNullableAnnotation) { if (!nullableTypeArguments.contains(i)) { - GenericsCheck.invalidInstantiationError(typeArguments.get(i), state, analysis, config); + GenericsCheck.invalidInstantiationError( + typeArguments.get(i), state, currentState, config); } } } } private static void invalidInstantiationError( - Tree tree, VisitorState state, NullAway analysis, Config config) { + Tree tree, VisitorState state, NullAway currentState, Config config) { ErrorBuilder errorBuilder = new ErrorBuilder(config, "", ImmutableSet.of()); ErrorMessage errorMessage = new ErrorMessage( @@ -128,16 +129,16 @@ private static void invalidInstantiationError( "Generic type parameter cannot be @Nullable"); state.reportMatch( errorBuilder.createErrorDescription( - errorMessage, analysis.buildDescription(tree), state, null)); + errorMessage, currentState.buildDescription(tree), state, null)); } public static void checkNestedParameterInstantiation( - Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { - GenericsCheck.checkInstantiatedType(type, state, tree, analysis, config); + Type type, VisitorState state, Tree tree, NullAway currentState, Config config) { + GenericsCheck.checkInstantiatedType(type, state, tree, currentState, config); List typeArguments = type.getTypeArguments(); for (Type typeArgument : typeArguments) { if (typeArgument.getTypeArguments().length() > 0) { - checkNestedParameterInstantiation(typeArgument, state, tree, analysis, config); + checkNestedParameterInstantiation(typeArgument, state, tree, currentState, config); } } } From 975dccd90b30e86d6d8058df31dc6c009d06dbfb Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sat, 22 Oct 2022 20:59:08 -0700 Subject: [PATCH 041/184] Suggested changes --- .../{GenericsCheck.java => GenericsChecks.java} | 9 ++++----- .../src/main/java/com/uber/nullaway/NullAway.java | 12 ++++++------ 2 files changed, 10 insertions(+), 11 deletions(-) rename nullaway/src/main/java/com/uber/nullaway/{GenericsCheck.java => GenericsChecks.java} (95%) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsCheck.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java similarity index 95% rename from nullaway/src/main/java/com/uber/nullaway/GenericsCheck.java rename to nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 40691b773e..ca0e2ecc4d 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsCheck.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -11,7 +11,7 @@ import java.util.HashSet; import java.util.List; -public class GenericsCheck { +public class GenericsChecks { // check that type is a valid instantiation of its generic type public static void checkInstantiatedType( @@ -60,7 +60,7 @@ public static void checkInstantiatedType( // if base type argument does not have @Nullable annotation then the instantiation is // invalid if (!hasNullableAnnotation) { - GenericsCheck.invalidInstantiationError(tree, state, currentState, config); + GenericsChecks.invalidInstantiationError(tree, state, currentState, config); } } index++; @@ -68,7 +68,6 @@ public static void checkInstantiatedType( } /** Generics checks for parameterized typed trees * */ - @SuppressWarnings("ModifiedButNotUsed") public static void checkInstantiationForParameterizedTypedTree( ParameterizedTypeTree tree, VisitorState state, NullAway currentState, Config config) { if (!config.isJSpecifyMode()) { @@ -113,7 +112,7 @@ public static void checkInstantiationForParameterizedTypedTree( } if (hasNullableAnnotation) { if (!nullableTypeArguments.contains(i)) { - GenericsCheck.invalidInstantiationError( + GenericsChecks.invalidInstantiationError( typeArguments.get(i), state, currentState, config); } } @@ -134,7 +133,7 @@ private static void invalidInstantiationError( public static void checkNestedParameterInstantiation( Type type, VisitorState state, Tree tree, NullAway currentState, Config config) { - GenericsCheck.checkInstantiatedType(type, state, tree, currentState, config); + GenericsChecks.checkInstantiatedType(type, state, tree, currentState, config); List typeArguments = type.getTypeArguments(); for (Type typeArgument : typeArguments) { if (typeArgument.getTypeArguments().length() > 0) { diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 42e0a26bcf..96dd5d4d2f 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -418,7 +418,7 @@ public Description matchNewClass(NewClassTree tree, VisitorState state) { Type classType = ASTHelpers.getType(tree); if (classType != null && classType.getTypeArguments().length() > 0) { ParameterizedTypeTree parameterizedTypeTree = (ParameterizedTypeTree) tree.getIdentifier(); - GenericsCheck.checkInstantiationForParameterizedTypedTree( + GenericsChecks.checkInstantiationForParameterizedTypedTree( parameterizedTypeTree, state, this, config); } } @@ -626,7 +626,7 @@ public Description matchMethod(MethodTree tree, VisitorState state) { for (VariableTree varTree : tree.getParameters()) { Type paramType = ASTHelpers.getType(varTree); if (paramType != null && paramType.getTypeArguments().length() > 0) { - GenericsCheck.checkNestedParameterInstantiation(paramType, state, varTree, this, config); + GenericsChecks.checkNestedParameterInstantiation(paramType, state, varTree, this, config); } } } @@ -639,7 +639,7 @@ public Description matchMethod(MethodTree tree, VisitorState state) { if (returnType != null && returnType.getTypeArguments() != null && returnType.getTypeArguments().length() > 0) { // generics check - GenericsCheck.checkNestedParameterInstantiation( + GenericsChecks.checkNestedParameterInstantiation( returnType, state, returnTypeTree, this, config); } } @@ -1356,7 +1356,7 @@ public Description matchVariable(VariableTree tree, VisitorState state) { if (config.isJSpecifyMode()) { Type variableType = ASTHelpers.getType(tree); if (variableType != null && variableType.getTypeArguments().length() > 0) { - GenericsCheck.checkNestedParameterInstantiation(variableType, state, tree, this, config); + GenericsChecks.checkNestedParameterInstantiation(variableType, state, tree, this, config); } } @@ -1468,7 +1468,7 @@ public Description matchClass(ClassTree tree, VisitorState state) { // check if the extended class is generic if (extendedClassType.getTypeArguments().length() > 0) { - GenericsCheck.checkNestedParameterInstantiation( + GenericsChecks.checkNestedParameterInstantiation( extendedClassType, state, tree, this, config); } } @@ -1479,7 +1479,7 @@ public Description matchClass(ClassTree tree, VisitorState state) { Type implementedInterfaceType = interfaces.get(i).type; // check if the interface is generic if (implementedInterfaceType.getTypeArguments().size() > 0) { - GenericsCheck.checkInstantiatedType( + GenericsChecks.checkInstantiatedType( implementedInterfaceType, state, classTree, this, config); } } From 6d22b007b056d2bade5fd514f049953fabbf2f52 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sat, 22 Oct 2022 21:01:18 -0700 Subject: [PATCH 042/184] Suggested changes --- .../com/uber/nullaway/GenericsChecks.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index ca0e2ecc4d..6e8a9841c6 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -15,7 +15,7 @@ public class GenericsChecks { // check that type is a valid instantiation of its generic type public static void checkInstantiatedType( - Type type, VisitorState state, Tree tree, NullAway currentState, Config config) { + Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { CodeAnnotationInfo codeAnnotationInfo = CodeAnnotationInfo.instance(state.context); if (!config.isJSpecifyMode()) { throw new IllegalStateException("should only check instantiated types in JSpecify mode"); @@ -60,7 +60,7 @@ public static void checkInstantiatedType( // if base type argument does not have @Nullable annotation then the instantiation is // invalid if (!hasNullableAnnotation) { - GenericsChecks.invalidInstantiationError(tree, state, currentState, config); + GenericsChecks.invalidInstantiationError(tree, state, analysis, config); } } index++; @@ -69,7 +69,7 @@ public static void checkInstantiatedType( /** Generics checks for parameterized typed trees * */ public static void checkInstantiationForParameterizedTypedTree( - ParameterizedTypeTree tree, VisitorState state, NullAway currentState, Config config) { + ParameterizedTypeTree tree, VisitorState state, NullAway analysis, Config config) { if (!config.isJSpecifyMode()) { throw new IllegalStateException("should only check type instantiations in JSpecify mode"); } @@ -95,7 +95,7 @@ public static void checkInstantiationForParameterizedTypedTree( && argumentType.getTypeArguments() != null && argumentType.getTypeArguments().length() > 0) { // Nested generics checkInstantiationForParameterizedTypedTree( - parameterizedTypeTreeForTypeArgument, state, currentState, config); + parameterizedTypeTreeForTypeArgument, state, analysis, config); } } if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { @@ -112,15 +112,14 @@ public static void checkInstantiationForParameterizedTypedTree( } if (hasNullableAnnotation) { if (!nullableTypeArguments.contains(i)) { - GenericsChecks.invalidInstantiationError( - typeArguments.get(i), state, currentState, config); + GenericsChecks.invalidInstantiationError(typeArguments.get(i), state, analysis, config); } } } } private static void invalidInstantiationError( - Tree tree, VisitorState state, NullAway currentState, Config config) { + Tree tree, VisitorState state, NullAway analysis, Config config) { ErrorBuilder errorBuilder = new ErrorBuilder(config, "", ImmutableSet.of()); ErrorMessage errorMessage = new ErrorMessage( @@ -128,16 +127,16 @@ private static void invalidInstantiationError( "Generic type parameter cannot be @Nullable"); state.reportMatch( errorBuilder.createErrorDescription( - errorMessage, currentState.buildDescription(tree), state, null)); + errorMessage, analysis.buildDescription(tree), state, null)); } public static void checkNestedParameterInstantiation( - Type type, VisitorState state, Tree tree, NullAway currentState, Config config) { - GenericsChecks.checkInstantiatedType(type, state, tree, currentState, config); + Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { + GenericsChecks.checkInstantiatedType(type, state, tree, analysis, config); List typeArguments = type.getTypeArguments(); for (Type typeArgument : typeArguments) { if (typeArgument.getTypeArguments().length() > 0) { - checkNestedParameterInstantiation(typeArgument, state, tree, currentState, config); + checkNestedParameterInstantiation(typeArgument, state, tree, analysis, config); } } } From 2ddbea9304aa44154f1de236e3dd01a853620699 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 24 Oct 2022 20:43:58 -0700 Subject: [PATCH 043/184] Suggested changes --- .../main/java/com/uber/nullaway/GenericsChecks.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 6e8a9841c6..e62df561f4 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -1,6 +1,5 @@ package com.uber.nullaway; -import com.google.common.collect.ImmutableSet; import com.google.errorprone.VisitorState; import com.google.errorprone.util.ASTHelpers; import com.sun.source.tree.ParameterizedTypeTree; @@ -118,26 +117,20 @@ public static void checkInstantiationForParameterizedTypedTree( } } + // tree - Tree on which the error needs to be shown private static void invalidInstantiationError( Tree tree, VisitorState state, NullAway analysis, Config config) { - ErrorBuilder errorBuilder = new ErrorBuilder(config, "", ImmutableSet.of()); ErrorMessage errorMessage = new ErrorMessage( ErrorMessage.MessageTypes.TYPE_PARAMETER_CANNOT_BE_NULLABLE, "Generic type parameter cannot be @Nullable"); state.reportMatch( - errorBuilder.createErrorDescription( + analysis.errorBuilder.createErrorDescription( errorMessage, analysis.buildDescription(tree), state, null)); } public static void checkNestedParameterInstantiation( Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { GenericsChecks.checkInstantiatedType(type, state, tree, analysis, config); - List typeArguments = type.getTypeArguments(); - for (Type typeArgument : typeArguments) { - if (typeArgument.getTypeArguments().length() > 0) { - checkNestedParameterInstantiation(typeArgument, state, tree, analysis, config); - } - } } } From b9cbbffb329c783b1e3f359cbd04abd612351da1 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 25 Oct 2022 09:38:59 -0700 Subject: [PATCH 044/184] working changes --- .../main/java/com/uber/nullaway/GenericsChecks.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index e62df561f4..6e8a9841c6 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -1,5 +1,6 @@ package com.uber.nullaway; +import com.google.common.collect.ImmutableSet; import com.google.errorprone.VisitorState; import com.google.errorprone.util.ASTHelpers; import com.sun.source.tree.ParameterizedTypeTree; @@ -117,20 +118,26 @@ public static void checkInstantiationForParameterizedTypedTree( } } - // tree - Tree on which the error needs to be shown private static void invalidInstantiationError( Tree tree, VisitorState state, NullAway analysis, Config config) { + ErrorBuilder errorBuilder = new ErrorBuilder(config, "", ImmutableSet.of()); ErrorMessage errorMessage = new ErrorMessage( ErrorMessage.MessageTypes.TYPE_PARAMETER_CANNOT_BE_NULLABLE, "Generic type parameter cannot be @Nullable"); state.reportMatch( - analysis.errorBuilder.createErrorDescription( + errorBuilder.createErrorDescription( errorMessage, analysis.buildDescription(tree), state, null)); } public static void checkNestedParameterInstantiation( Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { GenericsChecks.checkInstantiatedType(type, state, tree, analysis, config); + List typeArguments = type.getTypeArguments(); + for (Type typeArgument : typeArguments) { + if (typeArgument.getTypeArguments().length() > 0) { + checkNestedParameterInstantiation(typeArgument, state, tree, analysis, config); + } + } } } From 2002aec1be3b51820724dff830fc44a10a205292 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 25 Oct 2022 09:49:58 -0700 Subject: [PATCH 045/184] working changes --- .../main/java/com/uber/nullaway/GenericsChecks.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 6e8a9841c6..cc98f2a95d 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -1,6 +1,5 @@ package com.uber.nullaway; -import com.google.common.collect.ImmutableSet; import com.google.errorprone.VisitorState; import com.google.errorprone.util.ASTHelpers; import com.sun.source.tree.ParameterizedTypeTree; @@ -60,7 +59,7 @@ public static void checkInstantiatedType( // if base type argument does not have @Nullable annotation then the instantiation is // invalid if (!hasNullableAnnotation) { - GenericsChecks.invalidInstantiationError(tree, state, analysis, config); + GenericsChecks.invalidInstantiationError(tree, state, analysis); } } index++; @@ -112,15 +111,14 @@ public static void checkInstantiationForParameterizedTypedTree( } if (hasNullableAnnotation) { if (!nullableTypeArguments.contains(i)) { - GenericsChecks.invalidInstantiationError(typeArguments.get(i), state, analysis, config); + GenericsChecks.invalidInstantiationError(typeArguments.get(i), state, analysis); } } } } - private static void invalidInstantiationError( - Tree tree, VisitorState state, NullAway analysis, Config config) { - ErrorBuilder errorBuilder = new ErrorBuilder(config, "", ImmutableSet.of()); + private static void invalidInstantiationError(Tree tree, VisitorState state, NullAway analysis) { + ErrorBuilder errorBuilder = analysis.getErrorBuilder(); ErrorMessage errorMessage = new ErrorMessage( ErrorMessage.MessageTypes.TYPE_PARAMETER_CANNOT_BE_NULLABLE, From 5c11fbe1e5cf014a31fb55e8204b1033093ec9ce Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 25 Oct 2022 09:56:27 -0700 Subject: [PATCH 046/184] suggested changes --- .../src/main/java/com/uber/nullaway/GenericsChecks.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index cc98f2a95d..999568125e 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -47,8 +47,7 @@ public static void checkInstantiatedType( for (Type baseTypeArg : baseTypeArguments) { // if type argument at current index has @Nullable annotation base type argument at that index - // should also have - // the @Nullable annotation. check for the annotation + // should also have a @Nullable annotation on its upper bound. if (nullableTypeArguments.contains(index)) { Type upperBound = baseTypeArg.getUpperBound(); @@ -59,7 +58,7 @@ public static void checkInstantiatedType( // if base type argument does not have @Nullable annotation then the instantiation is // invalid if (!hasNullableAnnotation) { - GenericsChecks.invalidInstantiationError(tree, state, analysis); + invalidInstantiationError(tree, state, analysis); } } index++; @@ -111,7 +110,7 @@ public static void checkInstantiationForParameterizedTypedTree( } if (hasNullableAnnotation) { if (!nullableTypeArguments.contains(i)) { - GenericsChecks.invalidInstantiationError(typeArguments.get(i), state, analysis); + invalidInstantiationError(typeArguments.get(i), state, analysis); } } } From 736a6133cec1d451fdbfadd9924220bb574b66aa Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 27 Oct 2022 11:05:31 -0700 Subject: [PATCH 047/184] suggested changes --- .../com/uber/nullaway/GenericsChecks.java | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 999568125e..9c12ef5105 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -16,52 +16,52 @@ public class GenericsChecks { public static void checkInstantiatedType( Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { CodeAnnotationInfo codeAnnotationInfo = CodeAnnotationInfo.instance(state.context); - if (!config.isJSpecifyMode()) { - throw new IllegalStateException("should only check instantiated types in JSpecify mode"); - } - // typeArguments used in the instantiated type (like for Foo, this gets - // [String,Integer]) - // if base type is unannotated do not check for generics - // temporary check to handle testMapComputeIfAbsent - if (codeAnnotationInfo.isSymbolUnannotated(type.tsym, config)) { - return; - } - - com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); - HashSet nullableTypeArguments = new HashSet(); - int index = 0; - for (Type typArgument : typeArguments) { - com.sun.tools.javac.util.List annotationMirrors = - typArgument.getAnnotationMirrors(); - boolean hasNullableAnnotation = - Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - if (hasNullableAnnotation) { - nullableTypeArguments.add(index); + if (config.isJSpecifyMode()) { + // typeArguments used in the instantiated type (like for Foo, this gets + // [String,Integer]) + // if base type is unannotated do not check for generics + // temporary check to handle testMapComputeIfAbsent + if (codeAnnotationInfo.isSymbolUnannotated(type.tsym, config)) { + return; } - index++; - } - - Type baseType = type.tsym.type; - com.sun.tools.javac.util.List baseTypeArguments = baseType.getTypeArguments(); - index = 0; - for (Type baseTypeArg : baseTypeArguments) { - // if type argument at current index has @Nullable annotation base type argument at that index - // should also have a @Nullable annotation on its upper bound. - if (nullableTypeArguments.contains(index)) { - - Type upperBound = baseTypeArg.getUpperBound(); + com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); + HashSet nullableTypeArguments = new HashSet(); + int index = 0; + for (Type typArgument : typeArguments) { com.sun.tools.javac.util.List annotationMirrors = - upperBound.getAnnotationMirrors(); + typArgument.getAnnotationMirrors(); boolean hasNullableAnnotation = Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - // if base type argument does not have @Nullable annotation then the instantiation is - // invalid - if (!hasNullableAnnotation) { - invalidInstantiationError(tree, state, analysis); + if (hasNullableAnnotation) { + nullableTypeArguments.add(index); + } + index++; + } + + Type baseType = type.tsym.type; + com.sun.tools.javac.util.List baseTypeArguments = baseType.getTypeArguments(); + index = 0; + for (Type baseTypeArg : baseTypeArguments) { + + // if type argument at current index has @Nullable annotation base type argument at that + // index + // should also have a @Nullable annotation on its upper bound. + if (nullableTypeArguments.contains(index)) { + + Type upperBound = baseTypeArg.getUpperBound(); + com.sun.tools.javac.util.List annotationMirrors = + upperBound.getAnnotationMirrors(); + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + // if base type argument does not have @Nullable annotation then the instantiation is + // invalid + if (!hasNullableAnnotation) { + invalidInstantiationError(tree, state, analysis); + } } + index++; } - index++; } } From 80ba7a565366d022cb7f5cd1303f96c6d3ba258c Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 27 Oct 2022 11:11:09 -0700 Subject: [PATCH 048/184] suggested changes --- .../main/java/com/uber/nullaway/GenericsChecks.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 9c12ef5105..205315fbd1 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -75,11 +75,15 @@ public static void checkInstantiationForParameterizedTypedTree( HashSet nullableTypeArguments = new HashSet(); JCTree.JCTypeApply baseTypeTree = (JCTree.JCTypeApply) tree; Type t = baseTypeTree.type; - Type.ClassType classTyp = (Type.ClassType) t; - if (classTyp.tsym.getMetadata() != null) { + Type.ClassType classType = (Type.ClassType) t; + // If none of the arguments are @Nullable annotated MetaData is empty + if (classType.tsym.getMetadata() != null) { List baseTypeAttributes = - classTyp.tsym.getMetadata().getTypeAttributes(); + classType.tsym.getMetadata().getTypeAttributes(); + // Store the arguments in the base type that have @Nullable annotation in the set for (int i = 0; i < baseTypeAttributes.size(); i++) { + // position - index of the parameters in the list of base type attributes that have + // @Nullable annotations nullableTypeArguments.add(baseTypeAttributes.get(i).position.parameter_index); } } From e1864ee8a53fd981f80e0a5d9239e671258783cd Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 27 Oct 2022 11:38:33 -0700 Subject: [PATCH 049/184] suggested changes --- .../java/com/uber/nullaway/GenericsChecks.java | 17 ++++++----------- .../main/java/com/uber/nullaway/NullAway.java | 11 ++++------- 2 files changed, 10 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 205315fbd1..03948da1fa 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -62,6 +62,12 @@ public static void checkInstantiatedType( } index++; } + // Generics check for nested type parameters + for (Type typeArgument : typeArguments) { + if (typeArgument.getTypeArguments().length() > 0) { + checkInstantiatedType(typeArgument, state, tree, analysis, config); + } + } } } @@ -130,15 +136,4 @@ private static void invalidInstantiationError(Tree tree, VisitorState state, Nul errorBuilder.createErrorDescription( errorMessage, analysis.buildDescription(tree), state, null)); } - - public static void checkNestedParameterInstantiation( - Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { - GenericsChecks.checkInstantiatedType(type, state, tree, analysis, config); - List typeArguments = type.getTypeArguments(); - for (Type typeArgument : typeArguments) { - if (typeArgument.getTypeArguments().length() > 0) { - checkNestedParameterInstantiation(typeArgument, state, tree, analysis, config); - } - } - } } diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 96dd5d4d2f..5bdbf2b25b 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -626,7 +626,7 @@ public Description matchMethod(MethodTree tree, VisitorState state) { for (VariableTree varTree : tree.getParameters()) { Type paramType = ASTHelpers.getType(varTree); if (paramType != null && paramType.getTypeArguments().length() > 0) { - GenericsChecks.checkNestedParameterInstantiation(paramType, state, varTree, this, config); + GenericsChecks.checkInstantiatedType(paramType, state, varTree, this, config); } } } @@ -639,8 +639,7 @@ public Description matchMethod(MethodTree tree, VisitorState state) { if (returnType != null && returnType.getTypeArguments() != null && returnType.getTypeArguments().length() > 0) { // generics check - GenericsChecks.checkNestedParameterInstantiation( - returnType, state, returnTypeTree, this, config); + GenericsChecks.checkInstantiatedType(returnType, state, returnTypeTree, this, config); } } } @@ -1356,12 +1355,11 @@ public Description matchVariable(VariableTree tree, VisitorState state) { if (config.isJSpecifyMode()) { Type variableType = ASTHelpers.getType(tree); if (variableType != null && variableType.getTypeArguments().length() > 0) { - GenericsChecks.checkNestedParameterInstantiation(variableType, state, tree, this, config); + GenericsChecks.checkInstantiatedType(variableType, state, tree, this, config); } } // is nested variable - VarSymbol symbol = ASTHelpers.getSymbol(tree); if (symbol.type.isPrimitive() && tree.getInitializer() != null) { return doUnboxingCheck(state, tree.getInitializer()); @@ -1468,8 +1466,7 @@ public Description matchClass(ClassTree tree, VisitorState state) { // check if the extended class is generic if (extendedClassType.getTypeArguments().length() > 0) { - GenericsChecks.checkNestedParameterInstantiation( - extendedClassType, state, tree, this, config); + GenericsChecks.checkInstantiatedType(extendedClassType, state, tree, this, config); } } // check if the class implements any interface From 8d5e19394686f3b394681ecb72e1910af882d335 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Thu, 27 Oct 2022 14:18:46 -0700 Subject: [PATCH 050/184] extend test --- .../java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 0f81a430d0..30f94389a1 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -66,6 +66,7 @@ public void extendedClassTypeParamInstantiation() { " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", " // BUG: Diagnostic contains: Generic type parameter", " static class PartiallyInvalidSubclass extends MixedTypeParam<@Nullable String, String, String, String> {}", + " static class ValidSubclass extends MixedTypeParam {}", "}") .doTest(); } From 91aab18d4e1861227d15e8cbb64d20af99b6a0eb Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 27 Oct 2022 14:55:26 -0700 Subject: [PATCH 051/184] @Nullable annotation check for Paramterized typed tree --- .../src/main/java/com/uber/nullaway/GenericsChecks.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 03948da1fa..75aeaabbae 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -90,7 +90,11 @@ public static void checkInstantiationForParameterizedTypedTree( for (int i = 0; i < baseTypeAttributes.size(); i++) { // position - index of the parameters in the list of base type attributes that have // @Nullable annotations - nullableTypeArguments.add(baseTypeAttributes.get(i).position.parameter_index); + boolean hasNullableAnnotation = + baseTypeAttributes.get(i).toString().equals("@org.jspecify.nullness.Nullable"); + if (hasNullableAnnotation) { + nullableTypeArguments.add(baseTypeAttributes.get(i).position.parameter_index); + } } } for (int i = 0; i < typeArguments.size(); i++) { From 799f5dc80da30ad12cfd334cc039fe8c24a14430 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 27 Oct 2022 15:06:23 -0700 Subject: [PATCH 052/184] @Nullable annotation check for Paramterized typed tree --- .../nullaway/NullAwayJSpecifyGenericsTests.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 30f94389a1..2d66f074b0 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -153,6 +153,23 @@ public void returnTypeParamInstantiation() { .doTest(); } + @Test + public void testOKNewClassInstantiationForOtherAnnotations() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import lombok.NonNull;", + "class Test {", + " static class NonNullTypeParam {}", + " static void testBadNonNull(NonNullTypeParam t) {", + " // should not show error for annotation other than @Nullable", + " testBadNonNull(new NonNullTypeParam<@NonNull String>());", + " }", + "}") + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( Arrays.asList( From f042e60d9bbd966d19a294695cb1996c62bfdadd Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 31 Oct 2022 23:33:34 -0700 Subject: [PATCH 053/184] added updates --- .../src/main/java/com/uber/nullaway/GenericsChecks.java | 8 ++------ .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 4 ++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 75aeaabbae..17b60c1df5 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -89,12 +89,8 @@ public static void checkInstantiationForParameterizedTypedTree( // Store the arguments in the base type that have @Nullable annotation in the set for (int i = 0; i < baseTypeAttributes.size(); i++) { // position - index of the parameters in the list of base type attributes that have - // @Nullable annotations - boolean hasNullableAnnotation = - baseTypeAttributes.get(i).toString().equals("@org.jspecify.nullness.Nullable"); - if (hasNullableAnnotation) { - nullableTypeArguments.add(baseTypeAttributes.get(i).position.parameter_index); - } + // @Nullable annotation + nullableTypeArguments.add(baseTypeAttributes.get(i).position.parameter_index); } } for (int i = 0; i < typeArguments.size(); i++) { diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 2d66f074b0..33f370a5c3 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -162,9 +162,9 @@ public void testOKNewClassInstantiationForOtherAnnotations() { "import lombok.NonNull;", "class Test {", " static class NonNullTypeParam {}", - " static void testBadNonNull(NonNullTypeParam t) {", + " static void testOKOtherAnnotation(NonNullTypeParam t) {", " // should not show error for annotation other than @Nullable", - " testBadNonNull(new NonNullTypeParam<@NonNull String>());", + " testOKOtherAnnotation(new NonNullTypeParam<@NonNull String>());", " }", "}") .doTest(); From 852e4b1f994777e83f555e13181409417acf589a Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 1 Nov 2022 09:48:04 -0700 Subject: [PATCH 054/184] added updates --- .../java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 33f370a5c3..7e08335193 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -162,9 +162,11 @@ public void testOKNewClassInstantiationForOtherAnnotations() { "import lombok.NonNull;", "class Test {", " static class NonNullTypeParam {}", + " static class DifferentAnnotTypeParam {}", " static void testOKOtherAnnotation(NonNullTypeParam t) {", " // should not show error for annotation other than @Nullable", " testOKOtherAnnotation(new NonNullTypeParam<@NonNull String>());", + " DifferentAnnotTypeParam str = new DifferentAnnotTypeParam();", " }", "}") .doTest(); From 8b484c2120d1131d69f7d2b8e56a805f488e178c Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 1 Nov 2022 12:27:54 -0700 Subject: [PATCH 055/184] extra test cases for other annotations --- .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 7e08335193..f55c57eacf 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -160,13 +160,18 @@ public void testOKNewClassInstantiationForOtherAnnotations() { "Test.java", "package com.uber;", "import lombok.NonNull;", + "import org.jspecify.nullness.Nullable;", "class Test {", " static class NonNullTypeParam {}", - " static class DifferentAnnotTypeParam {}", + " static class DifferentAnnotTypeParam1 {}", + " static class DifferentAnnotTypeParam2<@NonNull Object> {}", " static void testOKOtherAnnotation(NonNullTypeParam t) {", " // should not show error for annotation other than @Nullable", " testOKOtherAnnotation(new NonNullTypeParam<@NonNull String>());", - " DifferentAnnotTypeParam str = new DifferentAnnotTypeParam();", + " DifferentAnnotTypeParam1 t1 = new DifferentAnnotTypeParam1();", + " DifferentAnnotTypeParam1 t2 = new DifferentAnnotTypeParam1();", + " // BUG: Diagnostic contains: Generic type parameter", + " DifferentAnnotTypeParam2 t3 = new DifferentAnnotTypeParam2<@Nullable String>();", " }", "}") .doTest(); From 172745826045bac43c3858e3095b3d4ae192c3a9 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 1 Nov 2022 12:46:00 -0700 Subject: [PATCH 056/184] extra test cases for other annotations --- .../src/main/java/com/uber/nullaway/GenericsChecks.java | 7 +++++-- .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 7 ++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 17b60c1df5..c427dd2f46 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -90,11 +90,12 @@ public static void checkInstantiationForParameterizedTypedTree( for (int i = 0; i < baseTypeAttributes.size(); i++) { // position - index of the parameters in the list of base type attributes that have // @Nullable annotation - nullableTypeArguments.add(baseTypeAttributes.get(i).position.parameter_index); + if (baseTypeAttributes.get(i).toString().equals("@org.jspecify.nullness.Nullable")) { + nullableTypeArguments.add(baseTypeAttributes.get(i).position.parameter_index); + } } } for (int i = 0; i < typeArguments.size(); i++) { - boolean hasNullableAnnotation = false; if (typeArguments.get(i).getClass().equals(JCTree.JCTypeApply.class)) { ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = (ParameterizedTypeTree) typeArguments.get(i); @@ -106,6 +107,8 @@ public static void checkInstantiationForParameterizedTypedTree( parameterizedTypeTreeForTypeArgument, state, analysis, config); } } + + boolean hasNullableAnnotation = false; if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index f55c57eacf..98190deb37 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -164,14 +164,15 @@ public void testOKNewClassInstantiationForOtherAnnotations() { "class Test {", " static class NonNullTypeParam {}", " static class DifferentAnnotTypeParam1 {}", - " static class DifferentAnnotTypeParam2<@NonNull Object> {}", + " static class DifferentAnnotTypeParam2<@NonNull E> {}", " static void testOKOtherAnnotation(NonNullTypeParam t) {", " // should not show error for annotation other than @Nullable", " testOKOtherAnnotation(new NonNullTypeParam<@NonNull String>());", " DifferentAnnotTypeParam1 t1 = new DifferentAnnotTypeParam1();", - " DifferentAnnotTypeParam1 t2 = new DifferentAnnotTypeParam1();", " // BUG: Diagnostic contains: Generic type parameter", - " DifferentAnnotTypeParam2 t3 = new DifferentAnnotTypeParam2<@Nullable String>();", + " DifferentAnnotTypeParam2 t2 = new DifferentAnnotTypeParam2<@Nullable String>();", + " // BUG: Diagnostic contains: Generic type parameter", + " DifferentAnnotTypeParam1 t3 = new DifferentAnnotTypeParam1<@Nullable String>();", " }", "}") .doTest(); From f0a0b6279afb5aa5c8d07430d91bdba7a2793539 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Thu, 3 Nov 2022 14:18:37 -0700 Subject: [PATCH 057/184] some comments and a todo --- .../main/java/com/uber/nullaway/GenericsChecks.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index c427dd2f46..356f58d659 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -78,14 +78,16 @@ public static void checkInstantiationForParameterizedTypedTree( throw new IllegalStateException("should only check type instantiations in JSpecify mode"); } List typeArguments = tree.getTypeArguments(); + // which type parameters in the base type have a @Nullable upper bound HashSet nullableTypeArguments = new HashSet(); - JCTree.JCTypeApply baseTypeTree = (JCTree.JCTypeApply) tree; - Type t = baseTypeTree.type; - Type.ClassType classType = (Type.ClassType) t; + // base type that is being instantiated + Type.ClassType baseType = (Type.ClassType) ((JCTree.JCTypeApply) tree).type; + com.sun.tools.javac.util.List baseTypeArgs = baseType.tsym.type.getTypeArguments(); + // TODO: use baseTypeArgs; iterate through them and call getUpperBound(), as in the other method // If none of the arguments are @Nullable annotated MetaData is empty - if (classType.tsym.getMetadata() != null) { + if (baseType.tsym.getMetadata() != null) { List baseTypeAttributes = - classType.tsym.getMetadata().getTypeAttributes(); + baseType.tsym.getMetadata().getTypeAttributes(); // Store the arguments in the base type that have @Nullable annotation in the set for (int i = 0; i < baseTypeAttributes.size(); i++) { // position - index of the parameters in the list of base type attributes that have From bc3c0bef6c416c676f22a0f749776bd8904ac362 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sun, 6 Nov 2022 07:56:06 -0800 Subject: [PATCH 058/184] reuse code --- .../com/uber/nullaway/GenericsChecks.java | 104 ++++++++---------- 1 file changed, 48 insertions(+), 56 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 356f58d659..3a8e2caf0d 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -41,27 +41,8 @@ public static void checkInstantiatedType( Type baseType = type.tsym.type; com.sun.tools.javac.util.List baseTypeArguments = baseType.getTypeArguments(); - index = 0; - for (Type baseTypeArg : baseTypeArguments) { - - // if type argument at current index has @Nullable annotation base type argument at that - // index - // should also have a @Nullable annotation on its upper bound. - if (nullableTypeArguments.contains(index)) { - - Type upperBound = baseTypeArg.getUpperBound(); - com.sun.tools.javac.util.List annotationMirrors = - upperBound.getAnnotationMirrors(); - boolean hasNullableAnnotation = - Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - // if base type argument does not have @Nullable annotation then the instantiation is - // invalid - if (!hasNullableAnnotation) { - invalidInstantiationError(tree, state, analysis); - } - } - index++; - } + checkNullableTypeArgsAgainstUpperBounds( + state, tree, analysis, config, nullableTypeArguments, baseTypeArguments); // Generics check for nested type parameters for (Type typeArgument : typeArguments) { if (typeArgument.getTypeArguments().length() > 0) { @@ -71,32 +52,62 @@ public static void checkInstantiatedType( } } + private static void checkNullableTypeArgsAgainstUpperBounds( + VisitorState state, + Tree tree, + NullAway analysis, + Config config, + HashSet nullableTypeArguments, + com.sun.tools.javac.util.List baseTypeArguments) { + int index = 0; + for (Type baseTypeArg : baseTypeArguments) { + + // if type argument at current index has @Nullable annotation base type argument at that + // index + // should also have a @Nullable annotation on its upper bound. + if (nullableTypeArguments.contains(index)) { + + Type upperBound = baseTypeArg.getUpperBound(); + com.sun.tools.javac.util.List annotationMirrors = + upperBound.getAnnotationMirrors(); + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + // if base type argument does not have @Nullable annotation then the instantiation is + // invalid + if (!hasNullableAnnotation) { + invalidInstantiationError(tree, state, analysis); + } + } + index++; + } + } + /** Generics checks for parameterized typed trees * */ public static void checkInstantiationForParameterizedTypedTree( ParameterizedTypeTree tree, VisitorState state, NullAway analysis, Config config) { if (!config.isJSpecifyMode()) { - throw new IllegalStateException("should only check type instantiations in JSpecify mode"); + return; } List typeArguments = tree.getTypeArguments(); - // which type parameters in the base type have a @Nullable upper bound HashSet nullableTypeArguments = new HashSet(); - // base type that is being instantiated - Type.ClassType baseType = (Type.ClassType) ((JCTree.JCTypeApply) tree).type; - com.sun.tools.javac.util.List baseTypeArgs = baseType.tsym.type.getTypeArguments(); - // TODO: use baseTypeArgs; iterate through them and call getUpperBound(), as in the other method - // If none of the arguments are @Nullable annotated MetaData is empty - if (baseType.tsym.getMetadata() != null) { - List baseTypeAttributes = - baseType.tsym.getMetadata().getTypeAttributes(); - // Store the arguments in the base type that have @Nullable annotation in the set - for (int i = 0; i < baseTypeAttributes.size(); i++) { - // position - index of the parameters in the list of base type attributes that have - // @Nullable annotation - if (baseTypeAttributes.get(i).toString().equals("@org.jspecify.nullness.Nullable")) { - nullableTypeArguments.add(baseTypeAttributes.get(i).position.parameter_index); + for (int i = 0; i < typeArguments.size(); i++) { + if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { + JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); + for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { + Attribute.Compound attribute = annotation.attribute; + if (attribute.toString().equals("@org.jspecify.nullness.Nullable")) { + nullableTypeArguments.add(i); + break; + } } } } + // base type that is being instantiated + Type.ClassType baseType = (Type.ClassType) ((JCTree.JCTypeApply) tree).type; + com.sun.tools.javac.util.List baseTypeArgs = baseType.tsym.type.getTypeArguments(); + checkNullableTypeArgsAgainstUpperBounds( + state, tree, analysis, config, nullableTypeArguments, baseTypeArgs); + // recursive check for nested parameterized types for (int i = 0; i < typeArguments.size(); i++) { if (typeArguments.get(i).getClass().equals(JCTree.JCTypeApply.class)) { ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = @@ -109,25 +120,6 @@ public static void checkInstantiationForParameterizedTypedTree( parameterizedTypeTreeForTypeArgument, state, analysis, config); } } - - boolean hasNullableAnnotation = false; - if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { - JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); - for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { - Attribute.Compound attribute = annotation.attribute; - hasNullableAnnotation = - hasNullableAnnotation - || attribute.toString().equals("@org.jspecify.nullness.Nullable"); - if (hasNullableAnnotation) { - break; - } - } - } - if (hasNullableAnnotation) { - if (!nullableTypeArguments.contains(i)) { - invalidInstantiationError(typeArguments.get(i), state, analysis); - } - } } } From 832f733b211a879f5419331e49c1a64ebefafa01 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sun, 6 Nov 2022 07:58:20 -0800 Subject: [PATCH 059/184] minor cleanup --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 3a8e2caf0d..13418394a0 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -103,7 +103,7 @@ public static void checkInstantiationForParameterizedTypedTree( } } // base type that is being instantiated - Type.ClassType baseType = (Type.ClassType) ((JCTree.JCTypeApply) tree).type; + Type baseType = ASTHelpers.getType(tree); com.sun.tools.javac.util.List baseTypeArgs = baseType.tsym.type.getTypeArguments(); checkNullableTypeArgsAgainstUpperBounds( state, tree, analysis, config, nullableTypeArguments, baseTypeArgs); From 0b5268c6d3b20e01a481113c9a1da97ba155e066 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sun, 6 Nov 2022 08:03:28 -0800 Subject: [PATCH 060/184] fix --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 13418394a0..4436fa544b 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -104,6 +104,9 @@ public static void checkInstantiationForParameterizedTypedTree( } // base type that is being instantiated Type baseType = ASTHelpers.getType(tree); + if (baseType == null) { + return; + } com.sun.tools.javac.util.List baseTypeArgs = baseType.tsym.type.getTypeArguments(); checkNullableTypeArgsAgainstUpperBounds( state, tree, analysis, config, nullableTypeArguments, baseTypeArgs); From 66a10680adc40b825f64b357574998f0c7827ec5 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 6 Nov 2022 11:18:10 -0800 Subject: [PATCH 061/184] Suggested changes --- .../com/uber/nullaway/GenericsChecks.java | 28 +++++-- .../main/java/com/uber/nullaway/NullAway.java | 82 ++++++++----------- 2 files changed, 58 insertions(+), 52 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 4436fa544b..479177f964 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -10,17 +10,18 @@ import java.util.HashSet; import java.util.List; +/** + * GenericsChecks class adds Nullability checks for the generics types instantiation including + * generic and nested generic type functions, function parameters, variables, assignments, new class + * and subclass + */ public class GenericsChecks { - // check that type is a valid instantiation of its generic type + /** check that type is a valid instantiation of its generic type */ public static void checkInstantiatedType( Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { CodeAnnotationInfo codeAnnotationInfo = CodeAnnotationInfo.instance(state.context); if (config.isJSpecifyMode()) { - // typeArguments used in the instantiated type (like for Foo, this gets - // [String,Integer]) - // if base type is unannotated do not check for generics - // temporary check to handle testMapComputeIfAbsent if (codeAnnotationInfo.isSymbolUnannotated(type.tsym, config)) { return; } @@ -52,6 +53,15 @@ public static void checkInstantiatedType( } } + /** + * checks if the arguments with @Nullable annotation in the instantiation have the @Nullable + * annotation in the declaration or not and generates errors if there are no matching @Nullable + * annotations. + * + * @param nullableTypeArguments the set of the arguments in the instantiation that have nullable + * annotations + * @param baseTypeArguments the list of arguments in the declared type + */ private static void checkNullableTypeArgsAgainstUpperBounds( VisitorState state, Tree tree, @@ -82,7 +92,13 @@ private static void checkNullableTypeArgsAgainstUpperBounds( } } - /** Generics checks for parameterized typed trees * */ + /** + * Generics type checks for the parameterized typed tree. Needed to separate this method from + * checkInstantiatedType as the annotations are lost for the parameterized typed tree. Need to + * fetch annotations from the MetaData + * + * @param analysis Instance of the NullAway class + */ public static void checkInstantiationForParameterizedTypedTree( ParameterizedTypeTree tree, VisitorState state, NullAway analysis, Config config) { if (!config.isJSpecifyMode()) { diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 5bdbf2b25b..44358309ed 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -414,13 +414,11 @@ public Description matchNewClass(NewClassTree tree, VisitorState state) { methodSymbol = getSymbolOfSuperConstructor(methodSymbol, state); } // check if the class is generic - if (config.isJSpecifyMode()) { - Type classType = ASTHelpers.getType(tree); - if (classType != null && classType.getTypeArguments().length() > 0) { - ParameterizedTypeTree parameterizedTypeTree = (ParameterizedTypeTree) tree.getIdentifier(); - GenericsChecks.checkInstantiationForParameterizedTypedTree( - parameterizedTypeTree, state, this, config); - } + Type classType = ASTHelpers.getType(tree); + if (classType != null && classType.getTypeArguments().length() > 0) { + ParameterizedTypeTree parameterizedTypeTree = (ParameterizedTypeTree) tree.getIdentifier(); + GenericsChecks.checkInstantiationForParameterizedTypedTree( + parameterizedTypeTree, state, this, config); } return handleInvocation(tree, state, methodSymbol, actualParams); } @@ -622,25 +620,21 @@ public Description matchMethod(MethodTree tree, VisitorState state) { Symbol.MethodSymbol methodSymbol = ASTHelpers.getSymbol(tree); handler.onMatchMethod(this, tree, state, methodSymbol); // check parameter types - if (config.isJSpecifyMode()) { - for (VariableTree varTree : tree.getParameters()) { - Type paramType = ASTHelpers.getType(varTree); - if (paramType != null && paramType.getTypeArguments().length() > 0) { - GenericsChecks.checkInstantiatedType(paramType, state, varTree, this, config); - } + for (VariableTree varTree : tree.getParameters()) { + Type paramType = ASTHelpers.getType(varTree); + if (paramType != null && paramType.getTypeArguments().length() > 0) { + GenericsChecks.checkInstantiatedType(paramType, state, varTree, this, config); } } // generics check for function return type Tree returnTypeTree = tree.getReturnType(); - if (config.isJSpecifyMode()) { - if (tree.getReturnType() != null) { - Type returnType = ASTHelpers.getType(returnTypeTree); - if (returnType != null - && returnType.getTypeArguments() != null - && returnType.getTypeArguments().length() > 0) { // generics check - GenericsChecks.checkInstantiatedType(returnType, state, returnTypeTree, this, config); - } + if (tree.getReturnType() != null) { + Type returnType = ASTHelpers.getType(returnTypeTree); + if (returnType != null + && returnType.getTypeArguments() != null + && returnType.getTypeArguments().length() > 0) { // generics check + GenericsChecks.checkInstantiatedType(returnType, state, returnTypeTree, this, config); } } @@ -1351,12 +1345,10 @@ public Description matchVariable(VariableTree tree, VisitorState state) { if (!withinAnnotatedCode(state)) { return Description.NO_MATCH; } - // Check if the variable is generic - if (config.isJSpecifyMode()) { - Type variableType = ASTHelpers.getType(tree); - if (variableType != null && variableType.getTypeArguments().length() > 0) { - GenericsChecks.checkInstantiatedType(variableType, state, tree, this, config); - } + // Check if the variable is generi + Type variableType = ASTHelpers.getType(tree); + if (variableType != null && variableType.getTypeArguments().length() > 0) { + GenericsChecks.checkInstantiatedType(variableType, state, tree, this, config); } // is nested variable @@ -1459,26 +1451,24 @@ public Description matchClass(ClassTree tree, VisitorState state) { checkFieldInitialization(tree, state); } JCTree.JCClassDecl classTree = (JCTree.JCClassDecl) tree; - if (config.isJSpecifyMode()) { - // check if the class extends any class - if (classTree.extending != null) { - Type extendedClassType = classTree.extending.type; - // check if the extended class is generic - if (extendedClassType.getTypeArguments().length() > 0) { - - GenericsChecks.checkInstantiatedType(extendedClassType, state, tree, this, config); - } + // check if the class extends any class + if (classTree.extending != null) { + Type extendedClassType = classTree.extending.type; + // check if the extended class is generic + if (extendedClassType.getTypeArguments().length() > 0) { + + GenericsChecks.checkInstantiatedType(extendedClassType, state, tree, this, config); } - // check if the class implements any interface - List interfaces = classTree.implementing; - if (interfaces.size() > 0) { - for (int i = 0; i < interfaces.size(); i++) { - Type implementedInterfaceType = interfaces.get(i).type; - // check if the interface is generic - if (implementedInterfaceType.getTypeArguments().size() > 0) { - GenericsChecks.checkInstantiatedType( - implementedInterfaceType, state, classTree, this, config); - } + } + // check if the class implements any interface + List interfaces = classTree.implementing; + if (interfaces.size() > 0) { + for (int i = 0; i < interfaces.size(); i++) { + Type implementedInterfaceType = interfaces.get(i).type; + // check if the interface is generic + if (implementedInterfaceType.getTypeArguments().size() > 0) { + GenericsChecks.checkInstantiatedType( + implementedInterfaceType, state, classTree, this, config); } } } From 1bc1ea62c232055b6c68d7a72208f83f66d54f21 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 6 Nov 2022 11:19:42 -0800 Subject: [PATCH 062/184] Suggested changes --- .../com/uber/nullaway/GenericsChecks.java | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 479177f964..dee0086cd2 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -21,34 +21,35 @@ public class GenericsChecks { public static void checkInstantiatedType( Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { CodeAnnotationInfo codeAnnotationInfo = CodeAnnotationInfo.instance(state.context); - if (config.isJSpecifyMode()) { - if (codeAnnotationInfo.isSymbolUnannotated(type.tsym, config)) { - return; - } + if (!config.isJSpecifyMode()) { + return; + } + if (codeAnnotationInfo.isSymbolUnannotated(type.tsym, config)) { + return; + } - com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); - HashSet nullableTypeArguments = new HashSet(); - int index = 0; - for (Type typArgument : typeArguments) { - com.sun.tools.javac.util.List annotationMirrors = - typArgument.getAnnotationMirrors(); - boolean hasNullableAnnotation = - Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - if (hasNullableAnnotation) { - nullableTypeArguments.add(index); - } - index++; + com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); + HashSet nullableTypeArguments = new HashSet(); + int index = 0; + for (Type typArgument : typeArguments) { + com.sun.tools.javac.util.List annotationMirrors = + typArgument.getAnnotationMirrors(); + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + if (hasNullableAnnotation) { + nullableTypeArguments.add(index); } + index++; + } - Type baseType = type.tsym.type; - com.sun.tools.javac.util.List baseTypeArguments = baseType.getTypeArguments(); - checkNullableTypeArgsAgainstUpperBounds( - state, tree, analysis, config, nullableTypeArguments, baseTypeArguments); - // Generics check for nested type parameters - for (Type typeArgument : typeArguments) { - if (typeArgument.getTypeArguments().length() > 0) { - checkInstantiatedType(typeArgument, state, tree, analysis, config); - } + Type baseType = type.tsym.type; + com.sun.tools.javac.util.List baseTypeArguments = baseType.getTypeArguments(); + checkNullableTypeArgsAgainstUpperBounds( + state, tree, analysis, config, nullableTypeArguments, baseTypeArguments); + // Generics check for nested type parameters + for (Type typeArgument : typeArguments) { + if (typeArgument.getTypeArguments().length() > 0) { + checkInstantiatedType(typeArgument, state, tree, analysis, config); } } } From cb1690ab6663ea5c43fbaa5ffd7adbdbc507eabd Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 6 Nov 2022 11:22:08 -0800 Subject: [PATCH 063/184] Suggested changes --- .../src/main/java/com/uber/nullaway/GenericsChecks.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index dee0086cd2..8f8069ab57 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -30,16 +30,14 @@ public static void checkInstantiatedType( com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); HashSet nullableTypeArguments = new HashSet(); - int index = 0; - for (Type typArgument : typeArguments) { + for (int index = 0; index < typeArguments.size(); index++) { com.sun.tools.javac.util.List annotationMirrors = - typArgument.getAnnotationMirrors(); + typeArguments.get(index).getAnnotationMirrors(); boolean hasNullableAnnotation = Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); if (hasNullableAnnotation) { nullableTypeArguments.add(index); } - index++; } Type baseType = type.tsym.type; From c523f2dd3d0ebd04c3c892d13772da8452516ef1 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Mon, 7 Nov 2022 08:30:36 -0800 Subject: [PATCH 064/184] Javadoc tweaks --- .../com/uber/nullaway/GenericsChecks.java | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 8f8069ab57..f74d8fbebd 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -10,14 +10,19 @@ import java.util.HashSet; import java.util.List; -/** - * GenericsChecks class adds Nullability checks for the generics types instantiation including - * generic and nested generic type functions, function parameters, variables, assignments, new class - * and subclass - */ +/** Methods for performing checks related to generic types and nullability. */ public class GenericsChecks { - /** check that type is a valid instantiation of its generic type */ + /** + * Checks that for an instantiated generic type, {@code @Nullable} types are only used for type + * variables that have a {@code @Nullable} upper bound. + * + * @param type the instantiated type + * @param state the visitor state + * @param tree the tree in the AST representing the instantiated type + * @param analysis the analysis object + * @param config the analysis configuration + */ public static void checkInstantiatedType( Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { CodeAnnotationInfo codeAnnotationInfo = CodeAnnotationInfo.instance(state.context); @@ -53,13 +58,15 @@ public static void checkInstantiatedType( } /** - * checks if the arguments with @Nullable annotation in the instantiation have the @Nullable - * annotation in the declaration or not and generates errors if there are no matching @Nullable - * annotations. + * Checks if the type arguments with a {@code @Nullable} annotation in an instantiated type have a + * {@code @Nullable} upper bound in the declaration, and reports an error otherwise. * - * @param nullableTypeArguments the set of the arguments in the instantiation that have nullable - * annotations - * @param baseTypeArguments the list of arguments in the declared type + * @param state the visitor state + * @param tree TODO not sure we need this + * @param analysis the analysis object + * @param config the analysis config + * @param nullableTypeArguments indices of {@code Nullable} type arguments + * @param baseTypeArguments list of type variables (with bounds) in the declared type */ private static void checkNullableTypeArgsAgainstUpperBounds( VisitorState state, @@ -92,11 +99,15 @@ private static void checkNullableTypeArgsAgainstUpperBounds( } /** - * Generics type checks for the parameterized typed tree. Needed to separate this method from - * checkInstantiatedType as the annotations are lost for the parameterized typed tree. Need to - * fetch annotations from the MetaData + * Checks that for an instantiated generic type, {@code @Nullable} types are only used for type + * variables that have a {@code @Nullable} upper bound. Similar to {@link + * #checkInstantiatedType(Type, VisitorState, Tree, NullAway, Config)} but specialized for when + * the instantiated type is represented as a {@link ParameterizedTypeTree}. * - * @param analysis Instance of the NullAway class + * @param tree the tree representing the instantiated type + * @param state visitor state + * @param analysis the analysis object + * @param config the analysis config */ public static void checkInstantiationForParameterizedTypedTree( ParameterizedTypeTree tree, VisitorState state, NullAway analysis, Config config) { From 8cf3819b16a17b0f3395f83fe1e1178a5a515ce5 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Mon, 7 Nov 2022 08:40:15 -0800 Subject: [PATCH 065/184] add private constructor --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index f74d8fbebd..9662b387de 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -13,6 +13,10 @@ /** Methods for performing checks related to generic types and nullability. */ public class GenericsChecks { + private GenericsChecks() { + // just utility methods + } + /** * Checks that for an instantiated generic type, {@code @Nullable} types are only used for type * variables that have a {@code @Nullable} upper bound. From 27d54886b0adc459e891717d6221e8ed8ac795f4 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 10 Nov 2022 10:45:49 -0800 Subject: [PATCH 066/184] suggested changes --- .../main/java/com/uber/nullaway/GenericsChecks.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 9662b387de..56367a4b49 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -79,15 +79,10 @@ private static void checkNullableTypeArgsAgainstUpperBounds( Config config, HashSet nullableTypeArguments, com.sun.tools.javac.util.List baseTypeArguments) { - int index = 0; - for (Type baseTypeArg : baseTypeArguments) { + for (int i = 0; i < baseTypeArguments.size(); i++) { + if (nullableTypeArguments.contains(i)) { - // if type argument at current index has @Nullable annotation base type argument at that - // index - // should also have a @Nullable annotation on its upper bound. - if (nullableTypeArguments.contains(index)) { - - Type upperBound = baseTypeArg.getUpperBound(); + Type upperBound = baseTypeArguments.get(i).getUpperBound(); com.sun.tools.javac.util.List annotationMirrors = upperBound.getAnnotationMirrors(); boolean hasNullableAnnotation = @@ -98,7 +93,6 @@ private static void checkNullableTypeArgsAgainstUpperBounds( invalidInstantiationError(tree, state, analysis); } } - index++; } } From 263edacc27b7a35f20f4075e2e1e8e13527d5326 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 10 Nov 2022 11:37:26 -0800 Subject: [PATCH 067/184] suggested changes --- .../com/uber/nullaway/GenericsChecks.java | 49 ++----------------- .../main/java/com/uber/nullaway/NullAway.java | 22 +++++---- 2 files changed, 15 insertions(+), 56 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 56367a4b49..1c99f38076 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -17,50 +17,6 @@ private GenericsChecks() { // just utility methods } - /** - * Checks that for an instantiated generic type, {@code @Nullable} types are only used for type - * variables that have a {@code @Nullable} upper bound. - * - * @param type the instantiated type - * @param state the visitor state - * @param tree the tree in the AST representing the instantiated type - * @param analysis the analysis object - * @param config the analysis configuration - */ - public static void checkInstantiatedType( - Type type, VisitorState state, Tree tree, NullAway analysis, Config config) { - CodeAnnotationInfo codeAnnotationInfo = CodeAnnotationInfo.instance(state.context); - if (!config.isJSpecifyMode()) { - return; - } - if (codeAnnotationInfo.isSymbolUnannotated(type.tsym, config)) { - return; - } - - com.sun.tools.javac.util.List typeArguments = type.getTypeArguments(); - HashSet nullableTypeArguments = new HashSet(); - for (int index = 0; index < typeArguments.size(); index++) { - com.sun.tools.javac.util.List annotationMirrors = - typeArguments.get(index).getAnnotationMirrors(); - boolean hasNullableAnnotation = - Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - if (hasNullableAnnotation) { - nullableTypeArguments.add(index); - } - } - - Type baseType = type.tsym.type; - com.sun.tools.javac.util.List baseTypeArguments = baseType.getTypeArguments(); - checkNullableTypeArgsAgainstUpperBounds( - state, tree, analysis, config, nullableTypeArguments, baseTypeArguments); - // Generics check for nested type parameters - for (Type typeArgument : typeArguments) { - if (typeArgument.getTypeArguments().length() > 0) { - checkInstantiatedType(typeArgument, state, tree, analysis, config); - } - } - } - /** * Checks if the type arguments with a {@code @Nullable} annotation in an instantiated type have a * {@code @Nullable} upper bound in the declaration, and reports an error otherwise. @@ -99,8 +55,9 @@ private static void checkNullableTypeArgsAgainstUpperBounds( /** * Checks that for an instantiated generic type, {@code @Nullable} types are only used for type * variables that have a {@code @Nullable} upper bound. Similar to {@link - * #checkInstantiatedType(Type, VisitorState, Tree, NullAway, Config)} but specialized for when - * the instantiated type is represented as a {@link ParameterizedTypeTree}. + * #checkInstantiationForParameterizedTypedTree(ParameterizedTypeTree, VisitorState, NullAway, + * Config)} but specialized for when the instantiated type is represented as a {@link + * ParameterizedTypeTree}. * * @param tree the tree representing the instantiated type * @param state visitor state diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 44358309ed..61a2f51f99 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -623,7 +623,8 @@ public Description matchMethod(MethodTree tree, VisitorState state) { for (VariableTree varTree : tree.getParameters()) { Type paramType = ASTHelpers.getType(varTree); if (paramType != null && paramType.getTypeArguments().length() > 0) { - GenericsChecks.checkInstantiatedType(paramType, state, varTree, this, config); + GenericsChecks.checkInstantiationForParameterizedTypedTree( + (ParameterizedTypeTree) varTree.getType(), state, this, config); } } @@ -634,7 +635,8 @@ public Description matchMethod(MethodTree tree, VisitorState state) { if (returnType != null && returnType.getTypeArguments() != null && returnType.getTypeArguments().length() > 0) { // generics check - GenericsChecks.checkInstantiatedType(returnType, state, returnTypeTree, this, config); + GenericsChecks.checkInstantiationForParameterizedTypedTree( + (ParameterizedTypeTree) ((JCTree.JCMethodDecl) tree).restype, state, this, config); } } @@ -1345,10 +1347,11 @@ public Description matchVariable(VariableTree tree, VisitorState state) { if (!withinAnnotatedCode(state)) { return Description.NO_MATCH; } - // Check if the variable is generi + // Check if the variable is generics type Type variableType = ASTHelpers.getType(tree); if (variableType != null && variableType.getTypeArguments().length() > 0) { - GenericsChecks.checkInstantiatedType(variableType, state, tree, this, config); + GenericsChecks.checkInstantiationForParameterizedTypedTree( + (ParameterizedTypeTree) ((JCTree.JCVariableDecl) tree).vartype, state, this, config); } // is nested variable @@ -1453,11 +1456,10 @@ public Description matchClass(ClassTree tree, VisitorState state) { JCTree.JCClassDecl classTree = (JCTree.JCClassDecl) tree; // check if the class extends any class if (classTree.extending != null) { - Type extendedClassType = classTree.extending.type; // check if the extended class is generic - if (extendedClassType.getTypeArguments().length() > 0) { - - GenericsChecks.checkInstantiatedType(extendedClassType, state, tree, this, config); + if (classTree.extending.type.getTypeArguments().length() > 0) { + GenericsChecks.checkInstantiationForParameterizedTypedTree( + (ParameterizedTypeTree) classTree.extending, state, this, config); } } // check if the class implements any interface @@ -1467,8 +1469,8 @@ public Description matchClass(ClassTree tree, VisitorState state) { Type implementedInterfaceType = interfaces.get(i).type; // check if the interface is generic if (implementedInterfaceType.getTypeArguments().size() > 0) { - GenericsChecks.checkInstantiatedType( - implementedInterfaceType, state, classTree, this, config); + GenericsChecks.checkInstantiationForParameterizedTypedTree( + (ParameterizedTypeTree) interfaces.get(i), state, this, config); } } } From 2fa8569f557b5862165c0b0ad7595ab45f070c3d Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 10 Nov 2022 11:42:05 -0800 Subject: [PATCH 068/184] suggested changes --- .../java/com/uber/nullaway/GenericsChecks.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 1c99f38076..7c11d1a5d4 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -7,7 +7,7 @@ import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.tree.JCTree; -import java.util.HashSet; +import java.util.HashMap; import java.util.List; /** Methods for performing checks related to generic types and nullability. */ @@ -22,7 +22,6 @@ private GenericsChecks() { * {@code @Nullable} upper bound in the declaration, and reports an error otherwise. * * @param state the visitor state - * @param tree TODO not sure we need this * @param analysis the analysis object * @param config the analysis config * @param nullableTypeArguments indices of {@code Nullable} type arguments @@ -30,13 +29,12 @@ private GenericsChecks() { */ private static void checkNullableTypeArgsAgainstUpperBounds( VisitorState state, - Tree tree, NullAway analysis, Config config, - HashSet nullableTypeArguments, + HashMap nullableTypeArguments, com.sun.tools.javac.util.List baseTypeArguments) { for (int i = 0; i < baseTypeArguments.size(); i++) { - if (nullableTypeArguments.contains(i)) { + if (nullableTypeArguments.containsKey(i)) { Type upperBound = baseTypeArguments.get(i).getUpperBound(); com.sun.tools.javac.util.List annotationMirrors = @@ -46,7 +44,7 @@ private static void checkNullableTypeArgsAgainstUpperBounds( // if base type argument does not have @Nullable annotation then the instantiation is // invalid if (!hasNullableAnnotation) { - invalidInstantiationError(tree, state, analysis); + invalidInstantiationError(nullableTypeArguments.get(i), state, analysis); } } } @@ -70,14 +68,14 @@ public static void checkInstantiationForParameterizedTypedTree( return; } List typeArguments = tree.getTypeArguments(); - HashSet nullableTypeArguments = new HashSet(); + HashMap nullableTypeArguments = new HashMap(); for (int i = 0; i < typeArguments.size(); i++) { if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { Attribute.Compound attribute = annotation.attribute; if (attribute.toString().equals("@org.jspecify.nullness.Nullable")) { - nullableTypeArguments.add(i); + nullableTypeArguments.put(i, typeArguments.get(i)); break; } } @@ -90,7 +88,7 @@ public static void checkInstantiationForParameterizedTypedTree( } com.sun.tools.javac.util.List baseTypeArgs = baseType.tsym.type.getTypeArguments(); checkNullableTypeArgsAgainstUpperBounds( - state, tree, analysis, config, nullableTypeArguments, baseTypeArgs); + state, analysis, config, nullableTypeArguments, baseTypeArgs); // recursive check for nested parameterized types for (int i = 0; i < typeArguments.size(); i++) { if (typeArguments.get(i).getClass().equals(JCTree.JCTypeApply.class)) { From f40a0da62ee013f530ba106237e087b4158dca9a Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 10 Nov 2022 11:44:08 -0800 Subject: [PATCH 069/184] suggested changes From 8308cf6cab00287661a55ede7488c4c4d74f7964 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Thu, 10 Nov 2022 14:49:19 -0800 Subject: [PATCH 070/184] code cleanup --- .../com/uber/nullaway/GenericsChecks.java | 84 +++++++------------ 1 file changed, 31 insertions(+), 53 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 7c11d1a5d4..cf05816291 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -2,13 +2,15 @@ import com.google.errorprone.VisitorState; import com.google.errorprone.util.ASTHelpers; +import com.sun.source.tree.AnnotatedTypeTree; +import com.sun.source.tree.AnnotationTree; import com.sun.source.tree.ParameterizedTypeTree; import com.sun.source.tree.Tree; import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.tree.JCTree; import java.util.HashMap; import java.util.List; +import java.util.Map; /** Methods for performing checks related to generic types and nullability. */ public class GenericsChecks { @@ -17,45 +19,9 @@ private GenericsChecks() { // just utility methods } - /** - * Checks if the type arguments with a {@code @Nullable} annotation in an instantiated type have a - * {@code @Nullable} upper bound in the declaration, and reports an error otherwise. - * - * @param state the visitor state - * @param analysis the analysis object - * @param config the analysis config - * @param nullableTypeArguments indices of {@code Nullable} type arguments - * @param baseTypeArguments list of type variables (with bounds) in the declared type - */ - private static void checkNullableTypeArgsAgainstUpperBounds( - VisitorState state, - NullAway analysis, - Config config, - HashMap nullableTypeArguments, - com.sun.tools.javac.util.List baseTypeArguments) { - for (int i = 0; i < baseTypeArguments.size(); i++) { - if (nullableTypeArguments.containsKey(i)) { - - Type upperBound = baseTypeArguments.get(i).getUpperBound(); - com.sun.tools.javac.util.List annotationMirrors = - upperBound.getAnnotationMirrors(); - boolean hasNullableAnnotation = - Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - // if base type argument does not have @Nullable annotation then the instantiation is - // invalid - if (!hasNullableAnnotation) { - invalidInstantiationError(nullableTypeArguments.get(i), state, analysis); - } - } - } - } - /** * Checks that for an instantiated generic type, {@code @Nullable} types are only used for type - * variables that have a {@code @Nullable} upper bound. Similar to {@link - * #checkInstantiationForParameterizedTypedTree(ParameterizedTypeTree, VisitorState, NullAway, - * Config)} but specialized for when the instantiated type is represented as a {@link - * ParameterizedTypeTree}. + * variables that have a {@code @Nullable} upper bound. * * @param tree the tree representing the instantiated type * @param state visitor state @@ -68,14 +34,16 @@ public static void checkInstantiationForParameterizedTypedTree( return; } List typeArguments = tree.getTypeArguments(); - HashMap nullableTypeArguments = new HashMap(); + Map nullableTypeArguments = new HashMap<>(); for (int i = 0; i < typeArguments.size(); i++) { - if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { - JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); - for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { - Attribute.Compound attribute = annotation.attribute; - if (attribute.toString().equals("@org.jspecify.nullness.Nullable")) { - nullableTypeArguments.put(i, typeArguments.get(i)); + Tree curTypeArg = typeArguments.get(i); + if (curTypeArg instanceof AnnotatedTypeTree) { + AnnotatedTypeTree annotatedType = (AnnotatedTypeTree) curTypeArg; + for (AnnotationTree annotation : annotatedType.getAnnotations()) { + Type annotationType = ASTHelpers.getType(annotation); + if (annotationType != null + && Nullness.isNullableAnnotation(annotationType.toString(), config)) { + nullableTypeArguments.put(i, curTypeArg); break; } } @@ -87,17 +55,27 @@ public static void checkInstantiationForParameterizedTypedTree( return; } com.sun.tools.javac.util.List baseTypeArgs = baseType.tsym.type.getTypeArguments(); - checkNullableTypeArgsAgainstUpperBounds( - state, analysis, config, nullableTypeArguments, baseTypeArgs); + for (int i = 0; i < baseTypeArgs.size(); i++) { + if (nullableTypeArguments.containsKey(i)) { + + Type upperBound = baseTypeArgs.get(i).getUpperBound(); + com.sun.tools.javac.util.List annotationMirrors = + upperBound.getAnnotationMirrors(); + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + // if base type argument does not have @Nullable annotation then the instantiation is + // invalid + if (!hasNullableAnnotation) { + invalidInstantiationError(nullableTypeArguments.get(i), state, analysis); + } + } + } // recursive check for nested parameterized types for (int i = 0; i < typeArguments.size(); i++) { - if (typeArguments.get(i).getClass().equals(JCTree.JCTypeApply.class)) { + if (typeArguments.get(i) instanceof ParameterizedTypeTree) { ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = (ParameterizedTypeTree) typeArguments.get(i); - Type argumentType = ASTHelpers.getType(parameterizedTypeTreeForTypeArgument); - if (argumentType != null - && argumentType.getTypeArguments() != null - && argumentType.getTypeArguments().length() > 0) { // Nested generics + if (parameterizedTypeTreeForTypeArgument.getTypeArguments().size() > 0) { checkInstantiationForParameterizedTypedTree( parameterizedTypeTreeForTypeArgument, state, analysis, config); } @@ -110,7 +88,7 @@ private static void invalidInstantiationError(Tree tree, VisitorState state, Nul ErrorMessage errorMessage = new ErrorMessage( ErrorMessage.MessageTypes.TYPE_PARAMETER_CANNOT_BE_NULLABLE, - "Generic type parameter cannot be @Nullable"); + "Generic type parameter cannot be @Nullable, as type variable does not have a @Nullable upper bound"); state.reportMatch( errorBuilder.createErrorDescription( errorMessage, analysis.buildDescription(tree), state, null)); From af6404a26d30a80564d7261078eebe8e23bad962 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Thu, 10 Nov 2022 14:53:00 -0800 Subject: [PATCH 071/184] tests for error positions --- .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 98190deb37..334aeff250 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -43,6 +43,9 @@ public void constructorTypeParamInstantiation() { " NonNullTypeParam t2 = new NonNullTypeParam<@Nullable String>();", " // BUG: Diagnostic contains: Generic type parameter", " testBadNonNull(new NonNullTypeParam<@Nullable String>());", + " testBadNonNull(new NonNullTypeParam<", + " // BUG: Diagnostic contains: Generic type parameter", + " @Nullable String>());", " }", " static void testOkNullable(NullableTypeParam t1, NullableTypeParam<@Nullable String> t2) {", " NullableTypeParam t3 = new NullableTypeParam();", @@ -67,6 +70,9 @@ public void extendedClassTypeParamInstantiation() { " // BUG: Diagnostic contains: Generic type parameter", " static class PartiallyInvalidSubclass extends MixedTypeParam<@Nullable String, String, String, String> {}", " static class ValidSubclass extends MixedTypeParam {}", + " static class PartiallyInvalidSubclass2 extends MixedTypeParam {}", "}") .doTest(); } From ad67e01f2de673485650ec81671feaac201fab99 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Thu, 10 Nov 2022 17:16:39 -0800 Subject: [PATCH 072/184] Clean up by implementing ParameterizedTypeTreeMatcher --- .../com/uber/nullaway/GenericsChecks.java | 11 ++-- .../main/java/com/uber/nullaway/NullAway.java | 65 +++---------------- 2 files changed, 13 insertions(+), 63 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index cf05816291..7ea95481d2 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -34,6 +34,9 @@ public static void checkInstantiationForParameterizedTypedTree( return; } List typeArguments = tree.getTypeArguments(); + if (typeArguments.size() == 0) { + return; + } Map nullableTypeArguments = new HashMap<>(); for (int i = 0; i < typeArguments.size(); i++) { Tree curTypeArg = typeArguments.get(i); @@ -73,12 +76,8 @@ public static void checkInstantiationForParameterizedTypedTree( // recursive check for nested parameterized types for (int i = 0; i < typeArguments.size(); i++) { if (typeArguments.get(i) instanceof ParameterizedTypeTree) { - ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = - (ParameterizedTypeTree) typeArguments.get(i); - if (parameterizedTypeTreeForTypeArgument.getTypeArguments().size() > 0) { - checkInstantiationForParameterizedTypedTree( - parameterizedTypeTreeForTypeArgument, state, analysis, config); - } + checkInstantiationForParameterizedTypedTree( + (ParameterizedTypeTree) typeArguments.get(i), state, analysis, config); } } } diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 61a2f51f99..c5fcc6e571 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -172,7 +172,8 @@ public class NullAway extends BugChecker BugChecker.MemberReferenceTreeMatcher, BugChecker.CompoundAssignmentTreeMatcher, BugChecker.SwitchTreeMatcher, - BugChecker.TypeCastTreeMatcher { + BugChecker.TypeCastTreeMatcher, + BugChecker.ParameterizedTypeTreeMatcher { static final String INITIALIZATION_CHECK_NAME = "NullAway.Init"; static final String OPTIONAL_CHECK_NAME = "NullAway.Optional"; @@ -413,13 +414,6 @@ public Description matchNewClass(NewClassTree tree, VisitorState state) { // see https://github.com/uber/NullAway/issues/102 methodSymbol = getSymbolOfSuperConstructor(methodSymbol, state); } - // check if the class is generic - Type classType = ASTHelpers.getType(tree); - if (classType != null && classType.getTypeArguments().length() > 0) { - ParameterizedTypeTree parameterizedTypeTree = (ParameterizedTypeTree) tree.getIdentifier(); - GenericsChecks.checkInstantiationForParameterizedTypedTree( - parameterizedTypeTree, state, this, config); - } return handleInvocation(tree, state, methodSymbol, actualParams); } @@ -619,26 +613,6 @@ public Description matchMethod(MethodTree tree, VisitorState state) { // package) Symbol.MethodSymbol methodSymbol = ASTHelpers.getSymbol(tree); handler.onMatchMethod(this, tree, state, methodSymbol); - // check parameter types - for (VariableTree varTree : tree.getParameters()) { - Type paramType = ASTHelpers.getType(varTree); - if (paramType != null && paramType.getTypeArguments().length() > 0) { - GenericsChecks.checkInstantiationForParameterizedTypedTree( - (ParameterizedTypeTree) varTree.getType(), state, this, config); - } - } - - // generics check for function return type - Tree returnTypeTree = tree.getReturnType(); - if (tree.getReturnType() != null) { - Type returnType = ASTHelpers.getType(returnTypeTree); - if (returnType != null - && returnType.getTypeArguments() != null - && returnType.getTypeArguments().length() > 0) { // generics check - GenericsChecks.checkInstantiationForParameterizedTypedTree( - (ParameterizedTypeTree) ((JCTree.JCMethodDecl) tree).restype, state, this, config); - } - } boolean isOverriding = ASTHelpers.hasAnnotation(methodSymbol, Override.class, state); boolean exhaustiveOverride = config.exhaustiveOverride(); @@ -692,6 +666,12 @@ public Description matchTypeCast(TypeCastTree tree, VisitorState state) { return Description.NO_MATCH; } + @Override + public Description matchParameterizedType(ParameterizedTypeTree tree, VisitorState state) { + GenericsChecks.checkInstantiationForParameterizedTypedTree(tree, state, this, config); + return Description.NO_MATCH; + } + /** * checks that an overriding method does not override a {@code @Nullable} parameter with a * {@code @NonNull} parameter @@ -1347,14 +1327,6 @@ public Description matchVariable(VariableTree tree, VisitorState state) { if (!withinAnnotatedCode(state)) { return Description.NO_MATCH; } - // Check if the variable is generics type - Type variableType = ASTHelpers.getType(tree); - if (variableType != null && variableType.getTypeArguments().length() > 0) { - GenericsChecks.checkInstantiationForParameterizedTypedTree( - (ParameterizedTypeTree) ((JCTree.JCVariableDecl) tree).vartype, state, this, config); - } - - // is nested variable VarSymbol symbol = ASTHelpers.getSymbol(tree); if (symbol.type.isPrimitive() && tree.getInitializer() != null) { return doUnboxingCheck(state, tree.getInitializer()); @@ -1453,27 +1425,6 @@ public Description matchClass(ClassTree tree, VisitorState state) { } checkFieldInitialization(tree, state); } - JCTree.JCClassDecl classTree = (JCTree.JCClassDecl) tree; - // check if the class extends any class - if (classTree.extending != null) { - // check if the extended class is generic - if (classTree.extending.type.getTypeArguments().length() > 0) { - GenericsChecks.checkInstantiationForParameterizedTypedTree( - (ParameterizedTypeTree) classTree.extending, state, this, config); - } - } - // check if the class implements any interface - List interfaces = classTree.implementing; - if (interfaces.size() > 0) { - for (int i = 0; i < interfaces.size(); i++) { - Type implementedInterfaceType = interfaces.get(i).type; - // check if the interface is generic - if (implementedInterfaceType.getTypeArguments().size() > 0) { - GenericsChecks.checkInstantiationForParameterizedTypedTree( - (ParameterizedTypeTree) interfaces.get(i), state, this, config); - } - } - } return Description.NO_MATCH; } From 67994da730cc639f7ea2092bb17281acd31b29d6 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Thu, 10 Nov 2022 17:18:13 -0800 Subject: [PATCH 073/184] remove extra blank line --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 1 - 1 file changed, 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index c5fcc6e571..2353a1bd17 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -613,7 +613,6 @@ public Description matchMethod(MethodTree tree, VisitorState state) { // package) Symbol.MethodSymbol methodSymbol = ASTHelpers.getSymbol(tree); handler.onMatchMethod(this, tree, state, methodSymbol); - boolean isOverriding = ASTHelpers.hasAnnotation(methodSymbol, Override.class, state); boolean exhaustiveOverride = config.exhaustiveOverride(); if (isOverriding || !exhaustiveOverride) { From 2631d6305d55fd59d7a8258f0902703dfa7e6425 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Thu, 10 Nov 2022 17:42:26 -0800 Subject: [PATCH 074/184] add test --- .../nullaway/NullAwayJSpecifyGenericsTests.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 334aeff250..b6b3f3fbd3 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -184,6 +184,23 @@ public void testOKNewClassInstantiationForOtherAnnotations() { .doTest(); } + @Test + public void downcastInstantiation() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.nullness.Nullable;", + "class Test {", + " static class NonNullTypeParam { }", + " static void instOf(Object o) {", + " // BUG: Diagnostic contains: Generic type parameter", + " Object p = (NonNullTypeParam<@Nullable String>) o;", + " }", + "}") + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( Arrays.asList( From 36a5c60a5274b2aaedc665a44cd742480f07145b Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 16 Nov 2022 09:57:09 -0800 Subject: [PATCH 075/184] suggested changes --- .../main/java/com/uber/nullaway/GenericsChecks.java | 2 +- .../uber/nullaway/NullAwayJSpecifyGenericsTests.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 7ea95481d2..13f7643735 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -13,7 +13,7 @@ import java.util.Map; /** Methods for performing checks related to generic types and nullability. */ -public class GenericsChecks { +public final class GenericsChecks { private GenericsChecks() { // just utility methods diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index b6b3f3fbd3..319a1c1d68 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -17,9 +17,10 @@ public void basicTypeParamInstantiation() { " static class NonNullTypeParam {}", " static class NullableTypeParam {}", " // BUG: Diagnostic contains: Generic type parameter", - " static void testBadNonNull(NonNullTypeParam<@Nullable String> t) {", + " static void testBadNonNull(NonNullTypeParam<@Nullable String> t1) {", " // BUG: Diagnostic contains: Generic type parameter", " NonNullTypeParam<@Nullable String> t2 = null;", + " NullableTypeParam<@Nullable String> t3 = null;", " }", "}") .doTest(); @@ -69,10 +70,11 @@ public void extendedClassTypeParamInstantiation() { " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", " // BUG: Diagnostic contains: Generic type parameter", " static class PartiallyInvalidSubclass extends MixedTypeParam<@Nullable String, String, String, String> {}", - " static class ValidSubclass extends MixedTypeParam {}", + " static class ValidSubclass1 extends MixedTypeParam {}", " static class PartiallyInvalidSubclass2 extends MixedTypeParam {}", + " static class ValidSubclass2 extends MixedTypeParam {}", "}") .doTest(); } @@ -104,8 +106,6 @@ public void interfaceImplementationTypeParamInstantiation() { "package com.uber;", "import org.jspecify.nullness.Nullable;", "class Test {", - " static class NonNullTypeParam {}", - " static class NullableTypeParam {}", " static interface NonNullTypeParamInterface{}", " static interface NullableTypeParamInterface{}", " // BUG: Diagnostic contains: Generic type parameter", @@ -149,8 +149,8 @@ public void returnTypeParamInstantiation() { " static class NonNullTypeParam {}", " static class NullableTypeParam {}", " // BUG: Diagnostic contains: Generic type parameter", - " static NonNullTypeParam<@Nullable String> testBadNonNull(NonNullTypeParam t) {", - " return t;", + " static NonNullTypeParam<@Nullable String> testBadNonNull() {", + " return new NonNullTypeParam();", " }", " static NullableTypeParam<@Nullable String> testOKNull() {", " return new NullableTypeParam<@Nullable String>();", From c8ebfe6f23f095c25b302edf11c94f5ade33cf5b Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 16 Nov 2022 10:00:01 -0800 Subject: [PATCH 076/184] suggested changes --- .../src/main/java/com/uber/nullaway/GenericsChecks.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 13f7643735..2b0edf1a5f 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -73,13 +73,6 @@ public static void checkInstantiationForParameterizedTypedTree( } } } - // recursive check for nested parameterized types - for (int i = 0; i < typeArguments.size(); i++) { - if (typeArguments.get(i) instanceof ParameterizedTypeTree) { - checkInstantiationForParameterizedTypedTree( - (ParameterizedTypeTree) typeArguments.get(i), state, analysis, config); - } - } } private static void invalidInstantiationError(Tree tree, VisitorState state, NullAway analysis) { From 3fb68563b2bc6a14e915df0cd505bd275a824d9c Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 16 Nov 2022 10:58:50 -0800 Subject: [PATCH 077/184] tweak error message --- .../main/java/com/uber/nullaway/GenericsChecks.java | 13 +++++++++---- .../nullaway/NullAwayJSpecifyGenericsTests.java | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 2b0edf1a5f..f7b0f3ac6e 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -61,7 +61,8 @@ public static void checkInstantiationForParameterizedTypedTree( for (int i = 0; i < baseTypeArgs.size(); i++) { if (nullableTypeArguments.containsKey(i)) { - Type upperBound = baseTypeArgs.get(i).getUpperBound(); + Type typeVariable = baseTypeArgs.get(i); + Type upperBound = typeVariable.getUpperBound(); com.sun.tools.javac.util.List annotationMirrors = upperBound.getAnnotationMirrors(); boolean hasNullableAnnotation = @@ -69,18 +70,22 @@ public static void checkInstantiationForParameterizedTypedTree( // if base type argument does not have @Nullable annotation then the instantiation is // invalid if (!hasNullableAnnotation) { - invalidInstantiationError(nullableTypeArguments.get(i), state, analysis); + invalidInstantiationError( + nullableTypeArguments.get(i), baseType, typeVariable, state, analysis); } } } } - private static void invalidInstantiationError(Tree tree, VisitorState state, NullAway analysis) { + private static void invalidInstantiationError( + Tree tree, Type baseType, Type baseTypeVariable, VisitorState state, NullAway analysis) { ErrorBuilder errorBuilder = analysis.getErrorBuilder(); ErrorMessage errorMessage = new ErrorMessage( ErrorMessage.MessageTypes.TYPE_PARAMETER_CANNOT_BE_NULLABLE, - "Generic type parameter cannot be @Nullable, as type variable does not have a @Nullable upper bound"); + String.format( + "Generic type parameter cannot be @Nullable, as type variable %s of type %s does not have a @Nullable upper bound", + baseTypeVariable.tsym.toString(), baseType.tsym.toString())); state.reportMatch( errorBuilder.createErrorDescription( errorMessage, analysis.buildDescription(tree), state, null)); diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 319a1c1d68..3eae90fa32 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -69,7 +69,7 @@ public void extendedClassTypeParamInstantiation() { " // BUG: Diagnostic contains: Generic type parameter", " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", " // BUG: Diagnostic contains: Generic type parameter", - " static class PartiallyInvalidSubclass extends MixedTypeParam<@Nullable String, String, String, String> {}", + " static class PartiallyInvalidSubclass extends MixedTypeParam<@Nullable String, String, String, @Nullable String> {}", " static class ValidSubclass1 extends MixedTypeParam {}", " static class PartiallyInvalidSubclass2 extends MixedTypeParam Date: Wed, 16 Nov 2022 11:45:05 -0800 Subject: [PATCH 078/184] clarify test name and purpose --- .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 3eae90fa32..0a761ff202 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -57,18 +57,15 @@ public void constructorTypeParamInstantiation() { } @Test - public void extendedClassTypeParamInstantiation() { + public void multipleTypeParametersInstantiation() { makeHelper() .addSourceLines( "Test.java", "package com.uber;", "import org.jspecify.nullness.Nullable;", "class Test {", - " static class NonNullTypeParam {}", " static class MixedTypeParam {}", " // BUG: Diagnostic contains: Generic type parameter", - " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", - " // BUG: Diagnostic contains: Generic type parameter", " static class PartiallyInvalidSubclass extends MixedTypeParam<@Nullable String, String, String, @Nullable String> {}", " static class ValidSubclass1 extends MixedTypeParam {}", " static class PartiallyInvalidSubclass2 extends MixedTypeParam Date: Wed, 16 Nov 2022 12:56:25 -0800 Subject: [PATCH 079/184] Assignment interface added --- .../com/uber/nullaway/AnnotatedTypeWrapper.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java diff --git a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java new file mode 100644 index 0000000000..faf7c2a604 --- /dev/null +++ b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java @@ -0,0 +1,13 @@ +package com.uber.nullaway; + +import java.util.List; +import java.util.Set; + +public interface AnnotatedTypeWrapper { + Set getNullableArgumentIndices(); + + List getTypeArgumentWrappers(); + + void checkSameTypeArgNullability( + AnnotatedTypeWrapper lhsWrapper, AnnotatedTypeWrapper rhsWrapper); +} From b5eb8a001a99d7af199a3979b369093d23621964 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 16 Nov 2022 13:02:54 -0800 Subject: [PATCH 080/184] structure for assignments checks --- .../uber/nullaway/AnnotatedTypeWrapper.java | 3 +++ .../com/uber/nullaway/GenericsChecks.java | 24 +++++++++++++++---- .../main/java/com/uber/nullaway/NullAway.java | 1 + 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java index faf7c2a604..d818ba7e22 100644 --- a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java +++ b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java @@ -1,9 +1,12 @@ package com.uber.nullaway; +import com.sun.source.tree.ParameterizedTypeTree; import java.util.List; import java.util.Set; public interface AnnotatedTypeWrapper { + ParameterizedTypeTree tree = null; + Set getNullableArgumentIndices(); List getTypeArgumentWrappers(); diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index f7b0f3ac6e..8b05c8c72d 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -2,18 +2,16 @@ import com.google.errorprone.VisitorState; import com.google.errorprone.util.ASTHelpers; -import com.sun.source.tree.AnnotatedTypeTree; -import com.sun.source.tree.AnnotationTree; -import com.sun.source.tree.ParameterizedTypeTree; -import com.sun.source.tree.Tree; +import com.sun.source.tree.*; import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Type; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; /** Methods for performing checks related to generic types and nullability. */ -public final class GenericsChecks { +public final class GenericsChecks implements AnnotatedTypeWrapper { private GenericsChecks() { // just utility methods @@ -90,4 +88,20 @@ private static void invalidInstantiationError( errorBuilder.createErrorDescription( errorMessage, analysis.buildDescription(tree), state, null)); } + + @Override + public Set getNullableArgumentIndices() { + return null; + } + + @Override + public List getTypeArgumentWrappers() { + return null; + } + + @Override + public void checkSameTypeArgNullability( + AnnotatedTypeWrapper lhsWrapper, AnnotatedTypeWrapper rhsWrapper) {} + + public static void checkInstantiationForAssignments(AssignmentTree tree) {} } diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index b0a07a7025..ba9f3f5563 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -463,6 +463,7 @@ public Description matchAssignment(AssignmentTree tree, VisitorState state) { if (lhsType != null && lhsType.isPrimitive()) { doUnboxingCheck(state, tree.getExpression()); } + GenericsChecks.checkInstantiationForAssignments(tree); Symbol assigned = ASTHelpers.getSymbol(tree.getVariable()); if (assigned == null || assigned.getKind() != ElementKind.FIELD) { // not a field of nullable type From eecc4c34a10314a9b137f5debe36c4d8ad5017b0 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 18 Nov 2022 03:50:42 -0800 Subject: [PATCH 081/184] Assignment changes --- .../uber/nullaway/AnnotatedTypeWrapper.java | 17 +- .../com/uber/nullaway/GenericsChecks.java | 152 ++++++++++++++++-- .../main/java/com/uber/nullaway/NullAway.java | 11 +- .../NullAwayJSpecifyGenericsTests.java | 42 +++++ 4 files changed, 196 insertions(+), 26 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java index d818ba7e22..f1b6beaffd 100644 --- a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java +++ b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java @@ -1,16 +1,13 @@ package com.uber.nullaway; -import com.sun.source.tree.ParameterizedTypeTree; -import java.util.List; -import java.util.Set; +import com.google.errorprone.VisitorState; +import com.sun.source.tree.AssignmentTree; +import java.util.HashSet; -public interface AnnotatedTypeWrapper { - ParameterizedTypeTree tree = null; +public interface AnnotatedTypeWrapper { - Set getNullableArgumentIndices(); + public HashSet getNullableTypeArgIndices(T2 wrapper, Config config); - List getTypeArgumentWrappers(); - - void checkSameTypeArgNullability( - AnnotatedTypeWrapper lhsWrapper, AnnotatedTypeWrapper rhsWrapper); + public void checkAssignmentTypeMatch( + AssignmentTree tree, T1 lhs, T2 rhs, Config config, VisitorState state, NullAway analysis); } diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 8b05c8c72d..739aac9c59 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -2,18 +2,23 @@ import com.google.errorprone.VisitorState; import com.google.errorprone.util.ASTHelpers; -import com.sun.source.tree.*; +import com.sun.source.tree.AnnotatedTypeTree; +import com.sun.source.tree.AnnotationTree; +import com.sun.source.tree.AssignmentTree; +import com.sun.source.tree.ParameterizedTypeTree; +import com.sun.source.tree.Tree; import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.tree.JCTree; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; /** Methods for performing checks related to generic types and nullability. */ -public final class GenericsChecks implements AnnotatedTypeWrapper { +public final class GenericsChecks { - private GenericsChecks() { + public GenericsChecks() { // just utility methods } @@ -26,7 +31,7 @@ private GenericsChecks() { * @param analysis the analysis object * @param config the analysis config */ - public static void checkInstantiationForParameterizedTypedTree( + public void checkInstantiationForParameterizedTypedTree( ParameterizedTypeTree tree, VisitorState state, NullAway analysis, Config config) { if (!config.isJSpecifyMode()) { return; @@ -75,7 +80,7 @@ public static void checkInstantiationForParameterizedTypedTree( } } - private static void invalidInstantiationError( + void invalidInstantiationError( Tree tree, Type baseType, Type baseTypeVariable, VisitorState state, NullAway analysis) { ErrorBuilder errorBuilder = analysis.getErrorBuilder(); ErrorMessage errorMessage = @@ -89,19 +94,140 @@ private static void invalidInstantiationError( errorMessage, analysis.buildDescription(tree), state, null)); } + @SuppressWarnings("UnusedVariable") + public void checkInstantiationForAssignments( + AssignmentTree tree, Config config, VisitorState state, NullAway analysis) { + Tree lhsTree = tree.getVariable(); + Tree rhsTree = tree.getExpression(); + if (rhsTree.getClass().equals(JCTree.JCNewClass.class)) { + ParameterizedTypeTreeNullableArgIndices typeWrapper = + new ParameterizedTypeTreeNullableArgIndices(); + typeWrapper.checkAssignmentTypeMatch( + tree, + ASTHelpers.getType(lhsTree), + (ParameterizedTypeTree) ((JCTree.JCNewClass) rhsTree).getIdentifier(), + config, + state, + analysis); + } else { + NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); + typeWrapper.checkAssignmentTypeMatch( + tree, ASTHelpers.getType(lhsTree), ASTHelpers.getType(rhsTree), config, state, analysis); + } + } +} + +class ParameterizedTypeTreeNullableArgIndices + implements AnnotatedTypeWrapper { + @SuppressWarnings("UnusedVariable") @Override - public Set getNullableArgumentIndices() { - return null; + public HashSet getNullableTypeArgIndices(ParameterizedTypeTree tree, Config config) { + List typeArguments = tree.getTypeArguments(); + HashSet nullableTypeArgIndices = new HashSet(); + for (int i = 0; i < typeArguments.size(); i++) { + if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { + JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); + for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { + Attribute.Compound attribute = annotation.attribute; + if (attribute.toString().equals("@org.jspecify.nullness.Nullable")) { + nullableTypeArgIndices.add(i); + break; + } + } + } + } + return nullableTypeArgIndices; } @Override - public List getTypeArgumentWrappers() { - return null; + public void checkAssignmentTypeMatch( + AssignmentTree tree, + Type lhs, + ParameterizedTypeTree rhs, + Config config, + VisitorState state, + NullAway analysis) { + NormalTypeTreeNullableTypeArgIndices normalTypeTreeNullableTypeArgIndices = + new NormalTypeTreeNullableTypeArgIndices(); + HashSet lhsNullableArgIndices = + normalTypeTreeNullableTypeArgIndices.getNullableTypeArgIndices(lhs, config); + HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs, config); + if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { + GenericsChecks genericsChecks = new GenericsChecks(); + genericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); + return; + } else { + // check for nested types if an error is not already generated + List rhsTypeArguments = rhs.getTypeArguments(); + List lhsTypeArguments = lhs.getTypeArguments(); + + for (int i = 0; i < rhsTypeArguments.size(); i++) { + if (rhsTypeArguments.get(i).getClass().equals(JCTree.JCTypeApply.class)) { + ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = + (ParameterizedTypeTree) rhsTypeArguments.get(i); + Type argumentType = ASTHelpers.getType(parameterizedTypeTreeForTypeArgument); + if (argumentType != null + && argumentType.getTypeArguments() != null + && argumentType.getTypeArguments().length() > 0) { // Nested generics + checkAssignmentTypeMatch( + tree, + lhsTypeArguments.get(i), + parameterizedTypeTreeForTypeArgument, + config, + state, + analysis); + } + } + } + } + } +} + +class NormalTypeTreeNullableTypeArgIndices implements AnnotatedTypeWrapper { + + @SuppressWarnings("UnusedVariable") + @Override + public HashSet getNullableTypeArgIndices(Type type, Config config) { + HashSet nullableTypeArgIndices = new HashSet(); + List typeArguments = type.getTypeArguments(); + for (int index = 0; index < typeArguments.size(); index++) { + com.sun.tools.javac.util.List annotationMirrors = + typeArguments.get(index).getAnnotationMirrors(); + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + if (hasNullableAnnotation) { + nullableTypeArgIndices.add(index); + } + } + return nullableTypeArgIndices; } @Override - public void checkSameTypeArgNullability( - AnnotatedTypeWrapper lhsWrapper, AnnotatedTypeWrapper rhsWrapper) {} + public void checkAssignmentTypeMatch( + AssignmentTree tree, + Type lhs, + Type rhs, + Config config, + VisitorState state, + NullAway analysis) { + HashSet lhsNullableArgIndices = getNullableTypeArgIndices(lhs, config); + HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs, config); - public static void checkInstantiationForAssignments(AssignmentTree tree) {} + if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { + GenericsChecks genericsChecks = new GenericsChecks(); + genericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); + return; + } else { + List lhsTypeArgs = lhs.getTypeArguments(); + List rhsTypeArgs = rhs.getTypeArguments(); + // if an error is not already generated check for nested types + for (int i = 0; i < lhsTypeArgs.size(); i++) { + // nested generics + if (lhsTypeArgs.get(i).getTypeArguments().length() > 0) { + checkAssignmentTypeMatch( + tree, lhsTypeArgs.get(i), rhsTypeArgs.get(i), config, state, analysis); + } + } + } + } } diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index ba9f3f5563..f212c432b3 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -262,7 +262,6 @@ private enum NullMarking { *

TODO remove this once NullAway requires JDK 11 */ @Nullable private final Class moduleElementClass; - /** * Error Prone requires us to have an empty constructor for each Plugin, in addition to the * constructor taking an ErrorProneFlags object. This constructor should not be used anywhere @@ -463,7 +462,12 @@ public Description matchAssignment(AssignmentTree tree, VisitorState state) { if (lhsType != null && lhsType.isPrimitive()) { doUnboxingCheck(state, tree.getExpression()); } - GenericsChecks.checkInstantiationForAssignments(tree); + // generics check + if (lhsType.getTypeArguments().length() > 0) { + GenericsChecks genericsChecks = new GenericsChecks(); + genericsChecks.checkInstantiationForAssignments(tree, config, state, this); + } + Symbol assigned = ASTHelpers.getSymbol(tree.getVariable()); if (assigned == null || assigned.getKind() != ElementKind.FIELD) { // not a field of nullable type @@ -666,7 +670,8 @@ public Description matchTypeCast(TypeCastTree tree, VisitorState state) { @Override public Description matchParameterizedType(ParameterizedTypeTree tree, VisitorState state) { - GenericsChecks.checkInstantiationForParameterizedTypedTree(tree, state, this, config); + GenericsChecks genericsChecks = new GenericsChecks(); + genericsChecks.checkInstantiationForParameterizedTypedTree(tree, state, this, config); return Description.NO_MATCH; } diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 0a761ff202..3af6a4a10d 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -198,6 +198,48 @@ public void downcastInstantiation() { .doTest(); } + @Test + public void genericsChecksForAssignments() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.nullness.Nullable;", + "class Test {", + " static class NullableTypeParam {}", + " static class NullableTypeParamMultipleArguments {}", + " static class NullableTypeParamMultipleArgumentsNested {}", + " static void testOKOtherAnnotation(NullableTypeParam t) {", + " NullableTypeParam t3;", + " // BUG: Diagnostic contains: Generic type parameter", + " t3 = new NullableTypeParam<@Nullable String>();", + " NullableTypeParam<@Nullable String> t4;", + " // BUG: Diagnostic contains: Generic type parameter", + " t4 = t;", + " NullableTypeParamMultipleArguments t5 = new NullableTypeParamMultipleArguments();", + " NullableTypeParamMultipleArguments<@Nullable String, String> t6 = new NullableTypeParamMultipleArguments<@Nullable String, String>();", + " // BUG: Diagnostic contains: Generic type parameter", + " t5 = t6;", + " NullableTypeParam>> t7 = new NullableTypeParam>>();", + " NullableTypeParam>> t8 = new NullableTypeParam>>();", + " // BUG: Diagnostic contains: Generic type parameter", + " t7 = t8;", + " NullableTypeParam>> t9 = new NullableTypeParam>> ();", + " //No error", + " t7 = t9;", + " NullableTypeParamMultipleArguments>, String> t10 = new NullableTypeParamMultipleArguments>, String> ();", + " NullableTypeParamMultipleArguments>, String> t11 = new NullableTypeParamMultipleArguments>, String> ();", + " // BUG: Diagnostic contains: Generic type parameter", + " t10 = t11;", + " NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> t12 = new NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> ();", + " NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> t13 = new NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> ();", + " // BUG: Diagnostic contains: Generic type parameter", + " t12 = t13;", + " }", + "}") + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( Arrays.asList( From 063c580714b9cdd729e6d7d93c713950871aba67 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 7 Dec 2022 00:01:40 -0800 Subject: [PATCH 082/184] supertype changes --- .../com/uber/nullaway/GenericsChecks.java | 24 ++++++++++++++++++- .../NullAwayJSpecifyGenericsTests.java | 19 +++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 739aac9c59..e5f5194b8f 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -22,6 +22,18 @@ public GenericsChecks() { // just utility methods } + @SuppressWarnings("UnusedVariable") + public Type supertypeMatchingLHS(Type.ClassType lhsType, Type.ClassType rhsType) { + List listOfDirectSuperTypes = rhsType.all_interfaces_field; + + for (int i = 0; i < listOfDirectSuperTypes.size(); i++) { + if (listOfDirectSuperTypes.get(i).tsym.equals(lhsType.tsym)) { + return listOfDirectSuperTypes.get(i); + } + } + return lhsType; + } + /** * Checks that for an instantiated generic type, {@code @Nullable} types are only used for type * variables that have a {@code @Nullable} upper bound. @@ -99,7 +111,17 @@ public void checkInstantiationForAssignments( AssignmentTree tree, Config config, VisitorState state, NullAway analysis) { Tree lhsTree = tree.getVariable(); Tree rhsTree = tree.getExpression(); - if (rhsTree.getClass().equals(JCTree.JCNewClass.class)) { + if (((Type.ClassType) ASTHelpers.getType(rhsTree)).tsym + != ((Type.ClassType) ASTHelpers.getType(lhsTree)).tsym) { + + Type matchingLHSType = + supertypeMatchingLHS( + (Type.ClassType) ASTHelpers.getType(lhsTree), + (Type.ClassType) ASTHelpers.getType(rhsTree)); + NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); + typeWrapper.checkAssignmentTypeMatch( + tree, ASTHelpers.getType(lhsTree), matchingLHSType, config, state, analysis); + } else if (rhsTree.getClass().equals(JCTree.JCNewClass.class)) { ParameterizedTypeTreeNullableArgIndices typeWrapper = new ParameterizedTypeTreeNullableArgIndices(); typeWrapper.checkAssignmentTypeMatch( diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 3af6a4a10d..b3f35a6529 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -240,6 +240,25 @@ public void genericsChecksForAssignments() { .doTest(); } + @Test + public void superTypeAssignmentChecks() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.nullness.Nullable;", + "class Test {", + " interface Fn

{}", + " class FnImpl implements Fn<@Nullable String, @Nullable String>{}", + " void sampleError() {", + " Fn<@Nullable String, String> f = null;", + " // BUG: Diagnostic contains: Generic type parameter", + " f = new FnImpl();", + " }", + " }") + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( Arrays.asList( From 823da4859a51129a370de0232321b4d1bc84a11d Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 9 Dec 2022 01:03:55 -0800 Subject: [PATCH 083/184] multiple interface implementation --- .../com/uber/nullaway/GenericsChecks.java | 23 +++++++----------- .../main/java/com/uber/nullaway/NullAway.java | 3 +-- .../NullAwayJSpecifyGenericsTests.java | 24 ++++++++++++++++++- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 656b68a8e5..481ed365eb 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -19,7 +19,7 @@ public final class GenericsChecks { @SuppressWarnings("UnusedVariable") - public Type supertypeMatchingLHS(Type.ClassType lhsType, Type.ClassType rhsType) { + public static Type supertypeMatchingLHS(Type.ClassType lhsType, Type.ClassType rhsType) { List listOfDirectSuperTypes = rhsType.all_interfaces_field; for (int i = 0; i < listOfDirectSuperTypes.size(); i++) { @@ -34,7 +34,6 @@ private GenericsChecks() { // just utility methods } - /** * Checks that for an instantiated generic type, {@code @Nullable} types are only used for type * variables that have a {@code @Nullable} upper bound. @@ -44,7 +43,6 @@ private GenericsChecks() { * @param analysis the analysis object * @param config the analysis config */ - public static void checkInstantiationForParameterizedTypedTree( ParameterizedTypeTree tree, VisitorState state, NullAway analysis, Config config) { if (!config.isJSpecifyMode()) { @@ -94,8 +92,7 @@ public static void checkInstantiationForParameterizedTypedTree( } } - private static void invalidInstantiationError( - + static void invalidInstantiationError( Tree tree, Type baseType, Type baseTypeVariable, VisitorState state, NullAway analysis) { ErrorBuilder errorBuilder = analysis.getErrorBuilder(); ErrorMessage errorMessage = @@ -110,13 +107,13 @@ private static void invalidInstantiationError( } @SuppressWarnings("UnusedVariable") - public void checkInstantiationForAssignments( + public static void checkInstantiationForAssignments( AssignmentTree tree, Config config, VisitorState state, NullAway analysis) { Tree lhsTree = tree.getVariable(); Tree rhsTree = tree.getExpression(); - if (((Type.ClassType) ASTHelpers.getType(rhsTree)).tsym - != ((Type.ClassType) ASTHelpers.getType(lhsTree)).tsym) { - + // if the lhs and rhs types are same then there is no need to check for the super types, we can + // directly match the annotations + if (ASTHelpers.getType(rhsTree).tsym != ASTHelpers.getType(lhsTree).tsym) { Type matchingLHSType = supertypeMatchingLHS( (Type.ClassType) ASTHelpers.getType(lhsTree), @@ -178,8 +175,7 @@ public void checkAssignmentTypeMatch( normalTypeTreeNullableTypeArgIndices.getNullableTypeArgIndices(lhs, config); HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs, config); if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { - GenericsChecks genericsChecks = new GenericsChecks(); - genericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); + GenericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); return; } else { // check for nested types if an error is not already generated @@ -239,8 +235,7 @@ public void checkAssignmentTypeMatch( HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs, config); if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { - GenericsChecks genericsChecks = new GenericsChecks(); - genericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); + GenericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); return; } else { List lhsTypeArgs = lhs.getTypeArguments(); @@ -255,4 +250,4 @@ public void checkAssignmentTypeMatch( } } } - +} diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 81cb18ef4b..958de701ed 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -464,8 +464,7 @@ public Description matchAssignment(AssignmentTree tree, VisitorState state) { } // generics check if (lhsType.getTypeArguments().length() > 0) { - GenericsChecks genericsChecks = new GenericsChecks(); - genericsChecks.checkInstantiationForAssignments(tree, config, state, this); + GenericsChecks.checkInstantiationForAssignments(tree, config, state, this); } Symbol assigned = ASTHelpers.getSymbol(tree.getVariable()); diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 10e32e6d0d..8a7ba4d1b3 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -197,6 +197,7 @@ public void downcastInstantiation() { "}") .doTest(); } + @Test public void genericsChecksForAssignments() { makeHelper() @@ -240,7 +241,7 @@ public void genericsChecksForAssignments() { } @Test - public void superTypeAssignmentChecks() { + public void superTypeAssignmentChecksSingleInterface() { makeHelper() .addSourceLines( "Test.java", @@ -257,6 +258,27 @@ public void superTypeAssignmentChecks() { " }") .doTest(); } + + @Test + public void superTypeAssignmentChecksMultipleInterface() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.nullness.Nullable;", + "class Test {", + " interface Fn1{}", + " interface Fn2

{}", + " class FnImpl implements Fn1<@Nullable String, @Nullable String>, Fn2 {}", + " void sampleError() {", + " Fn2<@Nullable String> f = null;", + " // BUG: Diagnostic contains: Generic type parameter", + " f = new FnImpl();", + " }", + " }") + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( Arrays.asList( From e26e088118089d6add7b4e29cc68a225535d17f9 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 9 Dec 2022 01:49:31 -0800 Subject: [PATCH 084/184] multilevel inheritance --- .../com/uber/nullaway/GenericsChecks.java | 15 ++++++++++- .../NullAwayJSpecifyGenericsTests.java | 27 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 481ed365eb..b25d775710 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -20,6 +20,7 @@ public final class GenericsChecks { @SuppressWarnings("UnusedVariable") public static Type supertypeMatchingLHS(Type.ClassType lhsType, Type.ClassType rhsType) { + // interfaces List listOfDirectSuperTypes = rhsType.all_interfaces_field; for (int i = 0; i < listOfDirectSuperTypes.size(); i++) { @@ -27,7 +28,19 @@ public static Type supertypeMatchingLHS(Type.ClassType lhsType, Type.ClassType r return listOfDirectSuperTypes.get(i); } } - return lhsType; + + // check for the super classes and interfaces implemented by the super classes + Type current_super_type = rhsType; + while (true) { + current_super_type = ((Type.ClassType) current_super_type).supertype_field; + if (current_super_type == null) { + break; + } + if (current_super_type.tsym.equals(lhsType.tsym)) { + return current_super_type; + } + } + return rhsType.baseType(); } private GenericsChecks() { diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 8a7ba4d1b3..9af83606e3 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -279,6 +279,33 @@ public void superTypeAssignmentChecksMultipleInterface() { .doTest(); } + @Test + public void superTypeAssignmentChecksMultipleLevelInheritance() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.nullness.Nullable;", + "class Test {", + " class SuperClassC{}", + " class SuperClassB

extends SuperClassC

{}", + " class SubClassA

extends SuperClassB

{}", + " class FnImpl1 extends SubClassA{}", + " class FnImpl2 extends SubClassA<@Nullable String>{}", + " void sampleError() {", + " SuperClassC<@Nullable String> f = null;", + " // BUG: Diagnostic contains: Generic type parameter", + " f = new FnImpl1();", + " }", + " void sampleValidInstantiation() {", + " SuperClassC<@Nullable String> f = null;", + " // No error", + " f = new FnImpl2();", + " }", + " }") + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( Arrays.asList( From f7009ae247a25798be499658c0c1559f0a51b4c0 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 9 Dec 2022 02:22:16 -0800 Subject: [PATCH 085/184] changes --- .../com/uber/nullaway/GenericsChecks.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index b25d775710..03b78d363e 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -17,36 +17,36 @@ /** Methods for performing checks related to generic types and nullability. */ public final class GenericsChecks { + private GenericsChecks() { + // just utility methods + } @SuppressWarnings("UnusedVariable") - public static Type supertypeMatchingLHS(Type.ClassType lhsType, Type.ClassType rhsType) { + public static Type supertypeMatchingLHS( + Type.ClassType lhsType, Type.ClassType rhsType, VisitorState state) { // interfaces List listOfDirectSuperTypes = rhsType.all_interfaces_field; - - for (int i = 0; i < listOfDirectSuperTypes.size(); i++) { - if (listOfDirectSuperTypes.get(i).tsym.equals(lhsType.tsym)) { - return listOfDirectSuperTypes.get(i); + if (listOfDirectSuperTypes != null) { + for (int i = 0; i < listOfDirectSuperTypes.size(); i++) { + if (ASTHelpers.isSameType(listOfDirectSuperTypes.get(i), lhsType, state)) { + return listOfDirectSuperTypes.get(i); + } } } - // check for the super classes and interfaces implemented by the super classes Type current_super_type = rhsType; while (true) { - current_super_type = ((Type.ClassType) current_super_type).supertype_field; if (current_super_type == null) { break; } - if (current_super_type.tsym.equals(lhsType.tsym)) { + if (ASTHelpers.isSameType(current_super_type, lhsType, state)) { return current_super_type; } + current_super_type = ((Type.ClassType) current_super_type).supertype_field; } return rhsType.baseType(); } - private GenericsChecks() { - // just utility methods - } - /** * Checks that for an instantiated generic type, {@code @Nullable} types are only used for type * variables that have a {@code @Nullable} upper bound. @@ -130,7 +130,8 @@ public static void checkInstantiationForAssignments( Type matchingLHSType = supertypeMatchingLHS( (Type.ClassType) ASTHelpers.getType(lhsTree), - (Type.ClassType) ASTHelpers.getType(rhsTree)); + (Type.ClassType) ASTHelpers.getType(rhsTree), + state); NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); typeWrapper.checkAssignmentTypeMatch( tree, ASTHelpers.getType(lhsTree), matchingLHSType, config, state, analysis); From 3b2cdf159afab3c3005c055297da7f04fc171379 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 9 Dec 2022 02:34:01 -0800 Subject: [PATCH 086/184] changes --- .../src/main/java/com/uber/nullaway/GenericsChecks.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 03b78d363e..b50b526e78 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -36,12 +36,12 @@ public static Type supertypeMatchingLHS( // check for the super classes and interfaces implemented by the super classes Type current_super_type = rhsType; while (true) { - if (current_super_type == null) { - break; - } if (ASTHelpers.isSameType(current_super_type, lhsType, state)) { return current_super_type; } + if (current_super_type.getClass().equals(Object.class)) { + break; + } current_super_type = ((Type.ClassType) current_super_type).supertype_field; } return rhsType.baseType(); From d957f564d434a64128e865efe657714fb75c2f17 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 9 Dec 2022 03:08:03 -0800 Subject: [PATCH 087/184] nested checks --- .../com/uber/nullaway/GenericsChecks.java | 4 +++ .../NullAwayJSpecifyGenericsTests.java | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index b50b526e78..a9ab1df421 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -245,6 +245,10 @@ public void checkAssignmentTypeMatch( Config config, VisitorState state, NullAway analysis) { + // if lhs and rhs are not of the same type check for the super types first + if (!ASTHelpers.isSameType(lhs, rhs, state)) { + rhs = GenericsChecks.supertypeMatchingLHS((Type.ClassType) lhs, (Type.ClassType) rhs, state); + } HashSet lhsNullableArgIndices = getNullableTypeArgIndices(lhs, config); HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs, config); diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 9af83606e3..1f15b06fd8 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -306,6 +306,32 @@ public void superTypeAssignmentChecksMultipleLevelInheritance() { .doTest(); } + @Test + public void NestedAssignmentChecks() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.nullness.Nullable;", + "class Test {", + " class A{}", + " class D

{}", + " class B

extends D

{}", + " class C

{}", + " void sampleError1() {", + " C> f = null;", + " // BUG: Diagnostic contains: Generic type parameter", + " f = new C>();", + " }", + " void sampleError2() {", + " D> f = null;", + " // BUG: Diagnostic contains: Generic type parameter", + " f = new B>();", + " }", + " }") + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( Arrays.asList( From 2d061fc507a1edb397f0ff96fc0c466f4d0684a7 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 9 Dec 2022 03:45:10 -0800 Subject: [PATCH 088/184] working changes --- .../com/uber/nullaway/GenericsChecks.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index a9ab1df421..f392dc4073 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -126,7 +126,7 @@ public static void checkInstantiationForAssignments( Tree rhsTree = tree.getExpression(); // if the lhs and rhs types are same then there is no need to check for the super types, we can // directly match the annotations - if (ASTHelpers.getType(rhsTree).tsym != ASTHelpers.getType(lhsTree).tsym) { + /*if (ASTHelpers.getType(rhsTree).tsym != ASTHelpers.getType(lhsTree).tsym) { Type matchingLHSType = supertypeMatchingLHS( (Type.ClassType) ASTHelpers.getType(lhsTree), @@ -135,7 +135,7 @@ public static void checkInstantiationForAssignments( NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); typeWrapper.checkAssignmentTypeMatch( tree, ASTHelpers.getType(lhsTree), matchingLHSType, config, state, analysis); - } else if (rhsTree.getClass().equals(JCTree.JCNewClass.class)) { + } else*/ if (rhsTree.getClass().equals(JCTree.JCNewClass.class)) { ParameterizedTypeTreeNullableArgIndices typeWrapper = new ParameterizedTypeTreeNullableArgIndices(); typeWrapper.checkAssignmentTypeMatch( @@ -175,6 +175,20 @@ public HashSet getNullableTypeArgIndices(ParameterizedTypeTree tree, Co return nullableTypeArgIndices; } + public static void superTypeMatchingRHSParameterizedTypeTree( + AssignmentTree tree, + ParameterizedTypeTree rhs, + Type lhs, + VisitorState state, + Config config, + NullAway analysis) { + Type rhsType = + GenericsChecks.supertypeMatchingLHS( + (Type.ClassType) lhs, (Type.ClassType) ASTHelpers.getType(rhs), state); + NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); + typeWrapper.checkAssignmentTypeMatch(tree, lhs, rhsType, config, state, analysis); + } + @Override public void checkAssignmentTypeMatch( AssignmentTree tree, @@ -183,6 +197,9 @@ public void checkAssignmentTypeMatch( Config config, VisitorState state, NullAway analysis) { + if (!ASTHelpers.isSameType(lhs, ASTHelpers.getType(rhs), state)) { + superTypeMatchingRHSParameterizedTypeTree(tree, rhs, lhs, state, config, analysis); + } NormalTypeTreeNullableTypeArgIndices normalTypeTreeNullableTypeArgIndices = new NormalTypeTreeNullableTypeArgIndices(); HashSet lhsNullableArgIndices = From 80f296e846ea43cb71ec2ed00740a6404fcb448b Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 9 Dec 2022 03:46:04 -0800 Subject: [PATCH 089/184] working changes --- .../java/com/uber/nullaway/GenericsChecks.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index f392dc4073..2e462df121 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -124,18 +124,7 @@ public static void checkInstantiationForAssignments( AssignmentTree tree, Config config, VisitorState state, NullAway analysis) { Tree lhsTree = tree.getVariable(); Tree rhsTree = tree.getExpression(); - // if the lhs and rhs types are same then there is no need to check for the super types, we can - // directly match the annotations - /*if (ASTHelpers.getType(rhsTree).tsym != ASTHelpers.getType(lhsTree).tsym) { - Type matchingLHSType = - supertypeMatchingLHS( - (Type.ClassType) ASTHelpers.getType(lhsTree), - (Type.ClassType) ASTHelpers.getType(rhsTree), - state); - NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); - typeWrapper.checkAssignmentTypeMatch( - tree, ASTHelpers.getType(lhsTree), matchingLHSType, config, state, analysis); - } else*/ if (rhsTree.getClass().equals(JCTree.JCNewClass.class)) { + if (rhsTree.getClass().equals(JCTree.JCNewClass.class)) { ParameterizedTypeTreeNullableArgIndices typeWrapper = new ParameterizedTypeTreeNullableArgIndices(); typeWrapper.checkAssignmentTypeMatch( @@ -197,6 +186,7 @@ public void checkAssignmentTypeMatch( Config config, VisitorState state, NullAway analysis) { + // if types are not same check for the super types if (!ASTHelpers.isSameType(lhs, ASTHelpers.getType(rhs), state)) { superTypeMatchingRHSParameterizedTypeTree(tree, rhs, lhs, state, config, analysis); } From c33fe3fa7bac079c55b50c88bee05c302f6db7f3 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 9 Dec 2022 04:00:28 -0800 Subject: [PATCH 090/184] Working changes --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 2e462df121..4b9025976e 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -124,7 +124,8 @@ public static void checkInstantiationForAssignments( AssignmentTree tree, Config config, VisitorState state, NullAway analysis) { Tree lhsTree = tree.getVariable(); Tree rhsTree = tree.getExpression(); - if (rhsTree.getClass().equals(JCTree.JCNewClass.class)) { + if (rhsTree.getClass().equals(JCTree.JCNewClass.class) + && !((JCTree.JCNewClass) rhsTree).getIdentifier().getClass().equals(JCTree.JCIdent.class)) { ParameterizedTypeTreeNullableArgIndices typeWrapper = new ParameterizedTypeTreeNullableArgIndices(); typeWrapper.checkAssignmentTypeMatch( From 31a3dcae0b4512e4d63577ea4b67d3c30843fbaa Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 9 Dec 2022 22:37:25 -0800 Subject: [PATCH 091/184] updates --- .../src/main/java/com/uber/nullaway/GenericsChecks.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 4b9025976e..07634ab2b1 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -36,12 +36,13 @@ public static Type supertypeMatchingLHS( // check for the super classes and interfaces implemented by the super classes Type current_super_type = rhsType; while (true) { + if (ASTHelpers.isSameType(current_super_type, Type.noType, state)) { + break; + } if (ASTHelpers.isSameType(current_super_type, lhsType, state)) { return current_super_type; } - if (current_super_type.getClass().equals(Object.class)) { - break; - } + current_super_type = ((Type.ClassType) current_super_type).supertype_field; } return rhsType.baseType(); From 3eca5a3fef4b79ddca5ff20a8ab8bd98ad64ccd6 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 15 Dec 2022 01:26:45 -0800 Subject: [PATCH 092/184] failing 3 tests --- .../uber/nullaway/AnnotatedTypeWrapper.java | 4 +-- .../com/uber/nullaway/GenericsChecks.java | 32 +++++++++++-------- .../main/java/com/uber/nullaway/NullAway.java | 3 ++ .../NullAwayJSpecifyGenericsTests.java | 27 +++++++--------- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java index f1b6beaffd..092a83cfec 100644 --- a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java +++ b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java @@ -1,7 +1,7 @@ package com.uber.nullaway; import com.google.errorprone.VisitorState; -import com.sun.source.tree.AssignmentTree; +import com.sun.source.tree.Tree; import java.util.HashSet; public interface AnnotatedTypeWrapper { @@ -9,5 +9,5 @@ public interface AnnotatedTypeWrapper { public HashSet getNullableTypeArgIndices(T2 wrapper, Config config); public void checkAssignmentTypeMatch( - AssignmentTree tree, T1 lhs, T2 rhs, Config config, VisitorState state, NullAway analysis); + Tree tree, T1 lhs, T2 rhs, Config config, VisitorState state, NullAway analysis); } diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 07634ab2b1..0c3158f432 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -122,10 +122,19 @@ static void invalidInstantiationError( @SuppressWarnings("UnusedVariable") public static void checkInstantiationForAssignments( - AssignmentTree tree, Config config, VisitorState state, NullAway analysis) { - Tree lhsTree = tree.getVariable(); - Tree rhsTree = tree.getExpression(); - if (rhsTree.getClass().equals(JCTree.JCNewClass.class) + Tree tree, Config config, VisitorState state, NullAway analysis) { + Tree lhsTree; + Tree rhsTree; + if (tree.getClass().equals(JCTree.JCVariableDecl.class)) { + lhsTree = ((JCTree.JCVariableDecl) tree).vartype; + rhsTree = ((JCTree.JCVariableDecl) tree).init; + } else { + lhsTree = ((AssignmentTree) tree).getVariable(); + rhsTree = ((AssignmentTree) tree).getExpression(); + } + + if (rhsTree != null + && rhsTree.getClass().equals(JCTree.JCNewClass.class) && !((JCTree.JCNewClass) rhsTree).getIdentifier().getClass().equals(JCTree.JCIdent.class)) { ParameterizedTypeTreeNullableArgIndices typeWrapper = new ParameterizedTypeTreeNullableArgIndices(); @@ -136,7 +145,7 @@ public static void checkInstantiationForAssignments( config, state, analysis); - } else { + } else if (rhsTree != null) { NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); typeWrapper.checkAssignmentTypeMatch( tree, ASTHelpers.getType(lhsTree), ASTHelpers.getType(rhsTree), config, state, analysis); @@ -156,7 +165,7 @@ public HashSet getNullableTypeArgIndices(ParameterizedTypeTree tree, Co JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { Attribute.Compound attribute = annotation.attribute; - if (attribute.toString().equals("@org.jspecify.nullness.Nullable")) { + if (attribute.toString().equals("@org.jspecify.annotations.Nullable")) { nullableTypeArgIndices.add(i); break; } @@ -167,7 +176,7 @@ public HashSet getNullableTypeArgIndices(ParameterizedTypeTree tree, Co } public static void superTypeMatchingRHSParameterizedTypeTree( - AssignmentTree tree, + Tree tree, ParameterizedTypeTree rhs, Type lhs, VisitorState state, @@ -182,7 +191,7 @@ public static void superTypeMatchingRHSParameterizedTypeTree( @Override public void checkAssignmentTypeMatch( - AssignmentTree tree, + Tree tree, Type lhs, ParameterizedTypeTree rhs, Config config, @@ -248,12 +257,7 @@ public HashSet getNullableTypeArgIndices(Type type, Config config) { @Override public void checkAssignmentTypeMatch( - AssignmentTree tree, - Type lhs, - Type rhs, - Config config, - VisitorState state, - NullAway analysis) { + Tree tree, Type lhs, Type rhs, Config config, VisitorState state, NullAway analysis) { // if lhs and rhs are not of the same type check for the super types first if (!ASTHelpers.isSameType(lhs, rhs, state)) { rhs = GenericsChecks.supertypeMatchingLHS((Type.ClassType) lhs, (Type.ClassType) rhs, state); diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 958de701ed..a142250f3c 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -1330,6 +1330,9 @@ public Description matchVariable(VariableTree tree, VisitorState state) { return Description.NO_MATCH; } VarSymbol symbol = ASTHelpers.getSymbol(tree); + if (ASTHelpers.constValue(tree.getInitializer()) != null) { + GenericsChecks.checkInstantiationForAssignments(tree, config, state, this); + } if (symbol.type.isPrimitive() && tree.getInitializer() != null) { doUnboxingCheck(state, tree.getInitializer()); } diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 1f15b06fd8..8296100554 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -204,7 +204,7 @@ public void genericsChecksForAssignments() { .addSourceLines( "Test.java", "package com.uber;", - "import org.jspecify.nullness.Nullable;", + "import org.jspecify.annotations.Nullable;", "class Test {", " static class NullableTypeParam {}", " static class NullableTypeParamMultipleArguments {}", @@ -246,14 +246,13 @@ public void superTypeAssignmentChecksSingleInterface() { .addSourceLines( "Test.java", "package com.uber;", - "import org.jspecify.nullness.Nullable;", + "import org.jspecify.annotations.Nullable;", "class Test {", " interface Fn

{}", " class FnImpl implements Fn<@Nullable String, @Nullable String>{}", " void sampleError() {", - " Fn<@Nullable String, String> f = null;", " // BUG: Diagnostic contains: Generic type parameter", - " f = new FnImpl();", + " Fn<@Nullable String, String> f = new FnImpl();", " }", " }") .doTest(); @@ -265,15 +264,14 @@ public void superTypeAssignmentChecksMultipleInterface() { .addSourceLines( "Test.java", "package com.uber;", - "import org.jspecify.nullness.Nullable;", + "import org.jspecify.annotations.Nullable;", "class Test {", " interface Fn1{}", " interface Fn2

{}", " class FnImpl implements Fn1<@Nullable String, @Nullable String>, Fn2 {}", " void sampleError() {", - " Fn2<@Nullable String> f = null;", " // BUG: Diagnostic contains: Generic type parameter", - " f = new FnImpl();", + " Fn2<@Nullable String> f = new FnImpl();", " }", " }") .doTest(); @@ -285,7 +283,7 @@ public void superTypeAssignmentChecksMultipleLevelInheritance() { .addSourceLines( "Test.java", "package com.uber;", - "import org.jspecify.nullness.Nullable;", + "import org.jspecify.annotations.Nullable;", "class Test {", " class SuperClassC{}", " class SuperClassB

extends SuperClassC

{}", @@ -293,12 +291,11 @@ public void superTypeAssignmentChecksMultipleLevelInheritance() { " class FnImpl1 extends SubClassA{}", " class FnImpl2 extends SubClassA<@Nullable String>{}", " void sampleError() {", - " SuperClassC<@Nullable String> f = null;", " // BUG: Diagnostic contains: Generic type parameter", - " f = new FnImpl1();", + " SuperClassC<@Nullable String> f = new FnImpl1();", " }", " void sampleValidInstantiation() {", - " SuperClassC<@Nullable String> f = null;", + " SuperClassC<@Nullable String> f;", " // No error", " f = new FnImpl2();", " }", @@ -312,21 +309,19 @@ public void NestedAssignmentChecks() { .addSourceLines( "Test.java", "package com.uber;", - "import org.jspecify.nullness.Nullable;", + "import org.jspecify.annotations.Nullable;", "class Test {", " class A{}", " class D

{}", " class B

extends D

{}", " class C

{}", " void sampleError1() {", - " C> f = null;", " // BUG: Diagnostic contains: Generic type parameter", - " f = new C>();", + " C> f = new C>();", " }", " void sampleError2() {", - " D> f = null;", " // BUG: Diagnostic contains: Generic type parameter", - " f = new B>();", + " D> f = new B>();", " }", " }") .doTest(); From 3435f89e07cc9d0487931dc49864c9c30007bbd4 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Thu, 15 Dec 2022 19:22:33 -0800 Subject: [PATCH 093/184] working tests --- .../nullaway/NullAwayJSpecifyGenericsTests.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 8296100554..ca49468ad2 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -251,8 +251,9 @@ public void superTypeAssignmentChecksSingleInterface() { " interface Fn

{}", " class FnImpl implements Fn<@Nullable String, @Nullable String>{}", " void sampleError() {", + " Fn<@Nullable String, String> f;", " // BUG: Diagnostic contains: Generic type parameter", - " Fn<@Nullable String, String> f = new FnImpl();", + " f = new FnImpl();", " }", " }") .doTest(); @@ -270,8 +271,9 @@ public void superTypeAssignmentChecksMultipleInterface() { " interface Fn2

{}", " class FnImpl implements Fn1<@Nullable String, @Nullable String>, Fn2 {}", " void sampleError() {", + " Fn2<@Nullable String> f;", " // BUG: Diagnostic contains: Generic type parameter", - " Fn2<@Nullable String> f = new FnImpl();", + " f = new FnImpl();", " }", " }") .doTest(); @@ -291,8 +293,9 @@ public void superTypeAssignmentChecksMultipleLevelInheritance() { " class FnImpl1 extends SubClassA{}", " class FnImpl2 extends SubClassA<@Nullable String>{}", " void sampleError() {", + " SuperClassC<@Nullable String> f;", " // BUG: Diagnostic contains: Generic type parameter", - " SuperClassC<@Nullable String> f = new FnImpl1();", + " f = new FnImpl1();", " }", " void sampleValidInstantiation() {", " SuperClassC<@Nullable String> f;", @@ -316,12 +319,14 @@ public void NestedAssignmentChecks() { " class B

extends D

{}", " class C

{}", " void sampleError1() {", + " C> f;", " // BUG: Diagnostic contains: Generic type parameter", - " C> f = new C>();", + " f = new C>();", " }", " void sampleError2() {", + " D> f;", " // BUG: Diagnostic contains: Generic type parameter", - " D> f = new B>();", + " f = new B>();", " }", " }") .doTest(); From 7972c05c67fb6ce31a3ba10fb19a2b8610876f30 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 20 Dec 2022 01:00:39 -0800 Subject: [PATCH 094/184] npe for variable initialization changes --- .../com/uber/nullaway/GenericsChecks.java | 4 ++-- .../main/java/com/uber/nullaway/NullAway.java | 4 +++- .../NullAwayJSpecifyGenericsTests.java | 20 +++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 0c3158f432..db0ec73da8 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -36,7 +36,7 @@ public static Type supertypeMatchingLHS( // check for the super classes and interfaces implemented by the super classes Type current_super_type = rhsType; while (true) { - if (ASTHelpers.isSameType(current_super_type, Type.noType, state)) { + if (current_super_type == null) { break; } if (ASTHelpers.isSameType(current_super_type, lhsType, state)) { @@ -259,7 +259,7 @@ public HashSet getNullableTypeArgIndices(Type type, Config config) { public void checkAssignmentTypeMatch( Tree tree, Type lhs, Type rhs, Config config, VisitorState state, NullAway analysis) { // if lhs and rhs are not of the same type check for the super types first - if (!ASTHelpers.isSameType(lhs, rhs, state)) { + if (!ASTHelpers.isSameType(lhs, rhs, state) && !rhs.toString().equals("null")) { rhs = GenericsChecks.supertypeMatchingLHS((Type.ClassType) lhs, (Type.ClassType) rhs, state); } HashSet lhsNullableArgIndices = getNullableTypeArgIndices(lhs, config); diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index a142250f3c..51b06ee62b 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -1330,9 +1330,11 @@ public Description matchVariable(VariableTree tree, VisitorState state) { return Description.NO_MATCH; } VarSymbol symbol = ASTHelpers.getSymbol(tree); - if (ASTHelpers.constValue(tree.getInitializer()) != null) { + if (tree.getInitializer() != null + && !state.getSourceForNode(tree.getInitializer()).equals("null")) { GenericsChecks.checkInstantiationForAssignments(tree, config, state, this); } + if (symbol.type.isPrimitive() && tree.getInitializer() != null) { doUnboxingCheck(state, tree.getInitializer()); } diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index ca49468ad2..d2a8c70ff6 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -332,6 +332,26 @@ public void NestedAssignmentChecks() { .doTest(); } + @Test + public void NestedVariableDeclarationChecks() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.annotations.Nullable;", + "class Test {", + " class A{}", + " class D

{}", + " class B

extends D

{}", + " class C

{}", + " void sampleError() {", + " // BUG: Diagnostic contains: Generic type parameter", + " D> f = new B>();", + " }", + " }") + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( Arrays.asList( From 4924722d7869c51c92eee1bdf3efab13b192f1ca Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 20 Dec 2022 01:45:23 -0800 Subject: [PATCH 095/184] npe for variable initialization changes --- .../com/uber/nullaway/GenericsChecks.java | 28 ++++++++++++------- .../main/java/com/uber/nullaway/NullAway.java | 11 ++++++-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index db0ec73da8..1c73d9ca8d 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -42,8 +42,9 @@ public static Type supertypeMatchingLHS( if (ASTHelpers.isSameType(current_super_type, lhsType, state)) { return current_super_type; } - - current_super_type = ((Type.ClassType) current_super_type).supertype_field; + if (current_super_type instanceof Type.ClassType) { + current_super_type = ((Type.ClassType) current_super_type).supertype_field; + } } return rhsType.baseType(); } @@ -182,11 +183,13 @@ public static void superTypeMatchingRHSParameterizedTypeTree( VisitorState state, Config config, NullAway analysis) { - Type rhsType = - GenericsChecks.supertypeMatchingLHS( - (Type.ClassType) lhs, (Type.ClassType) ASTHelpers.getType(rhs), state); - NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); - typeWrapper.checkAssignmentTypeMatch(tree, lhs, rhsType, config, state, analysis); + if (lhs instanceof Type.ClassType && ASTHelpers.getType(rhs) instanceof Type.ClassType) { + Type rhsType = + GenericsChecks.supertypeMatchingLHS( + (Type.ClassType) lhs, (Type.ClassType) ASTHelpers.getType(rhs), state); + NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); + typeWrapper.checkAssignmentTypeMatch(tree, lhs, rhsType, config, state, analysis); + } } @Override @@ -260,7 +263,10 @@ public void checkAssignmentTypeMatch( Tree tree, Type lhs, Type rhs, Config config, VisitorState state, NullAway analysis) { // if lhs and rhs are not of the same type check for the super types first if (!ASTHelpers.isSameType(lhs, rhs, state) && !rhs.toString().equals("null")) { - rhs = GenericsChecks.supertypeMatchingLHS((Type.ClassType) lhs, (Type.ClassType) rhs, state); + if (lhs instanceof Type.ClassType && rhs instanceof Type.ClassType) { + rhs = + GenericsChecks.supertypeMatchingLHS((Type.ClassType) lhs, (Type.ClassType) rhs, state); + } } HashSet lhsNullableArgIndices = getNullableTypeArgIndices(lhs, config); HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs, config); @@ -275,8 +281,10 @@ public void checkAssignmentTypeMatch( for (int i = 0; i < lhsTypeArgs.size(); i++) { // nested generics if (lhsTypeArgs.get(i).getTypeArguments().length() > 0) { - checkAssignmentTypeMatch( - tree, lhsTypeArgs.get(i), rhsTypeArgs.get(i), config, state, analysis); + if (rhsTypeArgs.size() > i) { + checkAssignmentTypeMatch( + tree, lhsTypeArgs.get(i), rhsTypeArgs.get(i), config, state, analysis); + } } } } diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 51b06ee62b..a59f3b9735 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -1330,9 +1330,14 @@ public Description matchVariable(VariableTree tree, VisitorState state) { return Description.NO_MATCH; } VarSymbol symbol = ASTHelpers.getSymbol(tree); - if (tree.getInitializer() != null - && !state.getSourceForNode(tree.getInitializer()).equals("null")) { - GenericsChecks.checkInstantiationForAssignments(tree, config, state, this); + // working on this. This part is needed to avoid assignment checks where the variable is + // assigned to null + if (tree.getInitializer() != null) { + if (state.getSourceForNode(tree.getInitializer()) != null) { + if (!state.getSourceForNode(tree.getInitializer()).equals("null")) { + GenericsChecks.checkInstantiationForAssignments(tree, config, state, this); + } + } } if (symbol.type.isPrimitive() && tree.getInitializer() != null) { From 35e2bc7af8b88e2ba6932caf28b24637e0f4899b Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 20 Dec 2022 01:53:31 -0800 Subject: [PATCH 096/184] All tests pass including the existing tests --- .../src/main/java/com/uber/nullaway/GenericsChecks.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 1c73d9ca8d..8aec44e813 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -36,7 +36,8 @@ public static Type supertypeMatchingLHS( // check for the super classes and interfaces implemented by the super classes Type current_super_type = rhsType; while (true) { - if (current_super_type == null) { + if (current_super_type == null + || ASTHelpers.isSameType(current_super_type, Type.noType, state)) { break; } if (ASTHelpers.isSameType(current_super_type, lhsType, state)) { @@ -136,7 +137,8 @@ public static void checkInstantiationForAssignments( if (rhsTree != null && rhsTree.getClass().equals(JCTree.JCNewClass.class) - && !((JCTree.JCNewClass) rhsTree).getIdentifier().getClass().equals(JCTree.JCIdent.class)) { + && !((JCTree.JCNewClass) rhsTree).getIdentifier().getClass().equals(JCTree.JCIdent.class) + && ((JCTree.JCNewClass) rhsTree).getIdentifier() instanceof ParameterizedTypeTree) { ParameterizedTypeTreeNullableArgIndices typeWrapper = new ParameterizedTypeTreeNullableArgIndices(); typeWrapper.checkAssignmentTypeMatch( From c8456f343ee66db1b6d591e4e105bbd33aee7166 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 21 Dec 2022 10:17:06 -0800 Subject: [PATCH 097/184] some cleanup --- .../com/uber/nullaway/GenericsChecks.java | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 8aec44e813..865b5d2f76 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -5,8 +5,10 @@ import com.sun.source.tree.AnnotatedTypeTree; import com.sun.source.tree.AnnotationTree; import com.sun.source.tree.AssignmentTree; +import com.sun.source.tree.NewClassTree; import com.sun.source.tree.ParameterizedTypeTree; import com.sun.source.tree.Tree; +import com.sun.source.tree.VariableTree; import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.tree.JCTree; @@ -127,28 +129,31 @@ public static void checkInstantiationForAssignments( Tree tree, Config config, VisitorState state, NullAway analysis) { Tree lhsTree; Tree rhsTree; - if (tree.getClass().equals(JCTree.JCVariableDecl.class)) { - lhsTree = ((JCTree.JCVariableDecl) tree).vartype; - rhsTree = ((JCTree.JCVariableDecl) tree).init; + if (tree instanceof VariableTree) { + VariableTree varTree = (VariableTree) tree; + lhsTree = varTree.getType(); + rhsTree = varTree.getInitializer(); } else { - lhsTree = ((AssignmentTree) tree).getVariable(); - rhsTree = ((AssignmentTree) tree).getExpression(); + AssignmentTree assignmentTree = (AssignmentTree) tree; + lhsTree = assignmentTree.getVariable(); + rhsTree = assignmentTree.getExpression(); } - - if (rhsTree != null - && rhsTree.getClass().equals(JCTree.JCNewClass.class) - && !((JCTree.JCNewClass) rhsTree).getIdentifier().getClass().equals(JCTree.JCIdent.class) - && ((JCTree.JCNewClass) rhsTree).getIdentifier() instanceof ParameterizedTypeTree) { + if (rhsTree == null) { + // Possible for VariableTrees with no initializer + return; + } + if (rhsTree instanceof NewClassTree + && ((NewClassTree) rhsTree).getIdentifier() instanceof ParameterizedTypeTree) { ParameterizedTypeTreeNullableArgIndices typeWrapper = new ParameterizedTypeTreeNullableArgIndices(); typeWrapper.checkAssignmentTypeMatch( tree, ASTHelpers.getType(lhsTree), - (ParameterizedTypeTree) ((JCTree.JCNewClass) rhsTree).getIdentifier(), + (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier(), config, state, analysis); - } else if (rhsTree != null) { + } else { NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); typeWrapper.checkAssignmentTypeMatch( tree, ASTHelpers.getType(lhsTree), ASTHelpers.getType(rhsTree), config, state, analysis); From 945df87488677c55c436eed55f34321964c68d15 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 21 Dec 2022 10:22:23 -0800 Subject: [PATCH 098/184] enable check for multiple top-level classes --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 82cc1fa2b7..6c9c798b97 100644 --- a/build.gradle +++ b/build.gradle @@ -73,6 +73,7 @@ subprojects { project -> check("CanIgnoreReturnValueSuggester", CheckSeverity.OFF) check("WildcardImport", CheckSeverity.ERROR) check("MissingBraces", CheckSeverity.ERROR) + check("MultipleTopLevelClasses", CheckSeverity.ERROR) check("TypeToString", CheckSeverity.ERROR) check("SymbolToString", CheckSeverity.ERROR) } From a3fa8698799f4164c66ee6a1790ec7a778840bc8 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 3 Jan 2023 15:15:59 +0530 Subject: [PATCH 099/184] suggested changes - enclosing class member fields --- .../com/uber/nullaway/GenericsChecks.java | 260 +++++++++--------- .../main/java/com/uber/nullaway/NullAway.java | 6 +- 2 files changed, 132 insertions(+), 134 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 865b5d2f76..5e43623729 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -18,16 +18,23 @@ import java.util.Map; /** Methods for performing checks related to generic types and nullability. */ +@SuppressWarnings("ClassCanBeStatic") public final class GenericsChecks { - private GenericsChecks() { - // just utility methods + VisitorState state; + Config config; + NullAway analysis; + + public GenericsChecks(VisitorState state, Config config, NullAway analysis) { + this.state = state; + this.config = config; + this.analysis = analysis; } @SuppressWarnings("UnusedVariable") public static Type supertypeMatchingLHS( Type.ClassType lhsType, Type.ClassType rhsType, VisitorState state) { - // interfaces - List listOfDirectSuperTypes = rhsType.all_interfaces_field; + // all supertypes including classes as well as interfaces + List listOfDirectSuperTypes = state.getTypes().closure(rhsType); if (listOfDirectSuperTypes != null) { for (int i = 0; i < listOfDirectSuperTypes.size(); i++) { if (ASTHelpers.isSameType(listOfDirectSuperTypes.get(i), lhsType, state)) { @@ -35,20 +42,7 @@ public static Type supertypeMatchingLHS( } } } - // check for the super classes and interfaces implemented by the super classes - Type current_super_type = rhsType; - while (true) { - if (current_super_type == null - || ASTHelpers.isSameType(current_super_type, Type.noType, state)) { - break; - } - if (ASTHelpers.isSameType(current_super_type, lhsType, state)) { - return current_super_type; - } - if (current_super_type instanceof Type.ClassType) { - current_super_type = ((Type.ClassType) current_super_type).supertype_field; - } - } + return rhsType.baseType(); } @@ -125,8 +119,7 @@ static void invalidInstantiationError( } @SuppressWarnings("UnusedVariable") - public static void checkInstantiationForAssignments( - Tree tree, Config config, VisitorState state, NullAway analysis) { + public void checkInstantiationForAssignments(Tree tree) { Tree lhsTree; Tree rhsTree; if (tree instanceof VariableTree) { @@ -159,138 +152,141 @@ public static void checkInstantiationForAssignments( tree, ASTHelpers.getType(lhsTree), ASTHelpers.getType(rhsTree), config, state, analysis); } } -} -class ParameterizedTypeTreeNullableArgIndices - implements AnnotatedTypeWrapper { - @SuppressWarnings("UnusedVariable") - @Override - public HashSet getNullableTypeArgIndices(ParameterizedTypeTree tree, Config config) { - List typeArguments = tree.getTypeArguments(); - HashSet nullableTypeArgIndices = new HashSet(); - for (int i = 0; i < typeArguments.size(); i++) { - if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { - JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); - for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { - Attribute.Compound attribute = annotation.attribute; - if (attribute.toString().equals("@org.jspecify.annotations.Nullable")) { - nullableTypeArgIndices.add(i); - break; + class ParameterizedTypeTreeNullableArgIndices + implements AnnotatedTypeWrapper { + ParameterizedTypeTreeNullableArgIndices() {} + + @SuppressWarnings("UnusedVariable") + @Override + public HashSet getNullableTypeArgIndices(ParameterizedTypeTree tree, Config config) { + List typeArguments = tree.getTypeArguments(); + HashSet nullableTypeArgIndices = new HashSet(); + for (int i = 0; i < typeArguments.size(); i++) { + if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { + JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); + for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { + Attribute.Compound attribute = annotation.attribute; + if (attribute.toString().equals("@org.jspecify.annotations.Nullable")) { + nullableTypeArgIndices.add(i); + break; + } } } } + return nullableTypeArgIndices; } - return nullableTypeArgIndices; - } - public static void superTypeMatchingRHSParameterizedTypeTree( - Tree tree, - ParameterizedTypeTree rhs, - Type lhs, - VisitorState state, - Config config, - NullAway analysis) { - if (lhs instanceof Type.ClassType && ASTHelpers.getType(rhs) instanceof Type.ClassType) { - Type rhsType = - GenericsChecks.supertypeMatchingLHS( - (Type.ClassType) lhs, (Type.ClassType) ASTHelpers.getType(rhs), state); - NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); - typeWrapper.checkAssignmentTypeMatch(tree, lhs, rhsType, config, state, analysis); + public void superTypeMatchingRHSParameterizedTypeTree( + Tree tree, + ParameterizedTypeTree rhs, + Type lhs, + VisitorState state, + Config config, + NullAway analysis) { + if (lhs instanceof Type.ClassType && ASTHelpers.getType(rhs) instanceof Type.ClassType) { + Type rhsType = + GenericsChecks.supertypeMatchingLHS( + (Type.ClassType) lhs, (Type.ClassType) ASTHelpers.getType(rhs), state); + NormalTypeTreeNullableTypeArgIndices typeWrapper = + new NormalTypeTreeNullableTypeArgIndices(); + typeWrapper.checkAssignmentTypeMatch(tree, lhs, rhsType, config, state, analysis); + } } - } - @Override - public void checkAssignmentTypeMatch( - Tree tree, - Type lhs, - ParameterizedTypeTree rhs, - Config config, - VisitorState state, - NullAway analysis) { - // if types are not same check for the super types - if (!ASTHelpers.isSameType(lhs, ASTHelpers.getType(rhs), state)) { - superTypeMatchingRHSParameterizedTypeTree(tree, rhs, lhs, state, config, analysis); - } - NormalTypeTreeNullableTypeArgIndices normalTypeTreeNullableTypeArgIndices = - new NormalTypeTreeNullableTypeArgIndices(); - HashSet lhsNullableArgIndices = - normalTypeTreeNullableTypeArgIndices.getNullableTypeArgIndices(lhs, config); - HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs, config); - if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { - GenericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); - return; - } else { - // check for nested types if an error is not already generated - List rhsTypeArguments = rhs.getTypeArguments(); - List lhsTypeArguments = lhs.getTypeArguments(); + @Override + public void checkAssignmentTypeMatch( + Tree tree, + Type lhs, + ParameterizedTypeTree rhs, + Config config, + VisitorState state, + NullAway analysis) { + // if types are not same check for the super types + if (!ASTHelpers.isSameType(lhs, ASTHelpers.getType(rhs), state)) { + superTypeMatchingRHSParameterizedTypeTree(tree, rhs, lhs, state, config, analysis); + } + NormalTypeTreeNullableTypeArgIndices normalTypeTreeNullableTypeArgIndices = + new NormalTypeTreeNullableTypeArgIndices(); + HashSet lhsNullableArgIndices = + normalTypeTreeNullableTypeArgIndices.getNullableTypeArgIndices(lhs, config); + HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs, config); + if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { + GenericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); + return; + } else { + // check for nested types if an error is not already generated + List rhsTypeArguments = rhs.getTypeArguments(); + List lhsTypeArguments = lhs.getTypeArguments(); - for (int i = 0; i < rhsTypeArguments.size(); i++) { - if (rhsTypeArguments.get(i).getClass().equals(JCTree.JCTypeApply.class)) { - ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = - (ParameterizedTypeTree) rhsTypeArguments.get(i); - Type argumentType = ASTHelpers.getType(parameterizedTypeTreeForTypeArgument); - if (argumentType != null - && argumentType.getTypeArguments() != null - && argumentType.getTypeArguments().length() > 0) { // Nested generics - checkAssignmentTypeMatch( - tree, - lhsTypeArguments.get(i), - parameterizedTypeTreeForTypeArgument, - config, - state, - analysis); + for (int i = 0; i < rhsTypeArguments.size(); i++) { + if (rhsTypeArguments.get(i).getClass().equals(JCTree.JCTypeApply.class)) { + ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = + (ParameterizedTypeTree) rhsTypeArguments.get(i); + Type argumentType = ASTHelpers.getType(parameterizedTypeTreeForTypeArgument); + if (argumentType != null + && argumentType.getTypeArguments() != null + && argumentType.getTypeArguments().length() > 0) { // Nested generics + checkAssignmentTypeMatch( + tree, + lhsTypeArguments.get(i), + parameterizedTypeTreeForTypeArgument, + config, + state, + analysis); + } } } } } } -} - -class NormalTypeTreeNullableTypeArgIndices implements AnnotatedTypeWrapper { - @SuppressWarnings("UnusedVariable") - @Override - public HashSet getNullableTypeArgIndices(Type type, Config config) { - HashSet nullableTypeArgIndices = new HashSet(); - List typeArguments = type.getTypeArguments(); - for (int index = 0; index < typeArguments.size(); index++) { - com.sun.tools.javac.util.List annotationMirrors = - typeArguments.get(index).getAnnotationMirrors(); - boolean hasNullableAnnotation = - Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - if (hasNullableAnnotation) { - nullableTypeArgIndices.add(index); + class NormalTypeTreeNullableTypeArgIndices implements AnnotatedTypeWrapper { + @SuppressWarnings("UnusedVariable") + @Override + public HashSet getNullableTypeArgIndices(Type type, Config config) { + HashSet nullableTypeArgIndices = new HashSet(); + List typeArguments = type.getTypeArguments(); + for (int index = 0; index < typeArguments.size(); index++) { + com.sun.tools.javac.util.List annotationMirrors = + typeArguments.get(index).getAnnotationMirrors(); + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + if (hasNullableAnnotation) { + nullableTypeArgIndices.add(index); + } } + return nullableTypeArgIndices; } - return nullableTypeArgIndices; - } - @Override - public void checkAssignmentTypeMatch( - Tree tree, Type lhs, Type rhs, Config config, VisitorState state, NullAway analysis) { - // if lhs and rhs are not of the same type check for the super types first - if (!ASTHelpers.isSameType(lhs, rhs, state) && !rhs.toString().equals("null")) { - if (lhs instanceof Type.ClassType && rhs instanceof Type.ClassType) { - rhs = - GenericsChecks.supertypeMatchingLHS((Type.ClassType) lhs, (Type.ClassType) rhs, state); + @Override + public void checkAssignmentTypeMatch( + Tree tree, Type lhs, Type rhs, Config config, VisitorState state, NullAway analysis) { + // if lhs and rhs are not of the same type check for the super types first + if (!ASTHelpers.isSameType(lhs, rhs, state) && !rhs.toString().equals("null")) { + if (lhs instanceof Type.ClassType && rhs instanceof Type.ClassType) { + rhs = + GenericsChecks.supertypeMatchingLHS( + (Type.ClassType) lhs, (Type.ClassType) rhs, state); + } } - } - HashSet lhsNullableArgIndices = getNullableTypeArgIndices(lhs, config); - HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs, config); + HashSet lhsNullableArgIndices = getNullableTypeArgIndices(lhs, config); + HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs, config); - if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { - GenericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); - return; - } else { - List lhsTypeArgs = lhs.getTypeArguments(); - List rhsTypeArgs = rhs.getTypeArguments(); - // if an error is not already generated check for nested types - for (int i = 0; i < lhsTypeArgs.size(); i++) { - // nested generics - if (lhsTypeArgs.get(i).getTypeArguments().length() > 0) { - if (rhsTypeArgs.size() > i) { - checkAssignmentTypeMatch( - tree, lhsTypeArgs.get(i), rhsTypeArgs.get(i), config, state, analysis); + if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { + GenericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); + return; + } else { + List lhsTypeArgs = lhs.getTypeArguments(); + List rhsTypeArgs = rhs.getTypeArguments(); + // if an error is not already generated check for nested types + for (int i = 0; i < lhsTypeArgs.size(); i++) { + // nested generics + if (lhsTypeArgs.get(i).getTypeArguments().length() > 0) { + if (rhsTypeArgs.size() > i) { + checkAssignmentTypeMatch( + tree, lhsTypeArgs.get(i), rhsTypeArgs.get(i), config, state, analysis); + } } } } diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 7e69deb353..2451434c6f 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -464,7 +464,8 @@ public Description matchAssignment(AssignmentTree tree, VisitorState state) { } // generics check if (lhsType.getTypeArguments().length() > 0) { - GenericsChecks.checkInstantiationForAssignments(tree, config, state, this); + GenericsChecks genericsChecks = new GenericsChecks(state, config, this); + genericsChecks.checkInstantiationForAssignments(tree); } Symbol assigned = ASTHelpers.getSymbol(tree.getVariable()); @@ -1335,7 +1336,8 @@ public Description matchVariable(VariableTree tree, VisitorState state) { if (tree.getInitializer() != null) { if (state.getSourceForNode(tree.getInitializer()) != null) { if (!state.getSourceForNode(tree.getInitializer()).equals("null")) { - GenericsChecks.checkInstantiationForAssignments(tree, config, state, this); + GenericsChecks genericsChecks = new GenericsChecks(state, config, this); + genericsChecks.checkInstantiationForAssignments(tree); } } } From 601f2b54a9158533e059ff8bc56095571871b78c Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 3 Jan 2023 15:21:27 +0530 Subject: [PATCH 100/184] code cleanup --- .../uber/nullaway/AnnotatedTypeWrapper.java | 6 +-- .../com/uber/nullaway/GenericsChecks.java | 52 ++++++------------- 2 files changed, 17 insertions(+), 41 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java index 092a83cfec..4aab1f974c 100644 --- a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java +++ b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java @@ -1,13 +1,11 @@ package com.uber.nullaway; -import com.google.errorprone.VisitorState; import com.sun.source.tree.Tree; import java.util.HashSet; public interface AnnotatedTypeWrapper { - public HashSet getNullableTypeArgIndices(T2 wrapper, Config config); + public HashSet getNullableTypeArgIndices(T2 wrapper); - public void checkAssignmentTypeMatch( - Tree tree, T1 lhs, T2 rhs, Config config, VisitorState state, NullAway analysis); + public void checkAssignmentTypeMatch(Tree tree, T1 lhs, T2 rhs); } diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 5e43623729..30c1015b82 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -142,24 +142,20 @@ public void checkInstantiationForAssignments(Tree tree) { typeWrapper.checkAssignmentTypeMatch( tree, ASTHelpers.getType(lhsTree), - (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier(), - config, - state, - analysis); + (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier()); } else { NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); typeWrapper.checkAssignmentTypeMatch( - tree, ASTHelpers.getType(lhsTree), ASTHelpers.getType(rhsTree), config, state, analysis); + tree, ASTHelpers.getType(lhsTree), ASTHelpers.getType(rhsTree)); } } class ParameterizedTypeTreeNullableArgIndices implements AnnotatedTypeWrapper { - ParameterizedTypeTreeNullableArgIndices() {} @SuppressWarnings("UnusedVariable") @Override - public HashSet getNullableTypeArgIndices(ParameterizedTypeTree tree, Config config) { + public HashSet getNullableTypeArgIndices(ParameterizedTypeTree tree) { List typeArguments = tree.getTypeArguments(); HashSet nullableTypeArgIndices = new HashSet(); for (int i = 0; i < typeArguments.size(); i++) { @@ -178,39 +174,28 @@ public HashSet getNullableTypeArgIndices(ParameterizedTypeTree tree, Co } public void superTypeMatchingRHSParameterizedTypeTree( - Tree tree, - ParameterizedTypeTree rhs, - Type lhs, - VisitorState state, - Config config, - NullAway analysis) { + Tree tree, ParameterizedTypeTree rhs, Type lhs) { if (lhs instanceof Type.ClassType && ASTHelpers.getType(rhs) instanceof Type.ClassType) { Type rhsType = GenericsChecks.supertypeMatchingLHS( (Type.ClassType) lhs, (Type.ClassType) ASTHelpers.getType(rhs), state); NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); - typeWrapper.checkAssignmentTypeMatch(tree, lhs, rhsType, config, state, analysis); + typeWrapper.checkAssignmentTypeMatch(tree, lhs, rhsType); } } @Override - public void checkAssignmentTypeMatch( - Tree tree, - Type lhs, - ParameterizedTypeTree rhs, - Config config, - VisitorState state, - NullAway analysis) { + public void checkAssignmentTypeMatch(Tree tree, Type lhs, ParameterizedTypeTree rhs) { // if types are not same check for the super types if (!ASTHelpers.isSameType(lhs, ASTHelpers.getType(rhs), state)) { - superTypeMatchingRHSParameterizedTypeTree(tree, rhs, lhs, state, config, analysis); + superTypeMatchingRHSParameterizedTypeTree(tree, rhs, lhs); } NormalTypeTreeNullableTypeArgIndices normalTypeTreeNullableTypeArgIndices = new NormalTypeTreeNullableTypeArgIndices(); HashSet lhsNullableArgIndices = - normalTypeTreeNullableTypeArgIndices.getNullableTypeArgIndices(lhs, config); - HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs, config); + normalTypeTreeNullableTypeArgIndices.getNullableTypeArgIndices(lhs); + HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs); if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { GenericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); return; @@ -228,12 +213,7 @@ public void checkAssignmentTypeMatch( && argumentType.getTypeArguments() != null && argumentType.getTypeArguments().length() > 0) { // Nested generics checkAssignmentTypeMatch( - tree, - lhsTypeArguments.get(i), - parameterizedTypeTreeForTypeArgument, - config, - state, - analysis); + tree, lhsTypeArguments.get(i), parameterizedTypeTreeForTypeArgument); } } } @@ -244,7 +224,7 @@ public void checkAssignmentTypeMatch( class NormalTypeTreeNullableTypeArgIndices implements AnnotatedTypeWrapper { @SuppressWarnings("UnusedVariable") @Override - public HashSet getNullableTypeArgIndices(Type type, Config config) { + public HashSet getNullableTypeArgIndices(Type type) { HashSet nullableTypeArgIndices = new HashSet(); List typeArguments = type.getTypeArguments(); for (int index = 0; index < typeArguments.size(); index++) { @@ -260,8 +240,7 @@ public HashSet getNullableTypeArgIndices(Type type, Config config) { } @Override - public void checkAssignmentTypeMatch( - Tree tree, Type lhs, Type rhs, Config config, VisitorState state, NullAway analysis) { + public void checkAssignmentTypeMatch(Tree tree, Type lhs, Type rhs) { // if lhs and rhs are not of the same type check for the super types first if (!ASTHelpers.isSameType(lhs, rhs, state) && !rhs.toString().equals("null")) { if (lhs instanceof Type.ClassType && rhs instanceof Type.ClassType) { @@ -270,8 +249,8 @@ public void checkAssignmentTypeMatch( (Type.ClassType) lhs, (Type.ClassType) rhs, state); } } - HashSet lhsNullableArgIndices = getNullableTypeArgIndices(lhs, config); - HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs, config); + HashSet lhsNullableArgIndices = getNullableTypeArgIndices(lhs); + HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs); if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { GenericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); @@ -284,8 +263,7 @@ public void checkAssignmentTypeMatch( // nested generics if (lhsTypeArgs.get(i).getTypeArguments().length() > 0) { if (rhsTypeArgs.size() > i) { - checkAssignmentTypeMatch( - tree, lhsTypeArgs.get(i), rhsTypeArgs.get(i), config, state, analysis); + checkAssignmentTypeMatch(tree, lhsTypeArgs.get(i), rhsTypeArgs.get(i)); } } } From a0aacdb26c44dcd7c5974bd756ace670e4c5b78f Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 3 Jan 2023 15:34:36 +0530 Subject: [PATCH 101/184] suggested changes --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 1 - .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 30c1015b82..be36aad54a 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -18,7 +18,6 @@ import java.util.Map; /** Methods for performing checks related to generic types and nullability. */ -@SuppressWarnings("ClassCanBeStatic") public final class GenericsChecks { VisitorState state; Config config; diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index d2a8c70ff6..9e9013a338 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -198,6 +198,7 @@ public void downcastInstantiation() { .doTest(); } + // assignment tree tests @Test public void genericsChecksForAssignments() { makeHelper() @@ -314,7 +315,6 @@ public void NestedAssignmentChecks() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " class A{}", " class D

{}", " class B

extends D

{}", " class C

{}", @@ -324,9 +324,8 @@ public void NestedAssignmentChecks() { " f = new C>();", " }", " void sampleError2() {", - " D> f;", " // BUG: Diagnostic contains: Generic type parameter", - " f = new B>();", + " D> f = new B>();", " }", " }") .doTest(); From 84140d0ef45608d0a7cd836bb2abd19d36418c74 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 4 Jan 2023 08:45:51 +0530 Subject: [PATCH 102/184] some suggested changes --- .../uber/nullaway/AnnotatedTypeWrapper.java | 1 + .../com/uber/nullaway/GenericsChecks.java | 127 ++++++++++-------- 2 files changed, 74 insertions(+), 54 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java index 4aab1f974c..f7fcd9497c 100644 --- a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java +++ b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java @@ -4,6 +4,7 @@ import java.util.HashSet; public interface AnnotatedTypeWrapper { + public T1 getWrapped(); public HashSet getNullableTypeArgIndices(T2 wrapper); diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index be36aad54a..831f5da421 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -16,6 +16,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import javax.annotation.Nullable; /** Methods for performing checks related to generic types and nullability. */ public final class GenericsChecks { @@ -134,8 +135,10 @@ public void checkInstantiationForAssignments(Tree tree) { // Possible for VariableTrees with no initializer return; } - if (rhsTree instanceof NewClassTree - && ((NewClassTree) rhsTree).getIdentifier() instanceof ParameterizedTypeTree) { + + AnnotatedTypeWrapper annotatedTypeWrapper = getAnnotatedTypeWrapper(rhsTree); + + if (annotatedTypeWrapper == null) { ParameterizedTypeTreeNullableArgIndices typeWrapper = new ParameterizedTypeTreeNullableArgIndices(); typeWrapper.checkAssignmentTypeMatch( @@ -143,15 +146,81 @@ public void checkInstantiationForAssignments(Tree tree) { ASTHelpers.getType(lhsTree), (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier()); } else { - NormalTypeTreeNullableTypeArgIndices typeWrapper = new NormalTypeTreeNullableTypeArgIndices(); - typeWrapper.checkAssignmentTypeMatch( + annotatedTypeWrapper.checkAssignmentTypeMatch( tree, ASTHelpers.getType(lhsTree), ASTHelpers.getType(rhsTree)); } } + private @Nullable AnnotatedTypeWrapper getAnnotatedTypeWrapper(Tree rhsTree) { + if (rhsTree instanceof NewClassTree + && ((NewClassTree) rhsTree).getIdentifier() instanceof ParameterizedTypeTree) { + return null; + } else { + return new AnnotatedTypeWrapper() { + + @Override + public Type getWrapped() { + return null; + } + + @Override + public HashSet getNullableTypeArgIndices(Type type) { + HashSet nullableTypeArgIndices = new HashSet(); + List typeArguments = type.getTypeArguments(); + for (int index = 0; index < typeArguments.size(); index++) { + com.sun.tools.javac.util.List annotationMirrors = + typeArguments.get(index).getAnnotationMirrors(); + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + if (hasNullableAnnotation) { + nullableTypeArgIndices.add(index); + } + } + return nullableTypeArgIndices; + } + + @Override + public void checkAssignmentTypeMatch(Tree tree, Type lhs, Type rhs) { + // if lhs and rhs are not of the same type check for the super types first + if (!ASTHelpers.isSameType(lhs, rhs, state) && !rhs.toString().equals("null")) { + if (lhs instanceof Type.ClassType && rhs instanceof Type.ClassType) { + rhs = + GenericsChecks.supertypeMatchingLHS( + (Type.ClassType) lhs, (Type.ClassType) rhs, state); + } + } + HashSet lhsNullableArgIndices = getNullableTypeArgIndices(lhs); + HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs); + + if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { + GenericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); + return; + } else { + List lhsTypeArgs = lhs.getTypeArguments(); + List rhsTypeArgs = rhs.getTypeArguments(); + // if an error is not already generated check for nested types + for (int i = 0; i < lhsTypeArgs.size(); i++) { + // nested generics + if (lhsTypeArgs.get(i).getTypeArguments().length() > 0) { + if (rhsTypeArgs.size() > i) { + checkAssignmentTypeMatch(tree, lhsTypeArgs.get(i), rhsTypeArgs.get(i)); + } + } + } + } + } + }; + } + } + class ParameterizedTypeTreeNullableArgIndices implements AnnotatedTypeWrapper { + @Override + public Type getWrapped() { + return null; + } + @SuppressWarnings("UnusedVariable") @Override public HashSet getNullableTypeArgIndices(ParameterizedTypeTree tree) { @@ -219,54 +288,4 @@ public void checkAssignmentTypeMatch(Tree tree, Type lhs, ParameterizedTypeTree } } } - - class NormalTypeTreeNullableTypeArgIndices implements AnnotatedTypeWrapper { - @SuppressWarnings("UnusedVariable") - @Override - public HashSet getNullableTypeArgIndices(Type type) { - HashSet nullableTypeArgIndices = new HashSet(); - List typeArguments = type.getTypeArguments(); - for (int index = 0; index < typeArguments.size(); index++) { - com.sun.tools.javac.util.List annotationMirrors = - typeArguments.get(index).getAnnotationMirrors(); - boolean hasNullableAnnotation = - Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - if (hasNullableAnnotation) { - nullableTypeArgIndices.add(index); - } - } - return nullableTypeArgIndices; - } - - @Override - public void checkAssignmentTypeMatch(Tree tree, Type lhs, Type rhs) { - // if lhs and rhs are not of the same type check for the super types first - if (!ASTHelpers.isSameType(lhs, rhs, state) && !rhs.toString().equals("null")) { - if (lhs instanceof Type.ClassType && rhs instanceof Type.ClassType) { - rhs = - GenericsChecks.supertypeMatchingLHS( - (Type.ClassType) lhs, (Type.ClassType) rhs, state); - } - } - HashSet lhsNullableArgIndices = getNullableTypeArgIndices(lhs); - HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs); - - if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { - GenericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); - return; - } else { - List lhsTypeArgs = lhs.getTypeArguments(); - List rhsTypeArgs = rhs.getTypeArguments(); - // if an error is not already generated check for nested types - for (int i = 0; i < lhsTypeArgs.size(); i++) { - // nested generics - if (lhsTypeArgs.get(i).getTypeArguments().length() > 0) { - if (rhsTypeArgs.size() > i) { - checkAssignmentTypeMatch(tree, lhsTypeArgs.get(i), rhsTypeArgs.get(i)); - } - } - } - } - } - } } From 20fae011424cd59162e2307d530d9471349b26f8 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 4 Jan 2023 10:34:02 +0530 Subject: [PATCH 103/184] suggested changes with working normal typed tree --- .../uber/nullaway/AnnotatedTypeWrapper.java | 11 +- .../com/uber/nullaway/GenericsChecks.java | 198 +++++++----------- 2 files changed, 76 insertions(+), 133 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java index f7fcd9497c..ee6553c511 100644 --- a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java +++ b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java @@ -1,12 +1,13 @@ package com.uber.nullaway; -import com.sun.source.tree.Tree; +import com.sun.tools.javac.code.Type; import java.util.HashSet; +import java.util.List; -public interface AnnotatedTypeWrapper { - public T1 getWrapped(); +public interface AnnotatedTypeWrapper { + public Type getWrapped(); - public HashSet getNullableTypeArgIndices(T2 wrapper); + public HashSet getNullableTypeArgIndices(); - public void checkAssignmentTypeMatch(Tree tree, T1 lhs, T2 rhs); + public List getWrappersForNestedTypes(); } diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 831f5da421..7222c05b77 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -11,7 +11,7 @@ import com.sun.source.tree.VariableTree; import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.tree.JCTree; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -136,155 +136,97 @@ public void checkInstantiationForAssignments(Tree tree) { return; } - AnnotatedTypeWrapper annotatedTypeWrapper = getAnnotatedTypeWrapper(rhsTree); + AnnotatedTypeWrapper lhsTypeWrapper = getAnnotatedTypeWrapper(lhsTree); + AnnotatedTypeWrapper rhsTypeWrapper = getAnnotatedTypeWrapper(rhsTree); - if (annotatedTypeWrapper == null) { - ParameterizedTypeTreeNullableArgIndices typeWrapper = - new ParameterizedTypeTreeNullableArgIndices(); - typeWrapper.checkAssignmentTypeMatch( - tree, - ASTHelpers.getType(lhsTree), - (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier()); - } else { - annotatedTypeWrapper.checkAssignmentTypeMatch( - tree, ASTHelpers.getType(lhsTree), ASTHelpers.getType(rhsTree)); - } + checkIdenticalWrappers(lhsTypeWrapper, rhsTypeWrapper); } - private @Nullable AnnotatedTypeWrapper getAnnotatedTypeWrapper(Tree rhsTree) { - if (rhsTree instanceof NewClassTree - && ((NewClassTree) rhsTree).getIdentifier() instanceof ParameterizedTypeTree) { + private @Nullable AnnotatedTypeWrapper getAnnotatedTypeWrapper(Tree tree) { + if (tree instanceof NewClassTree + && ((NewClassTree) tree).getIdentifier() instanceof ParameterizedTypeTree) { return null; } else { - return new AnnotatedTypeWrapper() { + return getNormalTypeAnnotatedWrapper(ASTHelpers.getType(tree)); + } + } - @Override - public Type getWrapped() { - return null; - } + private AnnotatedTypeWrapper getNormalTypeAnnotatedWrapper(Type type) { + return new AnnotatedTypeWrapper() { + Type wrappedObject = type; + + @Override + public Type getWrapped() { + return wrappedObject; + } - @Override - public HashSet getNullableTypeArgIndices(Type type) { - HashSet nullableTypeArgIndices = new HashSet(); - List typeArguments = type.getTypeArguments(); - for (int index = 0; index < typeArguments.size(); index++) { - com.sun.tools.javac.util.List annotationMirrors = - typeArguments.get(index).getAnnotationMirrors(); - boolean hasNullableAnnotation = - Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - if (hasNullableAnnotation) { - nullableTypeArgIndices.add(index); - } + @Override + public HashSet getNullableTypeArgIndices() { + HashSet nullableTypeArgIndices = new HashSet(); + List typeArguments = type.getTypeArguments(); + for (int index = 0; index < typeArguments.size(); index++) { + com.sun.tools.javac.util.List annotationMirrors = + typeArguments.get(index).getAnnotationMirrors(); + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + if (hasNullableAnnotation) { + nullableTypeArgIndices.add(index); } - return nullableTypeArgIndices; } + return nullableTypeArgIndices; + } - @Override - public void checkAssignmentTypeMatch(Tree tree, Type lhs, Type rhs) { - // if lhs and rhs are not of the same type check for the super types first - if (!ASTHelpers.isSameType(lhs, rhs, state) && !rhs.toString().equals("null")) { - if (lhs instanceof Type.ClassType && rhs instanceof Type.ClassType) { - rhs = - GenericsChecks.supertypeMatchingLHS( - (Type.ClassType) lhs, (Type.ClassType) rhs, state); - } - } - HashSet lhsNullableArgIndices = getNullableTypeArgIndices(lhs); - HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs); + @Override + public List getWrappersForNestedTypes() { + List wrappersForNestedTypes = new ArrayList(); + List typeArguments = wrappedObject.getTypeArguments(); - if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { - GenericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); - return; + for (int i = 0; i < typeArguments.size(); i++) { + // nested generics + if (typeArguments.get(i).getTypeArguments().length() > 0) { + wrappersForNestedTypes.add(getNormalTypeAnnotatedWrapper(typeArguments.get(i))); } else { - List lhsTypeArgs = lhs.getTypeArguments(); - List rhsTypeArgs = rhs.getTypeArguments(); - // if an error is not already generated check for nested types - for (int i = 0; i < lhsTypeArgs.size(); i++) { - // nested generics - if (lhsTypeArgs.get(i).getTypeArguments().length() > 0) { - if (rhsTypeArgs.size() > i) { - checkAssignmentTypeMatch(tree, lhsTypeArgs.get(i), rhsTypeArgs.get(i)); - } - } - } + wrappersForNestedTypes.add(null); } } - }; - } + return wrappersForNestedTypes; + } + }; } - class ParameterizedTypeTreeNullableArgIndices - implements AnnotatedTypeWrapper { - - @Override - public Type getWrapped() { - return null; + public void checkIdenticalWrappers( + AnnotatedTypeWrapper lhsWrapper, AnnotatedTypeWrapper rhsWrapper) { + if (lhsWrapper == null || rhsWrapper == null) { + return; } - - @SuppressWarnings("UnusedVariable") - @Override - public HashSet getNullableTypeArgIndices(ParameterizedTypeTree tree) { - List typeArguments = tree.getTypeArguments(); - HashSet nullableTypeArgIndices = new HashSet(); - for (int i = 0; i < typeArguments.size(); i++) { - if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { - JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); - for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { - Attribute.Compound attribute = annotation.attribute; - if (attribute.toString().equals("@org.jspecify.annotations.Nullable")) { - nullableTypeArgIndices.add(i); - break; - } - } - } + Type lhs = lhsWrapper.getWrapped(); + Type rhs = rhsWrapper.getWrapped(); + + // if types don't match check for super types matching the lhs type + if (!ASTHelpers.isSameType(lhsWrapper.getWrapped(), rhsWrapper.getWrapped(), state)) { + if (lhs instanceof Type.ClassType && rhs instanceof Type.ClassType) { + Type rhsSuperTypeMatchingLHSType = + supertypeMatchingLHS( + (Type.ClassType) lhsWrapper.getWrapped(), + (Type.ClassType) rhsWrapper.getWrapped(), + state); + rhsWrapper = getNormalTypeAnnotatedWrapper(rhsSuperTypeMatchingLHSType); } - return nullableTypeArgIndices; } - public void superTypeMatchingRHSParameterizedTypeTree( - Tree tree, ParameterizedTypeTree rhs, Type lhs) { - if (lhs instanceof Type.ClassType && ASTHelpers.getType(rhs) instanceof Type.ClassType) { - Type rhsType = - GenericsChecks.supertypeMatchingLHS( - (Type.ClassType) lhs, (Type.ClassType) ASTHelpers.getType(rhs), state); - NormalTypeTreeNullableTypeArgIndices typeWrapper = - new NormalTypeTreeNullableTypeArgIndices(); - typeWrapper.checkAssignmentTypeMatch(tree, lhs, rhsType); - } - } + // check for the same nullable type argument indices + HashSet lhsNullableTypeArgIndices = lhsWrapper.getNullableTypeArgIndices(); + HashSet rhsNullableTypeArgIndices = rhsWrapper.getNullableTypeArgIndices(); - @Override - public void checkAssignmentTypeMatch(Tree tree, Type lhs, ParameterizedTypeTree rhs) { - // if types are not same check for the super types - if (!ASTHelpers.isSameType(lhs, ASTHelpers.getType(rhs), state)) { - superTypeMatchingRHSParameterizedTypeTree(tree, rhs, lhs); - } - NormalTypeTreeNullableTypeArgIndices normalTypeTreeNullableTypeArgIndices = - new NormalTypeTreeNullableTypeArgIndices(); - HashSet lhsNullableArgIndices = - normalTypeTreeNullableTypeArgIndices.getNullableTypeArgIndices(lhs); - HashSet rhsNullableArgIndices = getNullableTypeArgIndices(rhs); - if (!lhsNullableArgIndices.equals(rhsNullableArgIndices)) { - GenericsChecks.invalidInstantiationError(tree, lhs.baseType(), lhs, state, analysis); - return; - } else { - // check for nested types if an error is not already generated - List rhsTypeArguments = rhs.getTypeArguments(); - List lhsTypeArguments = lhs.getTypeArguments(); + if (!lhsNullableTypeArgIndices.equals(rhsNullableTypeArgIndices)) { + // generate an error + } else { + // check for the nested types if and only if the error has not already been generated + List lhsNestedTypeWrappers = lhsWrapper.getWrappersForNestedTypes(); + List rhsNestedTypeWrappers = rhsWrapper.getWrappersForNestedTypes(); - for (int i = 0; i < rhsTypeArguments.size(); i++) { - if (rhsTypeArguments.get(i).getClass().equals(JCTree.JCTypeApply.class)) { - ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = - (ParameterizedTypeTree) rhsTypeArguments.get(i); - Type argumentType = ASTHelpers.getType(parameterizedTypeTreeForTypeArgument); - if (argumentType != null - && argumentType.getTypeArguments() != null - && argumentType.getTypeArguments().length() > 0) { // Nested generics - checkAssignmentTypeMatch( - tree, lhsTypeArguments.get(i), parameterizedTypeTreeForTypeArgument); - } - } - } + for (int i = 0; i < lhsNestedTypeWrappers.size(); i++) { + checkIdenticalWrappers(lhsNestedTypeWrappers.get(i), rhsNestedTypeWrappers.get(i)); } } } From c517b4bca57b4055986c31731e0915b0af0915e3 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 4 Jan 2023 10:46:58 +0530 Subject: [PATCH 104/184] Changes with parameterized typed tree without the error generation --- .../com/uber/nullaway/GenericsChecks.java | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 7222c05b77..c6cadd17c1 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -11,6 +11,7 @@ import com.sun.source.tree.VariableTree; import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.tree.JCTree; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -145,12 +146,66 @@ public void checkInstantiationForAssignments(Tree tree) { private @Nullable AnnotatedTypeWrapper getAnnotatedTypeWrapper(Tree tree) { if (tree instanceof NewClassTree && ((NewClassTree) tree).getIdentifier() instanceof ParameterizedTypeTree) { - return null; + return getParameterizedTypeAnnotatedWrapper((ParameterizedTypeTree) tree); } else { return getNormalTypeAnnotatedWrapper(ASTHelpers.getType(tree)); } } + private AnnotatedTypeWrapper getParameterizedTypeAnnotatedWrapper(ParameterizedTypeTree tree) { + return new AnnotatedTypeWrapper() { + Type wrappedObject = ASTHelpers.getType(tree); + + @Override + public Type getWrapped() { + return wrappedObject; + } + + @Override + public HashSet getNullableTypeArgIndices() { + List typeArguments = tree.getTypeArguments(); + HashSet nullableTypeArgIndices = new HashSet(); + for (int i = 0; i < typeArguments.size(); i++) { + if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { + JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); + for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { + Attribute.Compound attribute = annotation.attribute; + if (attribute.toString().equals("@org.jspecify.annotations.Nullable")) { + nullableTypeArgIndices.add(i); + break; + } + } + } + } + return nullableTypeArgIndices; + } + + @Override + public List getWrappersForNestedTypes() { + List wrappersForNestedTypes = new ArrayList(); + List typeArguments = tree.getTypeArguments(); + + for (int i = 0; i < typeArguments.size(); i++) { + if (typeArguments.get(i).getClass().equals(JCTree.JCTypeApply.class)) { + ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = + (ParameterizedTypeTree) typeArguments.get(i); + Type argumentType = ASTHelpers.getType(parameterizedTypeTreeForTypeArgument); + if (argumentType != null + && argumentType.getTypeArguments() != null + && argumentType.getTypeArguments().length() > 0) { // Nested generics + wrappersForNestedTypes.add( + getParameterizedTypeAnnotatedWrapper( + (ParameterizedTypeTree) typeArguments.get(i))); + } else { + wrappersForNestedTypes.add(null); + } + } + } + return wrappersForNestedTypes; + } + }; + } + private AnnotatedTypeWrapper getNormalTypeAnnotatedWrapper(Type type) { return new AnnotatedTypeWrapper() { Type wrappedObject = type; From def7ce276c0f2c8b9f58d42ae89f7a4fbdb3df34 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 4 Jan 2023 11:00:50 +0530 Subject: [PATCH 105/184] suggested changes with two test cases failing --- .../java/com/uber/nullaway/GenericsChecks.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index c6cadd17c1..2f67b40a72 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -140,13 +140,14 @@ public void checkInstantiationForAssignments(Tree tree) { AnnotatedTypeWrapper lhsTypeWrapper = getAnnotatedTypeWrapper(lhsTree); AnnotatedTypeWrapper rhsTypeWrapper = getAnnotatedTypeWrapper(rhsTree); - checkIdenticalWrappers(lhsTypeWrapper, rhsTypeWrapper); + checkIdenticalWrappers(tree, lhsTypeWrapper, rhsTypeWrapper); } private @Nullable AnnotatedTypeWrapper getAnnotatedTypeWrapper(Tree tree) { if (tree instanceof NewClassTree && ((NewClassTree) tree).getIdentifier() instanceof ParameterizedTypeTree) { - return getParameterizedTypeAnnotatedWrapper((ParameterizedTypeTree) tree); + return getParameterizedTypeAnnotatedWrapper( + (ParameterizedTypeTree) ((NewClassTree) tree).getIdentifier()); } else { return getNormalTypeAnnotatedWrapper(ASTHelpers.getType(tree)); } @@ -250,7 +251,7 @@ public List getWrappersForNestedTypes() { } public void checkIdenticalWrappers( - AnnotatedTypeWrapper lhsWrapper, AnnotatedTypeWrapper rhsWrapper) { + Tree tree, AnnotatedTypeWrapper lhsWrapper, AnnotatedTypeWrapper rhsWrapper) { if (lhsWrapper == null || rhsWrapper == null) { return; } @@ -275,13 +276,16 @@ public void checkIdenticalWrappers( if (!lhsNullableTypeArgIndices.equals(rhsNullableTypeArgIndices)) { // generate an error + invalidInstantiationError(tree, lhs, rhs, state, analysis); } else { // check for the nested types if and only if the error has not already been generated List lhsNestedTypeWrappers = lhsWrapper.getWrappersForNestedTypes(); List rhsNestedTypeWrappers = rhsWrapper.getWrappersForNestedTypes(); - + if (lhsNestedTypeWrappers.size() != rhsNestedTypeWrappers.size()) { + return; + } for (int i = 0; i < lhsNestedTypeWrappers.size(); i++) { - checkIdenticalWrappers(lhsNestedTypeWrappers.get(i), rhsNestedTypeWrappers.get(i)); + checkIdenticalWrappers(tree, lhsNestedTypeWrappers.get(i), rhsNestedTypeWrappers.get(i)); } } } From 75f36df204c2b498deec9160d3698f18cd3ccbff Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 4 Jan 2023 11:36:46 +0530 Subject: [PATCH 106/184] suggested changes with all passing tests --- .../java/com/uber/nullaway/GenericsChecks.java | 17 +++++++++++++++-- .../nullaway/NullAwayJSpecifyGenericsTests.java | 4 ---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 2f67b40a72..c4ff8faa56 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -17,7 +17,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import javax.annotation.Nullable; /** Methods for performing checks related to generic types and nullability. */ public final class GenericsChecks { @@ -143,7 +142,7 @@ public void checkInstantiationForAssignments(Tree tree) { checkIdenticalWrappers(tree, lhsTypeWrapper, rhsTypeWrapper); } - private @Nullable AnnotatedTypeWrapper getAnnotatedTypeWrapper(Tree tree) { + private AnnotatedTypeWrapper getAnnotatedTypeWrapper(Tree tree) { if (tree instanceof NewClassTree && ((NewClassTree) tree).getIdentifier() instanceof ParameterizedTypeTree) { return getParameterizedTypeAnnotatedWrapper( @@ -252,12 +251,14 @@ public List getWrappersForNestedTypes() { public void checkIdenticalWrappers( Tree tree, AnnotatedTypeWrapper lhsWrapper, AnnotatedTypeWrapper rhsWrapper) { + // non-nested typed wrappers if (lhsWrapper == null || rhsWrapper == null) { return; } Type lhs = lhsWrapper.getWrapped(); Type rhs = rhsWrapper.getWrapped(); + AnnotatedTypeWrapper prevOriginalRHSWrapper = rhsWrapper; // if types don't match check for super types matching the lhs type if (!ASTHelpers.isSameType(lhsWrapper.getWrapped(), rhsWrapper.getWrapped(), state)) { if (lhs instanceof Type.ClassType && rhs instanceof Type.ClassType) { @@ -288,5 +289,17 @@ public void checkIdenticalWrappers( checkIdenticalWrappers(tree, lhsNestedTypeWrappers.get(i), rhsNestedTypeWrappers.get(i)); } } + + // for new class trees need to check everything with original rhsType wrapper. Need to find a + // better way to do this + List lhsNestedTypeWrappers = lhsWrapper.getWrappersForNestedTypes(); + List rhsNestedTypeWrappers = + prevOriginalRHSWrapper.getWrappersForNestedTypes(); + if (lhsNestedTypeWrappers.size() != rhsNestedTypeWrappers.size()) { + return; + } + for (int i = 0; i < lhsNestedTypeWrappers.size(); i++) { + checkIdenticalWrappers(tree, lhsNestedTypeWrappers.get(i), rhsNestedTypeWrappers.get(i)); + } } } diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 9e9013a338..9e55b82430 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -323,10 +323,6 @@ public void NestedAssignmentChecks() { " // BUG: Diagnostic contains: Generic type parameter", " f = new C>();", " }", - " void sampleError2() {", - " // BUG: Diagnostic contains: Generic type parameter", - " D> f = new B>();", - " }", " }") .doTest(); } From 01256473275a95d9c4a7aea94cea95d17dc8502d Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 4 Jan 2023 11:45:41 +0530 Subject: [PATCH 107/184] All working changes --- .../uber/nullaway/AnnotatedTypeWrapper.java | 2 ++ .../com/uber/nullaway/GenericsChecks.java | 29 ++++++++++++++----- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java index ee6553c511..4d9ee30187 100644 --- a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java +++ b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java @@ -10,4 +10,6 @@ public interface AnnotatedTypeWrapper { public HashSet getNullableTypeArgIndices(); public List getWrappersForNestedTypes(); + + public boolean isParameterizedTypedWrapper(); } diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index c4ff8faa56..852758ad4e 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -203,6 +203,11 @@ public List getWrappersForNestedTypes() { } return wrappersForNestedTypes; } + + @Override + public boolean isParameterizedTypedWrapper() { + return true; + } }; } @@ -246,6 +251,11 @@ public List getWrappersForNestedTypes() { } return wrappersForNestedTypes; } + + @Override + public boolean isParameterizedTypedWrapper() { + return false; + } }; } @@ -278,6 +288,7 @@ public void checkIdenticalWrappers( if (!lhsNullableTypeArgIndices.equals(rhsNullableTypeArgIndices)) { // generate an error invalidInstantiationError(tree, lhs, rhs, state, analysis); + return; } else { // check for the nested types if and only if the error has not already been generated List lhsNestedTypeWrappers = lhsWrapper.getWrappersForNestedTypes(); @@ -292,14 +303,16 @@ public void checkIdenticalWrappers( // for new class trees need to check everything with original rhsType wrapper. Need to find a // better way to do this - List lhsNestedTypeWrappers = lhsWrapper.getWrappersForNestedTypes(); - List rhsNestedTypeWrappers = - prevOriginalRHSWrapper.getWrappersForNestedTypes(); - if (lhsNestedTypeWrappers.size() != rhsNestedTypeWrappers.size()) { - return; - } - for (int i = 0; i < lhsNestedTypeWrappers.size(); i++) { - checkIdenticalWrappers(tree, lhsNestedTypeWrappers.get(i), rhsNestedTypeWrappers.get(i)); + if (prevOriginalRHSWrapper.isParameterizedTypedWrapper()) { + List lhsNestedTypeWrappers = lhsWrapper.getWrappersForNestedTypes(); + List rhsNestedTypeWrappers = + prevOriginalRHSWrapper.getWrappersForNestedTypes(); + if (lhsNestedTypeWrappers.size() != rhsNestedTypeWrappers.size()) { + return; + } + for (int i = 0; i < lhsNestedTypeWrappers.size(); i++) { + checkIdenticalWrappers(tree, lhsNestedTypeWrappers.get(i), rhsNestedTypeWrappers.get(i)); + } } } } From 8fc5d18375cf1be2ab2bbc6936697460cfe448d1 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 4 Jan 2023 12:08:17 +0530 Subject: [PATCH 108/184] Continuous integration working --- .../com/uber/nullaway/AnnotatedTypeWrapper.java | 2 ++ .../java/com/uber/nullaway/GenericsChecks.java | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java index 4d9ee30187..9c02b4862d 100644 --- a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java +++ b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java @@ -12,4 +12,6 @@ public interface AnnotatedTypeWrapper { public List getWrappersForNestedTypes(); public boolean isParameterizedTypedWrapper(); + + public boolean isGenericTypedWrapper(); } diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 852758ad4e..f39eaf16ee 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -208,6 +208,11 @@ public List getWrappersForNestedTypes() { public boolean isParameterizedTypedWrapper() { return true; } + + @Override + public boolean isGenericTypedWrapper() { + return tree.getTypeArguments().size() > 0; + } }; } @@ -256,13 +261,21 @@ public List getWrappersForNestedTypes() { public boolean isParameterizedTypedWrapper() { return false; } + + @Override + public boolean isGenericTypedWrapper() { + return type.getTypeArguments().length() > 0; + } }; } public void checkIdenticalWrappers( Tree tree, AnnotatedTypeWrapper lhsWrapper, AnnotatedTypeWrapper rhsWrapper) { // non-nested typed wrappers - if (lhsWrapper == null || rhsWrapper == null) { + if (lhsWrapper == null + || rhsWrapper == null + || !lhsWrapper.isGenericTypedWrapper() + || !rhsWrapper.isGenericTypedWrapper()) { return; } Type lhs = lhsWrapper.getWrapped(); From 090ac0ca3a4a22de7f5d062a963e68fac250de9e Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 4 Jan 2023 12:29:37 +0530 Subject: [PATCH 109/184] Continuous integration working --- .../uber/nullaway/AnnotatedTypeWrapper.java | 2 -- .../com/uber/nullaway/GenericsChecks.java | 24 ++++++++----------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java index 9c02b4862d..4d9ee30187 100644 --- a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java +++ b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java @@ -12,6 +12,4 @@ public interface AnnotatedTypeWrapper { public List getWrappersForNestedTypes(); public boolean isParameterizedTypedWrapper(); - - public boolean isGenericTypedWrapper(); } diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index f39eaf16ee..6538e9388c 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -135,6 +135,15 @@ public void checkInstantiationForAssignments(Tree tree) { // Possible for VariableTrees with no initializer return; } + // check assignment instantiation only for the generics + if (rhsTree instanceof NewClassTree + && ((NewClassTree) rhsTree).getIdentifier() instanceof ParameterizedTypeTree) { + ParameterizedTypeTree paramTypedTree = + (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier(); + if (paramTypedTree.getTypeArguments().size() <= 0) { + return; + } + } AnnotatedTypeWrapper lhsTypeWrapper = getAnnotatedTypeWrapper(lhsTree); AnnotatedTypeWrapper rhsTypeWrapper = getAnnotatedTypeWrapper(rhsTree); @@ -208,11 +217,6 @@ public List getWrappersForNestedTypes() { public boolean isParameterizedTypedWrapper() { return true; } - - @Override - public boolean isGenericTypedWrapper() { - return tree.getTypeArguments().size() > 0; - } }; } @@ -261,21 +265,13 @@ public List getWrappersForNestedTypes() { public boolean isParameterizedTypedWrapper() { return false; } - - @Override - public boolean isGenericTypedWrapper() { - return type.getTypeArguments().length() > 0; - } }; } public void checkIdenticalWrappers( Tree tree, AnnotatedTypeWrapper lhsWrapper, AnnotatedTypeWrapper rhsWrapper) { // non-nested typed wrappers - if (lhsWrapper == null - || rhsWrapper == null - || !lhsWrapper.isGenericTypedWrapper() - || !rhsWrapper.isGenericTypedWrapper()) { + if (lhsWrapper == null || rhsWrapper == null) { return; } Type lhs = lhsWrapper.getWrapped(); From ba6b2295244ef1e4c9953df92f9a441c28061c8a Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 4 Jan 2023 13:41:42 +0530 Subject: [PATCH 110/184] changes --- .../java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 9e55b82430..57ac508ef8 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -335,7 +335,6 @@ public void NestedVariableDeclarationChecks() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " class A{}", " class D

{}", " class B

extends D

{}", " class C

{}", From bd6700f1ff44ed4cda65e0476036321e0c640c78 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 4 Jan 2023 13:42:03 +0530 Subject: [PATCH 111/184] minor changes From fd0b0969826350fb10c208e603767b63eb2518ca Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 4 Jan 2023 12:19:59 -0800 Subject: [PATCH 112/184] fix naming case --- .../java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 57ac508ef8..589cadf75f 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -308,7 +308,7 @@ public void superTypeAssignmentChecksMultipleLevelInheritance() { } @Test - public void NestedAssignmentChecks() { + public void nestedAssignmentChecks() { makeHelper() .addSourceLines( "Test.java", @@ -328,7 +328,7 @@ public void NestedAssignmentChecks() { } @Test - public void NestedVariableDeclarationChecks() { + public void nestedVariableDeclarationChecks() { makeHelper() .addSourceLines( "Test.java", From d5f34f217ad9ac6fb3a647c837b870b0b26f1fe6 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 4 Jan 2023 12:22:06 -0800 Subject: [PATCH 113/184] failing test --- .../NullAwayJSpecifyGenericsTests.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 589cadf75f..131eaf67af 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -327,6 +327,24 @@ public void nestedAssignmentChecks() { .doTest(); } + @Test + public void subtypeWithParameters() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.annotations.Nullable;", + "class Test {", + " class D

{}", + " class B

extends D

{}", + " void test1() {", + " // BUG: Diagnostic contains: Generic type parameter", + " D f = new B<@Nullable String>();", + " }", + " }") + .doTest(); + } + @Test public void nestedVariableDeclarationChecks() { makeHelper() From 01c550352414c4a93c2856062366517d0780bd04 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 4 Jan 2023 15:17:15 -0800 Subject: [PATCH 114/184] refactoring and comments --- .../uber/nullaway/AnnotatedTypeWrapper.java | 14 +- .../com/uber/nullaway/GenericsChecks.java | 238 ++++++++++-------- 2 files changed, 137 insertions(+), 115 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java index 4d9ee30187..42f3576c45 100644 --- a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java +++ b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java @@ -1,15 +1,19 @@ package com.uber.nullaway; import com.sun.tools.javac.code.Type; -import java.util.HashSet; import java.util.List; +import java.util.Set; public interface AnnotatedTypeWrapper { - public Type getWrapped(); + Type getWrapped(); - public HashSet getNullableTypeArgIndices(); + Set getNullableTypeArgIndices(); - public List getWrappersForNestedTypes(); + List getWrappersForNestedTypes(); - public boolean isParameterizedTypedWrapper(); + /** + * This method should return a new AnnotatedTypeWrapper that is a view of this as some supertype. + * Critically, the nullable type arg indices should still be correct. + */ + AnnotatedTypeWrapper asSupertype(Type.ClassType superType); } diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 6538e9388c..eb274080c8 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -17,6 +17,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; /** Methods for performing checks related to generic types and nullability. */ public final class GenericsChecks { @@ -162,110 +163,11 @@ private AnnotatedTypeWrapper getAnnotatedTypeWrapper(Tree tree) { } private AnnotatedTypeWrapper getParameterizedTypeAnnotatedWrapper(ParameterizedTypeTree tree) { - return new AnnotatedTypeWrapper() { - Type wrappedObject = ASTHelpers.getType(tree); - - @Override - public Type getWrapped() { - return wrappedObject; - } - - @Override - public HashSet getNullableTypeArgIndices() { - List typeArguments = tree.getTypeArguments(); - HashSet nullableTypeArgIndices = new HashSet(); - for (int i = 0; i < typeArguments.size(); i++) { - if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { - JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); - for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { - Attribute.Compound attribute = annotation.attribute; - if (attribute.toString().equals("@org.jspecify.annotations.Nullable")) { - nullableTypeArgIndices.add(i); - break; - } - } - } - } - return nullableTypeArgIndices; - } - - @Override - public List getWrappersForNestedTypes() { - List wrappersForNestedTypes = new ArrayList(); - List typeArguments = tree.getTypeArguments(); - - for (int i = 0; i < typeArguments.size(); i++) { - if (typeArguments.get(i).getClass().equals(JCTree.JCTypeApply.class)) { - ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = - (ParameterizedTypeTree) typeArguments.get(i); - Type argumentType = ASTHelpers.getType(parameterizedTypeTreeForTypeArgument); - if (argumentType != null - && argumentType.getTypeArguments() != null - && argumentType.getTypeArguments().length() > 0) { // Nested generics - wrappersForNestedTypes.add( - getParameterizedTypeAnnotatedWrapper( - (ParameterizedTypeTree) typeArguments.get(i))); - } else { - wrappersForNestedTypes.add(null); - } - } - } - return wrappersForNestedTypes; - } - - @Override - public boolean isParameterizedTypedWrapper() { - return true; - } - }; + return new ParameterizedTypeTreeWrapper(tree); } private AnnotatedTypeWrapper getNormalTypeAnnotatedWrapper(Type type) { - return new AnnotatedTypeWrapper() { - Type wrappedObject = type; - - @Override - public Type getWrapped() { - return wrappedObject; - } - - @Override - public HashSet getNullableTypeArgIndices() { - HashSet nullableTypeArgIndices = new HashSet(); - List typeArguments = type.getTypeArguments(); - for (int index = 0; index < typeArguments.size(); index++) { - com.sun.tools.javac.util.List annotationMirrors = - typeArguments.get(index).getAnnotationMirrors(); - boolean hasNullableAnnotation = - Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - if (hasNullableAnnotation) { - nullableTypeArgIndices.add(index); - } - } - return nullableTypeArgIndices; - } - - @Override - public List getWrappersForNestedTypes() { - List wrappersForNestedTypes = new ArrayList(); - List typeArguments = wrappedObject.getTypeArguments(); - - for (int i = 0; i < typeArguments.size(); i++) { - // nested generics - if (typeArguments.get(i).getTypeArguments().length() > 0) { - wrappersForNestedTypes.add(getNormalTypeAnnotatedWrapper(typeArguments.get(i))); - } else { - wrappersForNestedTypes.add(null); - } - } - return wrappersForNestedTypes; - } - - @Override - public boolean isParameterizedTypedWrapper() { - return false; - } - }; + return new NormalTypeWrapper(type); } public void checkIdenticalWrappers( @@ -281,18 +183,18 @@ public void checkIdenticalWrappers( // if types don't match check for super types matching the lhs type if (!ASTHelpers.isSameType(lhsWrapper.getWrapped(), rhsWrapper.getWrapped(), state)) { if (lhs instanceof Type.ClassType && rhs instanceof Type.ClassType) { - Type rhsSuperTypeMatchingLHSType = - supertypeMatchingLHS( - (Type.ClassType) lhsWrapper.getWrapped(), - (Type.ClassType) rhsWrapper.getWrapped(), - state); - rhsWrapper = getNormalTypeAnnotatedWrapper(rhsSuperTypeMatchingLHSType); + // Type rhsSuperTypeMatchingLHSType = + // supertypeMatchingLHS( + // (Type.ClassType) lhsWrapper.getWrapped(), + // (Type.ClassType) rhsWrapper.getWrapped(), + // state); + rhsWrapper = rhsWrapper.asSupertype((Type.ClassType) lhs); } } // check for the same nullable type argument indices - HashSet lhsNullableTypeArgIndices = lhsWrapper.getNullableTypeArgIndices(); - HashSet rhsNullableTypeArgIndices = rhsWrapper.getNullableTypeArgIndices(); + Set lhsNullableTypeArgIndices = lhsWrapper.getNullableTypeArgIndices(); + Set rhsNullableTypeArgIndices = rhsWrapper.getNullableTypeArgIndices(); if (!lhsNullableTypeArgIndices.equals(rhsNullableTypeArgIndices)) { // generate an error @@ -312,7 +214,8 @@ public void checkIdenticalWrappers( // for new class trees need to check everything with original rhsType wrapper. Need to find a // better way to do this - if (prevOriginalRHSWrapper.isParameterizedTypedWrapper()) { + // TODO yes this logic is not right and we should fix + if (prevOriginalRHSWrapper instanceof ParameterizedTypeTreeWrapper) { List lhsNestedTypeWrappers = lhsWrapper.getWrappersForNestedTypes(); List rhsNestedTypeWrappers = prevOriginalRHSWrapper.getWrappersForNestedTypes(); @@ -324,4 +227,119 @@ public void checkIdenticalWrappers( } } } + + private class NormalTypeWrapper implements AnnotatedTypeWrapper { + private final Type type; + + public NormalTypeWrapper(Type type) { + this.type = type; + } + + @Override + public Type getWrapped() { + return type; + } + + @Override + public Set getNullableTypeArgIndices() { + HashSet nullableTypeArgIndices = new HashSet<>(); + List typeArguments = type.getTypeArguments(); + for (int index = 0; index < typeArguments.size(); index++) { + com.sun.tools.javac.util.List annotationMirrors = + typeArguments.get(index).getAnnotationMirrors(); + boolean hasNullableAnnotation = + Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); + if (hasNullableAnnotation) { + nullableTypeArgIndices.add(index); + } + } + return nullableTypeArgIndices; + } + + @Override + public List getWrappersForNestedTypes() { + List wrappersForNestedTypes = new ArrayList<>(); + List typeArguments = type.getTypeArguments(); + + for (int i = 0; i < typeArguments.size(); i++) { + // nested generics + if (typeArguments.get(i).getTypeArguments().length() > 0) { + wrappersForNestedTypes.add(new NormalTypeWrapper(typeArguments.get(i))); + } else { + wrappersForNestedTypes.add(null); + } + } + return wrappersForNestedTypes; + } + + @Override + public AnnotatedTypeWrapper asSupertype(Type.ClassType lhsType) { + Type matchingSuperType = supertypeMatchingLHS(lhsType, (Type.ClassType) type, state); + return new NormalTypeWrapper(matchingSuperType); + } + } + + private class ParameterizedTypeTreeWrapper implements AnnotatedTypeWrapper { + private final ParameterizedTypeTree tree; + Type type; + + public ParameterizedTypeTreeWrapper(ParameterizedTypeTree tree) { + this.tree = tree; + type = ASTHelpers.getType(tree); + } + + @Override + public Type getWrapped() { + return type; + } + + @Override + public Set getNullableTypeArgIndices() { + List typeArguments = tree.getTypeArguments(); + HashSet nullableTypeArgIndices = new HashSet(); + for (int i = 0; i < typeArguments.size(); i++) { + if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { + JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); + for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { + Attribute.Compound attribute = annotation.attribute; + if (attribute.toString().equals("@org.jspecify.annotations.Nullable")) { + nullableTypeArgIndices.add(i); + break; + } + } + } + } + return nullableTypeArgIndices; + } + + @Override + public List getWrappersForNestedTypes() { + List wrappersForNestedTypes = new ArrayList(); + List typeArguments = tree.getTypeArguments(); + + for (int i = 0; i < typeArguments.size(); i++) { + if (typeArguments.get(i).getClass().equals(JCTree.JCTypeApply.class)) { + ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = + (ParameterizedTypeTree) typeArguments.get(i); + Type argumentType = ASTHelpers.getType(parameterizedTypeTreeForTypeArgument); + if (argumentType != null + && argumentType.getTypeArguments() != null + && argumentType.getTypeArguments().length() > 0) { // Nested generics + wrappersForNestedTypes.add( + new ParameterizedTypeTreeWrapper((ParameterizedTypeTree) typeArguments.get(i))); + } else { + wrappersForNestedTypes.add(null); + } + } + } + return wrappersForNestedTypes; + } + + @Override + public AnnotatedTypeWrapper asSupertype(Type.ClassType lhsType) { + // TODO this logic is incorrect for some cases; see subtypeWithParameters test + Type matchingSuperType = supertypeMatchingLHS(lhsType, (Type.ClassType) type, state); + return new NormalTypeWrapper(matchingSuperType); + } + } } From 25599ddcbfda45863d9a46ac77234950c69eecc7 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 4 Jan 2023 15:26:43 -0800 Subject: [PATCH 115/184] add a case --- .../java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 131eaf67af..34675d940c 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -341,6 +341,10 @@ public void subtypeWithParameters() { " // BUG: Diagnostic contains: Generic type parameter", " D f = new B<@Nullable String>();", " }", + " void test2(B<@Nullable String> b) {", + " // BUG: Diagnostic contains: Generic type parameter", + " D f = b;", + " }", " }") .doTest(); } From bf8084839fb7afa8018b8d1f3c7a2d18aabe0435 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 6 Jan 2023 21:37:41 +0530 Subject: [PATCH 116/184] working code with class type --- .../uber/nullaway/AnnotatedTypeWrapper.java | 19 -- .../com/uber/nullaway/GenericsChecks.java | 247 +++++------------- 2 files changed, 69 insertions(+), 197 deletions(-) delete mode 100644 nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java diff --git a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java b/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java deleted file mode 100644 index 42f3576c45..0000000000 --- a/nullaway/src/main/java/com/uber/nullaway/AnnotatedTypeWrapper.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.uber.nullaway; - -import com.sun.tools.javac.code.Type; -import java.util.List; -import java.util.Set; - -public interface AnnotatedTypeWrapper { - Type getWrapped(); - - Set getNullableTypeArgIndices(); - - List getWrappersForNestedTypes(); - - /** - * This method should return a new AnnotatedTypeWrapper that is a view of this as some supertype. - * Critically, the nullable type arg indices should still be correct. - */ - AnnotatedTypeWrapper asSupertype(Type.ClassType superType); -} diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index eb274080c8..439a7d6bf7 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -1,6 +1,8 @@ package com.uber.nullaway; import com.google.errorprone.VisitorState; +import com.google.errorprone.suppliers.Supplier; +import com.google.errorprone.suppliers.Suppliers; import com.google.errorprone.util.ASTHelpers; import com.sun.source.tree.AnnotatedTypeTree; import com.sun.source.tree.AnnotationTree; @@ -11,16 +13,20 @@ import com.sun.source.tree.VariableTree; import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.TypeMetadata; import com.sun.tools.javac.tree.JCTree; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; /** Methods for performing checks related to generic types and nullability. */ public final class GenericsChecks { + + private static final String NULLABLE_NAME = "org.jspecify.annotations.Nullable"; + + private static final Supplier NULLABLE_TYPE_SUPPLIER = + Suppliers.typeFromString(NULLABLE_NAME); VisitorState state; Config config; NullAway analysis; @@ -136,210 +142,95 @@ public void checkInstantiationForAssignments(Tree tree) { // Possible for VariableTrees with no initializer return; } - // check assignment instantiation only for the generics + Type lhsType = ASTHelpers.getType(lhsTree); + Type rhsType = ASTHelpers.getType(rhsTree); if (rhsTree instanceof NewClassTree && ((NewClassTree) rhsTree).getIdentifier() instanceof ParameterizedTypeTree) { + rhsType = messAround((ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier()); + ParameterizedTypeTree paramTypedTree = (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier(); + // not generic if (paramTypedTree.getTypeArguments().size() <= 0) { return; } } - - AnnotatedTypeWrapper lhsTypeWrapper = getAnnotatedTypeWrapper(lhsTree); - AnnotatedTypeWrapper rhsTypeWrapper = getAnnotatedTypeWrapper(rhsTree); - - checkIdenticalWrappers(tree, lhsTypeWrapper, rhsTypeWrapper); - } - - private AnnotatedTypeWrapper getAnnotatedTypeWrapper(Tree tree) { - if (tree instanceof NewClassTree - && ((NewClassTree) tree).getIdentifier() instanceof ParameterizedTypeTree) { - return getParameterizedTypeAnnotatedWrapper( - (ParameterizedTypeTree) ((NewClassTree) tree).getIdentifier()); - } else { - return getNormalTypeAnnotatedWrapper(ASTHelpers.getType(tree)); - } - } - - private AnnotatedTypeWrapper getParameterizedTypeAnnotatedWrapper(ParameterizedTypeTree tree) { - return new ParameterizedTypeTreeWrapper(tree); - } - - private AnnotatedTypeWrapper getNormalTypeAnnotatedWrapper(Type type) { - return new NormalTypeWrapper(type); + compareAnnotations(lhsType, rhsType, tree); } - public void checkIdenticalWrappers( - Tree tree, AnnotatedTypeWrapper lhsWrapper, AnnotatedTypeWrapper rhsWrapper) { - // non-nested typed wrappers - if (lhsWrapper == null || rhsWrapper == null) { - return; - } - Type lhs = lhsWrapper.getWrapped(); - Type rhs = rhsWrapper.getWrapped(); - - AnnotatedTypeWrapper prevOriginalRHSWrapper = rhsWrapper; - // if types don't match check for super types matching the lhs type - if (!ASTHelpers.isSameType(lhsWrapper.getWrapped(), rhsWrapper.getWrapped(), state)) { - if (lhs instanceof Type.ClassType && rhs instanceof Type.ClassType) { - // Type rhsSuperTypeMatchingLHSType = - // supertypeMatchingLHS( - // (Type.ClassType) lhsWrapper.getWrapped(), - // (Type.ClassType) rhsWrapper.getWrapped(), - // state); - rhsWrapper = rhsWrapper.asSupertype((Type.ClassType) lhs); + private void compareAnnotations(Type lhsType, Type rhsType, Tree tree) { + if (!ASTHelpers.isSameType(lhsType, rhsType, state)) { + if (lhsType instanceof Type.ClassType && rhsType instanceof Type.ClassType) { + rhsType = supertypeMatchingLHS((Type.ClassType) lhsType, (Type.ClassType) rhsType, state); } } - // check for the same nullable type argument indices - Set lhsNullableTypeArgIndices = lhsWrapper.getNullableTypeArgIndices(); - Set rhsNullableTypeArgIndices = rhsWrapper.getNullableTypeArgIndices(); + List lhsTypeArguments = lhsType.getTypeArguments(); + List rhsTypeArguments = rhsType.getTypeArguments(); - if (!lhsNullableTypeArgIndices.equals(rhsNullableTypeArgIndices)) { - // generate an error - invalidInstantiationError(tree, lhs, rhs, state, analysis); + // this error should already be generated by some other part of NullAway still adding a check to + // be safe + if (lhsTypeArguments.size() != rhsTypeArguments.size()) { return; - } else { - // check for the nested types if and only if the error has not already been generated - List lhsNestedTypeWrappers = lhsWrapper.getWrappersForNestedTypes(); - List rhsNestedTypeWrappers = rhsWrapper.getWrappersForNestedTypes(); - if (lhsNestedTypeWrappers.size() != rhsNestedTypeWrappers.size()) { - return; - } - for (int i = 0; i < lhsNestedTypeWrappers.size(); i++) { - checkIdenticalWrappers(tree, lhsNestedTypeWrappers.get(i), rhsNestedTypeWrappers.get(i)); - } } - // for new class trees need to check everything with original rhsType wrapper. Need to find a - // better way to do this - // TODO yes this logic is not right and we should fix - if (prevOriginalRHSWrapper instanceof ParameterizedTypeTreeWrapper) { - List lhsNestedTypeWrappers = lhsWrapper.getWrappersForNestedTypes(); - List rhsNestedTypeWrappers = - prevOriginalRHSWrapper.getWrappersForNestedTypes(); - if (lhsNestedTypeWrappers.size() != rhsNestedTypeWrappers.size()) { + for (int i = 0; i < lhsTypeArguments.size(); i++) { + com.sun.tools.javac.util.List annotationMirrorsLHS = + lhsTypeArguments.get(i).getAnnotationMirrors(); + com.sun.tools.javac.util.List annotationMirrorsRHS = + rhsTypeArguments.get(i).getAnnotationMirrors(); + boolean isLHSNullableAnnotated = + Nullness.hasNullableAnnotation(annotationMirrorsLHS.stream(), config); + boolean isRHSNullableAnnotated = + Nullness.hasNullableAnnotation(annotationMirrorsRHS.stream(), config); + if (isLHSNullableAnnotated != isRHSNullableAnnotated) { + invalidInstantiationError(tree, lhsType, lhsType.baseType(), state, analysis); return; } - for (int i = 0; i < lhsNestedTypeWrappers.size(); i++) { - checkIdenticalWrappers(tree, lhsNestedTypeWrappers.get(i), rhsNestedTypeWrappers.get(i)); - } - } - } - - private class NormalTypeWrapper implements AnnotatedTypeWrapper { - private final Type type; - - public NormalTypeWrapper(Type type) { - this.type = type; - } - - @Override - public Type getWrapped() { - return type; - } - - @Override - public Set getNullableTypeArgIndices() { - HashSet nullableTypeArgIndices = new HashSet<>(); - List typeArguments = type.getTypeArguments(); - for (int index = 0; index < typeArguments.size(); index++) { - com.sun.tools.javac.util.List annotationMirrors = - typeArguments.get(index).getAnnotationMirrors(); - boolean hasNullableAnnotation = - Nullness.hasNullableAnnotation(annotationMirrors.stream(), config); - if (hasNullableAnnotation) { - nullableTypeArgIndices.add(index); - } - } - return nullableTypeArgIndices; - } - - @Override - public List getWrappersForNestedTypes() { - List wrappersForNestedTypes = new ArrayList<>(); - List typeArguments = type.getTypeArguments(); - - for (int i = 0; i < typeArguments.size(); i++) { - // nested generics - if (typeArguments.get(i).getTypeArguments().length() > 0) { - wrappersForNestedTypes.add(new NormalTypeWrapper(typeArguments.get(i))); - } else { - wrappersForNestedTypes.add(null); - } + // nested generics + if (lhsTypeArguments.get(i).getTypeArguments().length() > 0) { + compareAnnotations(lhsTypeArguments.get(i), rhsTypeArguments.get(i), tree); } - return wrappersForNestedTypes; - } - - @Override - public AnnotatedTypeWrapper asSupertype(Type.ClassType lhsType) { - Type matchingSuperType = supertypeMatchingLHS(lhsType, (Type.ClassType) type, state); - return new NormalTypeWrapper(matchingSuperType); } } - private class ParameterizedTypeTreeWrapper implements AnnotatedTypeWrapper { - private final ParameterizedTypeTree tree; - Type type; - - public ParameterizedTypeTreeWrapper(ParameterizedTypeTree tree) { - this.tree = tree; - type = ASTHelpers.getType(tree); - } - - @Override - public Type getWrapped() { - return type; - } - - @Override - public Set getNullableTypeArgIndices() { - List typeArguments = tree.getTypeArguments(); - HashSet nullableTypeArgIndices = new HashSet(); - for (int i = 0; i < typeArguments.size(); i++) { - if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { - JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); - for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { - Attribute.Compound attribute = annotation.attribute; - if (attribute.toString().equals("@org.jspecify.annotations.Nullable")) { - nullableTypeArgIndices.add(i); - break; - } + private Type.ClassType messAround(ParameterizedTypeTree rhsTree) { + Type.ClassType type = (Type.ClassType) ASTHelpers.getType(rhsTree); + Type nullableType = NULLABLE_TYPE_SUPPLIER.get(state); + List typeArguments = rhsTree.getTypeArguments(); + List newTypeArgs = new ArrayList<>(); + for (int i = 0; i < typeArguments.size(); i++) { + List myAnnos = new ArrayList<>(); + if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { + JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); + for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { + Attribute.Compound attribute = annotation.attribute; + if (attribute.toString().equals("@org.jspecify.annotations.Nullable")) { + myAnnos.add( + new Attribute.TypeCompound( + nullableType, com.sun.tools.javac.util.List.nil(), null)); } } } - return nullableTypeArgIndices; - } - - @Override - public List getWrappersForNestedTypes() { - List wrappersForNestedTypes = new ArrayList(); - List typeArguments = tree.getTypeArguments(); - - for (int i = 0; i < typeArguments.size(); i++) { - if (typeArguments.get(i).getClass().equals(JCTree.JCTypeApply.class)) { - ParameterizedTypeTree parameterizedTypeTreeForTypeArgument = - (ParameterizedTypeTree) typeArguments.get(i); - Type argumentType = ASTHelpers.getType(parameterizedTypeTreeForTypeArgument); - if (argumentType != null - && argumentType.getTypeArguments() != null - && argumentType.getTypeArguments().length() > 0) { // Nested generics - wrappersForNestedTypes.add( - new ParameterizedTypeTreeWrapper((ParameterizedTypeTree) typeArguments.get(i))); - } else { - wrappersForNestedTypes.add(null); - } - } + // nested generics checks + Type currentArgType = ASTHelpers.getType(typeArguments.get(i)); + if (currentArgType.getTypeArguments().size() > 0) { + Type.ClassType nestedTyp = messAround((ParameterizedTypeTree) typeArguments.get(i)); + newTypeArgs.add(nestedTyp); + } else { + com.sun.tools.javac.util.List annos = + com.sun.tools.javac.util.List.from(myAnnos); + TypeMetadata md = new TypeMetadata(new TypeMetadata.Annotations(annos)); + Type arg = ASTHelpers.getType(typeArguments.get(i)); + Type.ClassType newArg = (Type.ClassType) arg.cloneWithMetadata(md); + newTypeArgs.add(newArg); } - return wrappersForNestedTypes; } + Type.ClassType finalType = + new Type.ClassType( + type.getEnclosingType(), com.sun.tools.javac.util.List.from(newTypeArgs), type.tsym); - @Override - public AnnotatedTypeWrapper asSupertype(Type.ClassType lhsType) { - // TODO this logic is incorrect for some cases; see subtypeWithParameters test - Type matchingSuperType = supertypeMatchingLHS(lhsType, (Type.ClassType) type, state); - return new NormalTypeWrapper(matchingSuperType); - } + System.err.println(finalType); + return finalType; } } From 8ca41d06d002d81a2c19a60599c19c56068b2000 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 6 Jan 2023 21:41:03 +0530 Subject: [PATCH 117/184] minor refactoring --- .../main/java/com/uber/nullaway/GenericsChecks.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 439a7d6bf7..d0aca17af9 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -146,7 +146,9 @@ public void checkInstantiationForAssignments(Tree tree) { Type rhsType = ASTHelpers.getType(rhsTree); if (rhsTree instanceof NewClassTree && ((NewClassTree) rhsTree).getIdentifier() instanceof ParameterizedTypeTree) { - rhsType = messAround((ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier()); + rhsType = + typeWithPreservedAnnotations( + (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier()); ParameterizedTypeTree paramTypedTree = (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier(); @@ -194,7 +196,7 @@ private void compareAnnotations(Type lhsType, Type rhsType, Tree tree) { } } - private Type.ClassType messAround(ParameterizedTypeTree rhsTree) { + private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree rhsTree) { Type.ClassType type = (Type.ClassType) ASTHelpers.getType(rhsTree); Type nullableType = NULLABLE_TYPE_SUPPLIER.get(state); List typeArguments = rhsTree.getTypeArguments(); @@ -215,7 +217,8 @@ private Type.ClassType messAround(ParameterizedTypeTree rhsTree) { // nested generics checks Type currentArgType = ASTHelpers.getType(typeArguments.get(i)); if (currentArgType.getTypeArguments().size() > 0) { - Type.ClassType nestedTyp = messAround((ParameterizedTypeTree) typeArguments.get(i)); + Type.ClassType nestedTyp = + typeWithPreservedAnnotations((ParameterizedTypeTree) typeArguments.get(i)); newTypeArgs.add(nestedTyp); } else { com.sun.tools.javac.util.List annos = @@ -229,8 +232,6 @@ private Type.ClassType messAround(ParameterizedTypeTree rhsTree) { Type.ClassType finalType = new Type.ClassType( type.getEnclosingType(), com.sun.tools.javac.util.List.from(newTypeArgs), type.tsym); - - System.err.println(finalType); return finalType; } } From 4a87b6c6d8f567ded029e543e1c6e0f4fc0d0972 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 6 Jan 2023 21:48:20 +0530 Subject: [PATCH 118/184] minor changes --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index d0aca17af9..9b69b8d127 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -125,7 +125,6 @@ static void invalidInstantiationError( errorMessage, analysis.buildDescription(tree), state, null)); } - @SuppressWarnings("UnusedVariable") public void checkInstantiationForAssignments(Tree tree) { Tree lhsTree; Tree rhsTree; @@ -146,6 +145,8 @@ public void checkInstantiationForAssignments(Tree tree) { Type rhsType = ASTHelpers.getType(rhsTree); if (rhsTree instanceof NewClassTree && ((NewClassTree) rhsTree).getIdentifier() instanceof ParameterizedTypeTree) { + // for the parameterized typed tree ASTHelpers.getType() returns a type that does not have + // annotations preserved rhsType = typeWithPreservedAnnotations( (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier()); From 44bea9b1f1f6bfb9e878a3e4ea858290bd69adba Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 6 Jan 2023 23:07:02 +0530 Subject: [PATCH 119/184] code cleaning --- .../main/java/com/uber/nullaway/GenericsChecks.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 9b69b8d127..52be9f73d8 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -167,16 +167,13 @@ private void compareAnnotations(Type lhsType, Type rhsType, Tree tree) { rhsType = supertypeMatchingLHS((Type.ClassType) lhsType, (Type.ClassType) rhsType, state); } } - List lhsTypeArguments = lhsType.getTypeArguments(); List rhsTypeArguments = rhsType.getTypeArguments(); - // this error should already be generated by some other part of NullAway still adding a check to // be safe if (lhsTypeArguments.size() != rhsTypeArguments.size()) { return; } - for (int i = 0; i < lhsTypeArguments.size(); i++) { com.sun.tools.javac.util.List annotationMirrorsLHS = lhsTypeArguments.get(i).getAnnotationMirrors(); @@ -197,10 +194,14 @@ private void compareAnnotations(Type lhsType, Type rhsType, Tree tree) { } } - private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree rhsTree) { - Type.ClassType type = (Type.ClassType) ASTHelpers.getType(rhsTree); + /** + * @param tree A parameterized typed tree for which we need class type with preserved annotations. + * @return A Type with preserved annotations. + */ + private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) { + Type.ClassType type = (Type.ClassType) ASTHelpers.getType(tree); Type nullableType = NULLABLE_TYPE_SUPPLIER.get(state); - List typeArguments = rhsTree.getTypeArguments(); + List typeArguments = tree.getTypeArguments(); List newTypeArgs = new ArrayList<>(); for (int i = 0; i < typeArguments.size(); i++) { List myAnnos = new ArrayList<>(); From b9a2ed4b0fdc4c49dbaf927760263f53e5688405 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Fri, 6 Jan 2023 23:12:06 +0530 Subject: [PATCH 120/184] code cleaning --- .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 34675d940c..998ca79e54 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -252,9 +252,8 @@ public void superTypeAssignmentChecksSingleInterface() { " interface Fn

{}", " class FnImpl implements Fn<@Nullable String, @Nullable String>{}", " void sampleError() {", - " Fn<@Nullable String, String> f;", " // BUG: Diagnostic contains: Generic type parameter", - " f = new FnImpl();", + " Fn<@Nullable String, String> f = new FnImpl();", " }", " }") .doTest(); @@ -319,7 +318,7 @@ public void nestedAssignmentChecks() { " class B

extends D

{}", " class C

{}", " void sampleError1() {", - " C> f;", + " C> f = new C>();", " // BUG: Diagnostic contains: Generic type parameter", " f = new C>();", " }", From ac7f33aec9e9484329a4e21cda4e980e96802ce3 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Fri, 6 Jan 2023 16:08:36 -0800 Subject: [PATCH 121/184] fancy test works! --- .../NullAwayJSpecifyGenericsTests.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 998ca79e54..56653839c3 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -348,6 +348,26 @@ public void subtypeWithParameters() { .doTest(); } + @Test + public void fancierSubtypeWithParameters() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.annotations.Nullable;", + "class Test {", + " class Super {}", + " class Sub extends Super {}", + " void test1() {", + " // valid assignment", + " Super<@Nullable String, String> s = new Sub();", + " // BUG: Diagnostic contains: Generic type parameter", + " Super<@Nullable String, String> s2 = new Sub<@Nullable String, String>();", + " }", + "}") + .doTest(); + } + @Test public void nestedVariableDeclarationChecks() { makeHelper() From b1119aba6e934df21bd57b29837f8b76327ff75b Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Fri, 6 Jan 2023 17:04:55 -0800 Subject: [PATCH 122/184] only run check in JSpecify mode --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 52be9f73d8..da6d05e7e3 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -38,7 +38,7 @@ public GenericsChecks(VisitorState state, Config config, NullAway analysis) { } @SuppressWarnings("UnusedVariable") - public static Type supertypeMatchingLHS( + private static Type supertypeMatchingLHS( Type.ClassType lhsType, Type.ClassType rhsType, VisitorState state) { // all supertypes including classes as well as interfaces List listOfDirectSuperTypes = state.getTypes().closure(rhsType); @@ -126,6 +126,9 @@ static void invalidInstantiationError( } public void checkInstantiationForAssignments(Tree tree) { + if (!config.isJSpecifyMode()) { + return; + } Tree lhsTree; Tree rhsTree; if (tree instanceof VariableTree) { From 92989ec213f8e3c628b5d1e5c60291c2f1a71bcd Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Fri, 6 Jan 2023 17:21:19 -0800 Subject: [PATCH 123/184] Fix NullAway errors --- .../java/com/uber/nullaway/GenericsChecks.java | 17 ++++++++++++----- .../main/java/com/uber/nullaway/NullAway.java | 10 +++------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index da6d05e7e3..59c886280b 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -1,5 +1,8 @@ package com.uber.nullaway; +import static com.uber.nullaway.NullabilityUtil.castToNonNull; + +import com.google.common.base.Preconditions; import com.google.errorprone.VisitorState; import com.google.errorprone.suppliers.Supplier; import com.google.errorprone.suppliers.Suppliers; @@ -140,8 +143,9 @@ public void checkInstantiationForAssignments(Tree tree) { lhsTree = assignmentTree.getVariable(); rhsTree = assignmentTree.getExpression(); } - if (rhsTree == null) { - // Possible for VariableTrees with no initializer + // rhsTree can be null for a VariableTree. Also, we don't need to do a check + // if rhsTree is the null literal + if (rhsTree == null || rhsTree.getKind().equals(Tree.Kind.NULL_LITERAL)) { return; } Type lhsType = ASTHelpers.getType(lhsTree); @@ -161,7 +165,9 @@ public void checkInstantiationForAssignments(Tree tree) { return; } } - compareAnnotations(lhsType, rhsType, tree); + if (lhsType != null && rhsType != null) { + compareAnnotations(lhsType, rhsType, tree); + } } private void compareAnnotations(Type lhsType, Type rhsType, Tree tree) { @@ -203,6 +209,7 @@ private void compareAnnotations(Type lhsType, Type rhsType, Tree tree) { */ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) { Type.ClassType type = (Type.ClassType) ASTHelpers.getType(tree); + Preconditions.checkNotNull(type); Type nullableType = NULLABLE_TYPE_SUPPLIER.get(state); List typeArguments = tree.getTypeArguments(); List newTypeArgs = new ArrayList<>(); @@ -221,7 +228,7 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) } // nested generics checks Type currentArgType = ASTHelpers.getType(typeArguments.get(i)); - if (currentArgType.getTypeArguments().size() > 0) { + if (currentArgType != null && currentArgType.getTypeArguments().size() > 0) { Type.ClassType nestedTyp = typeWithPreservedAnnotations((ParameterizedTypeTree) typeArguments.get(i)); newTypeArgs.add(nestedTyp); @@ -230,7 +237,7 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) com.sun.tools.javac.util.List.from(myAnnos); TypeMetadata md = new TypeMetadata(new TypeMetadata.Annotations(annos)); Type arg = ASTHelpers.getType(typeArguments.get(i)); - Type.ClassType newArg = (Type.ClassType) arg.cloneWithMetadata(md); + Type.ClassType newArg = (Type.ClassType) castToNonNull(arg).cloneWithMetadata(md); newTypeArgs.add(newArg); } } diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 2451434c6f..f77bbbd7e8 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -463,7 +463,7 @@ public Description matchAssignment(AssignmentTree tree, VisitorState state) { doUnboxingCheck(state, tree.getExpression()); } // generics check - if (lhsType.getTypeArguments().length() > 0) { + if (lhsType != null && lhsType.getTypeArguments().length() > 0) { GenericsChecks genericsChecks = new GenericsChecks(state, config, this); genericsChecks.checkInstantiationForAssignments(tree); } @@ -1334,12 +1334,8 @@ public Description matchVariable(VariableTree tree, VisitorState state) { // working on this. This part is needed to avoid assignment checks where the variable is // assigned to null if (tree.getInitializer() != null) { - if (state.getSourceForNode(tree.getInitializer()) != null) { - if (!state.getSourceForNode(tree.getInitializer()).equals("null")) { - GenericsChecks genericsChecks = new GenericsChecks(state, config, this); - genericsChecks.checkInstantiationForAssignments(tree); - } - } + GenericsChecks genericsChecks = new GenericsChecks(state, config, this); + genericsChecks.checkInstantiationForAssignments(tree); } if (symbol.type.isPrimitive() && tree.getInitializer() != null) { From 334d1e80dd054168939e5c53cb6a849a3813dc9f Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sat, 7 Jan 2023 11:14:52 +0530 Subject: [PATCH 124/184] modified assignment message --- .../com/uber/nullaway/GenericsChecks.java | 22 ++++++++++++++- .../NullAwayJSpecifyGenericsTests.java | 28 +++++++++---------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 59c886280b..09a87198dc 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -128,6 +128,24 @@ static void invalidInstantiationError( errorMessage, analysis.buildDescription(tree), state, null)); } + static void invalidAssignmentInstantiationError( + Tree tree, + String lhsAnnotation, + String rhsAnnotation, + VisitorState state, + NullAway analysis) { + ErrorBuilder errorBuilder = analysis.getErrorBuilder(); + ErrorMessage errorMessage = + new ErrorMessage( + ErrorMessage.MessageTypes.TYPE_PARAMETER_CANNOT_BE_NULLABLE, + String.format( + "Invalid Assignment, as assigning a %s value to a %s field", + rhsAnnotation, lhsAnnotation)); + state.reportMatch( + errorBuilder.createErrorDescription( + errorMessage, analysis.buildDescription(tree), state, null)); + } + public void checkInstantiationForAssignments(Tree tree) { if (!config.isJSpecifyMode()) { return; @@ -193,7 +211,9 @@ private void compareAnnotations(Type lhsType, Type rhsType, Tree tree) { boolean isRHSNullableAnnotated = Nullness.hasNullableAnnotation(annotationMirrorsRHS.stream(), config); if (isLHSNullableAnnotated != isRHSNullableAnnotated) { - invalidInstantiationError(tree, lhsType, lhsType.baseType(), state, analysis); + String lhsAnnotation = isLHSNullableAnnotated ? "Nullable" : "NonNull"; + String rhsAnnotation = isRHSNullableAnnotated ? "Nullable" : "NonNull"; + invalidAssignmentInstantiationError(tree, lhsAnnotation, rhsAnnotation, state, analysis); return; } // nested generics diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 56653839c3..89288764ab 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -212,29 +212,29 @@ public void genericsChecksForAssignments() { " static class NullableTypeParamMultipleArgumentsNested {}", " static void testOKOtherAnnotation(NullableTypeParam t) {", " NullableTypeParam t3;", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " t3 = new NullableTypeParam<@Nullable String>();", " NullableTypeParam<@Nullable String> t4;", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " t4 = t;", " NullableTypeParamMultipleArguments t5 = new NullableTypeParamMultipleArguments();", " NullableTypeParamMultipleArguments<@Nullable String, String> t6 = new NullableTypeParamMultipleArguments<@Nullable String, String>();", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " t5 = t6;", " NullableTypeParam>> t7 = new NullableTypeParam>>();", " NullableTypeParam>> t8 = new NullableTypeParam>>();", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " t7 = t8;", " NullableTypeParam>> t9 = new NullableTypeParam>> ();", " //No error", " t7 = t9;", " NullableTypeParamMultipleArguments>, String> t10 = new NullableTypeParamMultipleArguments>, String> ();", " NullableTypeParamMultipleArguments>, String> t11 = new NullableTypeParamMultipleArguments>, String> ();", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " t10 = t11;", " NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> t12 = new NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> ();", " NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> t13 = new NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> ();", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " t12 = t13;", " }", "}") @@ -252,7 +252,7 @@ public void superTypeAssignmentChecksSingleInterface() { " interface Fn

{}", " class FnImpl implements Fn<@Nullable String, @Nullable String>{}", " void sampleError() {", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " Fn<@Nullable String, String> f = new FnImpl();", " }", " }") @@ -272,7 +272,7 @@ public void superTypeAssignmentChecksMultipleInterface() { " class FnImpl implements Fn1<@Nullable String, @Nullable String>, Fn2 {}", " void sampleError() {", " Fn2<@Nullable String> f;", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " f = new FnImpl();", " }", " }") @@ -294,7 +294,7 @@ public void superTypeAssignmentChecksMultipleLevelInheritance() { " class FnImpl2 extends SubClassA<@Nullable String>{}", " void sampleError() {", " SuperClassC<@Nullable String> f;", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " f = new FnImpl1();", " }", " void sampleValidInstantiation() {", @@ -319,7 +319,7 @@ public void nestedAssignmentChecks() { " class C

{}", " void sampleError1() {", " C> f = new C>();", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " f = new C>();", " }", " }") @@ -337,11 +337,11 @@ public void subtypeWithParameters() { " class D

{}", " class B

extends D

{}", " void test1() {", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " D f = new B<@Nullable String>();", " }", " void test2(B<@Nullable String> b) {", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " D f = b;", " }", " }") @@ -361,7 +361,7 @@ public void fancierSubtypeWithParameters() { " void test1() {", " // valid assignment", " Super<@Nullable String, String> s = new Sub();", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " Super<@Nullable String, String> s2 = new Sub<@Nullable String, String>();", " }", "}") @@ -380,7 +380,7 @@ public void nestedVariableDeclarationChecks() { " class B

extends D

{}", " class C

{}", " void sampleError() {", - " // BUG: Diagnostic contains: Generic type parameter", + " // BUG: Diagnostic contains: Invalid Assignment", " D> f = new B>();", " }", " }") From 79b474b9ab73b3e271ee7d47a7f64f0192af8e7b Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sat, 7 Jan 2023 10:32:25 -0800 Subject: [PATCH 125/184] remove unneeded suppression --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 1 - 1 file changed, 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 09a87198dc..3971a62180 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -40,7 +40,6 @@ public GenericsChecks(VisitorState state, Config config, NullAway analysis) { this.analysis = analysis; } - @SuppressWarnings("UnusedVariable") private static Type supertypeMatchingLHS( Type.ClassType lhsType, Type.ClassType rhsType, VisitorState state) { // all supertypes including classes as well as interfaces From 05292c01f69e4b319f63eee07cbb5b510d2065ef Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sat, 7 Jan 2023 10:32:57 -0800 Subject: [PATCH 126/184] remove change to build.gradle --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6c9c798b97..82cc1fa2b7 100644 --- a/build.gradle +++ b/build.gradle @@ -73,7 +73,6 @@ subprojects { project -> check("CanIgnoreReturnValueSuggester", CheckSeverity.OFF) check("WildcardImport", CheckSeverity.ERROR) check("MissingBraces", CheckSeverity.ERROR) - check("MultipleTopLevelClasses", CheckSeverity.ERROR) check("TypeToString", CheckSeverity.ERROR) check("SymbolToString", CheckSeverity.ERROR) } From d9e268935603afa6cff34087d60bebecfc80ed58 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sat, 7 Jan 2023 10:37:31 -0800 Subject: [PATCH 127/184] remove local used only once --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index f77bbbd7e8..59cfcdbff1 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -464,8 +464,7 @@ public Description matchAssignment(AssignmentTree tree, VisitorState state) { } // generics check if (lhsType != null && lhsType.getTypeArguments().length() > 0) { - GenericsChecks genericsChecks = new GenericsChecks(state, config, this); - genericsChecks.checkInstantiationForAssignments(tree); + new GenericsChecks(state, config, this).checkInstantiationForAssignments(tree); } Symbol assigned = ASTHelpers.getSymbol(tree.getVariable()); @@ -1334,8 +1333,7 @@ public Description matchVariable(VariableTree tree, VisitorState state) { // working on this. This part is needed to avoid assignment checks where the variable is // assigned to null if (tree.getInitializer() != null) { - GenericsChecks genericsChecks = new GenericsChecks(state, config, this); - genericsChecks.checkInstantiationForAssignments(tree); + new GenericsChecks(state, config, this).checkInstantiationForAssignments(tree); } if (symbol.type.isPrimitive() && tree.getInitializer() != null) { From 1cc72f2a1467200f3da4fb4d6456f5d3a92960ba Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sat, 7 Jan 2023 10:44:32 -0800 Subject: [PATCH 128/184] cleanup supertypeMatchingLHS --- .../com/uber/nullaway/GenericsChecks.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 3971a62180..8f2888c786 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -40,19 +40,25 @@ public GenericsChecks(VisitorState state, Config config, NullAway analysis) { this.analysis = analysis; } - private static Type supertypeMatchingLHS( - Type.ClassType lhsType, Type.ClassType rhsType, VisitorState state) { + private Type supertypeMatchingLHS(Type.ClassType lhsType, Type.ClassType rhsType) { + if (ASTHelpers.isSameType(lhsType, rhsType, state)) { + return rhsType; + } // all supertypes including classes as well as interfaces - List listOfDirectSuperTypes = state.getTypes().closure(rhsType); - if (listOfDirectSuperTypes != null) { - for (int i = 0; i < listOfDirectSuperTypes.size(); i++) { - if (ASTHelpers.isSameType(listOfDirectSuperTypes.get(i), lhsType, state)) { - return listOfDirectSuperTypes.get(i); + List superTypes = state.getTypes().closure(rhsType); + Type result = null; + if (superTypes != null) { + for (Type superType : superTypes) { + if (ASTHelpers.isSameType(superType, lhsType, state)) { + result = superType; + break; } } } - - return rhsType.baseType(); + if (result == null) { + throw new RuntimeException("did not find supertype of " + rhsType + " matching " + lhsType); + } + return result; } /** @@ -188,10 +194,8 @@ public void checkInstantiationForAssignments(Tree tree) { } private void compareAnnotations(Type lhsType, Type rhsType, Tree tree) { - if (!ASTHelpers.isSameType(lhsType, rhsType, state)) { - if (lhsType instanceof Type.ClassType && rhsType instanceof Type.ClassType) { - rhsType = supertypeMatchingLHS((Type.ClassType) lhsType, (Type.ClassType) rhsType, state); - } + if (lhsType instanceof Type.ClassType && rhsType instanceof Type.ClassType) { + rhsType = supertypeMatchingLHS((Type.ClassType) lhsType, (Type.ClassType) rhsType); } List lhsTypeArguments = lhsType.getTypeArguments(); List rhsTypeArguments = rhsType.getTypeArguments(); From 85741bee85566f5224a3626ab0f60739b2a7f967 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sat, 7 Jan 2023 10:47:14 -0800 Subject: [PATCH 129/184] restore private --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 8f2888c786..2aa4360cd5 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -119,7 +119,7 @@ public static void checkInstantiationForParameterizedTypedTree( } } - static void invalidInstantiationError( + private static void invalidInstantiationError( Tree tree, Type baseType, Type baseTypeVariable, VisitorState state, NullAway analysis) { ErrorBuilder errorBuilder = analysis.getErrorBuilder(); ErrorMessage errorMessage = From c58d819dd4ab360928289d8dce08d289d71cf42c Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sat, 7 Jan 2023 10:47:46 -0800 Subject: [PATCH 130/184] add private --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 2aa4360cd5..28b3ca84f6 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -133,7 +133,7 @@ private static void invalidInstantiationError( errorMessage, analysis.buildDescription(tree), state, null)); } - static void invalidAssignmentInstantiationError( + private static void invalidAssignmentInstantiationError( Tree tree, String lhsAnnotation, String rhsAnnotation, From 8829bcd7e3b5575cec586652d5012f160e0e722c Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 8 Jan 2023 20:36:25 +0530 Subject: [PATCH 131/184] changed the error message --- nullaway/src/main/java/com/uber/nullaway/ErrorMessage.java | 1 + nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/ErrorMessage.java b/nullaway/src/main/java/com/uber/nullaway/ErrorMessage.java index 753f49431b..bb1395a6bf 100644 --- a/nullaway/src/main/java/com/uber/nullaway/ErrorMessage.java +++ b/nullaway/src/main/java/com/uber/nullaway/ErrorMessage.java @@ -53,6 +53,7 @@ public enum MessageTypes { WRONG_OVERRIDE_POSTCONDITION, WRONG_OVERRIDE_PRECONDITION, TYPE_PARAMETER_CANNOT_BE_NULLABLE, + ASSIGN_GENERIC_NULLABLE, } public String getMessage() { diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 28b3ca84f6..b3d9a8e3c8 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -142,7 +142,7 @@ private static void invalidAssignmentInstantiationError( ErrorBuilder errorBuilder = analysis.getErrorBuilder(); ErrorMessage errorMessage = new ErrorMessage( - ErrorMessage.MessageTypes.TYPE_PARAMETER_CANNOT_BE_NULLABLE, + ErrorMessage.MessageTypes.ASSIGN_GENERIC_NULLABLE, String.format( "Invalid Assignment, as assigning a %s value to a %s field", rhsAnnotation, lhsAnnotation)); From fd16446f9e5cb5cd09774a955614f327f095e469 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 8 Jan 2023 20:41:59 +0530 Subject: [PATCH 132/184] updated the error message text --- .../com/uber/nullaway/GenericsChecks.java | 17 +++++------ .../NullAwayJSpecifyGenericsTests.java | 28 +++++++++---------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index b3d9a8e3c8..1cb9f0d25a 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -134,18 +134,17 @@ private static void invalidInstantiationError( } private static void invalidAssignmentInstantiationError( - Tree tree, - String lhsAnnotation, - String rhsAnnotation, - VisitorState state, - NullAway analysis) { + Tree tree, Type lhsType, Type rhsType, VisitorState state, NullAway analysis) { ErrorBuilder errorBuilder = analysis.getErrorBuilder(); ErrorMessage errorMessage = new ErrorMessage( ErrorMessage.MessageTypes.ASSIGN_GENERIC_NULLABLE, String.format( - "Invalid Assignment, as assigning a %s value to a %s field", - rhsAnnotation, lhsAnnotation)); + "Cannot assign from type " + + rhsType + + " to type " + + lhsType + + " due to mismatched nullability of type parameters")); state.reportMatch( errorBuilder.createErrorDescription( errorMessage, analysis.buildDescription(tree), state, null)); @@ -214,9 +213,7 @@ private void compareAnnotations(Type lhsType, Type rhsType, Tree tree) { boolean isRHSNullableAnnotated = Nullness.hasNullableAnnotation(annotationMirrorsRHS.stream(), config); if (isLHSNullableAnnotated != isRHSNullableAnnotated) { - String lhsAnnotation = isLHSNullableAnnotated ? "Nullable" : "NonNull"; - String rhsAnnotation = isRHSNullableAnnotated ? "Nullable" : "NonNull"; - invalidAssignmentInstantiationError(tree, lhsAnnotation, rhsAnnotation, state, analysis); + invalidAssignmentInstantiationError(tree, lhsType, rhsType, state, analysis); return; } // nested generics diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 89288764ab..efc53820b2 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -212,29 +212,29 @@ public void genericsChecksForAssignments() { " static class NullableTypeParamMultipleArgumentsNested {}", " static void testOKOtherAnnotation(NullableTypeParam t) {", " NullableTypeParam t3;", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " t3 = new NullableTypeParam<@Nullable String>();", " NullableTypeParam<@Nullable String> t4;", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " t4 = t;", " NullableTypeParamMultipleArguments t5 = new NullableTypeParamMultipleArguments();", " NullableTypeParamMultipleArguments<@Nullable String, String> t6 = new NullableTypeParamMultipleArguments<@Nullable String, String>();", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " t5 = t6;", " NullableTypeParam>> t7 = new NullableTypeParam>>();", " NullableTypeParam>> t8 = new NullableTypeParam>>();", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " t7 = t8;", " NullableTypeParam>> t9 = new NullableTypeParam>> ();", " //No error", " t7 = t9;", " NullableTypeParamMultipleArguments>, String> t10 = new NullableTypeParamMultipleArguments>, String> ();", " NullableTypeParamMultipleArguments>, String> t11 = new NullableTypeParamMultipleArguments>, String> ();", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " t10 = t11;", " NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> t12 = new NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> ();", " NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> t13 = new NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> ();", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " t12 = t13;", " }", "}") @@ -252,7 +252,7 @@ public void superTypeAssignmentChecksSingleInterface() { " interface Fn

{}", " class FnImpl implements Fn<@Nullable String, @Nullable String>{}", " void sampleError() {", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " Fn<@Nullable String, String> f = new FnImpl();", " }", " }") @@ -272,7 +272,7 @@ public void superTypeAssignmentChecksMultipleInterface() { " class FnImpl implements Fn1<@Nullable String, @Nullable String>, Fn2 {}", " void sampleError() {", " Fn2<@Nullable String> f;", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " f = new FnImpl();", " }", " }") @@ -294,7 +294,7 @@ public void superTypeAssignmentChecksMultipleLevelInheritance() { " class FnImpl2 extends SubClassA<@Nullable String>{}", " void sampleError() {", " SuperClassC<@Nullable String> f;", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " f = new FnImpl1();", " }", " void sampleValidInstantiation() {", @@ -319,7 +319,7 @@ public void nestedAssignmentChecks() { " class C

{}", " void sampleError1() {", " C> f = new C>();", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " f = new C>();", " }", " }") @@ -337,11 +337,11 @@ public void subtypeWithParameters() { " class D

{}", " class B

extends D

{}", " void test1() {", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " D f = new B<@Nullable String>();", " }", " void test2(B<@Nullable String> b) {", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " D f = b;", " }", " }") @@ -361,7 +361,7 @@ public void fancierSubtypeWithParameters() { " void test1() {", " // valid assignment", " Super<@Nullable String, String> s = new Sub();", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " Super<@Nullable String, String> s2 = new Sub<@Nullable String, String>();", " }", "}") @@ -380,7 +380,7 @@ public void nestedVariableDeclarationChecks() { " class B

extends D

{}", " class C

{}", " void sampleError() {", - " // BUG: Diagnostic contains: Invalid Assignment", + " // BUG: Diagnostic contains: Cannot assign from type", " D> f = new B>();", " }", " }") From c0fd28ee5f149161d6b59c2ddb10f147d815373d Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 8 Jan 2023 20:48:10 +0530 Subject: [PATCH 133/184] Type.ClassType suggestion changes --- .../java/com/uber/nullaway/GenericsChecks.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 1cb9f0d25a..ca5ded1672 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -40,7 +40,7 @@ public GenericsChecks(VisitorState state, Config config, NullAway analysis) { this.analysis = analysis; } - private Type supertypeMatchingLHS(Type.ClassType lhsType, Type.ClassType rhsType) { + private Type.ClassType supertypeMatchingLHS(Type.ClassType lhsType, Type.ClassType rhsType) { if (ASTHelpers.isSameType(lhsType, rhsType, state)) { return rhsType; } @@ -58,7 +58,7 @@ private Type supertypeMatchingLHS(Type.ClassType lhsType, Type.ClassType rhsType if (result == null) { throw new RuntimeException("did not find supertype of " + rhsType + " matching " + lhsType); } - return result; + return (Type.ClassType) result; } /** @@ -188,14 +188,12 @@ public void checkInstantiationForAssignments(Tree tree) { } } if (lhsType != null && rhsType != null) { - compareAnnotations(lhsType, rhsType, tree); + compareAnnotations((Type.ClassType) lhsType, (Type.ClassType) rhsType, tree); } } - private void compareAnnotations(Type lhsType, Type rhsType, Tree tree) { - if (lhsType instanceof Type.ClassType && rhsType instanceof Type.ClassType) { - rhsType = supertypeMatchingLHS((Type.ClassType) lhsType, (Type.ClassType) rhsType); - } + private void compareAnnotations(Type.ClassType lhsType, Type.ClassType rhsType, Tree tree) { + rhsType = supertypeMatchingLHS((Type.ClassType) lhsType, (Type.ClassType) rhsType); List lhsTypeArguments = lhsType.getTypeArguments(); List rhsTypeArguments = rhsType.getTypeArguments(); // this error should already be generated by some other part of NullAway still adding a check to @@ -218,7 +216,10 @@ private void compareAnnotations(Type lhsType, Type rhsType, Tree tree) { } // nested generics if (lhsTypeArguments.get(i).getTypeArguments().length() > 0) { - compareAnnotations(lhsTypeArguments.get(i), rhsTypeArguments.get(i), tree); + compareAnnotations( + (Type.ClassType) lhsTypeArguments.get(i), + (Type.ClassType) rhsTypeArguments.get(i), + tree); } } } From abe3ed909008809f55dd336bc8e90827853e7da8 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 8 Jan 2023 20:48:42 +0530 Subject: [PATCH 134/184] changes From 7a18462fe6daa7905f27d2143658e0ddbcf169e4 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 8 Jan 2023 20:51:56 +0530 Subject: [PATCH 135/184] changes --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index ca5ded1672..f672438f73 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -28,6 +28,7 @@ public final class GenericsChecks { private static final String NULLABLE_NAME = "org.jspecify.annotations.Nullable"; + private static final String NULLABLE_TYPE = "@org.jspecify.annotations.Nullable"; private static final Supplier NULLABLE_TYPE_SUPPLIER = Suppliers.typeFromString(NULLABLE_NAME); VisitorState state; @@ -240,7 +241,7 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { Attribute.Compound attribute = annotation.attribute; - if (attribute.toString().equals("@org.jspecify.annotations.Nullable")) { + if (attribute.toString().equals(NULLABLE_TYPE)) { myAnnos.add( new Attribute.TypeCompound( nullableType, com.sun.tools.javac.util.List.nil(), null)); From 23c8fbb724a4d48b9e108a52585d8408028b7740 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 8 Jan 2023 20:53:36 +0530 Subject: [PATCH 136/184] changes --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 59cfcdbff1..4675b210df 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -1330,8 +1330,6 @@ public Description matchVariable(VariableTree tree, VisitorState state) { return Description.NO_MATCH; } VarSymbol symbol = ASTHelpers.getSymbol(tree); - // working on this. This part is needed to avoid assignment checks where the variable is - // assigned to null if (tree.getInitializer() != null) { new GenericsChecks(state, config, this).checkInstantiationForAssignments(tree); } From 88accaba63e3843bafb977ff63c2c5670bf17656 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 8 Jan 2023 21:10:27 +0530 Subject: [PATCH 137/184] extra test case --- .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index efc53820b2..34793486f5 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -378,10 +378,13 @@ public void nestedVariableDeclarationChecks() { "class Test {", " class D

{}", " class B

extends D

{}", - " class C

{}", + " class C

{}", + " class A, P extends @Nullable Object>{}", " void sampleError() {", " // BUG: Diagnostic contains: Cannot assign from type", - " D> f = new B>();", + " D> f1 = new B>();", + " // BUG: Diagnostic contains: Cannot assign from type", + "A, String> f2 = new A, @Nullable String>();", " }", " }") .doTest(); From 124e7c8479fcfb01e7a67d0bf5d8942519dd8bcb Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Sun, 8 Jan 2023 08:46:27 -0800 Subject: [PATCH 138/184] add failing test --- .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 34793486f5..66230a469c 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -381,10 +381,12 @@ public void nestedVariableDeclarationChecks() { " class C

{}", " class A, P extends @Nullable Object>{}", " void sampleError() {", - " // BUG: Diagnostic contains: Cannot assign from type", + " // BUG: Diagnostic contains: Cannot assign from type", " D> f1 = new B>();", " // BUG: Diagnostic contains: Cannot assign from type", - "A, String> f2 = new A, @Nullable String>();", + " A, String> f2 = new A, @Nullable String>();", + " // BUG: Diagnostic contains: Cannot assign from type", + " D> f3 = new B<@Nullable C>();", " }", " }") .doTest(); From 00802a14cf673b312be79d82d5ffcec8b2c0526b Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 8 Jan 2023 23:10:55 +0530 Subject: [PATCH 139/184] updated logic --- .../com/uber/nullaway/GenericsChecks.java | 30 ++++++++++++------- .../NullAwayJSpecifyGenericsTests.java | 4 --- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index f672438f73..69ca7cae3a 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -237,27 +237,35 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) List newTypeArgs = new ArrayList<>(); for (int i = 0; i < typeArguments.size(); i++) { List myAnnos = new ArrayList<>(); + List annotations = new ArrayList<>(); if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); - for (JCTree.JCAnnotation annotation : annotatedType.getAnnotations()) { - Attribute.Compound attribute = annotation.attribute; - if (attribute.toString().equals(NULLABLE_TYPE)) { - myAnnos.add( - new Attribute.TypeCompound( - nullableType, com.sun.tools.javac.util.List.nil(), null)); - } + annotations = annotatedType.getAnnotations(); + } else if (typeArguments.get(i) instanceof JCTree.JCTypeApply + && ((JCTree.JCTypeApply) typeArguments.get(i)).clazz instanceof AnnotatedTypeTree) { + JCTree.JCAnnotatedType annotatedType = + (JCTree.JCAnnotatedType) ((JCTree.JCTypeApply) typeArguments.get(i)).clazz; + annotations = annotatedType.getAnnotations(); + } + for (JCTree.JCAnnotation annotation : annotations) { + Attribute.Compound attribute = annotation.attribute; + if (attribute.toString().equals(NULLABLE_TYPE)) { + myAnnos.add( + new Attribute.TypeCompound(nullableType, com.sun.tools.javac.util.List.nil(), null)); } } + + com.sun.tools.javac.util.List annos = + com.sun.tools.javac.util.List.from(myAnnos); + TypeMetadata md = new TypeMetadata(new TypeMetadata.Annotations(annos)); // nested generics checks Type currentArgType = ASTHelpers.getType(typeArguments.get(i)); if (currentArgType != null && currentArgType.getTypeArguments().size() > 0) { Type.ClassType nestedTyp = typeWithPreservedAnnotations((ParameterizedTypeTree) typeArguments.get(i)); - newTypeArgs.add(nestedTyp); + Type.ClassType nestedTypArg = castToNonNull(nestedTyp).cloneWithMetadata(md); + newTypeArgs.add(nestedTypArg); } else { - com.sun.tools.javac.util.List annos = - com.sun.tools.javac.util.List.from(myAnnos); - TypeMetadata md = new TypeMetadata(new TypeMetadata.Annotations(annos)); Type arg = ASTHelpers.getType(typeArguments.get(i)); Type.ClassType newArg = (Type.ClassType) castToNonNull(arg).cloneWithMetadata(md); newTypeArgs.add(newArg); diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 66230a469c..e53b7aa718 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -382,10 +382,6 @@ public void nestedVariableDeclarationChecks() { " class A, P extends @Nullable Object>{}", " void sampleError() {", " // BUG: Diagnostic contains: Cannot assign from type", - " D> f1 = new B>();", - " // BUG: Diagnostic contains: Cannot assign from type", - " A, String> f2 = new A, @Nullable String>();", - " // BUG: Diagnostic contains: Cannot assign from type", " D> f3 = new B<@Nullable C>();", " }", " }") From 021435ad6504b1d157d726f3408960e00a384421 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 8 Jan 2023 23:12:44 +0530 Subject: [PATCH 140/184] minor updates --- .../java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index e53b7aa718..66230a469c 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -382,6 +382,10 @@ public void nestedVariableDeclarationChecks() { " class A, P extends @Nullable Object>{}", " void sampleError() {", " // BUG: Diagnostic contains: Cannot assign from type", + " D> f1 = new B>();", + " // BUG: Diagnostic contains: Cannot assign from type", + " A, String> f2 = new A, @Nullable String>();", + " // BUG: Diagnostic contains: Cannot assign from type", " D> f3 = new B<@Nullable C>();", " }", " }") From a12d549e23d7442c1e6c45092eddef2372f05d60 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 8 Jan 2023 23:16:53 +0530 Subject: [PATCH 141/184] minor code cleaning --- .../src/main/java/com/uber/nullaway/GenericsChecks.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 69ca7cae3a..b8179079de 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -236,7 +236,7 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) List typeArguments = tree.getTypeArguments(); List newTypeArgs = new ArrayList<>(); for (int i = 0; i < typeArguments.size(); i++) { - List myAnnos = new ArrayList<>(); + List allAnnotations = new ArrayList<>(); List annotations = new ArrayList<>(); if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); @@ -250,13 +250,13 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) for (JCTree.JCAnnotation annotation : annotations) { Attribute.Compound attribute = annotation.attribute; if (attribute.toString().equals(NULLABLE_TYPE)) { - myAnnos.add( + allAnnotations.add( new Attribute.TypeCompound(nullableType, com.sun.tools.javac.util.List.nil(), null)); } } com.sun.tools.javac.util.List annos = - com.sun.tools.javac.util.List.from(myAnnos); + com.sun.tools.javac.util.List.from(allAnnotations); TypeMetadata md = new TypeMetadata(new TypeMetadata.Annotations(annos)); // nested generics checks Type currentArgType = ASTHelpers.getType(typeArguments.get(i)); From 82d9e8d99a7874376e5a11f9bc3d8d8d263a11c1 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Sun, 8 Jan 2023 23:18:29 +0530 Subject: [PATCH 142/184] minor code cleaning --- .../src/main/java/com/uber/nullaway/GenericsChecks.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index b8179079de..0a4efaa9b3 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -257,17 +257,17 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) com.sun.tools.javac.util.List annos = com.sun.tools.javac.util.List.from(allAnnotations); - TypeMetadata md = new TypeMetadata(new TypeMetadata.Annotations(annos)); + TypeMetadata metaData = new TypeMetadata(new TypeMetadata.Annotations(annos)); // nested generics checks Type currentArgType = ASTHelpers.getType(typeArguments.get(i)); if (currentArgType != null && currentArgType.getTypeArguments().size() > 0) { Type.ClassType nestedTyp = typeWithPreservedAnnotations((ParameterizedTypeTree) typeArguments.get(i)); - Type.ClassType nestedTypArg = castToNonNull(nestedTyp).cloneWithMetadata(md); + Type.ClassType nestedTypArg = castToNonNull(nestedTyp).cloneWithMetadata(metaData); newTypeArgs.add(nestedTypArg); } else { Type arg = ASTHelpers.getType(typeArguments.get(i)); - Type.ClassType newArg = (Type.ClassType) castToNonNull(arg).cloneWithMetadata(md); + Type.ClassType newArg = (Type.ClassType) castToNonNull(arg).cloneWithMetadata(metaData); newTypeArgs.add(newArg); } } From f381d839c654e2f17137c1c270af4ae422907e09 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 9 Jan 2023 21:58:38 +0530 Subject: [PATCH 143/184] suggested changes --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 0a4efaa9b3..77bfd81f70 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -197,10 +197,8 @@ private void compareAnnotations(Type.ClassType lhsType, Type.ClassType rhsType, rhsType = supertypeMatchingLHS((Type.ClassType) lhsType, (Type.ClassType) rhsType); List lhsTypeArguments = lhsType.getTypeArguments(); List rhsTypeArguments = rhsType.getTypeArguments(); - // this error should already be generated by some other part of NullAway still adding a check to - // be safe if (lhsTypeArguments.size() != rhsTypeArguments.size()) { - return; + throw new RuntimeException(rhsType + " does not match " + lhsType); } for (int i = 0; i < lhsTypeArguments.size(); i++) { com.sun.tools.javac.util.List annotationMirrorsLHS = From 75234b86d7306e62985f214fde279d3b3304da29 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 9 Jan 2023 22:00:02 +0530 Subject: [PATCH 144/184] suggested changes --- .../main/java/com/uber/nullaway/GenericsChecks.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 77bfd81f70..627564d003 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -175,18 +175,17 @@ public void checkInstantiationForAssignments(Tree tree) { Type rhsType = ASTHelpers.getType(rhsTree); if (rhsTree instanceof NewClassTree && ((NewClassTree) rhsTree).getIdentifier() instanceof ParameterizedTypeTree) { - // for the parameterized typed tree ASTHelpers.getType() returns a type that does not have - // annotations preserved - rhsType = - typeWithPreservedAnnotations( - (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier()); - ParameterizedTypeTree paramTypedTree = (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier(); // not generic if (paramTypedTree.getTypeArguments().size() <= 0) { return; } + // for the parameterized typed tree ASTHelpers.getType() returns a type that does not have + // annotations preserved + rhsType = + typeWithPreservedAnnotations( + (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier()); } if (lhsType != null && rhsType != null) { compareAnnotations((Type.ClassType) lhsType, (Type.ClassType) rhsType, tree); From 1be7c4085d8c55ff513d1d2328327440e5b4e020 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 9 Jan 2023 22:39:15 +0530 Subject: [PATCH 145/184] replaced super type matching lhs with asSuper method --- .../com/uber/nullaway/GenericsChecks.java | 28 ++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 627564d003..0cc89c27a5 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -17,6 +17,7 @@ import com.sun.tools.javac.code.Attribute; 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.tree.JCTree; import java.util.ArrayList; import java.util.HashMap; @@ -41,27 +42,6 @@ public GenericsChecks(VisitorState state, Config config, NullAway analysis) { this.analysis = analysis; } - private Type.ClassType supertypeMatchingLHS(Type.ClassType lhsType, Type.ClassType rhsType) { - if (ASTHelpers.isSameType(lhsType, rhsType, state)) { - return rhsType; - } - // all supertypes including classes as well as interfaces - List superTypes = state.getTypes().closure(rhsType); - Type result = null; - if (superTypes != null) { - for (Type superType : superTypes) { - if (ASTHelpers.isSameType(superType, lhsType, state)) { - result = superType; - break; - } - } - } - if (result == null) { - throw new RuntimeException("did not find supertype of " + rhsType + " matching " + lhsType); - } - return (Type.ClassType) result; - } - /** * Checks that for an instantiated generic type, {@code @Nullable} types are only used for type * variables that have a {@code @Nullable} upper bound. @@ -193,7 +173,11 @@ public void checkInstantiationForAssignments(Tree tree) { } private void compareAnnotations(Type.ClassType lhsType, Type.ClassType rhsType, Tree tree) { - rhsType = supertypeMatchingLHS((Type.ClassType) lhsType, (Type.ClassType) rhsType); + Types types = state.getTypes(); + rhsType = (Type.ClassType) types.asSuper(rhsType, lhsType.tsym); + if (rhsType == null) { + throw new RuntimeException("did not find supertype of " + rhsType + " matching " + lhsType); + } List lhsTypeArguments = lhsType.getTypeArguments(); List rhsTypeArguments = rhsType.getTypeArguments(); if (lhsTypeArguments.size() != rhsTypeArguments.size()) { From 676e07deda59e93c1e45c2b3030aca895d4b7fb8 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 10 Jan 2023 10:30:11 +0530 Subject: [PATCH 146/184] updated assignment checks --- .../NullAwayJSpecifyGenericsTests.java | 59 ++++++------------- 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 66230a469c..570e4989a7 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -198,9 +198,25 @@ public void downcastInstantiation() { .doTest(); } - // assignment tree tests @Test public void genericsChecksForAssignments() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.annotations.Nullable;", + "class Test {", + " static class NullableTypeParam {}", + " static void testBadNonNull(NullableTypeParam<@Nullable String> t1) {", + " // BUG: Diagnostic contains: Cannot assign from type", + " NullableTypeParam t2 = t1;", + " }", + "}") + .doTest(); + } + + @Test + public void nestedChecksForAssignmentsMultipleArguments() { makeHelper() .addSourceLines( "Test.java", @@ -211,31 +227,10 @@ public void genericsChecksForAssignments() { " static class NullableTypeParamMultipleArguments {}", " static class NullableTypeParamMultipleArgumentsNested {}", " static void testOKOtherAnnotation(NullableTypeParam t) {", - " NullableTypeParam t3;", - " // BUG: Diagnostic contains: Cannot assign from type", - " t3 = new NullableTypeParam<@Nullable String>();", - " NullableTypeParam<@Nullable String> t4;", - " // BUG: Diagnostic contains: Cannot assign from type", - " t4 = t;", - " NullableTypeParamMultipleArguments t5 = new NullableTypeParamMultipleArguments();", - " NullableTypeParamMultipleArguments<@Nullable String, String> t6 = new NullableTypeParamMultipleArguments<@Nullable String, String>();", - " // BUG: Diagnostic contains: Cannot assign from type", - " t5 = t6;", - " NullableTypeParam>> t7 = new NullableTypeParam>>();", - " NullableTypeParam>> t8 = new NullableTypeParam>>();", - " // BUG: Diagnostic contains: Cannot assign from type", - " t7 = t8;", - " NullableTypeParam>> t9 = new NullableTypeParam>> ();", - " //No error", - " t7 = t9;", " NullableTypeParamMultipleArguments>, String> t10 = new NullableTypeParamMultipleArguments>, String> ();", " NullableTypeParamMultipleArguments>, String> t11 = new NullableTypeParamMultipleArguments>, String> ();", " // BUG: Diagnostic contains: Cannot assign from type", " t10 = t11;", - " NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> t12 = new NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> ();", - " NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> t13 = new NullableTypeParamMultipleArgumentsNested>, String, @Nullable String> ();", - " // BUG: Diagnostic contains: Cannot assign from type", - " t12 = t13;", " }", "}") .doTest(); @@ -306,26 +301,6 @@ public void superTypeAssignmentChecksMultipleLevelInheritance() { .doTest(); } - @Test - public void nestedAssignmentChecks() { - makeHelper() - .addSourceLines( - "Test.java", - "package com.uber;", - "import org.jspecify.annotations.Nullable;", - "class Test {", - " class D

{}", - " class B

extends D

{}", - " class C

{}", - " void sampleError1() {", - " C> f = new C>();", - " // BUG: Diagnostic contains: Cannot assign from type", - " f = new C>();", - " }", - " }") - .doTest(); - } - @Test public void subtypeWithParameters() { makeHelper() From a08544373ffb415ce142b0d9c9066c62b25a4f00 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 10 Jan 2023 11:38:15 +0530 Subject: [PATCH 147/184] changes --- .../java/com/uber/nullaway/GenericsChecks.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 0cc89c27a5..265e7c3143 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -216,8 +216,8 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) Type nullableType = NULLABLE_TYPE_SUPPLIER.get(state); List typeArguments = tree.getTypeArguments(); List newTypeArgs = new ArrayList<>(); + boolean hasNullableAnnotation = false; for (int i = 0; i < typeArguments.size(); i++) { - List allAnnotations = new ArrayList<>(); List annotations = new ArrayList<>(); if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); @@ -231,14 +231,18 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) for (JCTree.JCAnnotation annotation : annotations) { Attribute.Compound attribute = annotation.attribute; if (attribute.toString().equals(NULLABLE_TYPE)) { - allAnnotations.add( - new Attribute.TypeCompound(nullableType, com.sun.tools.javac.util.List.nil(), null)); + hasNullableAnnotation = true; } } - - com.sun.tools.javac.util.List annos = - com.sun.tools.javac.util.List.from(allAnnotations); - TypeMetadata metaData = new TypeMetadata(new TypeMetadata.Annotations(annos)); + com.sun.tools.javac.util.List nullableAnnotations = + com.sun.tools.javac.util.List.from(new ArrayList<>()); + if (hasNullableAnnotation) { + List nullableAnnotation = new ArrayList<>(); + nullableAnnotation.add( + new Attribute.TypeCompound(nullableType, com.sun.tools.javac.util.List.nil(), null)); + nullableAnnotations = com.sun.tools.javac.util.List.from(nullableAnnotation); + } + TypeMetadata metaData = new TypeMetadata(new TypeMetadata.Annotations(nullableAnnotations)); // nested generics checks Type currentArgType = ASTHelpers.getType(typeArguments.get(i)); if (currentArgType != null && currentArgType.getTypeArguments().size() > 0) { From c8303d7a5af1d2f4a385f84a5a25a9b3ea240090 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 10 Jan 2023 11:40:37 +0530 Subject: [PATCH 148/184] changes --- .../main/java/com/uber/nullaway/GenericsChecks.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 265e7c3143..67a6048b0f 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -20,6 +20,7 @@ import com.sun.tools.javac.code.Types; import com.sun.tools.javac.tree.JCTree; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -237,10 +238,11 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) com.sun.tools.javac.util.List nullableAnnotations = com.sun.tools.javac.util.List.from(new ArrayList<>()); if (hasNullableAnnotation) { - List nullableAnnotation = new ArrayList<>(); - nullableAnnotation.add( - new Attribute.TypeCompound(nullableType, com.sun.tools.javac.util.List.nil(), null)); - nullableAnnotations = com.sun.tools.javac.util.List.from(nullableAnnotation); + nullableAnnotations = + com.sun.tools.javac.util.List.from( + Collections.singletonList( + new Attribute.TypeCompound( + nullableType, com.sun.tools.javac.util.List.nil(), null))); } TypeMetadata metaData = new TypeMetadata(new TypeMetadata.Annotations(nullableAnnotations)); // nested generics checks From 4238a9a2720d51389f160af7d922dbb4c2cf892d Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 10 Jan 2023 12:05:37 +0530 Subject: [PATCH 149/184] suggested changes --- .../src/main/java/com/uber/nullaway/GenericsChecks.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 67a6048b0f..1581352498 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -220,13 +220,13 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) boolean hasNullableAnnotation = false; for (int i = 0; i < typeArguments.size(); i++) { List annotations = new ArrayList<>(); + JCTree.JCAnnotatedType annotatedType; if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { - JCTree.JCAnnotatedType annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); + annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); annotations = annotatedType.getAnnotations(); } else if (typeArguments.get(i) instanceof JCTree.JCTypeApply && ((JCTree.JCTypeApply) typeArguments.get(i)).clazz instanceof AnnotatedTypeTree) { - JCTree.JCAnnotatedType annotatedType = - (JCTree.JCAnnotatedType) ((JCTree.JCTypeApply) typeArguments.get(i)).clazz; + annotatedType = (JCTree.JCAnnotatedType) ((JCTree.JCTypeApply) typeArguments.get(i)).clazz; annotations = annotatedType.getAnnotations(); } for (JCTree.JCAnnotation annotation : annotations) { From f5ec4cd78c029cfea811413ed41b67a4bcabdcd1 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 10 Jan 2023 12:11:43 +0530 Subject: [PATCH 150/184] suggested changes --- .../main/java/com/uber/nullaway/GenericsChecks.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 1581352498..e3a0b871cb 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -248,13 +248,15 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) // nested generics checks Type currentArgType = ASTHelpers.getType(typeArguments.get(i)); if (currentArgType != null && currentArgType.getTypeArguments().size() > 0) { - Type.ClassType nestedTyp = - typeWithPreservedAnnotations((ParameterizedTypeTree) typeArguments.get(i)); - Type.ClassType nestedTypArg = castToNonNull(nestedTyp).cloneWithMetadata(metaData); + Type.ClassType nestedTypArg = + castToNonNull( + typeWithPreservedAnnotations((ParameterizedTypeTree) typeArguments.get(i))) + .cloneWithMetadata(metaData); newTypeArgs.add(nestedTypArg); } else { - Type arg = ASTHelpers.getType(typeArguments.get(i)); - Type.ClassType newArg = (Type.ClassType) castToNonNull(arg).cloneWithMetadata(metaData); + Type.ClassType newArg = + (Type.ClassType) + castToNonNull(ASTHelpers.getType(typeArguments.get(i))).cloneWithMetadata(metaData); newTypeArgs.add(newArg); } } From 257c42cde4e284b0c9b6a02651f7c45fa215c7ff Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 10 Jan 2023 12:16:56 +0530 Subject: [PATCH 151/184] suggested changes --- .../main/java/com/uber/nullaway/GenericsChecks.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index e3a0b871cb..2d41e1b065 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -185,10 +185,12 @@ private void compareAnnotations(Type.ClassType lhsType, Type.ClassType rhsType, throw new RuntimeException(rhsType + " does not match " + lhsType); } for (int i = 0; i < lhsTypeArguments.size(); i++) { + Type lhsTypeArgument = lhsTypeArguments.get(i); + Type rhsTypeArgument = rhsTypeArguments.get(i); com.sun.tools.javac.util.List annotationMirrorsLHS = - lhsTypeArguments.get(i).getAnnotationMirrors(); + lhsTypeArgument.getAnnotationMirrors(); com.sun.tools.javac.util.List annotationMirrorsRHS = - rhsTypeArguments.get(i).getAnnotationMirrors(); + rhsTypeArgument.getAnnotationMirrors(); boolean isLHSNullableAnnotated = Nullness.hasNullableAnnotation(annotationMirrorsLHS.stream(), config); boolean isRHSNullableAnnotated = @@ -198,11 +200,9 @@ private void compareAnnotations(Type.ClassType lhsType, Type.ClassType rhsType, return; } // nested generics - if (lhsTypeArguments.get(i).getTypeArguments().length() > 0) { + if (lhsTypeArgument.getTypeArguments().length() > 0) { compareAnnotations( - (Type.ClassType) lhsTypeArguments.get(i), - (Type.ClassType) rhsTypeArguments.get(i), - tree); + (Type.ClassType) lhsTypeArgument, (Type.ClassType) rhsTypeArgument, tree); } } } From a9e48904ff2e9736c20a3f006356789ea0776b79 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 10 Jan 2023 12:19:01 +0530 Subject: [PATCH 152/184] suggested changes --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 2d41e1b065..ddfec6f3b6 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -182,7 +182,8 @@ private void compareAnnotations(Type.ClassType lhsType, Type.ClassType rhsType, List lhsTypeArguments = lhsType.getTypeArguments(); List rhsTypeArguments = rhsType.getTypeArguments(); if (lhsTypeArguments.size() != rhsTypeArguments.size()) { - throw new RuntimeException(rhsType + " does not match " + lhsType); + throw new RuntimeException( + "number of types arguments in " + rhsType + " does not match " + lhsType); } for (int i = 0; i < lhsTypeArguments.size(); i++) { Type lhsTypeArgument = lhsTypeArguments.get(i); From f3fd30d8ecdc39012a2d03672c84a9be46d87cf6 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 10 Jan 2023 12:19:55 +0530 Subject: [PATCH 153/184] suggested changes --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index ddfec6f3b6..00a9e78027 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -30,7 +30,7 @@ public final class GenericsChecks { private static final String NULLABLE_NAME = "org.jspecify.annotations.Nullable"; - private static final String NULLABLE_TYPE = "@org.jspecify.annotations.Nullable"; + private static final String NULLABLE_TYPE = "@" + NULLABLE_NAME; private static final Supplier NULLABLE_TYPE_SUPPLIER = Suppliers.typeFromString(NULLABLE_NAME); VisitorState state; From aeddd14fb993600d43f346dcab933494bd921596 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 11 Jan 2023 10:49:54 -0800 Subject: [PATCH 154/184] fix nullaway error --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 00a9e78027..14a60811c4 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -250,8 +250,7 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) Type currentArgType = ASTHelpers.getType(typeArguments.get(i)); if (currentArgType != null && currentArgType.getTypeArguments().size() > 0) { Type.ClassType nestedTypArg = - castToNonNull( - typeWithPreservedAnnotations((ParameterizedTypeTree) typeArguments.get(i))) + typeWithPreservedAnnotations((ParameterizedTypeTree) typeArguments.get(i)) .cloneWithMetadata(metaData); newTypeArgs.add(nestedTypArg); } else { From e244e551df4ef6070162bb3168404f1815d6b88b Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 11 Jan 2023 13:35:27 -0800 Subject: [PATCH 155/184] fixes --- .../com/uber/nullaway/GenericsChecks.java | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 14a60811c4..26c64eeb76 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -18,7 +18,6 @@ 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.tree.JCTree; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -30,7 +29,6 @@ public final class GenericsChecks { private static final String NULLABLE_NAME = "org.jspecify.annotations.Nullable"; - private static final String NULLABLE_TYPE = "@" + NULLABLE_NAME; private static final Supplier NULLABLE_TYPE_SUPPLIER = Suppliers.typeFromString(NULLABLE_NAME); VisitorState state; @@ -220,31 +218,30 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) List newTypeArgs = new ArrayList<>(); boolean hasNullableAnnotation = false; for (int i = 0; i < typeArguments.size(); i++) { - List annotations = new ArrayList<>(); - JCTree.JCAnnotatedType annotatedType; - if (typeArguments.get(i).getClass().equals(JCTree.JCAnnotatedType.class)) { - annotatedType = (JCTree.JCAnnotatedType) typeArguments.get(i); - annotations = annotatedType.getAnnotations(); - } else if (typeArguments.get(i) instanceof JCTree.JCTypeApply - && ((JCTree.JCTypeApply) typeArguments.get(i)).clazz instanceof AnnotatedTypeTree) { - annotatedType = (JCTree.JCAnnotatedType) ((JCTree.JCTypeApply) typeArguments.get(i)).clazz; - annotations = annotatedType.getAnnotations(); + AnnotatedTypeTree annotatedType = null; + Tree curTypeArg = typeArguments.get(i); + if (curTypeArg instanceof AnnotatedTypeTree) { + annotatedType = (AnnotatedTypeTree) curTypeArg; + } else if (curTypeArg instanceof ParameterizedTypeTree + && ((ParameterizedTypeTree) curTypeArg).getType() instanceof AnnotatedTypeTree) { + annotatedType = (AnnotatedTypeTree) ((ParameterizedTypeTree) curTypeArg).getType(); } - for (JCTree.JCAnnotation annotation : annotations) { - Attribute.Compound attribute = annotation.attribute; - if (attribute.toString().equals(NULLABLE_TYPE)) { + List annotations = + annotatedType != null ? annotatedType.getAnnotations() : Collections.emptyList(); + for (AnnotationTree annotation : annotations) { + if (ASTHelpers.isSameType( + nullableType, ASTHelpers.getType(annotation.getAnnotationType()), state)) { hasNullableAnnotation = true; + break; } } com.sun.tools.javac.util.List nullableAnnotations = - com.sun.tools.javac.util.List.from(new ArrayList<>()); - if (hasNullableAnnotation) { - nullableAnnotations = - com.sun.tools.javac.util.List.from( - Collections.singletonList( - new Attribute.TypeCompound( - nullableType, com.sun.tools.javac.util.List.nil(), null))); - } + hasNullableAnnotation + ? com.sun.tools.javac.util.List.from( + Collections.singletonList( + new Attribute.TypeCompound( + nullableType, com.sun.tools.javac.util.List.nil(), null))) + : com.sun.tools.javac.util.List.nil(); TypeMetadata metaData = new TypeMetadata(new TypeMetadata.Annotations(nullableAnnotations)); // nested generics checks Type currentArgType = ASTHelpers.getType(typeArguments.get(i)); From 53f85467368e3d011d90ce82836d7b67f2e6578e Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 11 Jan 2023 14:22:55 -0800 Subject: [PATCH 156/184] more cleanup and javadoc --- .../com/uber/nullaway/GenericsChecks.java | 76 ++++++++++++------- .../main/java/com/uber/nullaway/NullAway.java | 4 +- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 26c64eeb76..4ebc1e579c 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -92,14 +92,14 @@ public static void checkInstantiationForParameterizedTypedTree( // if base type argument does not have @Nullable annotation then the instantiation is // invalid if (!hasNullableAnnotation) { - invalidInstantiationError( + reportInvalidInstantiationError( nullableTypeArguments.get(i), baseType, typeVariable, state, analysis); } } } } - private static void invalidInstantiationError( + private static void reportInvalidInstantiationError( Tree tree, Type baseType, Type baseTypeVariable, VisitorState state, NullAway analysis) { ErrorBuilder errorBuilder = analysis.getErrorBuilder(); ErrorMessage errorMessage = @@ -113,7 +113,7 @@ private static void invalidInstantiationError( errorMessage, analysis.buildDescription(tree), state, null)); } - private static void invalidAssignmentInstantiationError( + private static void reportInvalidAssignmentInstantiationError( Tree tree, Type lhsType, Type rhsType, VisitorState state, NullAway analysis) { ErrorBuilder errorBuilder = analysis.getErrorBuilder(); ErrorMessage errorMessage = @@ -130,7 +130,16 @@ private static void invalidAssignmentInstantiationError( errorMessage, analysis.buildDescription(tree), state, null)); } - public void checkInstantiationForAssignments(Tree tree) { + /** + * For a tree representing an assignment, ensures that from the perspective of type parameter + * nullability, the type of the right-hand side is assignable to (a subtype of) the type of the + * left-hand side. This check ensures that for every parameterized type nested in each of the + * types, the type parameters have identical nullability. + * + * @param tree the tree to check, which must be either an {@link AssignmentTree} or a {@link + * VariableTree} + */ + public void checkTypeParameterNullnessForAssignability(Tree tree) { if (!config.isJSpecifyMode()) { return; } @@ -152,27 +161,43 @@ public void checkInstantiationForAssignments(Tree tree) { } Type lhsType = ASTHelpers.getType(lhsTree); Type rhsType = ASTHelpers.getType(rhsTree); + // For NewClassTrees with annotated type parameters, javac does not preserve the annotations in + // its computed type for the expression. As a workaround, we construct a replacement Type + // object with the appropriate annotations. if (rhsTree instanceof NewClassTree && ((NewClassTree) rhsTree).getIdentifier() instanceof ParameterizedTypeTree) { ParameterizedTypeTree paramTypedTree = (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier(); - // not generic - if (paramTypedTree.getTypeArguments().size() <= 0) { + if (paramTypedTree.getTypeArguments().isEmpty()) { + // no explicit type parameters return; } - // for the parameterized typed tree ASTHelpers.getType() returns a type that does not have - // annotations preserved rhsType = typeWithPreservedAnnotations( (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier()); } if (lhsType != null && rhsType != null) { - compareAnnotations((Type.ClassType) lhsType, (Type.ClassType) rhsType, tree); + compareNullabilityAnnotations((Type.ClassType) lhsType, (Type.ClassType) rhsType, tree); } } - private void compareAnnotations(Type.ClassType lhsType, Type.ClassType rhsType, Tree tree) { + /** + * Compare two types from an assignment for identical type parameter nullability, recursively + * checking nested generic types. See the JSpecify + * specification and the JLS + * subtyping rules for class and interface types. + * + * @param lhsType type for the lhs of the assignment + * @param rhsType type for the rhs of the assignment + * @param tree tree representing the assignment + */ + private void compareNullabilityAnnotations( + Type.ClassType lhsType, Type.ClassType rhsType, Tree tree) { Types types = state.getTypes(); + // The base type of rhsType may be a subtype of lhsType's base type. In such cases, we must + // compare lhsType against the supertype of rhsType with a matching base type. rhsType = (Type.ClassType) types.asSuper(rhsType, lhsType.tsym); if (rhsType == null) { throw new RuntimeException("did not find supertype of " + rhsType + " matching " + lhsType); @@ -195,12 +220,12 @@ private void compareAnnotations(Type.ClassType lhsType, Type.ClassType rhsType, boolean isRHSNullableAnnotated = Nullness.hasNullableAnnotation(annotationMirrorsRHS.stream(), config); if (isLHSNullableAnnotated != isRHSNullableAnnotated) { - invalidAssignmentInstantiationError(tree, lhsType, rhsType, state, analysis); + reportInvalidAssignmentInstantiationError(tree, lhsType, rhsType, state, analysis); return; } // nested generics if (lhsTypeArgument.getTypeArguments().length() > 0) { - compareAnnotations( + compareNullabilityAnnotations( (Type.ClassType) lhsTypeArgument, (Type.ClassType) rhsTypeArgument, tree); } } @@ -220,6 +245,8 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) for (int i = 0; i < typeArguments.size(); i++) { AnnotatedTypeTree annotatedType = null; Tree curTypeArg = typeArguments.get(i); + // If the type argument has an annotation, it will either be an AnnotatedTypeTree, or a + // ParameterizedTypeTree in the case of a nested generic type if (curTypeArg instanceof AnnotatedTypeTree) { annotatedType = (AnnotatedTypeTree) curTypeArg; } else if (curTypeArg instanceof ParameterizedTypeTree @@ -235,27 +262,24 @@ private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) break; } } - com.sun.tools.javac.util.List nullableAnnotations = + // construct a TypeMetadata object containing a nullability annotation if needed + com.sun.tools.javac.util.List nullableAnnotationCompound = hasNullableAnnotation ? com.sun.tools.javac.util.List.from( Collections.singletonList( new Attribute.TypeCompound( nullableType, com.sun.tools.javac.util.List.nil(), null))) : com.sun.tools.javac.util.List.nil(); - TypeMetadata metaData = new TypeMetadata(new TypeMetadata.Annotations(nullableAnnotations)); - // nested generics checks - Type currentArgType = ASTHelpers.getType(typeArguments.get(i)); - if (currentArgType != null && currentArgType.getTypeArguments().size() > 0) { - Type.ClassType nestedTypArg = - typeWithPreservedAnnotations((ParameterizedTypeTree) typeArguments.get(i)) - .cloneWithMetadata(metaData); - newTypeArgs.add(nestedTypArg); - } else { - Type.ClassType newArg = - (Type.ClassType) - castToNonNull(ASTHelpers.getType(typeArguments.get(i))).cloneWithMetadata(metaData); - newTypeArgs.add(newArg); + TypeMetadata typeMetadata = + new TypeMetadata(new TypeMetadata.Annotations(nullableAnnotationCompound)); + Type currentTypeArgType = castToNonNull(ASTHelpers.getType(curTypeArg)); + if (currentTypeArgType.getTypeArguments().size() > 0) { + // nested generic type; recursively preserve its nullability type argument annotations + currentTypeArgType = typeWithPreservedAnnotations((ParameterizedTypeTree) curTypeArg); } + Type.ClassType newTypeArgType = + (Type.ClassType) currentTypeArgType.cloneWithMetadata(typeMetadata); + newTypeArgs.add(newTypeArgType); } Type.ClassType finalType = new Type.ClassType( diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 06a0d5eca8..f444d780ae 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -464,7 +464,7 @@ public Description matchAssignment(AssignmentTree tree, VisitorState state) { } // generics check if (lhsType != null && lhsType.getTypeArguments().length() > 0) { - new GenericsChecks(state, config, this).checkInstantiationForAssignments(tree); + new GenericsChecks(state, config, this).checkTypeParameterNullnessForAssignability(tree); } Symbol assigned = ASTHelpers.getSymbol(tree.getVariable()); @@ -1337,7 +1337,7 @@ public Description matchVariable(VariableTree tree, VisitorState state) { } VarSymbol symbol = ASTHelpers.getSymbol(tree); if (tree.getInitializer() != null) { - new GenericsChecks(state, config, this).checkInstantiationForAssignments(tree); + new GenericsChecks(state, config, this).checkTypeParameterNullnessForAssignability(tree); } if (symbol.type.isPrimitive() && tree.getInitializer() != null) { From d6bc8101517d98516aa0b505b78b2a3f122975b0 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 23 Jan 2023 19:11:47 +0530 Subject: [PATCH 157/184] suggested changes in test nestedChecksForAssignmentsMultipleArguments --- .../uber/nullaway/NullAwayJSpecifyGenericsTests.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 24ed23af64..9332101153 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -223,14 +223,12 @@ public void nestedChecksForAssignmentsMultipleArguments() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " static class NullableTypeParam {}", - " static class NullableTypeParamMultipleArguments {}", - " static class NullableTypeParamMultipleArgumentsNested {}", - " static void testOKOtherAnnotation(NullableTypeParam t) {", - " NullableTypeParamMultipleArguments>, String> t10 = new NullableTypeParamMultipleArguments>, String> ();", - " NullableTypeParamMultipleArguments>, String> t11 = new NullableTypeParamMultipleArguments>, String> ();", + " static class SampleClass {}", + " static class SampleClassMultipleArguments {}", + " static void testOKOtherAnnotation() {", " // BUG: Diagnostic contains: Cannot assign from type", - " t10 = t11;", + " SampleClassMultipleArguments>, String> t1 = ", + " new SampleClassMultipleArguments>, String> ();", " }", "}") .doTest(); From 3127339b789283570024ec5c86c69714318c5edc Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 23 Jan 2023 19:13:30 +0530 Subject: [PATCH 158/184] suggested changes in test - superTypeAssignmentChecksSingleInterface --- .../java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 9332101153..b86dcf0e54 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -247,8 +247,8 @@ public void superTypeAssignmentChecksSingleInterface() { " void sampleError() {", " // BUG: Diagnostic contains: Cannot assign from type", " Fn<@Nullable String, String> f = new FnImpl();", - " }", - " }") + " }", + "}") .doTest(); } From 4aacb5a47d182c723a8c0d05a75d59374fa7365c Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 23 Jan 2023 19:14:32 +0530 Subject: [PATCH 159/184] suggested indentation changes in test - superTypeAssignmentChecksMultipleInterface --- .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index b86dcf0e54..aebfe98f92 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -265,10 +265,10 @@ public void superTypeAssignmentChecksMultipleInterface() { " class FnImpl implements Fn1<@Nullable String, @Nullable String>, Fn2 {}", " void sampleError() {", " Fn2<@Nullable String> f;", - " // BUG: Diagnostic contains: Cannot assign from type", + " // BUG: Diagnostic contains: Cannot assign from type", " f = new FnImpl();", - " }", - " }") + " }", + " }") .doTest(); } From f3e6b45e90d3bc7090d2fad26fb6ff5b72105521 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 23 Jan 2023 19:17:02 +0530 Subject: [PATCH 160/184] suggested changes --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 4ebc1e579c..6011dbc916 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -199,8 +199,10 @@ private void compareNullabilityAnnotations( // The base type of rhsType may be a subtype of lhsType's base type. In such cases, we must // compare lhsType against the supertype of rhsType with a matching base type. rhsType = (Type.ClassType) types.asSuper(rhsType, lhsType.tsym); + // This is impossible, considering the fact that standard Java subtyping succeeds before running + // NullAway if (rhsType == null) { - throw new RuntimeException("did not find supertype of " + rhsType + " matching " + lhsType); + throw new RuntimeException("Did not find supertype of " + rhsType + " matching " + lhsType); } List lhsTypeArguments = lhsType.getTypeArguments(); List rhsTypeArguments = rhsType.getTypeArguments(); From 38f2ef6a8c10f3d0e5b446bf52c98ccafe447a26 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 23 Jan 2023 19:19:59 +0530 Subject: [PATCH 161/184] suggested changes --- .../src/main/java/com/uber/nullaway/GenericsChecks.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 6011dbc916..621f5e91bb 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -213,14 +213,10 @@ private void compareNullabilityAnnotations( for (int i = 0; i < lhsTypeArguments.size(); i++) { Type lhsTypeArgument = lhsTypeArguments.get(i); Type rhsTypeArgument = rhsTypeArguments.get(i); - com.sun.tools.javac.util.List annotationMirrorsLHS = - lhsTypeArgument.getAnnotationMirrors(); - com.sun.tools.javac.util.List annotationMirrorsRHS = - rhsTypeArgument.getAnnotationMirrors(); boolean isLHSNullableAnnotated = - Nullness.hasNullableAnnotation(annotationMirrorsLHS.stream(), config); + Nullness.hasNullableAnnotation(lhsTypeArgument.getAnnotationMirrors().stream(), config); boolean isRHSNullableAnnotated = - Nullness.hasNullableAnnotation(annotationMirrorsRHS.stream(), config); + Nullness.hasNullableAnnotation(rhsTypeArgument.getAnnotationMirrors().stream(), config); if (isLHSNullableAnnotated != isRHSNullableAnnotated) { reportInvalidAssignmentInstantiationError(tree, lhsType, rhsType, state, analysis); return; From 5245c4ddaba443bc3c3ad2fe096d434583b46767 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 23 Jan 2023 19:51:01 +0530 Subject: [PATCH 162/184] suggested test for the lambda expressions --- .../NullAwayJSpecifyGenericsTests.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index aebfe98f92..e02fb079a5 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -382,6 +382,27 @@ public void instantiationInUnannotatedCode() { .doTest(); } + @Test + public void testForLambdaExpressionInAnAssignment() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.other;", + "import org.jspecify.annotations.Nullable;", + " class Test {", + " interface A{", + " String function(@Nullable Object o, String string);", + " }", + " static @Nullable String foo(@Nullable Object o, @Nullable String string) {", + " return o != null ? o.toString() : string;", + " }", + " static void bar() {", + " A<@Nullable Object,String> p = Test::foo;", + " }", + "}") + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( Arrays.asList( From 0344360218affcb747f40229f29d01dd698e9476 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 23 Jan 2023 20:04:54 +0530 Subject: [PATCH 163/184] Java doc for type with preserved annotations --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 621f5e91bb..d535894116 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -230,6 +230,10 @@ private void compareNullabilityAnnotations( } /** + * For the Parameterized typed trees ASTHelpers.getType(tree) does not return a Type with + * preserved annotations. This method takes a Parameterized typed tree as an input and returns the + * Type of the tree with the annotations. + * * @param tree A parameterized typed tree for which we need class type with preserved annotations. * @return A Type with preserved annotations. */ From 00cad6f16632b638400b7fd415d52b44825ec009 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 23 Jan 2023 20:07:19 +0530 Subject: [PATCH 164/184] comments --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index d535894116..326855e846 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -206,6 +206,8 @@ private void compareNullabilityAnnotations( } List lhsTypeArguments = lhsType.getTypeArguments(); List rhsTypeArguments = rhsType.getTypeArguments(); + // This is impossible, considering the fact that standard Java subtyping succeeds before running + // NullAway if (lhsTypeArguments.size() != rhsTypeArguments.size()) { throw new RuntimeException( "number of types arguments in " + rhsType + " does not match " + lhsType); From d09c190bf67627c0cbf43e00f148038c7f9c5d61 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 23 Jan 2023 20:08:30 +0530 Subject: [PATCH 165/184] code cleaning for the tests --- .../com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index e02fb079a5..a1a7069bb0 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -268,7 +268,7 @@ public void superTypeAssignmentChecksMultipleInterface() { " // BUG: Diagnostic contains: Cannot assign from type", " f = new FnImpl();", " }", - " }") + "}") .doTest(); } @@ -295,7 +295,7 @@ public void superTypeAssignmentChecksMultipleLevelInheritance() { " // No error", " f = new FnImpl2();", " }", - " }") + "}") .doTest(); } @@ -317,7 +317,7 @@ public void subtypeWithParameters() { " // BUG: Diagnostic contains: Cannot assign from type", " D f = b;", " }", - " }") + "}") .doTest(); } @@ -361,7 +361,7 @@ public void nestedVariableDeclarationChecks() { " // BUG: Diagnostic contains: Cannot assign from type", " D> f3 = new B<@Nullable C>();", " }", - " }") + "}") .doTest(); } From 8bb552c40473985f94dd149c9d79df5d7d27d9ed Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 23 Jan 2023 20:09:48 +0530 Subject: [PATCH 166/184] code cleaning for the tests --- .../java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index a1a7069bb0..ba626e08af 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -225,7 +225,7 @@ public void nestedChecksForAssignmentsMultipleArguments() { "class Test {", " static class SampleClass {}", " static class SampleClassMultipleArguments {}", - " static void testOKOtherAnnotation() {", + " static void test() {", " // BUG: Diagnostic contains: Cannot assign from type", " SampleClassMultipleArguments>, String> t1 = ", " new SampleClassMultipleArguments>, String> ();", From 0cff82f49e21b58457877f300336d29c21c021ba Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 23 Jan 2023 20:13:16 +0530 Subject: [PATCH 167/184] changes --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 326855e846..50e428acc5 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -172,9 +172,7 @@ public void checkTypeParameterNullnessForAssignability(Tree tree) { // no explicit type parameters return; } - rhsType = - typeWithPreservedAnnotations( - (ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier()); + rhsType = typeWithPreservedAnnotations(paramTypedTree); } if (lhsType != null && rhsType != null) { compareNullabilityAnnotations((Type.ClassType) lhsType, (Type.ClassType) rhsType, tree); From 9906f255ce7f903e7cf6b7b8dd279e9e97793184 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 23 Jan 2023 20:14:38 +0530 Subject: [PATCH 168/184] suggested changes --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 50e428acc5..38aed0f0cb 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -174,7 +174,10 @@ public void checkTypeParameterNullnessForAssignability(Tree tree) { } rhsType = typeWithPreservedAnnotations(paramTypedTree); } - if (lhsType != null && rhsType != null) { + if (lhsType != null + && lhsType instanceof Type.ClassType + && rhsType != null + && rhsType instanceof Type.ClassType) { compareNullabilityAnnotations((Type.ClassType) lhsType, (Type.ClassType) rhsType, tree); } } From f6dcc6988436f5d761333344b8eee0247bd7616d Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Mon, 23 Jan 2023 23:26:36 +0530 Subject: [PATCH 169/184] negative tests --- .../NullAwayJSpecifyGenericsTests.java | 51 +++++++++++++------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index ba626e08af..433b205d92 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -207,10 +207,13 @@ public void genericsChecksForAssignments() { "import org.jspecify.annotations.Nullable;", "class Test {", " static class NullableTypeParam {}", - " static void testBadNonNull(NullableTypeParam<@Nullable String> t1) {", + " static void testPositive(NullableTypeParam<@Nullable String> t1) {", " // BUG: Diagnostic contains: Cannot assign from type", " NullableTypeParam t2 = t1;", " }", + " static void testNegative(NullableTypeParam<@Nullable String> t1) {", + " NullableTypeParam<@Nullable String> t2 = t1;", + " }", "}") .doTest(); } @@ -225,11 +228,15 @@ public void nestedChecksForAssignmentsMultipleArguments() { "class Test {", " static class SampleClass {}", " static class SampleClassMultipleArguments {}", - " static void test() {", + " static void testPositive() {", " // BUG: Diagnostic contains: Cannot assign from type", " SampleClassMultipleArguments>, String> t1 = ", " new SampleClassMultipleArguments>, String> ();", " }", + " static void testNegative() {", + " SampleClassMultipleArguments>, String> t1 = ", + " new SampleClassMultipleArguments>, String> ();", + " }", "}") .doTest(); } @@ -244,10 +251,13 @@ public void superTypeAssignmentChecksSingleInterface() { "class Test {", " interface Fn

{}", " class FnImpl implements Fn<@Nullable String, @Nullable String>{}", - " void sampleError() {", + " void testPositive() {", " // BUG: Diagnostic contains: Cannot assign from type", " Fn<@Nullable String, String> f = new FnImpl();", " }", + " void testNegative() {", + " Fn<@Nullable String, @Nullable String> f = new FnImpl();", + " }", "}") .doTest(); } @@ -263,10 +273,12 @@ public void superTypeAssignmentChecksMultipleInterface() { " interface Fn1{}", " interface Fn2

{}", " class FnImpl implements Fn1<@Nullable String, @Nullable String>, Fn2 {}", - " void sampleError() {", - " Fn2<@Nullable String> f;", + " void testPositive() {", " // BUG: Diagnostic contains: Cannot assign from type", - " f = new FnImpl();", + " Fn2<@Nullable String> f = new FnImpl();", + " }", + " void testNegative() {", + " Fn2 f = new FnImpl();", " }", "}") .doTest(); @@ -285,12 +297,12 @@ public void superTypeAssignmentChecksMultipleLevelInheritance() { " class SubClassA

extends SuperClassB

{}", " class FnImpl1 extends SubClassA{}", " class FnImpl2 extends SubClassA<@Nullable String>{}", - " void sampleError() {", + " void testPositive() {", " SuperClassC<@Nullable String> f;", " // BUG: Diagnostic contains: Cannot assign from type", " f = new FnImpl1();", " }", - " void sampleValidInstantiation() {", + " void testNegative() {", " SuperClassC<@Nullable String> f;", " // No error", " f = new FnImpl2();", @@ -309,13 +321,15 @@ public void subtypeWithParameters() { "class Test {", " class D

{}", " class B

extends D

{}", - " void test1() {", + " void testPositive(B<@Nullable String> b) {", " // BUG: Diagnostic contains: Cannot assign from type", - " D f = new B<@Nullable String>();", - " }", - " void test2(B<@Nullable String> b) {", + " D f1 = new B<@Nullable String>();", " // BUG: Diagnostic contains: Cannot assign from type", - " D f = b;", + " D f2 = b;", + " }", + " void testNegative(B b) {", + " D f1 = new B();", + " D f2 = b;", " }", "}") .doTest(); @@ -331,9 +345,11 @@ public void fancierSubtypeWithParameters() { "class Test {", " class Super {}", " class Sub extends Super {}", - " void test1() {", + " void testNegative() {", " // valid assignment", " Super<@Nullable String, String> s = new Sub();", + " }", + " void testPositive() {", " // BUG: Diagnostic contains: Cannot assign from type", " Super<@Nullable String, String> s2 = new Sub<@Nullable String, String>();", " }", @@ -353,7 +369,7 @@ public void nestedVariableDeclarationChecks() { " class B

extends D

{}", " class C

{}", " class A, P extends @Nullable Object>{}", - " void sampleError() {", + " void testPositive() {", " // BUG: Diagnostic contains: Cannot assign from type", " D> f1 = new B>();", " // BUG: Diagnostic contains: Cannot assign from type", @@ -361,6 +377,11 @@ public void nestedVariableDeclarationChecks() { " // BUG: Diagnostic contains: Cannot assign from type", " D> f3 = new B<@Nullable C>();", " }", + " void testNegative() {", + " D> f1 = new B>();", + " A, String> f2 = new A, String>();", + " D<@Nullable C> f3 = new B<@Nullable C>();", + " }", "}") .doTest(); } From 4323d48a33d1c3303e71a476831f310756f4a516 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Mon, 23 Jan 2023 13:21:05 -0800 Subject: [PATCH 170/184] fix formatting in tests --- .../NullAwayJSpecifyGenericsTests.java | 296 +++++++++--------- 1 file changed, 152 insertions(+), 144 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 433b205d92..9008a3f71a 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -14,14 +14,14 @@ public void basicTypeParamInstantiation() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " static class NonNullTypeParam {}", - " static class NullableTypeParam {}", + " static class NonNullTypeParam {}", + " static class NullableTypeParam {}", + " // BUG: Diagnostic contains: Generic type parameter", + " static void testBadNonNull(NonNullTypeParam<@Nullable String> t1) {", " // BUG: Diagnostic contains: Generic type parameter", - " static void testBadNonNull(NonNullTypeParam<@Nullable String> t1) {", - " // BUG: Diagnostic contains: Generic type parameter", - " NonNullTypeParam<@Nullable String> t2 = null;", - " NullableTypeParam<@Nullable String> t3 = null;", - " }", + " NonNullTypeParam<@Nullable String> t2 = null;", + " NullableTypeParam<@Nullable String> t3 = null;", + " }", "}") .doTest(); } @@ -34,24 +34,25 @@ public void constructorTypeParamInstantiation() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " static class NonNullTypeParam {}", - " static class NullableTypeParam {}", - " static void testOkNonNull(NonNullTypeParam t) {", - " NonNullTypeParam t2 = new NonNullTypeParam();", - " }", - " static void testBadNonNull(NonNullTypeParam t) {", - " // BUG: Diagnostic contains: Generic type parameter", - " NonNullTypeParam t2 = new NonNullTypeParam<@Nullable String>();", - " // BUG: Diagnostic contains: Generic type parameter", - " testBadNonNull(new NonNullTypeParam<@Nullable String>());", - " testBadNonNull(new NonNullTypeParam<", - " // BUG: Diagnostic contains: Generic type parameter", - " @Nullable String>());", - " }", - " static void testOkNullable(NullableTypeParam t1, NullableTypeParam<@Nullable String> t2) {", - " NullableTypeParam t3 = new NullableTypeParam();", - " NullableTypeParam<@Nullable String> t4 = new NullableTypeParam<@Nullable String>();", - " }", + " static class NonNullTypeParam {}", + " static class NullableTypeParam {}", + " static void testOkNonNull(NonNullTypeParam t) {", + " NonNullTypeParam t2 = new NonNullTypeParam();", + " }", + " static void testBadNonNull(NonNullTypeParam t) {", + " // BUG: Diagnostic contains: Generic type parameter", + " NonNullTypeParam t2 = new NonNullTypeParam<@Nullable String>();", + " // BUG: Diagnostic contains: Generic type parameter", + " testBadNonNull(new NonNullTypeParam<@Nullable String>());", + " testBadNonNull(", + " new NonNullTypeParam<", + " // BUG: Diagnostic contains: Generic type parameter", + " @Nullable String>());", + " }", + " static void testOkNullable(NullableTypeParam t1, NullableTypeParam<@Nullable String> t2) {", + " NullableTypeParam t3 = new NullableTypeParam();", + " NullableTypeParam<@Nullable String> t4 = new NullableTypeParam<@Nullable String>();", + " }", "}") .doTest(); } @@ -64,14 +65,20 @@ public void multipleTypeParametersInstantiation() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " static class MixedTypeParam {}", - " // BUG: Diagnostic contains: Generic type parameter", - " static class PartiallyInvalidSubclass extends MixedTypeParam<@Nullable String, String, String, @Nullable String> {}", - " static class ValidSubclass1 extends MixedTypeParam {}", - " static class PartiallyInvalidSubclass2 extends MixedTypeParam {}", - " static class ValidSubclass2 extends MixedTypeParam {}", + " static class MixedTypeParam {}", + " static class PartiallyInvalidSubclass", + " // BUG: Diagnostic contains: Generic type parameter", + " extends MixedTypeParam<@Nullable String, String, String, @Nullable String> {}", + " static class ValidSubclass1", + " extends MixedTypeParam {}", + " static class PartiallyInvalidSubclass2", + " extends MixedTypeParam<", + " String,", + " String,", + " String,", + " // BUG: Diagnostic contains: Generic type parameter", + " @Nullable String> {}", + " static class ValidSubclass2 extends MixedTypeParam {}", "}") .doTest(); } @@ -84,13 +91,13 @@ public void subClassTypeParamInstantiation() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " static class NonNullTypeParam {}", - " static class NullableTypeParam {}", - " static class SuperClassForValidSubclass {", - " static class ValidSubclass extends NullableTypeParam<@Nullable String> {}", - " // BUG: Diagnostic contains: Generic type parameter", - " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", - " }", + " static class NonNullTypeParam {}", + " static class NullableTypeParam {}", + " static class SuperClassForValidSubclass {", + " static class ValidSubclass extends NullableTypeParam<@Nullable String> {}", + " // BUG: Diagnostic contains: Generic type parameter", + " static class InvalidSubclass extends NonNullTypeParam<@Nullable String> {}", + " }", "}") .doTest(); } @@ -103,11 +110,12 @@ public void interfaceImplementationTypeParamInstantiation() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " static interface NonNullTypeParamInterface{}", - " static interface NullableTypeParamInterface{}", - " // BUG: Diagnostic contains: Generic type parameter", - " static class InvalidInterfaceImplementation implements NonNullTypeParamInterface<@Nullable String> {}", - " static class ValidInterfaceImplementation implements NullableTypeParamInterface {}", + " static interface NonNullTypeParamInterface {}", + " static interface NullableTypeParamInterface {}", + " static class InvalidInterfaceImplementation", + " // BUG: Diagnostic contains: Generic type parameter", + " implements NonNullTypeParamInterface<@Nullable String> {}", + " static class ValidInterfaceImplementation implements NullableTypeParamInterface {}", "}") .doTest(); } @@ -120,17 +128,17 @@ public void nestedTypeParams() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " static class NonNullTypeParam {}", - " static class NullableTypeParam {}", + " static class NonNullTypeParam {}", + " static class NullableTypeParam {}", + " // BUG: Diagnostic contains: Generic type parameter", + " static void testBadNonNull(NullableTypeParam> t) {", + " // BUG: Diagnostic contains: Generic type parameter", + " NullableTypeParam>> t2 = null;", " // BUG: Diagnostic contains: Generic type parameter", - " static void testBadNonNull(NullableTypeParam> t) {", - " // BUG: Diagnostic contains: Generic type parameter", - " NullableTypeParam>> t2 = null;", - " // BUG: Diagnostic contains: Generic type parameter", - " t2 = new NullableTypeParam>>();", - " // this is fine", - " NullableTypeParam>> t3 = null;", - " }", + " t2 = new NullableTypeParam>>();", + " // this is fine", + " NullableTypeParam>> t3 = null;", + " }", "}") .doTest(); } @@ -143,15 +151,15 @@ public void returnTypeParamInstantiation() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " static class NonNullTypeParam {}", - " static class NullableTypeParam {}", - " // BUG: Diagnostic contains: Generic type parameter", - " static NonNullTypeParam<@Nullable String> testBadNonNull() {", - " return new NonNullTypeParam();", - " }", - " static NullableTypeParam<@Nullable String> testOKNull() {", - " return new NullableTypeParam<@Nullable String>();", - " }", + " static class NonNullTypeParam {}", + " static class NullableTypeParam {}", + " // BUG: Diagnostic contains: Generic type parameter", + " static NonNullTypeParam<@Nullable String> testBadNonNull() {", + " return new NonNullTypeParam();", + " }", + " static NullableTypeParam<@Nullable String> testOKNull() {", + " return new NullableTypeParam<@Nullable String>();", + " }", "}") .doTest(); } @@ -165,18 +173,18 @@ public void testOKNewClassInstantiationForOtherAnnotations() { "import lombok.NonNull;", "import org.jspecify.annotations.Nullable;", "class Test {", - " static class NonNullTypeParam {}", - " static class DifferentAnnotTypeParam1 {}", - " static class DifferentAnnotTypeParam2<@NonNull E> {}", - " static void testOKOtherAnnotation(NonNullTypeParam t) {", - " // should not show error for annotation other than @Nullable", - " testOKOtherAnnotation(new NonNullTypeParam<@NonNull String>());", - " DifferentAnnotTypeParam1 t1 = new DifferentAnnotTypeParam1();", - " // BUG: Diagnostic contains: Generic type parameter", - " DifferentAnnotTypeParam2 t2 = new DifferentAnnotTypeParam2<@Nullable String>();", - " // BUG: Diagnostic contains: Generic type parameter", - " DifferentAnnotTypeParam1 t3 = new DifferentAnnotTypeParam1<@Nullable String>();", - " }", + " static class NonNullTypeParam {}", + " static class DifferentAnnotTypeParam1 {}", + " static class DifferentAnnotTypeParam2<@NonNull E> {}", + " static void testOKOtherAnnotation(NonNullTypeParam t) {", + " // should not show error for annotation other than @Nullable", + " testOKOtherAnnotation(new NonNullTypeParam<@NonNull String>());", + " DifferentAnnotTypeParam1 t1 = new DifferentAnnotTypeParam1();", + " // BUG: Diagnostic contains: Generic type parameter", + " DifferentAnnotTypeParam2 t2 = new DifferentAnnotTypeParam2<@Nullable String>();", + " // BUG: Diagnostic contains: Generic type parameter", + " DifferentAnnotTypeParam1 t3 = new DifferentAnnotTypeParam1<@Nullable String>();", + " }", "}") .doTest(); } @@ -189,7 +197,7 @@ public void downcastInstantiation() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " static class NonNullTypeParam { }", + " static class NonNullTypeParam {}", " static void instOf(Object o) {", " // BUG: Diagnostic contains: Generic type parameter", " Object p = (NonNullTypeParam<@Nullable String>) o;", @@ -206,14 +214,14 @@ public void genericsChecksForAssignments() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " static class NullableTypeParam {}", - " static void testPositive(NullableTypeParam<@Nullable String> t1) {", - " // BUG: Diagnostic contains: Cannot assign from type", - " NullableTypeParam t2 = t1;", - " }", - " static void testNegative(NullableTypeParam<@Nullable String> t1) {", - " NullableTypeParam<@Nullable String> t2 = t1;", - " }", + " static class NullableTypeParam {}", + " static void testPositive(NullableTypeParam<@Nullable String> t1) {", + " // BUG: Diagnostic contains: Cannot assign from type", + " NullableTypeParam t2 = t1;", + " }", + " static void testNegative(NullableTypeParam<@Nullable String> t1) {", + " NullableTypeParam<@Nullable String> t2 = t1;", + " }", "}") .doTest(); } @@ -226,17 +234,17 @@ public void nestedChecksForAssignmentsMultipleArguments() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " static class SampleClass {}", - " static class SampleClassMultipleArguments {}", - " static void testPositive() {", - " // BUG: Diagnostic contains: Cannot assign from type", - " SampleClassMultipleArguments>, String> t1 = ", - " new SampleClassMultipleArguments>, String> ();", - " }", - " static void testNegative() {", - " SampleClassMultipleArguments>, String> t1 = ", - " new SampleClassMultipleArguments>, String> ();", - " }", + " static class SampleClass {}", + " static class SampleClassMultipleArguments {}", + " static void testPositive() {", + " // BUG: Diagnostic contains: Cannot assign from type", + " SampleClassMultipleArguments>, String> t1 =", + " new SampleClassMultipleArguments>, String>();", + " }", + " static void testNegative() {", + " SampleClassMultipleArguments>, String> t1 =", + " new SampleClassMultipleArguments>, String>();", + " }", "}") .doTest(); } @@ -249,14 +257,14 @@ public void superTypeAssignmentChecksSingleInterface() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " interface Fn

{}", - " class FnImpl implements Fn<@Nullable String, @Nullable String>{}", - " void testPositive() {", + " interface Fn

{}", + " class FnImpl implements Fn<@Nullable String, @Nullable String> {}", + " void testPositive() {", " // BUG: Diagnostic contains: Cannot assign from type", - " Fn<@Nullable String, String> f = new FnImpl();", + " Fn<@Nullable String, String> f = new FnImpl();", " }", - " void testNegative() {", - " Fn<@Nullable String, @Nullable String> f = new FnImpl();", + " void testNegative() {", + " Fn<@Nullable String, @Nullable String> f = new FnImpl();", " }", "}") .doTest(); @@ -270,15 +278,15 @@ public void superTypeAssignmentChecksMultipleInterface() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " interface Fn1{}", - " interface Fn2

{}", + " interface Fn1 {}", + " interface Fn2

{}", " class FnImpl implements Fn1<@Nullable String, @Nullable String>, Fn2 {}", - " void testPositive() {", - " // BUG: Diagnostic contains: Cannot assign from type", - " Fn2<@Nullable String> f = new FnImpl();", + " void testPositive() {", + " // BUG: Diagnostic contains: Cannot assign from type", + " Fn2<@Nullable String> f = new FnImpl();", " }", - " void testNegative() {", - " Fn2 f = new FnImpl();", + " void testNegative() {", + " Fn2 f = new FnImpl();", " }", "}") .doTest(); @@ -292,18 +300,18 @@ public void superTypeAssignmentChecksMultipleLevelInheritance() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " class SuperClassC{}", - " class SuperClassB

extends SuperClassC

{}", - " class SubClassA

extends SuperClassB

{}", - " class FnImpl1 extends SubClassA{}", - " class FnImpl2 extends SubClassA<@Nullable String>{}", + " class SuperClassC {}", + " class SuperClassB

extends SuperClassC

{}", + " class SubClassA

extends SuperClassB

{}", + " class FnImpl1 extends SubClassA {}", + " class FnImpl2 extends SubClassA<@Nullable String> {}", " void testPositive() {", " SuperClassC<@Nullable String> f;", " // BUG: Diagnostic contains: Cannot assign from type", " f = new FnImpl1();", - " }", + " }", " void testNegative() {", - " SuperClassC<@Nullable String> f;", + " SuperClassC<@Nullable String> f;", " // No error", " f = new FnImpl2();", " }", @@ -320,17 +328,17 @@ public void subtypeWithParameters() { "import org.jspecify.annotations.Nullable;", "class Test {", " class D

{}", - " class B

extends D

{}", - " void testPositive(B<@Nullable String> b) {", + " class B

extends D

{}", + " void testPositive(B<@Nullable String> b) {", " // BUG: Diagnostic contains: Cannot assign from type", " D f1 = new B<@Nullable String>();", " // BUG: Diagnostic contains: Cannot assign from type", " D f2 = b;", - " }", - " void testNegative(B b) {", + " }", + " void testNegative(B b) {", " D f1 = new B();", " D f2 = b;", - " }", + " }", "}") .doTest(); } @@ -366,22 +374,22 @@ public void nestedVariableDeclarationChecks() { "import org.jspecify.annotations.Nullable;", "class Test {", " class D

{}", - " class B

extends D

{}", - " class C

{}", - " class A, P extends @Nullable Object>{}", - " void testPositive() {", - " // BUG: Diagnostic contains: Cannot assign from type", - " D> f1 = new B>();", - " // BUG: Diagnostic contains: Cannot assign from type", - " A, String> f2 = new A, @Nullable String>();", - " // BUG: Diagnostic contains: Cannot assign from type", - " D> f3 = new B<@Nullable C>();", - " }", - " void testNegative() {", - " D> f1 = new B>();", - " A, String> f2 = new A, String>();", - " D<@Nullable C> f3 = new B<@Nullable C>();", - " }", + " class B

extends D

{}", + " class C

{}", + " class A, P extends @Nullable Object> {}", + " void testPositive() {", + " // BUG: Diagnostic contains: Cannot assign from type", + " D> f1 = new B>();", + " // BUG: Diagnostic contains: Cannot assign from type", + " A, String> f2 = new A, @Nullable String>();", + " // BUG: Diagnostic contains: Cannot assign from type", + " D> f3 = new B<@Nullable C>();", + " }", + " void testNegative() {", + " D> f1 = new B>();", + " A, String> f2 = new A, String>();", + " D<@Nullable C> f3 = new B<@Nullable C>();", + " }", "}") .doTest(); } @@ -395,7 +403,7 @@ public void instantiationInUnannotatedCode() { "package com.other;", "import org.jspecify.annotations.Nullable;", "class Test {", - " static class NonNullTypeParam { }", + " static class NonNullTypeParam {}", " static void instOf(Object o) {", " Object p = (NonNullTypeParam<@Nullable String>) o;", " }", @@ -410,15 +418,15 @@ public void testForLambdaExpressionInAnAssignment() { "Test.java", "package com.other;", "import org.jspecify.annotations.Nullable;", - " class Test {", - " interface A{", - " String function(@Nullable Object o, String string);", - " }", + "class Test {", + " interface A {", + " String function(@Nullable Object o, String string);", + " }", " static @Nullable String foo(@Nullable Object o, @Nullable String string) {", - " return o != null ? o.toString() : string;", + " return o != null ? o.toString() : string;", " }", " static void bar() {", - " A<@Nullable Object,String> p = Test::foo;", + " A<@Nullable Object, String> p = Test::foo;", " }", "}") .doTest(); From 5ec8fa1f9c769eb46c4f813f57c10d0ea36d943e Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 24 Jan 2023 23:06:38 +0530 Subject: [PATCH 171/184] test cases for diamond operator and the lambdas --- .../NullAwayJSpecifyGenericsTests.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 9008a3f71a..ca23869d80 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -416,13 +416,14 @@ public void testForLambdaExpressionInAnAssignment() { makeHelper() .addSourceLines( "Test.java", - "package com.other;", + "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", " interface A {", " String function(@Nullable Object o, String string);", " }", - " static @Nullable String foo(@Nullable Object o, @Nullable String string) {", + " static String foo(@Nullable Object o, String string) {", + " //Should generate an error here. This will be handled in the future PRs", " return o != null ? o.toString() : string;", " }", " static void bar() {", @@ -432,6 +433,23 @@ public void testForLambdaExpressionInAnAssignment() { .doTest(); } + @Test + public void testForDiamondInAnAssignment() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.annotations.Nullable;", + "class Test {", + " class A{}", + " void fun() {", + " //This case is ignored for now.", + " A p = new A<>();", + " }", + "}") + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( Arrays.asList( From 7c07d98088bdd6e71159fba04717c2674799682f Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 25 Jan 2023 00:38:36 +0530 Subject: [PATCH 172/184] test cases for diamond operator and the lambdas --- .../NullAwayJSpecifyGenericsTests.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index ca23869d80..884a15c8d8 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -412,7 +412,7 @@ public void instantiationInUnannotatedCode() { } @Test - public void testForLambdaExpressionInAnAssignment() { + public void testForMethodReferenceInAnAssignment() { makeHelper() .addSourceLines( "Test.java", @@ -433,6 +433,24 @@ public void testForLambdaExpressionInAnAssignment() { .doTest(); } + @Test + public void testForLambdasInAnAssignment() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.uber;", + "import org.jspecify.annotations.Nullable;", + "class Test {", + " interface A {", + " @Nullable String function(@Nullable T1 t1, T2 t2 );", + " }", + " static void function() {", + " A p = (s1, s2) -> null;", + " }", + "}") + .doTest(); + } + @Test public void testForDiamondInAnAssignment() { makeHelper() From 6755d6674f6f91fc60ec63c818ac56dc1fd34bd1 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 25 Jan 2023 23:07:32 +0530 Subject: [PATCH 173/184] private fields --- .../main/java/com/uber/nullaway/GenericsChecks.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 38aed0f0cb..072f8eba6c 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -31,9 +31,9 @@ public final class GenericsChecks { private static final Supplier NULLABLE_TYPE_SUPPLIER = Suppliers.typeFromString(NULLABLE_NAME); - VisitorState state; - Config config; - NullAway analysis; + private VisitorState state; + private Config config; + private NullAway analysis; public GenericsChecks(VisitorState state, Config config, NullAway analysis) { this.state = state; @@ -174,10 +174,7 @@ public void checkTypeParameterNullnessForAssignability(Tree tree) { } rhsType = typeWithPreservedAnnotations(paramTypedTree); } - if (lhsType != null - && lhsType instanceof Type.ClassType - && rhsType != null - && rhsType instanceof Type.ClassType) { + if (lhsType instanceof Type.ClassType && rhsType instanceof Type.ClassType) { compareNullabilityAnnotations((Type.ClassType) lhsType, (Type.ClassType) rhsType, tree); } } From 41f45b1a81295f685009ee5b6f239ea47f378653 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Wed, 25 Jan 2023 23:27:57 +0530 Subject: [PATCH 174/184] check only for jspecify nullable annotation --- .../com/uber/nullaway/GenericsChecks.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 072f8eba6c..ab967c1785 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -213,10 +213,24 @@ private void compareNullabilityAnnotations( for (int i = 0; i < lhsTypeArguments.size(); i++) { Type lhsTypeArgument = lhsTypeArguments.get(i); Type rhsTypeArgument = rhsTypeArguments.get(i); - boolean isLHSNullableAnnotated = - Nullness.hasNullableAnnotation(lhsTypeArgument.getAnnotationMirrors().stream(), config); - boolean isRHSNullableAnnotated = - Nullness.hasNullableAnnotation(rhsTypeArgument.getAnnotationMirrors().stream(), config); + boolean isLHSNullableAnnotated = false; + List lhsAnnotations = lhsTypeArgument.getAnnotationMirrors(); + // To ensure that we are checking only jspecify nullable annotations + for (Attribute.TypeCompound annotation : lhsAnnotations) { + if (annotation.getAnnotationType().toString().equals(NULLABLE_NAME)) { + isLHSNullableAnnotated = true; + break; + } + } + boolean isRHSNullableAnnotated = false; + List rhsAnnotations = rhsTypeArgument.getAnnotationMirrors(); + // To ensure that we are checking only jspecify nullable annotations + for (Attribute.TypeCompound annotation : rhsAnnotations) { + if (annotation.getAnnotationType().toString().equals(NULLABLE_NAME)) { + isRHSNullableAnnotated = true; + break; + } + } if (isLHSNullableAnnotated != isRHSNullableAnnotated) { reportInvalidAssignmentInstantiationError(tree, lhsType, rhsType, state, analysis); return; From 322c3c2ad6a478dd5664ca907d5dc2c79f0a7088 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 25 Jan 2023 11:52:58 -0800 Subject: [PATCH 175/184] move test method to more appropriate place --- .../NullAwayJSpecifyGenericsTests.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 884a15c8d8..4a5a3bd85c 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -206,6 +206,23 @@ public void downcastInstantiation() { .doTest(); } + /** check that we don't report errors on invalid instantiations in unannotated code */ + @Test + public void instantiationInUnannotatedCode() { + makeHelper() + .addSourceLines( + "Test.java", + "package com.other;", + "import org.jspecify.annotations.Nullable;", + "class Test {", + " static class NonNullTypeParam {}", + " static void instOf(Object o) {", + " Object p = (NonNullTypeParam<@Nullable String>) o;", + " }", + "}") + .doTest(); + } + @Test public void genericsChecksForAssignments() { makeHelper() @@ -394,23 +411,6 @@ public void nestedVariableDeclarationChecks() { .doTest(); } - /** check that we don't report errors on invalid instantiations in unannotated code */ - @Test - public void instantiationInUnannotatedCode() { - makeHelper() - .addSourceLines( - "Test.java", - "package com.other;", - "import org.jspecify.annotations.Nullable;", - "class Test {", - " static class NonNullTypeParam {}", - " static void instOf(Object o) {", - " Object p = (NonNullTypeParam<@Nullable String>) o;", - " }", - "}") - .doTest(); - } - @Test public void testForMethodReferenceInAnAssignment() { makeHelper() From 4a46a46a2e1bd06d84b8b37021b22717a8459716 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 25 Jan 2023 11:58:34 -0800 Subject: [PATCH 176/184] tweak method reference test --- .../uber/nullaway/NullAwayJSpecifyGenericsTests.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 4a5a3bd85c..0a9423d5cb 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -420,13 +420,17 @@ public void testForMethodReferenceInAnAssignment() { "import org.jspecify.annotations.Nullable;", "class Test {", " interface A {", - " String function(@Nullable Object o, String string);", + " String function(T1 o, T2 p);", " }", " static String foo(@Nullable Object o, String string) {", - " //Should generate an error here. This will be handled in the future PRs", " return o != null ? o.toString() : string;", " }", - " static void bar() {", + " static void testPositive() {", + " // we should report an error here, since Test::foo conforms to", + " // A<@Nullable Object, String>. But we do not handle this case yet", + " A p = Test::foo;", + " }", + " static void testNegative() {", " A<@Nullable Object, String> p = Test::foo;", " }", "}") From 4a1ce05c6bfaddac004013e991caa5c9fa1301c5 Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 25 Jan 2023 13:17:29 -0800 Subject: [PATCH 177/184] re-add blank line --- nullaway/src/main/java/com/uber/nullaway/NullAway.java | 1 + 1 file changed, 1 insertion(+) diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 4f45717f32..cb12e61cd1 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -263,6 +263,7 @@ private enum NullMarking { *

TODO remove this once NullAway requires JDK 11 */ @Nullable private final Class moduleElementClass; + /** * Error Prone requires us to have an empty constructor for each Plugin, in addition to the * constructor taking an ErrorProneFlags object. This constructor should not be used anywhere From fce345bcb4015c7177baea0f9be797ecdbc2249a Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 25 Jan 2023 13:20:34 -0800 Subject: [PATCH 178/184] clarify method ref test --- .../nullaway/NullAwayJSpecifyGenericsTests.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 0a9423d5cb..c266641fb0 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -419,19 +419,19 @@ public void testForMethodReferenceInAnAssignment() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " interface A {", - " String function(T1 o, T2 p);", + " interface A {", + " String function(T1 o);", " }", - " static String foo(@Nullable Object o, String string) {", - " return o != null ? o.toString() : string;", + " static String foo(Object o) {", + " return o.toString();", " }", " static void testPositive() {", - " // we should report an error here, since Test::foo conforms to", - " // A<@Nullable Object, String>. But we do not handle this case yet", - " A p = Test::foo;", + " // we should report an error here, since Test::foo cannot take", + " // a @Nullable parameter. we don't catch this yet", + " A<@Nullable Object> p = Test::foo;", " }", " static void testNegative() {", - " A<@Nullable Object, String> p = Test::foo;", + " A p = Test::foo;", " }", "}") .doTest(); From 02bbd9f3a7decfbb5e4aa8dec5a723395764875f Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 25 Jan 2023 13:25:04 -0800 Subject: [PATCH 179/184] tweak lambda and diamond operator tests --- .../NullAwayJSpecifyGenericsTests.java | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index c266641fb0..5f0a1dd8b2 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -445,11 +445,16 @@ public void testForLambdasInAnAssignment() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " interface A {", - " @Nullable String function(@Nullable T1 t1, T2 t2 );", + " interface A {", + " String function(T1 o);", " }", - " static void function() {", - " A p = (s1, s2) -> null;", + " static void testPositive() {", + " // we should report an error here, since the lambda cannot take", + " // a @Nullable parameter. we don't catch this yet", + " A<@Nullable Object> p = o -> o.toString();", + " }", + " static void testNegative() {", + " A p = o -> o.toString();", " }", "}") .doTest(); @@ -463,10 +468,22 @@ public void testForDiamondInAnAssignment() { "package com.uber;", "import org.jspecify.annotations.Nullable;", "class Test {", - " class A{}", - " void fun() {", - " //This case is ignored for now.", - " A p = new A<>();", + " interface A {", + " String function(T1 o);", + " }", + " static void testPositive() {", + " // we should report an error here, since the overriding method cannot take", + " // a @Nullable parameter. we don't catch this yet", + " A<@Nullable Object> p = new A<>() {", + " @Override", + " public String function(Object o) { return o.toString(); }", + " };", + " }", + " static void testNegative() {", + " A p = new A<>() {", + " @Override", + " public String function(Object o) { return o.toString(); }", + " };", " }", "}") .doTest(); From 514829d6215229e7480d56c4c0d011f4cbe7852f Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Wed, 25 Jan 2023 16:16:06 -0800 Subject: [PATCH 180/184] make test Java 8 compatible --- .../NullAwayJSpecifyGenericsTests.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 5f0a1dd8b2..af4f8fa0af 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -471,19 +471,18 @@ public void testForDiamondInAnAssignment() { " interface A {", " String function(T1 o);", " }", + " static class B implements A {", + " public String function(T1 o) {", + " return o.toString();", + " }", + " }", " static void testPositive() {", - " // we should report an error here, since the overriding method cannot take", - " // a @Nullable parameter. we don't catch this yet", - " A<@Nullable Object> p = new A<>() {", - " @Override", - " public String function(Object o) { return o.toString(); }", - " };", + " // we should report an error here, since B's type parameter", + " // cannot be @Nullable; we do not catch this yet", + " A<@Nullable Object> p = new B<>();", " }", " static void testNegative() {", - " A p = new A<>() {", - " @Override", - " public String function(Object o) { return o.toString(); }", - " };", + " A p = new B<>();", " }", "}") .doTest(); From 7412439975841d20c15157e613354c0fdbd71461 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 7 Feb 2023 09:30:45 -0800 Subject: [PATCH 181/184] suggested changes --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index ab967c1785..2d02e09219 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -208,7 +208,7 @@ private void compareNullabilityAnnotations( // NullAway if (lhsTypeArguments.size() != rhsTypeArguments.size()) { throw new RuntimeException( - "number of types arguments in " + rhsType + " does not match " + lhsType); + "Number of types arguments in " + rhsType + " does not match " + lhsType); } for (int i = 0; i < lhsTypeArguments.size(); i++) { Type lhsTypeArgument = lhsTypeArguments.get(i); From 228cf0f44b2ba8d924d3fbf845fa049fe81fc854 Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 7 Feb 2023 09:32:06 -0800 Subject: [PATCH 182/184] suggested changes --- nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java index 2d02e09219..4fdfa4b9d1 100644 --- a/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java @@ -244,7 +244,7 @@ private void compareNullabilityAnnotations( } /** - * For the Parameterized typed trees ASTHelpers.getType(tree) does not return a Type with + * For the Parameterized typed trees, ASTHelpers.getType(tree) does not return a Type with * preserved annotations. This method takes a Parameterized typed tree as an input and returns the * Type of the tree with the annotations. * From b7bbf7c08bef38a132fea8d6d40508e3e4ff870f Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 7 Feb 2023 09:33:08 -0800 Subject: [PATCH 183/184] suggested changes --- .../java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index af4f8fa0af..72d77b94c6 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -426,7 +426,7 @@ public void testForMethodReferenceInAnAssignment() { " return o.toString();", " }", " static void testPositive() {", - " // we should report an error here, since Test::foo cannot take", + " // TODO: we should report an error here, since Test::foo cannot take", " // a @Nullable parameter. we don't catch this yet", " A<@Nullable Object> p = Test::foo;", " }", From edb4f86a6c7922a7bba1a5f1764b3d05202109ae Mon Sep 17 00:00:00 2001 From: NikitaAware Date: Tue, 7 Feb 2023 09:49:42 -0800 Subject: [PATCH 184/184] suggested changes --- .../java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java index 72d77b94c6..18f2e69b84 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java @@ -449,7 +449,7 @@ public void testForLambdasInAnAssignment() { " String function(T1 o);", " }", " static void testPositive() {", - " // we should report an error here, since the lambda cannot take", + " // TODO: we should report an error here, since the lambda cannot take", " // a @Nullable parameter. we don't catch this yet", " A<@Nullable Object> p = o -> o.toString();", " }", @@ -477,7 +477,7 @@ public void testForDiamondInAnAssignment() { " }", " }", " static void testPositive() {", - " // we should report an error here, since B's type parameter", + " // TODO: we should report an error here, since B's type parameter", " // cannot be @Nullable; we do not catch this yet", " A<@Nullable Object> p = new B<>();", " }",