Redundant 'inner' modifier: fix false positive/negative with constructor call

#KT-40879 Fixed
#KT-41223 Fixed
#KT-41311 Fixed
#KT-41680 Fixed
This commit is contained in:
Toshiaki Kameyama
2020-08-07 10:22:11 +09:00
committed by Dmitry Gridin
parent e9669bf5cb
commit 09e1bed5c9
18 changed files with 131 additions and 9 deletions
@@ -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<KtExpression> { expression ->
when (expression) {
is KtNameReferenceExpression -> {
val reference = expression.mainReference.resolve()
val referenceClass = reference?.getStrictParentOfType<KtClass>()
if (expression.getStrictParentOfType<KtSuperTypeCallEntry>() != 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<KtClass>()
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<PsiClass>()?.getJavaClassDescriptor()
?: (expression.resolveToCall()?.resultingDescriptor as? SyntheticJavaPropertyDescriptor)
?.getMethod?.containingDeclaration as? ClassDescriptor
@@ -0,0 +1,3 @@
public class Java {
public abstract class NestedClass {}
}
@@ -0,0 +1,4 @@
// PROBLEM: none
class Test : Java() {
<caret>inner class Foo : Java.NestedClass()
}
@@ -0,0 +1,3 @@
public class Java {
public interface NestedInterface {}
}
@@ -0,0 +1,3 @@
public class Java {
public interface NestedInterface {}
}
@@ -0,0 +1,3 @@
class Test : Java() {
<caret>inner class Foo : Java.NestedInterface
}
@@ -0,0 +1,3 @@
class Test : Java() {
class Foo : Java.NestedInterface
}
@@ -0,0 +1,3 @@
public class Java {
public abstract static class NestedStaticClass {}
}
@@ -0,0 +1,3 @@
public class Java {
public abstract static class NestedStaticClass {}
}
@@ -0,0 +1,3 @@
class Test : Java() {
<caret>inner class Foo2 : Java.NestedStaticClass()
}
@@ -0,0 +1,3 @@
class Test : Java() {
class Foo2 : Java.NestedStaticClass()
}
@@ -0,0 +1,8 @@
// PROBLEM: none
class Test {
private <caret>inner class Inner {
val inner2 = Inner2()
}
private inner class Inner2
}
@@ -0,0 +1,8 @@
// PROBLEM: none
class Test {
private <caret>inner class Inner {
val inner2 = Inner2()
}
private inner class Inner2()
}
@@ -0,0 +1,7 @@
class Test {
private <caret>inner class Inner {
val inner2 = Inner2()
}
private class Inner2
}
@@ -0,0 +1,7 @@
class Test {
private class Inner {
val inner2 = Inner2()
}
private class Inner2
}
@@ -0,0 +1,11 @@
// PROBLEM: none
abstract class Base(val x: Int)
open class Outer(val x: Int) {
<caret>inner class Inner {
fun useX() {
object : Base(x) {
}
}
}
}
@@ -0,0 +1,6 @@
// PROBLEM: none
class A(private val someText: String) {
private <caret>inner class B() : C(someText)
}
abstract class C(private val text: String)
@@ -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");