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:
@@ -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);
|
||||
|
||||
+2
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user