-
Notifications
You must be signed in to change notification settings - Fork 299
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create com.uber.nullaway.generics package (#855)
Fixes #817. This is a refactoring with no semantic changes.
- Loading branch information
Showing
7 changed files
with
267 additions
and
228 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
85 changes: 85 additions & 0 deletions
85
nullaway/src/main/java/com/uber/nullaway/generics/CompareNullabilityVisitor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package com.uber.nullaway.generics; | ||
|
||
import com.google.errorprone.VisitorState; | ||
import com.sun.tools.javac.code.Attribute; | ||
import com.sun.tools.javac.code.Type; | ||
import com.sun.tools.javac.code.Types; | ||
import java.util.List; | ||
|
||
/** | ||
* Visitor that checks equality of nullability annotations for all nested generic type arguments | ||
* within a type. Compares the Type it is called upon, i.e. the LHS type and the Type passed as an | ||
* argument, i.e. The RHS type. | ||
*/ | ||
public class CompareNullabilityVisitor extends Types.DefaultTypeVisitor<Boolean, Type> { | ||
private final VisitorState state; | ||
|
||
CompareNullabilityVisitor(VisitorState state) { | ||
this.state = state; | ||
} | ||
|
||
@Override | ||
public Boolean visitClassType(Type.ClassType lhsType, Type rhsType) { | ||
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); | ||
// 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); | ||
} | ||
List<Type> lhsTypeArguments = lhsType.getTypeArguments(); | ||
List<Type> 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); | ||
} | ||
for (int i = 0; i < lhsTypeArguments.size(); i++) { | ||
Type lhsTypeArgument = lhsTypeArguments.get(i); | ||
Type rhsTypeArgument = rhsTypeArguments.get(i); | ||
boolean isLHSNullableAnnotated = false; | ||
List<Attribute.TypeCompound> lhsAnnotations = lhsTypeArgument.getAnnotationMirrors(); | ||
// To ensure that we are checking only jspecify nullable annotations | ||
for (Attribute.TypeCompound annotation : lhsAnnotations) { | ||
if (annotation.getAnnotationType().toString().equals(GenericsChecks.NULLABLE_NAME)) { | ||
isLHSNullableAnnotated = true; | ||
break; | ||
} | ||
} | ||
boolean isRHSNullableAnnotated = false; | ||
List<Attribute.TypeCompound> rhsAnnotations = rhsTypeArgument.getAnnotationMirrors(); | ||
// To ensure that we are checking only jspecify nullable annotations | ||
for (Attribute.TypeCompound annotation : rhsAnnotations) { | ||
if (annotation.getAnnotationType().toString().equals(GenericsChecks.NULLABLE_NAME)) { | ||
isRHSNullableAnnotated = true; | ||
break; | ||
} | ||
} | ||
if (isLHSNullableAnnotated != isRHSNullableAnnotated) { | ||
return false; | ||
} | ||
// nested generics | ||
if (!lhsTypeArgument.accept(this, rhsTypeArgument)) { | ||
return false; | ||
} | ||
} | ||
// If there is an enclosing type (for non-static inner classes), its type argument nullability | ||
// should also match. When there is no enclosing type, getEnclosingType() returns a NoType | ||
// object, which gets handled by the fallback visitType() method | ||
return lhsType.getEnclosingType().accept(this, rhsType.getEnclosingType()); | ||
} | ||
|
||
@Override | ||
public Boolean visitArrayType(Type.ArrayType lhsType, Type rhsType) { | ||
Type.ArrayType arrRhsType = (Type.ArrayType) rhsType; | ||
return lhsType.getComponentType().accept(this, arrRhsType.getComponentType()); | ||
} | ||
|
||
@Override | ||
public Boolean visitType(Type t, Type type) { | ||
return true; | ||
} | ||
} |
75 changes: 75 additions & 0 deletions
75
nullaway/src/main/java/com/uber/nullaway/generics/GenericTypePrettyPrintingVisitor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package com.uber.nullaway.generics; | ||
|
||
import static java.util.stream.Collectors.joining; | ||
|
||
import com.google.errorprone.VisitorState; | ||
import com.google.errorprone.util.ASTHelpers; | ||
import com.sun.tools.javac.code.Attribute; | ||
import com.sun.tools.javac.code.BoundKind; | ||
import com.sun.tools.javac.code.Type; | ||
import com.sun.tools.javac.code.Types; | ||
|
||
/** | ||
* A visitor that pretty prints a generic type including its type-use nullability annotations, for | ||
* use in error messages. | ||
* | ||
* <p>This code is a modified and extended version of code in {@link | ||
* com.google.errorprone.util.Signatures} | ||
*/ | ||
final class GenericTypePrettyPrintingVisitor extends Types.DefaultTypeVisitor<String, Void> { | ||
|
||
private final VisitorState state; | ||
|
||
GenericTypePrettyPrintingVisitor(VisitorState state) { | ||
this.state = state; | ||
} | ||
|
||
@Override | ||
public String visitWildcardType(Type.WildcardType t, Void unused) { | ||
// NOTE: we have not tested this code yet as we do not yet support wildcard types | ||
StringBuilder sb = new StringBuilder(); | ||
sb.append(t.kind); | ||
if (t.kind != BoundKind.UNBOUND) { | ||
sb.append(t.type.accept(this, null)); | ||
} | ||
return sb.toString(); | ||
} | ||
|
||
@Override | ||
public String visitClassType(Type.ClassType t, Void s) { | ||
StringBuilder sb = new StringBuilder(); | ||
Type enclosingType = t.getEnclosingType(); | ||
if (!ASTHelpers.isSameType(enclosingType, Type.noType, state)) { | ||
sb.append(enclosingType.accept(this, null)).append('.'); | ||
} | ||
for (Attribute.TypeCompound compound : t.getAnnotationMirrors()) { | ||
sb.append('@'); | ||
sb.append(compound.type.accept(this, null)); | ||
sb.append(' '); | ||
} | ||
sb.append(t.tsym.getSimpleName()); | ||
if (t.getTypeArguments().nonEmpty()) { | ||
sb.append('<'); | ||
sb.append( | ||
t.getTypeArguments().stream().map(a -> a.accept(this, null)).collect(joining(", "))); | ||
sb.append(">"); | ||
} | ||
return sb.toString(); | ||
} | ||
|
||
@Override | ||
public String visitCapturedType(Type.CapturedType t, Void s) { | ||
return t.wildcard.accept(this, null); | ||
} | ||
|
||
@Override | ||
public String visitArrayType(Type.ArrayType t, Void unused) { | ||
// TODO properly print cases like int @Nullable[] | ||
return t.elemtype.accept(this, null) + "[]"; | ||
} | ||
|
||
@Override | ||
public String visitType(Type t, Void s) { | ||
return t.toString(); | ||
} | ||
} |
Oops, something went wrong.