Deprecate ambiguous cases in FE 1.0: companion property vs enum entry

^KT-37591 Fixed
This commit is contained in:
Denis.Zharkov
2021-06-16 18:58:34 +03:00
committed by TeamCityServer
parent 24bb9a4e14
commit 46b297477c
10 changed files with 159 additions and 1 deletions
@@ -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 {
@@ -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
@@ -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(
@@ -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>() }
}
@@ -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 {
@@ -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");