diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantInnerClassModifierInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantInnerClassModifierInspection.kt index 46a28ffb3cc..e0d46b3d0d4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantInnerClassModifierInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantInnerClassModifierInspection.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType +import org.jetbrains.kotlin.psi.psiUtil.containingClass import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf @@ -54,18 +55,21 @@ class RedundantInnerClassModifierInspection : AbstractKotlinInspection() { return anyDescendantOfType { expression -> when (expression) { is KtNameReferenceExpression -> { - val reference = expression.mainReference.resolve() - val referenceClass = reference?.getStrictParentOfType() - if (expression.getStrictParentOfType() != null) { - return@anyDescendantOfType reference is KtClass && reference.isInner() - || reference is KtPrimaryConstructor && referenceClass?.isInner() == true + val reference = expression.mainReference.resolve()?.let { + (it as? KtConstructor<*>)?.containingClass() ?: it } - if (referenceClass != null) { - if (referenceClass == targetClass) return@anyDescendantOfType false - if (referenceClass in outerClasses) return@anyDescendantOfType true + if (reference is PsiClass && reference.parent is PsiClass) { + return@anyDescendantOfType reference.getJavaClassDescriptor()?.isInner == true + } + val referenceContainingClass = reference?.getStrictParentOfType() + if (referenceContainingClass != null) { + if (referenceContainingClass == targetClass) return@anyDescendantOfType false + if (referenceContainingClass in outerClasses) { + return@anyDescendantOfType reference !is KtClass || reference.isInner() + } } if (!hasSuperType) return@anyDescendantOfType false - val referenceClassDescriptor = referenceClass?.descriptor as? ClassDescriptor + val referenceClassDescriptor = referenceContainingClass?.descriptor as? ClassDescriptor ?: reference?.getStrictParentOfType()?.getJavaClassDescriptor() ?: (expression.resolveToCall()?.resultingDescriptor as? SyntheticJavaPropertyDescriptor) ?.getMethod?.containingDeclaration as? ClassDescriptor diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedClass.1.java b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedClass.1.java new file mode 100644 index 00000000000..734a588b631 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedClass.1.java @@ -0,0 +1,3 @@ +public class Java { + public abstract class NestedClass {} +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedClass.kt b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedClass.kt new file mode 100644 index 00000000000..deb8d78e4ed --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedClass.kt @@ -0,0 +1,4 @@ +// PROBLEM: none +class Test : Java() { + inner class Foo : Java.NestedClass() +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedInterface.1.java b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedInterface.1.java new file mode 100644 index 00000000000..8d6b55783aa --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedInterface.1.java @@ -0,0 +1,3 @@ +public class Java { + public interface NestedInterface {} +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedInterface.1.java.after b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedInterface.1.java.after new file mode 100644 index 00000000000..8d6b55783aa --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedInterface.1.java.after @@ -0,0 +1,3 @@ +public class Java { + public interface NestedInterface {} +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedInterface.kt b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedInterface.kt new file mode 100644 index 00000000000..806e71bbaf9 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedInterface.kt @@ -0,0 +1,3 @@ +class Test : Java() { + inner class Foo : Java.NestedInterface +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedInterface.kt.after b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedInterface.kt.after new file mode 100644 index 00000000000..9c7a31868d6 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedInterface.kt.after @@ -0,0 +1,3 @@ +class Test : Java() { + class Foo : Java.NestedInterface +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedStaticClass.1.java b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedStaticClass.1.java new file mode 100644 index 00000000000..367b724177c --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedStaticClass.1.java @@ -0,0 +1,3 @@ +public class Java { + public abstract static class NestedStaticClass {} +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedStaticClass.1.java.after b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedStaticClass.1.java.after new file mode 100644 index 00000000000..367b724177c --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedStaticClass.1.java.after @@ -0,0 +1,3 @@ +public class Java { + public abstract static class NestedStaticClass {} +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedStaticClass.kt b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedStaticClass.kt new file mode 100644 index 00000000000..9a2bee584f0 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedStaticClass.kt @@ -0,0 +1,3 @@ +class Test : Java() { + inner class Foo2 : Java.NestedStaticClass() +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedStaticClass.kt.after b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedStaticClass.kt.after new file mode 100644 index 00000000000..5391a5a8b98 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedStaticClass.kt.after @@ -0,0 +1,3 @@ +class Test : Java() { + class Foo2 : Java.NestedStaticClass() +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember.kt b/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember.kt new file mode 100644 index 00000000000..7b7d34c90dd --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember.kt @@ -0,0 +1,8 @@ +// PROBLEM: none +class Test { + private inner class Inner { + val inner2 = Inner2() + } + + private inner class Inner2 +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember2.kt b/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember2.kt new file mode 100644 index 00000000000..4f978ba4716 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember2.kt @@ -0,0 +1,8 @@ +// PROBLEM: none +class Test { + private inner class Inner { + val inner2 = Inner2() + } + + private inner class Inner2() +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember3.kt b/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember3.kt new file mode 100644 index 00000000000..b87e81c2575 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember3.kt @@ -0,0 +1,7 @@ +class Test { + private inner class Inner { + val inner2 = Inner2() + } + + private class Inner2 +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember3.kt.after b/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember3.kt.after new file mode 100644 index 00000000000..b32b6e22a55 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember3.kt.after @@ -0,0 +1,7 @@ +class Test { + private class Inner { + val inner2 = Inner2() + } + + private class Inner2 +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasOuterClassMemberReferenceInSuperTypeConstructorCall.kt b/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasOuterClassMemberReferenceInSuperTypeConstructorCall.kt new file mode 100644 index 00000000000..bc82844c65f --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasOuterClassMemberReferenceInSuperTypeConstructorCall.kt @@ -0,0 +1,11 @@ +// PROBLEM: none +abstract class Base(val x: Int) + +open class Outer(val x: Int) { + inner class Inner { + fun useX() { + object : Base(x) { + } + } + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasOuterClassMemberReferenceInSuperTypeConstructorCall2.kt b/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasOuterClassMemberReferenceInSuperTypeConstructorCall2.kt new file mode 100644 index 00000000000..29065924d10 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantInnerClassModifier/hasOuterClassMemberReferenceInSuperTypeConstructorCall2.kt @@ -0,0 +1,6 @@ +// PROBLEM: none +class A(private val someText: String) { + private inner class B() : C(someText) +} + +abstract class C(private val text: String) \ 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..e5d4e063f74 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -7978,6 +7978,36 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/redundantInnerClassModifier/extendInnerClass2.kt"); } + @TestMetadata("extendJavaNestedClass.kt") + public void testExtendJavaNestedClass() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedClass.kt"); + } + + @TestMetadata("extendJavaNestedInterface.kt") + public void testExtendJavaNestedInterface() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedInterface.kt"); + } + + @TestMetadata("extendJavaNestedStaticClass.kt") + public void testExtendJavaNestedStaticClass() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantInnerClassModifier/extendJavaNestedStaticClass.kt"); + } + + @TestMetadata("hasConstructorCallOfOuterClassMember.kt") + public void testHasConstructorCallOfOuterClassMember() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember.kt"); + } + + @TestMetadata("hasConstructorCallOfOuterClassMember2.kt") + public void testHasConstructorCallOfOuterClassMember2() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember2.kt"); + } + + @TestMetadata("hasConstructorCallOfOuterClassMember3.kt") + public void testHasConstructorCallOfOuterClassMember3() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantInnerClassModifier/hasConstructorCallOfOuterClassMember3.kt"); + } + @TestMetadata("hasOuterClassMemberReference.kt") public void testHasOuterClassMemberReference() throws Exception { runTest("idea/testData/inspectionsLocal/redundantInnerClassModifier/hasOuterClassMemberReference.kt"); @@ -8003,6 +8033,16 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/redundantInnerClassModifier/hasOuterClassMemberReference5.kt"); } + @TestMetadata("hasOuterClassMemberReferenceInSuperTypeConstructorCall.kt") + public void testHasOuterClassMemberReferenceInSuperTypeConstructorCall() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantInnerClassModifier/hasOuterClassMemberReferenceInSuperTypeConstructorCall.kt"); + } + + @TestMetadata("hasOuterClassMemberReferenceInSuperTypeConstructorCall2.kt") + public void testHasOuterClassMemberReferenceInSuperTypeConstructorCall2() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantInnerClassModifier/hasOuterClassMemberReferenceInSuperTypeConstructorCall2.kt"); + } + @TestMetadata("hasOuterClassTypeReference.kt") public void testHasOuterClassTypeReference() throws Exception { runTest("idea/testData/inspectionsLocal/redundantInnerClassModifier/hasOuterClassTypeReference.kt");