Skip to content

Commit 7d8c7e4

Browse files
committed
Revert "JSpecify: initial checks for generic type compatibility at assignments (uber#715)"
This reverts commit 14d3693.
1 parent 1dd8ca6 commit 7d8c7e4

File tree

4 files changed

+82
-577
lines changed

4 files changed

+82
-577
lines changed

nullaway/src/main/java/com/uber/nullaway/ErrorMessage.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ public enum MessageTypes {
5353
WRONG_OVERRIDE_POSTCONDITION,
5454
WRONG_OVERRIDE_PRECONDITION,
5555
TYPE_PARAMETER_CANNOT_BE_NULLABLE,
56-
ASSIGN_GENERIC_NULLABLE,
5756
}
5857

5958
public String getMessage() {
Lines changed: 4 additions & 216 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,22 @@
11
package com.uber.nullaway;
22

3-
import static com.uber.nullaway.NullabilityUtil.castToNonNull;
4-
5-
import com.google.common.base.Preconditions;
63
import com.google.errorprone.VisitorState;
7-
import com.google.errorprone.suppliers.Supplier;
8-
import com.google.errorprone.suppliers.Suppliers;
94
import com.google.errorprone.util.ASTHelpers;
105
import com.sun.source.tree.AnnotatedTypeTree;
116
import com.sun.source.tree.AnnotationTree;
12-
import com.sun.source.tree.AssignmentTree;
13-
import com.sun.source.tree.NewClassTree;
147
import com.sun.source.tree.ParameterizedTypeTree;
158
import com.sun.source.tree.Tree;
16-
import com.sun.source.tree.VariableTree;
179
import com.sun.tools.javac.code.Attribute;
1810
import com.sun.tools.javac.code.Type;
19-
import com.sun.tools.javac.code.TypeMetadata;
20-
import com.sun.tools.javac.code.Types;
21-
import java.util.ArrayList;
22-
import java.util.Collections;
2311
import java.util.HashMap;
2412
import java.util.List;
2513
import java.util.Map;
2614

2715
/** Methods for performing checks related to generic types and nullability. */
2816
public final class GenericsChecks {
2917

30-
private static final String NULLABLE_NAME = "org.jspecify.annotations.Nullable";
31-
32-
private static final Supplier<Type> NULLABLE_TYPE_SUPPLIER =
33-
Suppliers.typeFromString(NULLABLE_NAME);
34-
private VisitorState state;
35-
private Config config;
36-
private NullAway analysis;
37-
38-
public GenericsChecks(VisitorState state, Config config, NullAway analysis) {
39-
this.state = state;
40-
this.config = config;
41-
this.analysis = analysis;
18+
private GenericsChecks() {
19+
// just utility methods
4220
}
4321

4422
/**
@@ -92,14 +70,14 @@ public static void checkInstantiationForParameterizedTypedTree(
9270
// if base type argument does not have @Nullable annotation then the instantiation is
9371
// invalid
9472
if (!hasNullableAnnotation) {
95-
reportInvalidInstantiationError(
73+
invalidInstantiationError(
9674
nullableTypeArguments.get(i), baseType, typeVariable, state, analysis);
9775
}
9876
}
9977
}
10078
}
10179

102-
private static void reportInvalidInstantiationError(
80+
private static void invalidInstantiationError(
10381
Tree tree, Type baseType, Type baseTypeVariable, VisitorState state, NullAway analysis) {
10482
ErrorBuilder errorBuilder = analysis.getErrorBuilder();
10583
ErrorMessage errorMessage =
@@ -112,194 +90,4 @@ private static void reportInvalidInstantiationError(
11290
errorBuilder.createErrorDescription(
11391
errorMessage, analysis.buildDescription(tree), state, null));
11492
}
115-
116-
private static void reportInvalidAssignmentInstantiationError(
117-
Tree tree, Type lhsType, Type rhsType, VisitorState state, NullAway analysis) {
118-
ErrorBuilder errorBuilder = analysis.getErrorBuilder();
119-
ErrorMessage errorMessage =
120-
new ErrorMessage(
121-
ErrorMessage.MessageTypes.ASSIGN_GENERIC_NULLABLE,
122-
String.format(
123-
"Cannot assign from type "
124-
+ rhsType
125-
+ " to type "
126-
+ lhsType
127-
+ " due to mismatched nullability of type parameters"));
128-
state.reportMatch(
129-
errorBuilder.createErrorDescription(
130-
errorMessage, analysis.buildDescription(tree), state, null));
131-
}
132-
133-
/**
134-
* For a tree representing an assignment, ensures that from the perspective of type parameter
135-
* nullability, the type of the right-hand side is assignable to (a subtype of) the type of the
136-
* left-hand side. This check ensures that for every parameterized type nested in each of the
137-
* types, the type parameters have identical nullability.
138-
*
139-
* @param tree the tree to check, which must be either an {@link AssignmentTree} or a {@link
140-
* VariableTree}
141-
*/
142-
public void checkTypeParameterNullnessForAssignability(Tree tree) {
143-
if (!config.isJSpecifyMode()) {
144-
return;
145-
}
146-
Tree lhsTree;
147-
Tree rhsTree;
148-
if (tree instanceof VariableTree) {
149-
VariableTree varTree = (VariableTree) tree;
150-
lhsTree = varTree.getType();
151-
rhsTree = varTree.getInitializer();
152-
} else {
153-
AssignmentTree assignmentTree = (AssignmentTree) tree;
154-
lhsTree = assignmentTree.getVariable();
155-
rhsTree = assignmentTree.getExpression();
156-
}
157-
// rhsTree can be null for a VariableTree. Also, we don't need to do a check
158-
// if rhsTree is the null literal
159-
if (rhsTree == null || rhsTree.getKind().equals(Tree.Kind.NULL_LITERAL)) {
160-
return;
161-
}
162-
Type lhsType = ASTHelpers.getType(lhsTree);
163-
Type rhsType = ASTHelpers.getType(rhsTree);
164-
// For NewClassTrees with annotated type parameters, javac does not preserve the annotations in
165-
// its computed type for the expression. As a workaround, we construct a replacement Type
166-
// object with the appropriate annotations.
167-
if (rhsTree instanceof NewClassTree
168-
&& ((NewClassTree) rhsTree).getIdentifier() instanceof ParameterizedTypeTree) {
169-
ParameterizedTypeTree paramTypedTree =
170-
(ParameterizedTypeTree) ((NewClassTree) rhsTree).getIdentifier();
171-
if (paramTypedTree.getTypeArguments().isEmpty()) {
172-
// no explicit type parameters
173-
return;
174-
}
175-
rhsType = typeWithPreservedAnnotations(paramTypedTree);
176-
}
177-
if (lhsType instanceof Type.ClassType && rhsType instanceof Type.ClassType) {
178-
compareNullabilityAnnotations((Type.ClassType) lhsType, (Type.ClassType) rhsType, tree);
179-
}
180-
}
181-
182-
/**
183-
* Compare two types from an assignment for identical type parameter nullability, recursively
184-
* checking nested generic types. See <a
185-
* href="https://jspecify.dev/docs/spec/#nullness-delegating-subtyping">the JSpecify
186-
* specification</a> and <a
187-
* href="https://docs.oracle.com/javase/specs/jls/se14/html/jls-4.html#jls-4.10.2">the JLS
188-
* subtyping rules for class and interface types</a>.
189-
*
190-
* @param lhsType type for the lhs of the assignment
191-
* @param rhsType type for the rhs of the assignment
192-
* @param tree tree representing the assignment
193-
*/
194-
private void compareNullabilityAnnotations(
195-
Type.ClassType lhsType, Type.ClassType rhsType, Tree tree) {
196-
Types types = state.getTypes();
197-
// The base type of rhsType may be a subtype of lhsType's base type. In such cases, we must
198-
// compare lhsType against the supertype of rhsType with a matching base type.
199-
rhsType = (Type.ClassType) types.asSuper(rhsType, lhsType.tsym);
200-
// This is impossible, considering the fact that standard Java subtyping succeeds before running
201-
// NullAway
202-
if (rhsType == null) {
203-
throw new RuntimeException("Did not find supertype of " + rhsType + " matching " + lhsType);
204-
}
205-
List<Type> lhsTypeArguments = lhsType.getTypeArguments();
206-
List<Type> rhsTypeArguments = rhsType.getTypeArguments();
207-
// This is impossible, considering the fact that standard Java subtyping succeeds before running
208-
// NullAway
209-
if (lhsTypeArguments.size() != rhsTypeArguments.size()) {
210-
throw new RuntimeException(
211-
"Number of types arguments in " + rhsType + " does not match " + lhsType);
212-
}
213-
for (int i = 0; i < lhsTypeArguments.size(); i++) {
214-
Type lhsTypeArgument = lhsTypeArguments.get(i);
215-
Type rhsTypeArgument = rhsTypeArguments.get(i);
216-
boolean isLHSNullableAnnotated = false;
217-
List<Attribute.TypeCompound> lhsAnnotations = lhsTypeArgument.getAnnotationMirrors();
218-
// To ensure that we are checking only jspecify nullable annotations
219-
for (Attribute.TypeCompound annotation : lhsAnnotations) {
220-
if (annotation.getAnnotationType().toString().equals(NULLABLE_NAME)) {
221-
isLHSNullableAnnotated = true;
222-
break;
223-
}
224-
}
225-
boolean isRHSNullableAnnotated = false;
226-
List<Attribute.TypeCompound> rhsAnnotations = rhsTypeArgument.getAnnotationMirrors();
227-
// To ensure that we are checking only jspecify nullable annotations
228-
for (Attribute.TypeCompound annotation : rhsAnnotations) {
229-
if (annotation.getAnnotationType().toString().equals(NULLABLE_NAME)) {
230-
isRHSNullableAnnotated = true;
231-
break;
232-
}
233-
}
234-
if (isLHSNullableAnnotated != isRHSNullableAnnotated) {
235-
reportInvalidAssignmentInstantiationError(tree, lhsType, rhsType, state, analysis);
236-
return;
237-
}
238-
// nested generics
239-
if (lhsTypeArgument.getTypeArguments().length() > 0) {
240-
compareNullabilityAnnotations(
241-
(Type.ClassType) lhsTypeArgument, (Type.ClassType) rhsTypeArgument, tree);
242-
}
243-
}
244-
}
245-
246-
/**
247-
* For the Parameterized typed trees, ASTHelpers.getType(tree) does not return a Type with
248-
* preserved annotations. This method takes a Parameterized typed tree as an input and returns the
249-
* Type of the tree with the annotations.
250-
*
251-
* @param tree A parameterized typed tree for which we need class type with preserved annotations.
252-
* @return A Type with preserved annotations.
253-
*/
254-
private Type.ClassType typeWithPreservedAnnotations(ParameterizedTypeTree tree) {
255-
Type.ClassType type = (Type.ClassType) ASTHelpers.getType(tree);
256-
Preconditions.checkNotNull(type);
257-
Type nullableType = NULLABLE_TYPE_SUPPLIER.get(state);
258-
List<? extends Tree> typeArguments = tree.getTypeArguments();
259-
List<Type> newTypeArgs = new ArrayList<>();
260-
boolean hasNullableAnnotation = false;
261-
for (int i = 0; i < typeArguments.size(); i++) {
262-
AnnotatedTypeTree annotatedType = null;
263-
Tree curTypeArg = typeArguments.get(i);
264-
// If the type argument has an annotation, it will either be an AnnotatedTypeTree, or a
265-
// ParameterizedTypeTree in the case of a nested generic type
266-
if (curTypeArg instanceof AnnotatedTypeTree) {
267-
annotatedType = (AnnotatedTypeTree) curTypeArg;
268-
} else if (curTypeArg instanceof ParameterizedTypeTree
269-
&& ((ParameterizedTypeTree) curTypeArg).getType() instanceof AnnotatedTypeTree) {
270-
annotatedType = (AnnotatedTypeTree) ((ParameterizedTypeTree) curTypeArg).getType();
271-
}
272-
List<? extends AnnotationTree> annotations =
273-
annotatedType != null ? annotatedType.getAnnotations() : Collections.emptyList();
274-
for (AnnotationTree annotation : annotations) {
275-
if (ASTHelpers.isSameType(
276-
nullableType, ASTHelpers.getType(annotation.getAnnotationType()), state)) {
277-
hasNullableAnnotation = true;
278-
break;
279-
}
280-
}
281-
// construct a TypeMetadata object containing a nullability annotation if needed
282-
com.sun.tools.javac.util.List<Attribute.TypeCompound> nullableAnnotationCompound =
283-
hasNullableAnnotation
284-
? com.sun.tools.javac.util.List.from(
285-
Collections.singletonList(
286-
new Attribute.TypeCompound(
287-
nullableType, com.sun.tools.javac.util.List.nil(), null)))
288-
: com.sun.tools.javac.util.List.nil();
289-
TypeMetadata typeMetadata =
290-
new TypeMetadata(new TypeMetadata.Annotations(nullableAnnotationCompound));
291-
Type currentTypeArgType = castToNonNull(ASTHelpers.getType(curTypeArg));
292-
if (currentTypeArgType.getTypeArguments().size() > 0) {
293-
// nested generic type; recursively preserve its nullability type argument annotations
294-
currentTypeArgType = typeWithPreservedAnnotations((ParameterizedTypeTree) curTypeArg);
295-
}
296-
Type.ClassType newTypeArgType =
297-
(Type.ClassType) currentTypeArgType.cloneWithMetadata(typeMetadata);
298-
newTypeArgs.add(newTypeArgType);
299-
}
300-
Type.ClassType finalType =
301-
new Type.ClassType(
302-
type.getEnclosingType(), com.sun.tools.javac.util.List.from(newTypeArgs), type.tsym);
303-
return finalType;
304-
}
30593
}

nullaway/src/main/java/com/uber/nullaway/NullAway.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -466,11 +466,6 @@ public Description matchAssignment(AssignmentTree tree, VisitorState state) {
466466
if (lhsType != null && lhsType.isPrimitive()) {
467467
doUnboxingCheck(state, tree.getExpression());
468468
}
469-
// generics check
470-
if (lhsType != null && lhsType.getTypeArguments().length() > 0) {
471-
new GenericsChecks(state, config, this).checkTypeParameterNullnessForAssignability(tree);
472-
}
473-
474469
Symbol assigned = ASTHelpers.getSymbol(tree.getVariable());
475470
if (assigned == null || assigned.getKind() != ElementKind.FIELD) {
476471
// not a field of nullable type
@@ -1338,10 +1333,6 @@ public Description matchVariable(VariableTree tree, VisitorState state) {
13381333
return Description.NO_MATCH;
13391334
}
13401335
VarSymbol symbol = ASTHelpers.getSymbol(tree);
1341-
if (tree.getInitializer() != null) {
1342-
new GenericsChecks(state, config, this).checkTypeParameterNullnessForAssignability(tree);
1343-
}
1344-
13451336
if (symbol.type.isPrimitive() && tree.getInitializer() != null) {
13461337
doUnboxingCheck(state, tree.getInitializer());
13471338
}

0 commit comments

Comments
 (0)