Deprecate ambiguous cases in FE 1.0: companion property vs enum entry
^KT-37591 Fixed
This commit is contained in:
committed by
TeamCityServer
parent
24bb9a4e14
commit
46b297477c
+6
@@ -23273,6 +23273,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/parameterAsDefaultValueInLocalFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propertyInCompanionOfEnum.kt")
|
||||
public void testPropertyInCompanionOfEnum() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/propertyInCompanionOfEnum.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("resolveAnnotatedLambdaArgument.kt")
|
||||
public void testResolveAnnotatedLambdaArgument() throws Exception {
|
||||
|
||||
+6
@@ -23273,6 +23273,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/parameterAsDefaultValueInLocalFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propertyInCompanionOfEnum.kt")
|
||||
public void testPropertyInCompanionOfEnum() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/propertyInCompanionOfEnum.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("resolveAnnotatedLambdaArgument.kt")
|
||||
public void testResolveAnnotatedLambdaArgument() throws Exception {
|
||||
|
||||
@@ -128,6 +128,8 @@ public interface Errors {
|
||||
DiagnosticFactory3<PsiElement, DeclarationDescriptor, DescriptorVisibility, DeclarationDescriptor> INVISIBLE_MEMBER = DiagnosticFactory3.create(ERROR, CALL_ELEMENT);
|
||||
DiagnosticFactory1<KtElement, DeclarationDescriptor> DEPRECATED_ACCESS_BY_SHORT_NAME = DiagnosticFactory1.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<PsiElement, PropertyDescriptor> DEPRECATED_ACCESS_TO_ENUM_COMPANION_PROPERTY = DiagnosticFactory1.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<PsiElement, ConstructorDescriptor> PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
// Exposed visibility group
|
||||
|
||||
+1
@@ -71,6 +71,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(INVISIBLE_REFERENCE, "Cannot access ''{0}'': it is {1} in {2}", NAME, VISIBILITY, NAME_OF_CONTAINING_DECLARATION_OR_FILE);
|
||||
MAP.put(INVISIBLE_MEMBER, "Cannot access ''{0}'': it is {1} in {2}", NAME, VISIBILITY, NAME_OF_CONTAINING_DECLARATION_OR_FILE);
|
||||
MAP.put(DEPRECATED_ACCESS_BY_SHORT_NAME, "Access to this type by short name is deprecated, and soon is going to be removed. Please, add explicit qualifier or import", NAME);
|
||||
MAP.put(DEPRECATED_ACCESS_TO_ENUM_COMPANION_PROPERTY, "Ambiguous access to companion's property ''{0}'' in enum is deprecated. Please, add explicit Companion qualifier to the class name", NAME);
|
||||
|
||||
MAP.put(PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL, "Protected constructor ''{0}'' from other classes can only be used in super-call", Renderers.SHORT_NAMES_IN_TYPES);
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ private val DEFAULT_CALL_CHECKERS = listOf(
|
||||
MissingDependencySupertypeChecker.ForCalls, AbstractClassInstantiationChecker, SuspendConversionCallChecker,
|
||||
UnitConversionCallChecker, FunInterfaceConstructorReferenceChecker, NullableExtensionOperatorWithSafeCallChecker,
|
||||
ReferencingToUnderscoreNamedParameterOfCatchBlockChecker, VarargWrongExecutionOrderChecker, SelfCallInNestedObjectConstructorChecker,
|
||||
NewSchemeOfIntegerOperatorResolutionChecker
|
||||
NewSchemeOfIntegerOperatorResolutionChecker, EnumEntryVsCompanionPriorityCallChecker,
|
||||
)
|
||||
private val DEFAULT_TYPE_CHECKERS = emptyList<AdditionalTypeChecker>()
|
||||
private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf(
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.resolve.DescriptorEquivalenceForOverrides
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassValueReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
|
||||
object EnumEntryVsCompanionPriorityCallChecker : CallChecker {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
val descriptor = resolvedCall.candidateDescriptor
|
||||
if (descriptor !is PropertyDescriptor) return
|
||||
val propertyName = descriptor.name
|
||||
|
||||
val containingDescriptor = descriptor.containingDeclaration
|
||||
if (containingDescriptor !is ClassDescriptor || !containingDescriptor.isCompanionObject) return
|
||||
|
||||
val grandParent = containingDescriptor.containingDeclaration
|
||||
|
||||
if (grandParent is ClassDescriptor &&
|
||||
grandParent.kind == ClassKind.ENUM_CLASS &&
|
||||
grandParent.containsEntryWithName(propertyName) &&
|
||||
resolvedCall.dispatchReceiver.isQualifierFor(grandParent)) {
|
||||
context.resolutionContext.trace.report(Errors.DEPRECATED_ACCESS_TO_ENUM_COMPANION_PROPERTY.on(reportOn, descriptor))
|
||||
}
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.containsEntryWithName(name: Name): Boolean {
|
||||
val foundDescriptor = unsubstitutedMemberScope.getContributedClassifier(name, NoLookupLocation.FOR_ALREADY_TRACKED)
|
||||
return foundDescriptor is ClassDescriptor && foundDescriptor.kind == ClassKind.ENUM_ENTRY
|
||||
}
|
||||
|
||||
private fun ReceiverValue?.isQualifierFor(classDescriptor: ClassDescriptor): Boolean {
|
||||
if (this !is ClassValueReceiver) return false
|
||||
val thisClass = this.classQualifier.descriptor as? ClassDescriptor ?: return false
|
||||
return thisClass.typeConstructor == classDescriptor.typeConstructor
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// !CHECK_TYPE
|
||||
// SKIP_TXT
|
||||
|
||||
// FILE: test.kt
|
||||
package test
|
||||
enum class E {
|
||||
Entry;
|
||||
companion object {
|
||||
val Entry = ""
|
||||
val NotEntry = ""
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
import test.E.Entry
|
||||
import test.E.Companion as W
|
||||
import test.E as U
|
||||
import test.E
|
||||
|
||||
fun foo() {
|
||||
E.Entry checkType { _<E>() }
|
||||
E.Entry checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() }
|
||||
E.Companion.Entry checkType { _<String>() }
|
||||
E.NotEntry checkType { _<String>() }
|
||||
Entry checkType { _<E>() }
|
||||
|
||||
W.Entry checkType { _<String>() }
|
||||
}
|
||||
|
||||
// FILE: Aliased.kt
|
||||
|
||||
import test.E as U
|
||||
|
||||
fun bar() {
|
||||
U.Entry checkType { <!INAPPLICABLE_CANDIDATE!>_<!><<!UNRESOLVED_REFERENCE!>E<!>>() }
|
||||
U.Entry checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() }
|
||||
U.Companion.Entry checkType { _<String>() }
|
||||
U.NotEntry checkType { _<String>() }
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// !CHECK_TYPE
|
||||
// SKIP_TXT
|
||||
|
||||
// FILE: test.kt
|
||||
package test
|
||||
enum class E {
|
||||
Entry;
|
||||
companion object {
|
||||
val Entry = ""
|
||||
val NotEntry = ""
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
import test.E.Entry
|
||||
import test.E.Companion as W
|
||||
import test.E as U
|
||||
import test.E
|
||||
|
||||
fun foo() {
|
||||
E.<!DEPRECATED_ACCESS_TO_ENUM_COMPANION_PROPERTY!>Entry<!> checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><E>() }
|
||||
E.<!DEPRECATED_ACCESS_TO_ENUM_COMPANION_PROPERTY!>Entry<!> checkType { _<String>() }
|
||||
E.Companion.Entry checkType { _<String>() }
|
||||
E.NotEntry checkType { _<String>() }
|
||||
Entry checkType { _<E>() }
|
||||
|
||||
W.Entry checkType { _<String>() }
|
||||
}
|
||||
|
||||
// FILE: Aliased.kt
|
||||
|
||||
import test.E as U
|
||||
|
||||
fun bar() {
|
||||
U.<!DEPRECATED_ACCESS_TO_ENUM_COMPANION_PROPERTY!>Entry<!> checkType { _<<!UNRESOLVED_REFERENCE!>E<!>>() }
|
||||
U.<!DEPRECATED_ACCESS_TO_ENUM_COMPANION_PROPERTY!>Entry<!> checkType { _<String>() }
|
||||
U.Companion.Entry checkType { _<String>() }
|
||||
U.NotEntry checkType { _<String>() }
|
||||
}
|
||||
Generated
+6
@@ -23285,6 +23285,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/parameterAsDefaultValueInLocalFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propertyInCompanionOfEnum.kt")
|
||||
public void testPropertyInCompanionOfEnum() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/propertyInCompanionOfEnum.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("resolveAnnotatedLambdaArgument.kt")
|
||||
public void testResolveAnnotatedLambdaArgument() throws Exception {
|
||||
|
||||
+5
@@ -23274,6 +23274,11 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propertyInCompanionOfEnum.kt")
|
||||
public void testPropertyInCompanionOfEnum() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/propertyInCompanionOfEnum.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("resolveAnnotatedLambdaArgument.kt")
|
||||
public void testResolveAnnotatedLambdaArgument() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/resolveAnnotatedLambdaArgument.kt");
|
||||
|
||||
Reference in New Issue
Block a user