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<JetClassInitializer> ANONYMOUS_INITIALIZER_WITHOUT_CONSTRUCTOR = SimpleDiagnosticFactory.create(ERROR);
|
||||||
SimpleDiagnosticFactory<JetNullableType> NULLABLE_SUPERTYPE = SimpleDiagnosticFactory.create(ERROR, NULLABLE_TYPE);
|
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);
|
DiagnosticFactory1<PsiElement, JetType> UNSAFE_CALL = DiagnosticFactory1.create(ERROR);
|
||||||
SimpleDiagnosticFactory<JetSimpleNameExpression> AMBIGUOUS_LABEL = SimpleDiagnosticFactory.create(ERROR);
|
SimpleDiagnosticFactory<JetSimpleNameExpression> AMBIGUOUS_LABEL = SimpleDiagnosticFactory.create(ERROR);
|
||||||
DiagnosticFactory1<PsiElement, String> UNSUPPORTED = DiagnosticFactory1.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(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(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(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(AMBIGUOUS_LABEL, "Ambiguous label");
|
||||||
MAP.put(UNSUPPORTED, "Unsupported [{0}]", TO_STRING);
|
MAP.put(UNSUPPORTED, "Unsupported [{0}]", TO_STRING);
|
||||||
|
|||||||
@@ -200,21 +200,8 @@ public class DescriptorResolver {
|
|||||||
JetTypeReference typeReference = delegationSpecifier.getTypeReference();
|
JetTypeReference typeReference = delegationSpecifier.getTypeReference();
|
||||||
if (typeReference != null) {
|
if (typeReference != null) {
|
||||||
result.add(resolver.resolveType(extensibleScope, typeReference, trace, checkBounds));
|
result.add(resolver.resolveType(extensibleScope, typeReference, trace, checkBounds));
|
||||||
JetTypeElement typeElement = typeReference.getTypeElement();
|
JetTypeElement bareSuperType = checkNullableSupertypeAndStripQuestionMarks(trace, typeReference.getTypeElement());
|
||||||
while (typeElement instanceof JetNullableType) {
|
checkProjectionsInImmediateArguments(trace, bareSuperType);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result.add(ErrorUtils.createErrorType("No type reference"));
|
result.add(ErrorUtils.createErrorType("No type reference"));
|
||||||
@@ -223,6 +210,31 @@ public class DescriptorResolver {
|
|||||||
return result;
|
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
|
@NotNull
|
||||||
public SimpleFunctionDescriptor resolveFunctionDescriptor(
|
public SimpleFunctionDescriptor resolveFunctionDescriptor(
|
||||||
DeclarationDescriptor containingDescriptor,
|
DeclarationDescriptor containingDescriptor,
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class TypeResolver {
|
|||||||
final List<AnnotationDescriptor> annotations = annotationResolver.getResolvedAnnotations(typeReference.getAnnotations(), trace);
|
final List<AnnotationDescriptor> annotations = annotationResolver.getResolvedAnnotations(typeReference.getAnnotations(), trace);
|
||||||
|
|
||||||
JetTypeElement typeElement = typeReference.getTypeElement();
|
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, typeReference, type);
|
||||||
trace.record(BindingContext.TYPE_RESOLUTION_SCOPE, typeReference, scope);
|
trace.record(BindingContext.TYPE_RESOLUTION_SCOPE, typeReference, scope);
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ public class TypeResolver {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JetType resolveTypeElement(final JetScope scope, final List<AnnotationDescriptor> annotations,
|
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];
|
final JetType[] result = new JetType[1];
|
||||||
if (typeElement != null) {
|
if (typeElement != null) {
|
||||||
@@ -118,7 +118,7 @@ public class TypeResolver {
|
|||||||
result[0] = new JetTypeImpl(
|
result[0] = new JetTypeImpl(
|
||||||
annotations,
|
annotations,
|
||||||
typeParameterDescriptor.getTypeConstructor(),
|
typeParameterDescriptor.getTypeConstructor(),
|
||||||
nullable || TypeUtils.hasNullableLowerBound(typeParameterDescriptor),
|
TypeUtils.hasNullableLowerBound(typeParameterDescriptor),
|
||||||
Collections.<TypeProjection>emptyList(),
|
Collections.<TypeProjection>emptyList(),
|
||||||
scopeForTypeParameter
|
scopeForTypeParameter
|
||||||
);
|
);
|
||||||
@@ -151,7 +151,7 @@ public class TypeResolver {
|
|||||||
result[0] = new JetTypeImpl(
|
result[0] = new JetTypeImpl(
|
||||||
annotations,
|
annotations,
|
||||||
typeConstructor,
|
typeConstructor,
|
||||||
nullable,
|
false,
|
||||||
arguments,
|
arguments,
|
||||||
classDescriptor.getMemberScope(arguments)
|
classDescriptor.getMemberScope(arguments)
|
||||||
);
|
);
|
||||||
@@ -174,7 +174,11 @@ public class TypeResolver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitNullableType(JetNullableType nullableType) {
|
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
|
@Override
|
||||||
@@ -222,9 +226,6 @@ public class TypeResolver {
|
|||||||
if (result[0] == null) {
|
if (result[0] == null) {
|
||||||
return ErrorUtils.createErrorType(typeElement == null ? "No type element" : typeElement.getText());
|
return ErrorUtils.createErrorType(typeElement == null ? "No type element" : typeElement.getText());
|
||||||
}
|
}
|
||||||
if (nullable) {
|
|
||||||
return TypeUtils.makeNullable(result[0]);
|
|
||||||
}
|
|
||||||
return result[0];
|
return result[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ trait B<T> {}
|
|||||||
trait C<T> {}
|
trait C<T> {}
|
||||||
trait D<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")
|
@TestMetadata("compiler/testData/diagnostics/tests/objects")
|
||||||
public static class Objects extends AbstractDiagnosticsTestWithEagerResolve {
|
public static class Objects extends AbstractDiagnosticsTestWithEagerResolve {
|
||||||
public void testAllFilesPresentInObjects() throws Exception {
|
public void testAllFilesPresentInObjects() throws Exception {
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ trait B<T> {}
|
|||||||
trait C<T> {}
|
trait C<T> {}
|
||||||
trait D<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