Introduce warning for secondary constructor in enums without delegation to primary constructors (KT-35870)

This commit is contained in:
Victor Petukhov
2020-09-25 11:50:35 +03:00
parent 416874f9d0
commit 63d825fa24
13 changed files with 626 additions and 15 deletions
@@ -388,6 +388,9 @@ public interface Errors {
DiagnosticFactory0<KtConstructorDelegationCall> PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED =
DiagnosticFactory0.create(ERROR, PositioningStrategies.SECONDARY_CONSTRUCTOR_DELEGATION_CALL);
DiagnosticFactory0<KtConstructorDelegationCall> PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED_IN_ENUM =
DiagnosticFactory0.create(WARNING, PositioningStrategies.SECONDARY_CONSTRUCTOR_DELEGATION_CALL);
DiagnosticFactory0<KtConstructorDelegationReferenceExpression> DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR =
DiagnosticFactory0.create(ERROR);
@@ -634,6 +634,7 @@ public class DefaultErrorMessages {
MAP.put(CONSTRUCTOR_IN_OBJECT, "Constructors are not allowed for objects");
MAP.put(SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, "Supertype initialization is impossible without primary constructor");
MAP.put(PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED, "Primary constructor call expected");
MAP.put(PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED_IN_ENUM, "Primary constructor call expected. It's going to be an error in 1.5.");
MAP.put(DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR, "Call to super is not allowed in enum constructor");
MAP.put(PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS, "Primary constructor required for data class");
MAP.put(EXPLICIT_DELEGATION_CALL_REQUIRED,
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
import org.jetbrains.kotlin.psi.*;
@@ -334,8 +335,12 @@ public class CallResolver {
KtConstructorDelegationCall delegationCall = (KtConstructorDelegationCall) context.call.getCallElement();
DeclarationDescriptor container = context.scope.getOwnerDescriptor();
assert container instanceof ConstructorDescriptor : "Trying to resolve JetConstructorDelegationCall not in constructor. scope.ownerDescriptor = " + container;
return (OverloadResolutionResults) resolveConstructorDelegationCall(context, delegationCall, (KtConstructorDelegationReferenceExpression) calleeExpression,
(ClassConstructorDescriptor) container);
return (OverloadResolutionResults) resolveConstructorDelegationCall(
context,
delegationCall,
(KtConstructorDelegationReferenceExpression) calleeExpression,
(ClassDescriptor) container.getContainingDeclaration()
);
}
else if (calleeExpression == null) {
return checkArgumentTypesAndFail(context);
@@ -433,18 +438,28 @@ public class CallResolver {
dataFlowValueFactory,
InferenceSession.Companion.getDefault());
if (call.getCalleeExpression() == null) return checkArgumentTypesAndFail(context);
KtConstructorDelegationReferenceExpression calleeExpression = call.getCalleeExpression();
if (calleeExpression == null) return checkArgumentTypesAndFail(context);
ClassDescriptor currentClassDescriptor = constructorDescriptor.getContainingDeclaration();
if (constructorDescriptor.getConstructedClass().getKind() == ClassKind.ENUM_CLASS && call.isImplicit()) {
if (currentClassDescriptor.getUnsubstitutedPrimaryConstructor() != null) {
DiagnosticFactory0<KtConstructorDelegationCall> warningOrError;
if (languageVersionSettings.supportsFeature(LanguageFeature.RequiredPrimaryConstructorDelegationCallInEnums)) {
warningOrError = PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED; // error
} else {
warningOrError = PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED_IN_ENUM; // warning
}
context.trace.report(warningOrError.on((KtConstructorDelegationCall) calleeExpression.getParent()));
}
return null;
}
return resolveConstructorDelegationCall(
context,
call,
call.getCalleeExpression(),
constructorDescriptor
);
return resolveConstructorDelegationCall(context, call, call.getCalleeExpression(), currentClassDescriptor);
}
@NotNull
@@ -452,12 +467,10 @@ public class CallResolver {
@NotNull BasicCallResolutionContext context,
@NotNull KtConstructorDelegationCall call,
@NotNull KtConstructorDelegationReferenceExpression calleeExpression,
@NotNull ClassConstructorDescriptor calleeConstructor
@NotNull ClassDescriptor currentClassDescriptor
) {
context.trace.record(BindingContext.LEXICAL_SCOPE, call, context.scope);
ClassDescriptor currentClassDescriptor = calleeConstructor.getContainingDeclaration();
boolean isThisCall = calleeExpression.isThis();
if (currentClassDescriptor.getKind() == ClassKind.ENUM_CLASS && !isThisCall) {
context.trace.report(DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR.on(calleeExpression));
@@ -484,9 +497,8 @@ public class CallResolver {
}
KotlinType superType = isThisCall ?
calleeConstructor.getContainingDeclaration().getDefaultType() :
DescriptorUtils.getSuperClassType(currentClassDescriptor);
KotlinType superType =
isThisCall ? currentClassDescriptor.getDefaultType() : DescriptorUtils.getSuperClassType(currentClassDescriptor);
Pair<Collection<ResolutionCandidate<ConstructorDescriptor>>, BasicCallResolutionContext> candidatesAndContext =
prepareCandidatesAndContextForConstructorCall(superType, context, syntheticScopes);