Report EXPLICIT_DELEGATION_CALL_REQUIRED on relevant element
^KT-38959 Fixed
This commit is contained in:
committed by
Vladimir Dolzhenko
parent
7af564c9f2
commit
5eac949b43
@@ -385,17 +385,17 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtDeclaration> CONSTRUCTOR_IN_OBJECT = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtSuperTypeCallEntry> SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<KtConstructorDelegationCall> PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED =
|
||||
DiagnosticFactory0<PsiElement> PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED =
|
||||
DiagnosticFactory0.create(ERROR, PositioningStrategies.SECONDARY_CONSTRUCTOR_DELEGATION_CALL);
|
||||
|
||||
DiagnosticFactory0<KtConstructorDelegationCall> PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED_IN_ENUM =
|
||||
DiagnosticFactory0<PsiElement> 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);
|
||||
|
||||
DiagnosticFactory0<PsiElement> PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtConstructorDelegationCall> EXPLICIT_DELEGATION_CALL_REQUIRED =
|
||||
DiagnosticFactory0<PsiElement> EXPLICIT_DELEGATION_CALL_REQUIRED =
|
||||
DiagnosticFactory0.create(ERROR, PositioningStrategies.SECONDARY_CONSTRUCTOR_DELEGATION_CALL);
|
||||
|
||||
DiagnosticFactory1<PsiElement, DeclarationDescriptor> INSTANCE_ACCESS_BEFORE_SUPER_CALL = DiagnosticFactory1.create(ERROR);
|
||||
@@ -1108,7 +1108,7 @@ public interface Errors {
|
||||
DiagnosticFactory1<KtExpression, ClassifierDescriptorWithTypeParameters> NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory2<KtExpression, ClassDescriptor, String> NESTED_CLASS_SHOULD_BE_QUALIFIED = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
DiagnosticFactory1<PsiElement, ClassDescriptor> INACCESSIBLE_OUTER_CLASS_EXPRESSION = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, ClassDescriptor> INACCESSIBLE_OUTER_CLASS_EXPRESSION = DiagnosticFactory1.create(ERROR, SECONDARY_CONSTRUCTOR_DELEGATION_CALL);
|
||||
DiagnosticFactory1<KtClassOrObject, String> NESTED_CLASS_NOT_ALLOWED = DiagnosticFactory1.create(ERROR, DECLARATION_NAME);
|
||||
DiagnosticFactory1<KtClassOrObject, String> NESTED_CLASS_DEPRECATED = DiagnosticFactory1.create(WARNING, DECLARATION_NAME);
|
||||
|
||||
|
||||
@@ -46,10 +46,7 @@ object PositioningStrategies {
|
||||
is KtObjectLiteralExpression -> {
|
||||
val objectDeclaration = element.objectDeclaration
|
||||
val objectKeyword = objectDeclaration.getObjectKeyword()!!
|
||||
val delegationSpecifierList = objectDeclaration.getSuperTypeList()
|
||||
if (delegationSpecifierList == null) {
|
||||
return markElement(objectKeyword)
|
||||
}
|
||||
val delegationSpecifierList = objectDeclaration.getSuperTypeList() ?: return markElement(objectKeyword)
|
||||
return markRange(objectKeyword, delegationSpecifierList)
|
||||
}
|
||||
is KtObjectDeclaration -> {
|
||||
@@ -612,15 +609,26 @@ object PositioningStrategies {
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val SECONDARY_CONSTRUCTOR_DELEGATION_CALL: PositioningStrategy<KtConstructorDelegationCall> =
|
||||
object : PositioningStrategy<KtConstructorDelegationCall>() {
|
||||
override fun mark(element: KtConstructorDelegationCall): List<TextRange> {
|
||||
if (element.isImplicit) {
|
||||
val constructor = element.getStrictParentOfType<KtSecondaryConstructor>()!!
|
||||
val valueParameterList = constructor.valueParameterList ?: return markElement(constructor)
|
||||
return markRange(constructor.getConstructorKeyword(), valueParameterList.lastChild)
|
||||
val SECONDARY_CONSTRUCTOR_DELEGATION_CALL: PositioningStrategy<PsiElement> =
|
||||
object : PositioningStrategy<PsiElement>() {
|
||||
override fun mark(element: PsiElement): List<TextRange> {
|
||||
when (element) {
|
||||
is KtSecondaryConstructor -> {
|
||||
val valueParameterList = element.valueParameterList ?: return markElement(element)
|
||||
return markRange(element.getConstructorKeyword(), valueParameterList.lastChild)
|
||||
}
|
||||
is KtConstructorDelegationCall -> {
|
||||
if (element.isImplicit) {
|
||||
// TODO: [VD] FIR collects for some reason implicit KtConstructorDelegationCall
|
||||
// check(!element.isImplicit) { "Implicit KtConstructorDelegationCall should not be collected directly" }
|
||||
val constructor = element.getStrictParentOfType<KtSecondaryConstructor>()!!
|
||||
val valueParameterList = constructor.valueParameterList ?: return markElement(constructor)
|
||||
return markRange(constructor.getConstructorKeyword(), valueParameterList.lastChild)
|
||||
}
|
||||
return markElement(element.calleeExpression ?: element)
|
||||
}
|
||||
else -> error("unexpected element $element")
|
||||
}
|
||||
return markElement(element.calleeExpression ?: element)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory;
|
||||
@@ -1371,7 +1372,9 @@ public class DescriptorResolver {
|
||||
}
|
||||
|
||||
if (isStaticNestedClass(classDescriptor)) {
|
||||
trace.report(INACCESSIBLE_OUTER_CLASS_EXPRESSION.on(reportErrorsOn, classDescriptor));
|
||||
PsiElement onReport = (reportErrorsOn instanceof KtConstructorDelegationCall)
|
||||
? CallResolverUtilKt.reportOnElement((KtConstructorDelegationCall) reportErrorsOn) : reportErrorsOn;
|
||||
trace.report(INACCESSIBLE_OUTER_CLASS_EXPRESSION.on(onReport, classDescriptor));
|
||||
return false;
|
||||
}
|
||||
classDescriptor = getParentOfType(classDescriptor, ClassDescriptor.class, true);
|
||||
|
||||
@@ -446,15 +446,15 @@ public class CallResolver {
|
||||
|
||||
if (constructorDescriptor.getConstructedClass().getKind() == ClassKind.ENUM_CLASS && call.isImplicit()) {
|
||||
if (currentClassDescriptor.getUnsubstitutedPrimaryConstructor() != null) {
|
||||
DiagnosticFactory0<KtConstructorDelegationCall> warningOrError;
|
||||
DiagnosticFactory0<PsiElement> 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()));
|
||||
PsiElement reportOn = calcReportOn(calleeExpression);
|
||||
context.trace.report(warningOrError.on(reportOn));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -484,9 +484,8 @@ public class CallResolver {
|
||||
if (!isThisCall && currentClassDescriptor.getUnsubstitutedPrimaryConstructor() != null) {
|
||||
if (DescriptorUtils.canHaveDeclaredConstructors(currentClassDescriptor)) {
|
||||
// Diagnostic is meaningless when reporting on interfaces and object
|
||||
context.trace.report(PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED.on(
|
||||
(KtConstructorDelegationCall) calleeExpression.getParent()
|
||||
));
|
||||
PsiElement reportOn = calcReportOn(calleeExpression);
|
||||
context.trace.report(PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED.on(reportOn));
|
||||
}
|
||||
if (call.isImplicit()) return OverloadResolutionResultsImpl.nameNotFound();
|
||||
}
|
||||
@@ -520,6 +519,13 @@ public class CallResolver {
|
||||
return computeTasksFromCandidatesAndResolvedCall(context, candidates, tracing);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiElement calcReportOn(@NotNull KtConstructorDelegationReferenceExpression calleeExpression) {
|
||||
PsiElement delegationCall = calleeExpression.getParent();
|
||||
return delegationCall instanceof KtConstructorDelegationCall
|
||||
? CallResolverUtilKt.reportOnElement((KtConstructorDelegationCall) delegationCall) : delegationCall;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Pair<Collection<ResolutionCandidate<ConstructorDescriptor>>, BasicCallResolutionContext> prepareCandidatesAndContextForConstructorCall(
|
||||
@NotNull KotlinType superType,
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.lexer.KtToken
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
||||
import org.jetbrains.kotlin.resolve.calls.components.isVararg
|
||||
@@ -320,3 +321,7 @@ fun createResolutionCandidatesForConstructors(
|
||||
ResolutionCandidate.create(call, it, dispatchReceiver, receiverKind, knownSubstitutor)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun KtConstructorDelegationCall.reportOnElement() = if (this.isImplicit) {
|
||||
this.getStrictParentOfType<KtSecondaryConstructor>()!!
|
||||
} else this
|
||||
|
||||
+4
-4
@@ -22,12 +22,11 @@ import org.jetbrains.kotlin.diagnostics.Errors.UNRESOLVED_REFERENCE
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER
|
||||
import org.jetbrains.kotlin.psi.Call
|
||||
import org.jetbrains.kotlin.psi.KtConstructorDelegationCall
|
||||
import org.jetbrains.kotlin.psi.KtLambdaArgument
|
||||
import org.jetbrains.kotlin.psi.KtSecondaryConstructor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.CALL
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.RESOLVED_CALL
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.reportOnElement
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
@@ -83,8 +82,9 @@ class TracingStrategyForImplicitConstructorDelegationCall(
|
||||
}
|
||||
|
||||
private fun reportError(trace: BindingTrace) {
|
||||
if (!trace.bindingContext.diagnostics.forElement(delegationCall).any { it.factory == Errors.EXPLICIT_DELEGATION_CALL_REQUIRED }) {
|
||||
trace.report(Errors.EXPLICIT_DELEGATION_CALL_REQUIRED.on(delegationCall))
|
||||
val reportOn = delegationCall.reportOnElement()
|
||||
if (!trace.bindingContext.diagnostics.forElement(reportOn).any { it.factory == Errors.EXPLICIT_DELEGATION_CALL_REQUIRED }) {
|
||||
trace.report(Errors.EXPLICIT_DELEGATION_CALL_REQUIRED.on(reportOn))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -274,6 +274,18 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
|
||||
whatDiagnosticsToConsider.value(it.diagnostic)
|
||||
}
|
||||
|
||||
filteredDiagnostics.map { it.diagnostic }.forEach { diagnostic ->
|
||||
val diagnosticElementTextRange = diagnostic.psiElement.textRange
|
||||
diagnostic.textRanges.forEach {
|
||||
check(diagnosticElementTextRange.contains(it)) {
|
||||
"Annotation API violation:" +
|
||||
" diagnostic text range $it has to be in range of" +
|
||||
" diagnostic element ${diagnostic.psiElement} '${diagnostic.psiElement.text}'" +
|
||||
" (factory ${diagnostic.factory.name}): $diagnosticElementTextRange"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actualDiagnostics.addAll(filteredDiagnostics)
|
||||
|
||||
val uncheckedDiagnostics = mutableListOf<PositionalTextDiagnostic>()
|
||||
|
||||
Generated
+5
@@ -40,6 +40,11 @@ public class FirHighlightingTestGenerated extends AbstractFirHighlightingTest {
|
||||
runTest("idea/testData/highlighter/AutoCreatedItParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("DelegatingCtor.kt")
|
||||
public void testDelegatingCtor() throws Exception {
|
||||
runTest("idea/testData/highlighter/DelegatingCtor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("Destructuring.kt")
|
||||
public void testDestructuring() throws Exception {
|
||||
runTest("idea/testData/highlighter/Destructuring.kt");
|
||||
|
||||
Generated
+5
@@ -38,6 +38,11 @@ public class PerformanceHighlightingTestGenerated extends AbstractPerformanceHig
|
||||
runTest("idea/testData/highlighter/AutoCreatedItParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("DelegatingCtor.kt")
|
||||
public void testDelegatingCtor() throws Exception {
|
||||
runTest("idea/testData/highlighter/DelegatingCtor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("Destructuring.kt")
|
||||
public void testDestructuring() throws Exception {
|
||||
runTest("idea/testData/highlighter/Destructuring.kt");
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
<info textAttributesKey="KOTLIN_BUILTIN_ANNOTATION">open</info> class <info textAttributesKey="KOTLIN_CLASS">Foo</info> {
|
||||
<info textAttributesKey="KOTLIN_KEYWORD">constructor</info>(<warning descr="[UNUSED_PARAMETER] Parameter 'i' is never used" textAttributesKey="NOT_USED_ELEMENT_ATTRIBUTES"><info textAttributesKey="KOTLIN_PARAMETER">i</info></warning>: <info textAttributesKey="KOTLIN_CLASS">Int</info>)
|
||||
}
|
||||
|
||||
class <info textAttributesKey="KOTLIN_CLASS">Bar</info> : <info textAttributesKey="KOTLIN_CLASS">Foo</info> {
|
||||
<error descr="[EXPLICIT_DELEGATION_CALL_REQUIRED] Explicit 'this' or 'super' call is required. There is no constructor in superclass that can be called without arguments" textAttributesKey="ERRORS_ATTRIBUTES"><info textAttributesKey="KOTLIN_KEYWORD">constructor</info>(s: String)</error>
|
||||
}
|
||||
|
||||
class <info textAttributesKey="KOTLIN_CLASS">F</info>(<warning descr="[UNUSED_PARAMETER] Parameter 'foo' is never used" textAttributesKey="NOT_USED_ELEMENT_ATTRIBUTES"><info textAttributesKey="KOTLIN_PARAMETER">foo</info></warning>: <info textAttributesKey="KOTLIN_CLASS">String</info>) {
|
||||
<error descr="[PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED] Primary constructor call expected" textAttributesKey="ERRORS_ATTRIBUTES"><info textAttributesKey="KOTLIN_KEYWORD">constructor</info>()</error> {}
|
||||
}
|
||||
|
||||
<info textAttributesKey="KOTLIN_BUILTIN_ANNOTATION">enum</info> class <info textAttributesKey="KOTLIN_ENUM">E</info>(val <info textAttributesKey="KOTLIN_INSTANCE_PROPERTY">a</info>: <info textAttributesKey="KOTLIN_CLASS">String</info>) {
|
||||
<info textAttributesKey="KOTLIN_ENUM_ENTRY">A</info>;
|
||||
<warning descr="[PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED_IN_ENUM] Primary constructor call expected. It's going to be an error in 1.5." textAttributesKey="WARNING_ATTRIBUTES"><info textAttributesKey="KOTLIN_KEYWORD">constructor</info>()</warning>
|
||||
}
|
||||
+5
@@ -38,6 +38,11 @@ public class HighlightingTestGenerated extends AbstractHighlightingTest {
|
||||
runTest("idea/testData/highlighter/AutoCreatedItParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("DelegatingCtor.kt")
|
||||
public void testDelegatingCtor() throws Exception {
|
||||
runTest("idea/testData/highlighter/DelegatingCtor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("Destructuring.kt")
|
||||
public void testDestructuring() throws Exception {
|
||||
runTest("idea/testData/highlighter/Destructuring.kt");
|
||||
|
||||
Reference in New Issue
Block a user