Skip to content

Commit

Permalink
Merge 2689a62 into 8821567
Browse files Browse the repository at this point in the history
  • Loading branch information
msridhar committed Apr 27, 2023
2 parents 8821567 + 2689a62 commit 38e9c22
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 14 deletions.
75 changes: 67 additions & 8 deletions nullaway/src/main/java/com/uber/nullaway/GenericsChecks.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.uber.nullaway;

import static com.uber.nullaway.NullabilityUtil.castToNonNull;
import static java.util.stream.Collectors.joining;

import com.google.common.base.Preconditions;
import com.google.errorprone.VisitorState;
Expand All @@ -17,6 +18,7 @@
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.BoundKind;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeMetadata;
Expand Down Expand Up @@ -125,9 +127,9 @@ private static void reportInvalidAssignmentInstantiationError(
ErrorMessage.MessageTypes.ASSIGN_GENERIC_NULLABLE,
String.format(
"Cannot assign from type "
+ rhsType
+ prettyTypeForError(rhsType)
+ " to type "
+ lhsType
+ prettyTypeForError(lhsType)
+ " due to mismatched nullability of type parameters"));
state.reportMatch(
errorBuilder.createErrorDescription(
Expand All @@ -142,9 +144,9 @@ private static void reportInvalidReturnTypeError(
ErrorMessage.MessageTypes.RETURN_NULLABLE_GENERIC,
String.format(
"Cannot return expression of type "
+ returnType
+ prettyTypeForError(returnType)
+ " from method with return type "
+ methodType
+ prettyTypeForError(methodType)
+ " due to mismatched nullability of type parameters"));
state.reportMatch(
errorBuilder.createErrorDescription(
Expand All @@ -159,9 +161,9 @@ private static void reportMismatchedTypeForTernaryOperator(
ErrorMessage.MessageTypes.ASSIGN_GENERIC_NULLABLE,
String.format(
"Conditional expression must have type "
+ expressionType
+ prettyTypeForError(expressionType)
+ " but the sub-expression has type "
+ subPartType
+ prettyTypeForError(subPartType)
+ ", which has mismatched nullability of type parameters"));
state.reportMatch(
errorBuilder.createErrorDescription(
Expand All @@ -179,9 +181,9 @@ private void reportInvalidParametersNullabilityError(
new ErrorMessage(
ErrorMessage.MessageTypes.PASS_NULLABLE_GENERIC,
"Cannot pass parameter of type "
+ actualParameterType
+ prettyTypeForError(actualParameterType)
+ ", as formal parameter has type "
+ formalParameterType
+ prettyTypeForError(formalParameterType)
+ ", which has mismatched type parameter nullability");
state.reportMatch(
errorBuilder.createErrorDescription(
Expand Down Expand Up @@ -504,4 +506,61 @@ public void compareGenericTypeParameterNullabilityForCall(
}
}
}

/**
* Returns a pretty-printed representation of type suitable for error messages. The representation
* uses simple names rather than fully-qualified names, and retains all type-use annotations.
*/
public static String prettyTypeForError(Type type) {
return type.accept(PRETTY_TYPE_VISITOR, null);
}

/** This code is a modified version of code in {@link com.google.errorprone.util.Signatures} */
private static final Type.Visitor<String, Void> PRETTY_TYPE_VISITOR =
new Types.DefaultTypeVisitor<String, Void>() {
@Override
public String visitWildcardType(Type.WildcardType t, Void unused) {
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();
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) {
return t.elemtype.accept(this, null) + "[]";
}

@Override
public String visitType(Type t, Void s) {
return t.toString();
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ public void genericsChecksForAssignments() {
"class Test {",
" static class NullableTypeParam<E extends @Nullable Object> {}",
" static void testPositive(NullableTypeParam<@Nullable String> t1) {",
" // BUG: Diagnostic contains: Cannot assign from type",
" // BUG: Diagnostic contains: Cannot assign from type NullableTypeParam<@Nullable String>",
" NullableTypeParam<String> t2 = t1;",
" }",
" static void testNegative(NullableTypeParam<@Nullable String> t1) {",
Expand All @@ -255,7 +255,7 @@ public void nestedChecksForAssignmentsMultipleArguments() {
" static class SampleClass<E extends @Nullable Object> {}",
" static class SampleClassMultipleArguments<E1 extends @Nullable Object, E2> {}",
" static void testPositive() {",
" // BUG: Diagnostic contains: Cannot assign from type",
" // BUG: Diagnostic contains: Cannot assign from type SampleClassMultipleArguments<SampleClass<SampleClass<String>>",
" SampleClassMultipleArguments<SampleClass<SampleClass<@Nullable String>>, String> t1 =",
" new SampleClassMultipleArguments<SampleClass<SampleClass<String>>, String>();",
" }",
Expand All @@ -278,7 +278,7 @@ public void superTypeAssignmentChecksSingleInterface() {
" interface Fn<P extends @Nullable Object, R extends @Nullable Object> {}",
" class FnImpl implements Fn<@Nullable String, @Nullable String> {}",
" void testPositive() {",
" // BUG: Diagnostic contains: Cannot assign from type",
" // BUG: Diagnostic contains: Cannot assign from type FnImpl",
" Fn<@Nullable String, String> f = new FnImpl();",
" }",
" void testNegative() {",
Expand Down Expand Up @@ -499,7 +499,7 @@ public void genericFunctionReturnTypeNewClassTree() {
"class Test {",
" static class A<T extends @Nullable Object> { }",
" static A<String> testPositive1() {",
" // BUG: Diagnostic contains: mismatched nullability of type parameters",
" // BUG: Diagnostic contains: Cannot return expression of type A<@Nullable String>",
" return new A<@Nullable String>();",
" }",
" static A<@Nullable String> testPositive2() {",
Expand Down Expand Up @@ -567,7 +567,7 @@ public void genericsChecksForTernaryOperator() {
"class Test {",
"static class A<T extends @Nullable Object> { }",
" static A<String> testPositive(A<String> a, boolean t) {",
" // BUG: Diagnostic contains: Conditional expression must have type",
" // BUG: Diagnostic contains: Conditional expression must have type A<@Nullable String>",
" A<@Nullable String> t1 = t ? new A<String>() : new A<@Nullable String>();",
" // BUG: Diagnostic contains: Conditional expression must have type",
" return t ? new A<@Nullable String>() : new A<@Nullable String>();",
Expand Down Expand Up @@ -678,7 +678,7 @@ public void parameterPassing() {
" return a2;",
" }",
" static void testPositive1(A<A<@Nullable String>> a1, A<String> a2) {",
" // BUG: Diagnostic contains: Cannot pass parameter of type",
" // BUG: Diagnostic contains: Cannot pass parameter of type A<A<@Nullable String>>",
" A<String> a = sampleMethod1(a1, a2);",
" }",
" static void testPositive2(A<A<String>> a1, A<String> a2) {",
Expand Down

0 comments on commit 38e9c22

Please sign in to comment.