A warning for redundant '?' in types
This commit is contained in:
@@ -283,6 +283,7 @@ public interface Errors {
|
||||
|
||||
SimpleDiagnosticFactory<JetClassInitializer> ANONYMOUS_INITIALIZER_WITHOUT_CONSTRUCTOR = SimpleDiagnosticFactory.create(ERROR);
|
||||
SimpleDiagnosticFactory<JetNullableType> NULLABLE_SUPERTYPE = SimpleDiagnosticFactory.create(ERROR, NULLABLE_TYPE);
|
||||
SimpleDiagnosticFactory<JetNullableType> REDUNDANT_NULLABLE = SimpleDiagnosticFactory.create(WARNING, NULLABLE_TYPE);
|
||||
DiagnosticFactory1<PsiElement, JetType> UNSAFE_CALL = DiagnosticFactory1.create(ERROR);
|
||||
SimpleDiagnosticFactory<JetSimpleNameExpression> AMBIGUOUS_LABEL = SimpleDiagnosticFactory.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> UNSUPPORTED = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
+1
@@ -306,6 +306,7 @@ public class DefaultErrorMessages {
|
||||
|
||||
MAP.put(ANONYMOUS_INITIALIZER_WITHOUT_CONSTRUCTOR, "Anonymous initializers are only allowed in the presence of a primary constructor");
|
||||
MAP.put(NULLABLE_SUPERTYPE, "A supertype cannot be nullable");
|
||||
MAP.put(REDUNDANT_NULLABLE, "Redundant '?'");
|
||||
MAP.put(UNSAFE_CALL, "Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type {0}", RENDER_TYPE);
|
||||
MAP.put(AMBIGUOUS_LABEL, "Ambiguous label");
|
||||
MAP.put(UNSUPPORTED, "Unsupported [{0}]", TO_STRING);
|
||||
|
||||
@@ -200,21 +200,8 @@ public class DescriptorResolver {
|
||||
JetTypeReference typeReference = delegationSpecifier.getTypeReference();
|
||||
if (typeReference != null) {
|
||||
result.add(resolver.resolveType(extensibleScope, typeReference, trace, checkBounds));
|
||||
JetTypeElement typeElement = typeReference.getTypeElement();
|
||||
while (typeElement instanceof JetNullableType) {
|
||||
JetNullableType nullableType = (JetNullableType) typeElement;
|
||||
trace.report(NULLABLE_SUPERTYPE.on(nullableType));
|
||||
typeElement = nullableType.getInnerType();
|
||||
}
|
||||
if (typeElement instanceof JetUserType) {
|
||||
JetUserType userType = (JetUserType) typeElement;
|
||||
List<JetTypeProjection> typeArguments = userType.getTypeArguments();
|
||||
for (JetTypeProjection typeArgument : typeArguments) {
|
||||
if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) {
|
||||
trace.report(PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE.on(typeArgument));
|
||||
}
|
||||
}
|
||||
}
|
||||
JetTypeElement bareSuperType = checkNullableSupertypeAndStripQuestionMarks(trace, typeReference.getTypeElement());
|
||||
checkProjectionsInImmediateArguments(trace, bareSuperType);
|
||||
}
|
||||
else {
|
||||
result.add(ErrorUtils.createErrorType("No type reference"));
|
||||
@@ -223,6 +210,31 @@ public class DescriptorResolver {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JetTypeElement checkNullableSupertypeAndStripQuestionMarks(@NotNull BindingTrace trace, @Nullable JetTypeElement typeElement) {
|
||||
while (typeElement instanceof JetNullableType) {
|
||||
JetNullableType nullableType = (JetNullableType) typeElement;
|
||||
typeElement = nullableType.getInnerType();
|
||||
// report only for innermost '?', the rest gets a 'redundant' warning
|
||||
if (!(typeElement instanceof JetNullableType)) {
|
||||
trace.report(NULLABLE_SUPERTYPE.on(nullableType));
|
||||
}
|
||||
}
|
||||
return typeElement;
|
||||
}
|
||||
|
||||
private static void checkProjectionsInImmediateArguments(@NotNull BindingTrace trace, @Nullable JetTypeElement typeElement) {
|
||||
if (typeElement instanceof JetUserType) {
|
||||
JetUserType userType = (JetUserType) typeElement;
|
||||
List<JetTypeProjection> typeArguments = userType.getTypeArguments();
|
||||
for (JetTypeProjection typeArgument : typeArguments) {
|
||||
if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) {
|
||||
trace.report(PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE.on(typeArgument));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SimpleFunctionDescriptor resolveFunctionDescriptor(
|
||||
DeclarationDescriptor containingDescriptor,
|
||||
|
||||
@@ -77,7 +77,7 @@ public class TypeResolver {
|
||||
final List<AnnotationDescriptor> annotations = annotationResolver.getResolvedAnnotations(typeReference.getAnnotations(), trace);
|
||||
|
||||
JetTypeElement typeElement = typeReference.getTypeElement();
|
||||
JetType type = resolveTypeElement(scope, annotations, typeElement, false, trace, checkBounds);
|
||||
JetType type = resolveTypeElement(scope, annotations, typeElement, trace, checkBounds);
|
||||
trace.record(BindingContext.TYPE, typeReference, type);
|
||||
trace.record(BindingContext.TYPE_RESOLUTION_SCOPE, typeReference, scope);
|
||||
|
||||
@@ -86,7 +86,7 @@ public class TypeResolver {
|
||||
|
||||
@NotNull
|
||||
private JetType resolveTypeElement(final JetScope scope, final List<AnnotationDescriptor> annotations,
|
||||
JetTypeElement typeElement, final boolean nullable, final BindingTrace trace, final boolean checkBounds) {
|
||||
JetTypeElement typeElement, final BindingTrace trace, final boolean checkBounds) {
|
||||
|
||||
final JetType[] result = new JetType[1];
|
||||
if (typeElement != null) {
|
||||
@@ -118,7 +118,7 @@ public class TypeResolver {
|
||||
result[0] = new JetTypeImpl(
|
||||
annotations,
|
||||
typeParameterDescriptor.getTypeConstructor(),
|
||||
nullable || TypeUtils.hasNullableLowerBound(typeParameterDescriptor),
|
||||
TypeUtils.hasNullableLowerBound(typeParameterDescriptor),
|
||||
Collections.<TypeProjection>emptyList(),
|
||||
scopeForTypeParameter
|
||||
);
|
||||
@@ -151,7 +151,7 @@ public class TypeResolver {
|
||||
result[0] = new JetTypeImpl(
|
||||
annotations,
|
||||
typeConstructor,
|
||||
nullable,
|
||||
false,
|
||||
arguments,
|
||||
classDescriptor.getMemberScope(arguments)
|
||||
);
|
||||
@@ -174,7 +174,11 @@ public class TypeResolver {
|
||||
|
||||
@Override
|
||||
public void visitNullableType(JetNullableType nullableType) {
|
||||
result[0] = resolveTypeElement(scope, annotations, nullableType.getInnerType(), true, trace, checkBounds);
|
||||
JetType baseType = resolveTypeElement(scope, annotations, nullableType.getInnerType(), trace, checkBounds);
|
||||
if (baseType.isNullable()) {
|
||||
trace.report(REDUNDANT_NULLABLE.on(nullableType));
|
||||
}
|
||||
result[0] = TypeUtils.makeNullable(baseType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -222,9 +226,6 @@ public class TypeResolver {
|
||||
if (result[0] == null) {
|
||||
return ErrorUtils.createErrorType(typeElement == null ? "No type element" : typeElement.getText());
|
||||
}
|
||||
if (nullable) {
|
||||
return TypeUtils.makeNullable(result[0]);
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@ trait B<T> {}
|
||||
trait C<T> {}
|
||||
trait D<T> {}
|
||||
|
||||
trait Test : A<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>in<!> Int>, B<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>out<!> Int>, C<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>*<!>><!NULLABLE_SUPERTYPE!>?<!><!NULLABLE_SUPERTYPE!>?<!><!NULLABLE_SUPERTYPE!>?<!>, D<Int> {}
|
||||
trait Test : A<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>in<!> Int>, B<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>out<!> Int>, C<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>*<!>><!NULLABLE_SUPERTYPE!>?<!><!REDUNDANT_NULLABLE!>?<!><!REDUNDANT_NULLABLE!>?<!>, D<Int> {}
|
||||
@@ -0,0 +1,9 @@
|
||||
class Generic<T>
|
||||
|
||||
fun redundantNullable(
|
||||
<!UNUSED_PARAMETER!>i<!>: Int?<!REDUNDANT_NULLABLE!>?<!>,
|
||||
<!UNUSED_PARAMETER!>three<!>: Int?<!REDUNDANT_NULLABLE!>?<!><!REDUNDANT_NULLABLE!>?<!>,
|
||||
<!UNUSED_PARAMETER!>gOut<!>: Generic<Int>?<!REDUNDANT_NULLABLE!>?<!>,
|
||||
<!UNUSED_PARAMETER!>gIn<!>: Generic<Int?<!REDUNDANT_NULLABLE!>?<!>>
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
trait X: Any<!NULLABLE_SUPERTYPE!>?<!><!REDUNDANT_NULLABLE!>?<!> {
|
||||
|
||||
}
|
||||
|
||||
fun interaction<T>(t: T) {
|
||||
if (<!SENSELESS_COMPARISON!>t == null<!>) {}
|
||||
|
||||
}
|
||||
@@ -2288,6 +2288,24 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/nullableTypes")
|
||||
public static class NullableTypes extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
public void testAllFilesPresentInNullableTypes() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve", new File("compiler/testData/diagnostics/tests/nullableTypes"), "kt", true);
|
||||
}
|
||||
|
||||
@TestMetadata("redundantNullable.kt")
|
||||
public void testRedundantNullable() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/nullableTypes/redundantNullable.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("redundantNullableInSupertype.kt")
|
||||
public void testRedundantNullableInSupertype() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/nullableTypes/redundantNullableInSupertype.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/objects")
|
||||
public static class Objects extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
public void testAllFilesPresentInObjects() throws Exception {
|
||||
|
||||
@@ -3,4 +3,4 @@ trait B<T> {}
|
||||
trait C<T> {}
|
||||
trait D<T> {}
|
||||
|
||||
trait Test : A<<error>in</error> Int>, B<<error>out</error> Int>, C<<error>*</error>><error>?</error><error>?</error><error>?</error>, D<Int> {}
|
||||
trait Test : A<<error>in</error> Int>, B<<error>out</error> Int>, C<<error>*</error>><error>?</error><warning>?</warning><warning>?</warning>, D<Int> {}
|
||||
Reference in New Issue
Block a user