From 55d55446c8de12a574990587a58771b89431be87 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Fri, 11 Oct 2019 00:14:50 +0900 Subject: [PATCH] Redundant companion reference: do not report 'values/valueOf' function in enum #KT-34285 Fixed --- .../RedundantCompanionReferenceInspection.kt | 209 ++++++++++-------- .../RemoveRedundantQualifierNameInspection.kt | 10 +- .../inspections/UnusedSymbolInspection.kt | 33 +-- .../jetbrains/kotlin/idea/intentions/Utils.kt | 34 ++- .../enumValueOf.kt | 14 ++ .../enumValueOf2.kt | 14 ++ .../redundantCompanionReference/enumValues.kt | 14 ++ .../enumValues2.kt | 14 ++ .../LocalInspectionTestGenerated.java | 20 ++ 9 files changed, 224 insertions(+), 138 deletions(-) create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/enumValueOf.kt create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/enumValueOf2.kt create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/enumValues.kt create mode 100644 idea/testData/inspectionsLocal/redundantCompanionReference/enumValues2.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantCompanionReferenceInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantCompanionReferenceInspection.kt index b8eb5c17ed4..86396259d32 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantCompanionReferenceInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantCompanionReferenceInspection.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.analysis.analyzeAsReplacement import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.intentions.isReferenceToBuiltInEnumFunction import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.resolveToDescriptors import org.jetbrains.kotlin.idea.util.getResolutionScope @@ -50,112 +51,124 @@ class RedundantCompanionReferenceInspection : AbstractKotlinInspection() { }) } - companion object { - fun isRedundantCompanionReference(reference: KtReferenceExpression): Boolean { - val parent = reference.parent as? KtDotQualifiedExpression ?: return false - val grandParent = parent.parent - val selectorExpression = parent.selectorExpression - if (reference == selectorExpression && grandParent !is KtDotQualifiedExpression) return false - if (parent.getStrictParentOfType() != null) return false + private fun isRedundantCompanionReference(reference: KtReferenceExpression): Boolean { + val parent = reference.parent as? KtDotQualifiedExpression ?: return false + val grandParent = parent.parent as? KtElement + val selectorExpression = parent.selectorExpression + if (reference == selectorExpression && grandParent !is KtDotQualifiedExpression) return false + if (parent.getStrictParentOfType() != null) return false - val objectDeclaration = reference.mainReference.resolve() as? KtObjectDeclaration ?: return false - if (!objectDeclaration.isCompanion()) return false - val referenceText = reference.text - if (referenceText != objectDeclaration.name) return false - if (reference != selectorExpression && referenceText == (selectorExpression as? KtNameReferenceExpression)?.text) return false + val objectDeclaration = reference.mainReference.resolve() as? KtObjectDeclaration ?: return false + if (!objectDeclaration.isCompanion()) return false + val referenceText = reference.text + if (referenceText != objectDeclaration.name) return false + if (reference != selectorExpression && referenceText == (selectorExpression as? KtNameReferenceExpression)?.text) return false - val containingClass = objectDeclaration.containingClass() ?: return false - if (reference.containingClass() != containingClass && reference == parent.receiverExpression) return false - val context = reference.analyze() - val containingClassDescriptor = - context[BindingContext.DECLARATION_TO_DESCRIPTOR, containingClass] as? ClassDescriptor ?: return false - when (val selectorDescriptor = selectorExpression?.getResolvedCall(context)?.resultingDescriptor) { - is PropertyDescriptor -> { - val name = selectorDescriptor.name - if (containingClassDescriptor.findMemberVariable(name) != null) return false + val containingClass = objectDeclaration.containingClass() ?: return false + if (reference.containingClass() != containingClass && reference == parent.receiverExpression) return false + if (parent.isReferenceToBuildInEnumFunctionInEnumClass(containingClass)) return false - val type = selectorDescriptor.type - val javaGetter = containingClassDescriptor.findMemberFunction( - Name.identifier(JvmAbi.getterName(name.asString())) - )?.takeIf { f -> f is JavaMethodDescriptor || f.overriddenDescriptors.any { it is JavaMethodDescriptor } } - if (javaGetter?.valueParameters?.isEmpty() == true && javaGetter.returnType?.makeNotNullable() == type) return false + val context = reference.analyze() + if (grandParent.isReferenceToClassOrObject(context)) return false - val variable = reference.getResolutionScope().findVariable(name, NoLookupLocation.FROM_IDE) - if (variable != null && variable.isLocalOrExtension(containingClassDescriptor)) return false - } - is FunctionDescriptor -> { - val name = selectorDescriptor.name - if (containingClassDescriptor.findMemberFunction(name) != null) return false - val function = reference.getResolutionScope().findFunction(name, NoLookupLocation.FROM_IDE) - if (function != null && function.isLocalOrExtension(containingClassDescriptor)) return false - } + val containingClassDescriptor = + context[BindingContext.DECLARATION_TO_DESCRIPTOR, containingClass] as? ClassDescriptor ?: return false + if (containingClassDescriptor.hasSameNameMemberAs(selectorExpression, context)) return false + + (reference as? KtSimpleNameExpression)?.getReceiverExpression()?.getQualifiedElementSelector() + ?.mainReference?.resolveToDescriptors(context)?.firstOrNull() + ?.let { if (it != containingClassDescriptor) return false } + + if (selectorExpression is KtCallExpression && referenceText == selectorExpression.calleeExpression?.text) { + val newExpression = KtPsiFactory(reference).createExpressionByPattern("$0", selectorExpression) + val newContext = newExpression.analyzeAsReplacement(parent, context) + val descriptor = newExpression.getResolvedCall(newContext)?.resultingDescriptor as? FunctionDescriptor + if (descriptor?.isOperator == true) return false + } + + return true + } + + private fun KtDotQualifiedExpression.isReferenceToBuildInEnumFunctionInEnumClass(containingClass: KtClass): Boolean { + return containingClass.isEnum() + && (isReferenceToBuiltInEnumFunction() || (parent as? KtElement)?.isReferenceToBuiltInEnumFunction() == true) + } + + private fun KtElement?.isReferenceToClassOrObject(context: BindingContext): Boolean { + if (this !is KtQualifiedExpression) return false + val descriptor = getResolvedCall(context)?.resultingDescriptor + return descriptor == null || descriptor is ConstructorDescriptor || descriptor is FakeCallableDescriptorForObject + } + + private fun ClassDescriptor.hasSameNameMemberAs(expression: KtExpression?, context: BindingContext): Boolean { + when (val descriptor = expression?.getResolvedCall(context)?.resultingDescriptor) { + is PropertyDescriptor -> { + val name = descriptor.name + if (findMemberVariable(name) != null) return true + + val type = descriptor.type + val javaGetter = findMemberFunction(Name.identifier(JvmAbi.getterName(name.asString()))) + ?.takeIf { f -> f is JavaMethodDescriptor || f.overriddenDescriptors.any { it is JavaMethodDescriptor } } + if (javaGetter?.valueParameters?.isEmpty() == true && javaGetter.returnType?.makeNotNullable() == type) return true + + val variable = expression.getResolutionScope().findVariable(name, NoLookupLocation.FROM_IDE) + if (variable != null && variable.isLocalOrExtension(this)) return true } - - (reference as? KtSimpleNameExpression)?.getReceiverExpression()?.getQualifiedElementSelector() - ?.mainReference?.resolveToDescriptors(context)?.firstOrNull() - ?.let { if (it != containingClassDescriptor) return false } - - if (grandParent is KtQualifiedExpression) { - val grandParentDescriptor = grandParent.getResolvedCall(context)?.resultingDescriptor ?: return false - if (grandParentDescriptor is ConstructorDescriptor || grandParentDescriptor is FakeCallableDescriptorForObject) return false + is FunctionDescriptor -> { + val name = descriptor.name + if (findMemberFunction(name) != null) return true + val function = expression.getResolutionScope().findFunction(name, NoLookupLocation.FROM_IDE) + if (function != null && function.isLocalOrExtension(this)) return true } + } + return false + } - if (selectorExpression is KtCallExpression && referenceText == selectorExpression.calleeExpression?.text) { - val newExpression = KtPsiFactory(reference).createExpressionByPattern("$0", selectorExpression) - val newContext = newExpression.analyzeAsReplacement(parent, context) - val descriptor = newExpression.getResolvedCall(newContext)?.resultingDescriptor as? FunctionDescriptor - if (descriptor?.isOperator == true) return false + private fun ClassDescriptor.findMemberByName(name: Name, find: ClassDescriptor.(Name) -> D?): D? { + val member = find(name) + if (member != null) return member + + val memberInSuperClass = getSuperClassNotAny()?.findMemberByName(name, find) + if (memberInSuperClass != null) return memberInSuperClass + + getSuperInterfaces().forEach { + val memberInInterface = it.findMemberByName(name, find) + if (memberInInterface != null) return memberInInterface + } + + return null + } + + private fun ClassDescriptor.findMemberVariable(name: Name): PropertyDescriptor? = findMemberByName(name) { + unsubstitutedMemberScope.getContributedVariables(it, NoLookupLocation.FROM_IDE).firstOrNull() + } + + private fun ClassDescriptor.findMemberFunction(name: Name): FunctionDescriptor? = findMemberByName(name) { + unsubstitutedMemberScope.getContributedFunctions(it, NoLookupLocation.FROM_IDE).firstOrNull() + } + + private fun CallableDescriptor.isLocalOrExtension(extensionClassDescriptor: ClassDescriptor): Boolean { + return visibility == DescriptorVisibilities.LOCAL || + extensionReceiverParameter?.type?.constructor?.declarationDescriptor == extensionClassDescriptor + } + + private class RemoveRedundantCompanionReferenceFix : LocalQuickFix { + override fun getName() = KotlinBundle.message("remove.redundant.companion.reference.fix.text") + + override fun getFamilyName() = name + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + val expression = descriptor.psiElement as? KtReferenceExpression ?: return + removeRedundantCompanionReference(expression) + } + + companion object { + fun removeRedundantCompanionReference(expression: KtReferenceExpression) { + val parent = expression.parent as? KtDotQualifiedExpression ?: return + val selector = parent.selectorExpression ?: return + val receiver = parent.receiverExpression + if (expression == receiver) parent.replace(selector) else parent.replace(receiver) } - - return true - } - } -} - -private fun ClassDescriptor.findMemberByName(name: Name, find: ClassDescriptor.(Name) -> D?): D? { - val member = find(name) - if (member != null) return member - - val memberInSuperClass = getSuperClassNotAny()?.findMemberByName(name, find) - if (memberInSuperClass != null) return memberInSuperClass - - getSuperInterfaces().forEach { - val memberInInterface = it.findMemberByName(name, find) - if (memberInInterface != null) return memberInInterface - } - - return null -} - -private fun ClassDescriptor.findMemberVariable(name: Name): PropertyDescriptor? = findMemberByName(name) { - unsubstitutedMemberScope.getContributedVariables(it, NoLookupLocation.FROM_IDE).firstOrNull() -} - -private fun ClassDescriptor.findMemberFunction(name: Name): FunctionDescriptor? = findMemberByName(name) { - unsubstitutedMemberScope.getContributedFunctions(it, NoLookupLocation.FROM_IDE).firstOrNull() -} - -private fun CallableDescriptor.isLocalOrExtension(extensionClassDescriptor: ClassDescriptor): Boolean { - return visibility == DescriptorVisibilities.LOCAL || - extensionReceiverParameter?.type?.constructor?.declarationDescriptor == extensionClassDescriptor -} - -class RemoveRedundantCompanionReferenceFix : LocalQuickFix { - override fun getName() = KotlinBundle.message("remove.redundant.companion.reference.fix.text") - - override fun getFamilyName() = name - - override fun applyFix(project: Project, descriptor: ProblemDescriptor) { - val expression = descriptor.psiElement as? KtReferenceExpression ?: return - removeRedundantCompanionReference(expression) - } - - companion object { - fun removeRedundantCompanionReference(expression: KtReferenceExpression) { - val parent = expression.parent as? KtDotQualifiedExpression ?: return - val selector = parent.selectorExpression ?: return - val receiver = parent.receiverExpression - if (expression == receiver) parent.replace(selector) else parent.replace(receiver) } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RemoveRedundantQualifierNameInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RemoveRedundantQualifierNameInspection.kt index 41342522c30..acb3769efda 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/RemoveRedundantQualifierNameInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RemoveRedundantQualifierNameInspection.kt @@ -19,7 +19,7 @@ import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.idea.core.compareDescriptors import org.jetbrains.kotlin.idea.core.unwrapIfFakeOverride import org.jetbrains.kotlin.idea.imports.importableFqName -import org.jetbrains.kotlin.idea.intentions.callExpression +import org.jetbrains.kotlin.idea.intentions.isReferenceToBuiltInEnumFunction import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.resolveToDescriptors import org.jetbrains.kotlin.idea.util.getResolutionScope @@ -36,10 +36,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs import javax.swing.JComponent class RemoveRedundantQualifierNameInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { - companion object { - private val ENUM_STATIC_METHODS = listOf("values", "valueOf") - } - /** * In order to detect that `foo()` and `GrandBase.foo()` point to the same method, * we need to unwrap fake overrides from descriptors. If we don't do that, they will @@ -77,7 +73,7 @@ class RemoveRedundantQualifierNameInspection : AbstractKotlinInspection(), Clean if (receiverReference?.safeAs()?.isEnum() == true && expressionForAnalyze.getParentOfTypesAndPredicate(true, KtClass::class.java) { it.isEnum() } != receiverReference - && (expressionForAnalyze.isEnumStaticMethodCall() || expressionForAnalyze.isCompanionObjectReference()) + && (expressionForAnalyze.isReferenceToBuiltInEnumFunction() || expressionForAnalyze.isCompanionObjectReference()) ) return val context = originalExpression.analyze() @@ -107,8 +103,6 @@ class RemoveRedundantQualifierNameInspection : AbstractKotlinInspection(), Clean } } - private fun KtDotQualifiedExpression.isEnumStaticMethodCall() = callExpression?.calleeExpression?.text in ENUM_STATIC_METHODS - private fun KtDotQualifiedExpression.isCompanionObjectReference(): Boolean { val selector = receiverExpression.safeAs()?.selectorExpression ?: selectorExpression return selector?.referenceExpression()?.mainReference?.resolve()?.safeAs()?.isCompanion() == true diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt index 0729e666794..6b270afcc29 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt @@ -48,8 +48,7 @@ import org.jetbrains.kotlin.idea.core.script.configuration.DefaultScriptingSuppo import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler -import org.jetbrains.kotlin.idea.inspections.collections.isCalling -import org.jetbrains.kotlin.idea.intentions.callExpression +import org.jetbrains.kotlin.idea.intentions.isReferenceToBuiltInEnumFunction import org.jetbrains.kotlin.idea.intentions.isFinalizeMethod import org.jetbrains.kotlin.idea.isMainFunction import org.jetbrains.kotlin.idea.project.languageVersionSettings @@ -69,15 +68,12 @@ import org.jetbrains.kotlin.idea.util.hasActualsFor import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.load.java.JvmAbi -import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.isInlineClassType -import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.util.findCallableMemberBySignature import java.awt.GridBagConstraints import java.awt.GridBagLayout @@ -92,10 +88,6 @@ class UnusedSymbolInspection : AbstractKotlinInspection() { private val KOTLIN_ADDITIONAL_ANNOTATIONS = listOf("kotlin.test.*", "kotlin.js.JsExport") - private val KOTLIN_BUILTIN_ENUM_FUNCTIONS = listOf(FqName("kotlin.enumValues"), FqName("kotlin.enumValueOf")) - - private val ENUM_STATIC_METHODS = listOf("values", "valueOf") - private fun KtDeclaration.hasKotlinAdditionalAnnotation() = this is KtNamedDeclaration && checkAnnotatedUsingPatterns(this, KOTLIN_ADDITIONAL_ANNOTATIONS) @@ -470,30 +462,13 @@ class UnusedSymbolInspection : AbstractKotlinInspection() { } private fun hasBuiltInEnumFunctionReference(reference: PsiReference): Boolean { - return when (val parent = reference.element.getParentOfTypes( + val parent = reference.element.getParentOfTypes( true, KtTypeReference::class.java, KtQualifiedExpression::class.java, KtCallableReferenceExpression::class.java - )) { - is KtTypeReference -> { - val target = (parent.getStrictParentOfType() ?: parent) - .getParentOfTypes(true, KtCallExpression::class.java, KtCallableDeclaration::class.java) - when (target) { - is KtCallExpression -> target.isCalling(KOTLIN_BUILTIN_ENUM_FUNCTIONS) - is KtCallableDeclaration -> { - target.anyDescendantOfType { - val context = it.analyze(BodyResolveMode.PARTIAL_WITH_CFA) - it.isCalling(KOTLIN_BUILTIN_ENUM_FUNCTIONS, context) && it.isUsedAsExpression(context) - } - } - else -> false - } - } - is KtQualifiedExpression -> parent.callExpression?.calleeExpression?.text in ENUM_STATIC_METHODS - is KtCallableReferenceExpression -> parent.callableReference.text in ENUM_STATIC_METHODS - else -> false - } + ) ?: return false + return parent.isReferenceToBuiltInEnumFunction() } private fun checkPrivateDeclaration(declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor?): Boolean { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt index 3b27a34683b..39246c4ef21 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt @@ -17,18 +17,19 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall import org.jetbrains.kotlin.idea.core.getDeepestSuperDeclarations import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.core.setType +import org.jetbrains.kotlin.idea.inspections.collections.isCalling import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.resolveToDescriptors import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.containingClass -import org.jetbrains.kotlin.psi.psiUtil.getCallNameExpression -import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType +import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.resolve.ArrayFqNames import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode @@ -368,3 +369,30 @@ fun KotlinType.reflectToRegularFunctionType(): KotlinType { val CallableDescriptor.isInvokeOperator: Boolean get() = this is FunctionDescriptor && isOperator && name == OperatorNameConventions.INVOKE + +private val KOTLIN_BUILTIN_ENUM_FUNCTIONS = listOf(FqName("kotlin.enumValues"), FqName("kotlin.enumValueOf")) + +private val ENUM_STATIC_METHODS = listOf("values", "valueOf") + +fun KtElement.isReferenceToBuiltInEnumFunction(): Boolean { + return when (this) { + is KtTypeReference -> { + val target = (parent.getStrictParentOfType() ?: this) + .getParentOfTypes(true, KtCallExpression::class.java, KtCallableDeclaration::class.java) + when (target) { + is KtCallExpression -> target.isCalling(KOTLIN_BUILTIN_ENUM_FUNCTIONS) + is KtCallableDeclaration -> { + target.anyDescendantOfType { + val context = it.analyze(BodyResolveMode.PARTIAL_WITH_CFA) + it.isCalling(KOTLIN_BUILTIN_ENUM_FUNCTIONS, context) && it.isUsedAsExpression(context) + } + } + else -> false + } + } + is KtQualifiedExpression -> this.callExpression?.calleeExpression?.text in ENUM_STATIC_METHODS + is KtCallExpression -> this.calleeExpression?.text in ENUM_STATIC_METHODS + is KtCallableReferenceExpression -> this.callableReference.text in ENUM_STATIC_METHODS + else -> false + } +} diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/enumValueOf.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/enumValueOf.kt new file mode 100644 index 00000000000..4483be14eaf --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/enumValueOf.kt @@ -0,0 +1,14 @@ +// PROBLEM: none + +enum class A { + TEST; + + companion object { + fun valueOf(name: String) { + } + } +} + +fun main() { + A.Companion.valueOf("TEST") +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/enumValueOf2.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/enumValueOf2.kt new file mode 100644 index 00000000000..08fc30bd002 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/enumValueOf2.kt @@ -0,0 +1,14 @@ +// PROBLEM: none + +enum class A { + TEST; + + companion object { + fun valueOf(name: String) { + } + } + + fun test() { + Companion.valueOf("TEST") + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/enumValues.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/enumValues.kt new file mode 100644 index 00000000000..ea8abc355f7 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/enumValues.kt @@ -0,0 +1,14 @@ +// PROBLEM: none + +enum class A { + TEST; + + companion object { + fun values() { + } + } +} + +fun main() { + A.Companion.values() +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantCompanionReference/enumValues2.kt b/idea/testData/inspectionsLocal/redundantCompanionReference/enumValues2.kt new file mode 100644 index 00000000000..657e1623797 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantCompanionReference/enumValues2.kt @@ -0,0 +1,14 @@ +// PROBLEM: none + +enum class A { + TEST; + + companion object { + fun values() { + } + } + + fun test() { + Companion.values() + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 7752c4b1cbd..94f10ad324e 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -7417,6 +7417,26 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/redundantCompanionReference/directCompanion.kt"); } + @TestMetadata("enumValueOf.kt") + public void testEnumValueOf() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/enumValueOf.kt"); + } + + @TestMetadata("enumValueOf2.kt") + public void testEnumValueOf2() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/enumValueOf2.kt"); + } + + @TestMetadata("enumValues.kt") + public void testEnumValues() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/enumValues.kt"); + } + + @TestMetadata("enumValues2.kt") + public void testEnumValues2() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantCompanionReference/enumValues2.kt"); + } + @TestMetadata("functionReference.kt") public void testFunctionReference() throws Exception { runTest("idea/testData/inspectionsLocal/redundantCompanionReference/functionReference.kt");