Check componentN functions for override conflicts

Check if newly generated component functions happen to override something
which they're not supposed to.
Create new slice to store mapping from annotation descriptors to
corresponding PSI elements, which is used by override checker to report
errors in data classes on.
This commit is contained in:
Alexander Udalov
2012-08-31 20:47:17 +04:00
parent c29312043c
commit fbeaaf5fbb
9 changed files with 112 additions and 4 deletions
@@ -145,6 +145,8 @@ public interface Errors {
DiagnosticFactory3.create(ERROR, NAMED_ELEMENT);
DiagnosticFactory3<JetModifierListOwner, CallableMemberDescriptor, CallableDescriptor, DeclarationDescriptor> CANNOT_OVERRIDE_INVISIBLE_MEMBER =
DiagnosticFactory3.create(ERROR, OVERRIDE_MODIFIER);
DiagnosticFactory2<JetAnnotationEntry, CallableMemberDescriptor, DeclarationDescriptor> DATA_CLASS_OVERRIDE_CONFLICT =
DiagnosticFactory2.create(ERROR);
SimpleDiagnosticFactory<JetDeclaration> CANNOT_INFER_VISIBILITY = SimpleDiagnosticFactory.create(ERROR, DECLARATION);
DiagnosticFactory1<JetClass, ClassDescriptor> ENUM_ENTRY_SHOULD_BE_INITIALIZED = DiagnosticFactory1.create(ERROR, NAME_IDENTIFIER);
@@ -156,6 +156,8 @@ public class DefaultErrorMessages {
MAP.put(NOTHING_TO_OVERRIDE, "''{0}'' overrides nothing", NAME);
MAP.put(VIRTUAL_MEMBER_HIDDEN, "''{0}'' hides member of supertype ''{2}'' and needs ''override'' modifier", NAME, NAME, NAME);
MAP.put(DATA_CLASS_OVERRIDE_CONFLICT, "Function ''{0}'' generated for the data class conflicts with member of supertype ''{1}''", NAME, NAME);
MAP.put(CANNOT_OVERRIDE_INVISIBLE_MEMBER, "''{0}'' cannot has no access to ''{1}'' in class {2}, so it cannot override it",
DescriptorRenderer.TEXT, DescriptorRenderer.TEXT, DescriptorRenderer.TEXT);
MAP.put(CANNOT_INFER_VISIBILITY, "Cannot infer visibility. Please specify it explicitly");
@@ -61,7 +61,9 @@ public interface BindingContext {
}
};
WritableSlice<JetAnnotationEntry, AnnotationDescriptor> ANNOTATION = Slices.createSimpleSlice();
WritableSlice<AnnotationDescriptor, JetAnnotationEntry> ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT = Slices.createSimpleSlice();
WritableSlice<JetAnnotationEntry, AnnotationDescriptor> ANNOTATION =
Slices.<JetAnnotationEntry, AnnotationDescriptor>sliceBuilder().setOpposite(ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT).build();
WritableSlice<JetExpression, CompileTimeConstant<?>> COMPILE_TIME_VALUE = Slices.createSimpleSlice();
WritableSlice<JetTypeReference, JetType> TYPE = Slices.createSimpleSlice();
@@ -26,12 +26,14 @@ import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.util.CommonSuppliers;
@@ -564,6 +566,14 @@ public class OverrideResolver {
}
private void checkOverrideForMember(@NotNull final CallableMemberDescriptor declared) {
if (declared.getKind() == CallableMemberDescriptor.Kind.SYNTHESIZED) {
// TODO: this should be replaced soon by a framework of synthesized member generation tools
if (declared.getName().getName().startsWith(DescriptorResolver.COMPONENT_FUNCTION_NAME_PREFIX)) {
checkOverrideForComponentFunction(declared);
}
return;
}
if (declared.getKind() != CallableMemberDescriptor.Kind.DECLARATION) {
return;
}
@@ -578,7 +588,7 @@ public class OverrideResolver {
Set<? extends CallableMemberDescriptor> overriddenDescriptors = declared.getOverriddenDescriptors();
if (overrideNode != null) {
checkOverridesForMemberMarkedOverride(declared, new CheckOverrideReportStrategy() {
checkOverridesForMemberMarkedOverride(declared, true, new CheckOverrideReportStrategy() {
private boolean finalOverriddenError = false;
private boolean typeMismatchError = false;
private boolean kindMismatchError = false;
@@ -624,7 +634,11 @@ public class OverrideResolver {
}
}
private void checkOverridesForMemberMarkedOverride(@NotNull CallableMemberDescriptor declared, @NotNull CheckOverrideReportStrategy reportError) {
private void checkOverridesForMemberMarkedOverride(
@NotNull CallableMemberDescriptor declared,
boolean checkIfOverridesNothing,
@NotNull CheckOverrideReportStrategy reportError
) {
Set<? extends CallableMemberDescriptor> overriddenDescriptors = declared.getOverriddenDescriptors();
for (CallableMemberDescriptor overridden : overriddenDescriptors) {
@@ -643,7 +657,7 @@ public class OverrideResolver {
}
}
if (overriddenDescriptors.isEmpty()) {
if (checkIfOverridesNothing && overriddenDescriptors.isEmpty()) {
DeclarationDescriptor containingDeclaration = declared.getContainingDeclaration();
assert containingDeclaration instanceof ClassDescriptor : "Overrides may only be resolved in a class, but " + declared + " comes from " + containingDeclaration;
ClassDescriptor declaringClass = (ClassDescriptor) containingDeclaration;
@@ -658,6 +672,58 @@ public class OverrideResolver {
}
}
private void checkOverrideForComponentFunction(@NotNull final CallableMemberDescriptor componentFunction) {
final JetAnnotationEntry dataAnnotation = findDataAnnotationForDataClass(componentFunction.getContainingDeclaration());
checkOverridesForMemberMarkedOverride(componentFunction, false, new CheckOverrideReportStrategy() {
private boolean overrideConflict = false;
@Override
public void overridingFinalMember(@NotNull CallableMemberDescriptor overridden) {
if (!overrideConflict) {
overrideConflict = true;
trace.report(DATA_CLASS_OVERRIDE_CONFLICT.on(dataAnnotation, componentFunction, overridden.getContainingDeclaration()));
}
}
@Override
public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) {
if (!overrideConflict) {
overrideConflict = true;
trace.report(DATA_CLASS_OVERRIDE_CONFLICT.on(dataAnnotation, componentFunction, overridden.getContainingDeclaration()));
}
}
@Override
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) {
throw new IllegalStateException("Component functions are not properties");
}
@Override
public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor invisibleOverridden) {
throw new IllegalStateException("CANNOT_OVERRIDE_INVISIBLE_MEMBER should be reported on the corresponding property");
}
@Override
public void nothingToOverride() {
throw new IllegalStateException("Component functions are OK to override nothing");
}
});
}
@NotNull
private JetAnnotationEntry findDataAnnotationForDataClass(@NotNull DeclarationDescriptor dataClass) {
ClassDescriptor stdDataClassAnnotation = JetStandardLibrary.getInstance().getDataClassAnnotation();
for (AnnotationDescriptor annotation : dataClass.getAnnotations()) {
if (stdDataClassAnnotation.equals(annotation.getType().getConstructor().getDeclarationDescriptor())) {
return BindingContextUtils.getNotNull(trace.getBindingContext(),
BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT,
annotation);
}
}
throw new IllegalStateException("No data annotation is found for data class");
}
private CallableMemberDescriptor findInvisibleOverriddenDescriptor(CallableMemberDescriptor declared, ClassDescriptor declaringClass) {
CallableMemberDescriptor invisibleOverride = null;
outer:
@@ -0,0 +1,3 @@
open data class A(val x: Int, val y: String)
<!DATA_CLASS_OVERRIDE_CONFLICT!>data<!> class B(val z: String) : A(42, "")
@@ -0,0 +1,5 @@
trait T {
fun component1(): Int
}
data class A(val x: Int) : T
@@ -0,0 +1,5 @@
trait T {
final fun component1(): Int = 42
}
<!DATA_CLASS_OVERRIDE_CONFLICT!>data<!> class A(val x: Int) : T
@@ -0,0 +1,3 @@
open data class D(private final val x: Int)
data class E(internal <!CANNOT_OVERRIDE_INVISIBLE_MEMBER!>override<!> val x: Int) : D(42)
@@ -977,6 +977,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/dataClasses/componentNamedComponent1.kt");
}
@TestMetadata("dataClassOverrideConflict.kt")
public void testDataClassOverrideConflict() throws Exception {
doTest("compiler/testData/diagnostics/tests/dataClasses/dataClassOverrideConflict.kt");
}
@TestMetadata("emptyConstructor.kt")
public void testEmptyConstructor() throws Exception {
doTest("compiler/testData/diagnostics/tests/dataClasses/emptyConstructor.kt");
@@ -992,6 +997,16 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/dataClasses/firstParamIsVar.kt");
}
@TestMetadata("implementTraitWhichHasComponent1.kt")
public void testImplementTraitWhichHasComponent1() throws Exception {
doTest("compiler/testData/diagnostics/tests/dataClasses/implementTraitWhichHasComponent1.kt");
}
@TestMetadata("implementTraitWhichHasFinalComponent1.kt")
public void testImplementTraitWhichHasFinalComponent1() throws Exception {
doTest("compiler/testData/diagnostics/tests/dataClasses/implementTraitWhichHasFinalComponent1.kt");
}
@TestMetadata("multiDeclaration.kt")
public void testMultiDeclaration() throws Exception {
doTest("compiler/testData/diagnostics/tests/dataClasses/multiDeclaration.kt");
@@ -1012,6 +1027,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/dataClasses/oneValParam.kt");
}
@TestMetadata("overrideInvisibleMember.kt")
public void testOverrideInvisibleMember() throws Exception {
doTest("compiler/testData/diagnostics/tests/dataClasses/overrideInvisibleMember.kt");
}
@TestMetadata("secondParamIsVal.kt")
public void testSecondParamIsVal() throws Exception {
doTest("compiler/testData/diagnostics/tests/dataClasses/secondParamIsVal.kt");