Report errors for type parameters of properties that are not used in receiver types

This commit is contained in:
Pavel V. Talanov
2015-10-12 14:18:45 +03:00
parent b5537e7d42
commit be15399313
6 changed files with 101 additions and 0 deletions
@@ -269,6 +269,8 @@ public interface Errors {
DiagnosticFactory0<JetDeclaration> TYPE_PARAMETERS_NOT_ALLOWED
= DiagnosticFactory0.create(ERROR, TYPE_PARAMETERS_OR_DECLARATION_SIGNATURE);
DiagnosticFactory0<JetTypeParameter> TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> CYCLIC_GENERIC_UPPER_BOUND = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetTypeParameter> MISPLACED_TYPE_PARAMETER_CONSTRAINTS = DiagnosticFactory0.create(WARNING);
@@ -629,6 +629,8 @@ public class DefaultErrorMessages {
MAP.put(REIFIED_TYPE_FORBIDDEN_SUBSTITUTION, "Cannot use ''{0}'' as reified type parameter", RENDER_TYPE);
MAP.put(TYPE_PARAMETERS_NOT_ALLOWED, "Type parameters are not allowed here");
MAP.put(TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER, "Type parameter of a property must be used in its receiver type");
MAP.put(SUPERTYPES_FOR_ANNOTATION_CLASS, "Annotation class cannot have supertypes");
MAP.put(MISSING_VAL_ON_ANNOTATION_PARAMETER, "'val' keyword is missing on annotation parameter");
MAP.put(ANNOTATION_CLASS_CONSTRUCTOR_CALL, "Annotation class cannot be instantiated");
@@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
@@ -471,6 +472,33 @@ public class DeclarationsChecker {
checkAccessors(property, propertyDescriptor);
checkTypeParameterConstraints(property);
checkPropertyExposedType(property, propertyDescriptor);
checkPropertyTypeParametersAreUsedInReceiverType(propertyDescriptor);
}
private void checkPropertyTypeParametersAreUsedInReceiverType(@NotNull PropertyDescriptor descriptor) {
for (TypeParameterDescriptor typeParameter : descriptor.getTypeParameters()) {
if (isTypeParameterUsedInReceiverType(typeParameter, descriptor)) continue;
PsiElement typeParameterPsi = DescriptorToSourceUtils.getSourceFromDescriptor(typeParameter);
if (typeParameterPsi instanceof JetTypeParameter) {
trace.report(TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER.on((JetTypeParameter) typeParameterPsi));
}
}
}
private static boolean isTypeParameterUsedInReceiverType(
@NotNull final TypeParameterDescriptor parameter,
@NotNull PropertyDescriptor descriptor
) {
ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
if (receiverParameter == null) return false;
return TypeUtils.containsSpecialType(receiverParameter.getType(), new Function1<JetType, Boolean>() {
@Override
public Boolean invoke(JetType type) {
return parameter.equals(type.getConstructor().getDeclarationDescriptor());
}
});
}
private void checkPropertyLateInit(@NotNull JetCallableDeclaration property, @NotNull PropertyDescriptor propertyDescriptor) {
@@ -0,0 +1,33 @@
// !DIAGNOSTICS: -REDUNDANT_PROJECTION -CONFLICTING_PROJECTION
interface G
val <T> T.a: Int
get() = 3
val <T1, T2> Map<T1, T2>.b: String
get() = "asds"
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T : G<!>> G.c: Int get() = 5
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T1<!>, T2, T3> List<Map<T2, T3>>.d: Int get() = 6
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T: Any<!>> G.e: T?
get() = null
val <T> List<Map<Int, Map<String, T>>>.f: Int get() = 7
val <T> List<Map<Int, Map<String, out T>>>.g: Int get() = 7
val <T> List<Map<Int, Map<String, in T>>>.h: Int get() = 7
val <T> List<Map<T, Map<T, T>>>.i: Int get() = 7
var <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T1<!>, <!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T2<!>, <!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T3<!>, <!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T4<!>> p = 1
class C<T1, T2> {
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>E<!>> T1.a: Int get() = 3
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>E<!>> T2.b: Int get() = 3
val <E> E.c: Int get() = 3
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>E<!>> Map<T1, T2>.d: Int get() = 3
val <E> Map<T1, E>.e: Int get() = 3
}
@@ -0,0 +1,30 @@
package
public var </*0*/ T1, /*1*/ T2, /*2*/ T3, /*3*/ T4> p: kotlin.Int
public val </*0*/ T> T.a: kotlin.Int
public val </*0*/ T1, /*1*/ T2> kotlin.Map<T1, T2>.b: kotlin.String
public val </*0*/ T : G> G.c: kotlin.Int
public val </*0*/ T1, /*1*/ T2, /*2*/ T3> kotlin.List<kotlin.Map<T2, T3>>.d: kotlin.Int
public val </*0*/ T : kotlin.Any> G.e: T?
public val </*0*/ T> kotlin.List<kotlin.Map<kotlin.Int, kotlin.Map<kotlin.String, T>>>.f: kotlin.Int
public val </*0*/ T> kotlin.List<kotlin.Map<kotlin.Int, kotlin.Map<kotlin.String, out T>>>.g: kotlin.Int
public val </*0*/ T> kotlin.List<kotlin.Map<kotlin.Int, kotlin.Map<kotlin.String, in T>>>.h: kotlin.Int
public val </*0*/ T> kotlin.List<kotlin.Map<T, kotlin.Map<T, T>>>.i: kotlin.Int
public final class C</*0*/ T1, /*1*/ T2> {
public constructor C</*0*/ T1, /*1*/ T2>()
public final val </*0*/ E> T1.a: kotlin.Int
public final val </*0*/ E> T2.b: kotlin.Int
public final val </*0*/ E> E.c: kotlin.Int
public final val </*0*/ E> kotlin.Map<T1, T2>.d: kotlin.Int
public final val </*0*/ E> kotlin.Map<T1, E>.e: kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface G {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -15805,6 +15805,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("propertyTypeParameters.kt")
public void testPropertyTypeParameters() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typeParameters/propertyTypeParameters.kt");
doTest(fileName);
}
@TestMetadata("upperBoundCannotBeArray.kt")
public void testUpperBoundCannotBeArray() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typeParameters/upperBoundCannotBeArray.kt");