RemoveRedundantQualifierNameInspection: support class literal expression

#KT-32046 Fixed
This commit is contained in:
Dmitry Gridin
2019-06-20 18:12:39 +07:00
parent b930c061a8
commit a170de2c56
12 changed files with 163 additions and 5 deletions
@@ -20,7 +20,6 @@ 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.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.isCompanionObject
import org.jetbrains.kotlin.resolve.scopes.utils.findFirstClassifierWithDeprecationStatus
@@ -28,16 +27,23 @@ class RemoveRedundantQualifierNameInspection : AbstractKotlinInspection(), Clean
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor =
object : KtVisitorVoid() {
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
if (expression.parent is KtDotQualifiedExpression? || expression.isInImportDirective()) return
if (expression.parent is KtDotQualifiedExpression || expression.isInImportDirective()) return
val expressionForAnalyze = expression.firstExpressionWithoutReceiver() ?: return
val context = expressionForAnalyze.analyze()
val parent = expressionForAnalyze.parent
@Suppress("USELESS_CAST") val originalExpression = if (parent is KtClassLiteralExpression)
parent as KtExpression
else
expressionForAnalyze
val context = originalExpression.analyze()
val importableFqName = expressionForAnalyze.getQualifiedElementSelector()
?.mainReference?.resolveToDescriptors(context)?.firstOrNull()
?.importableFqName ?: return
val applicableExpression = expressionForAnalyze.firstApplicableExpression(validator = {
applicableExpression(expressionForAnalyze, context, importableFqName)
applicableExpression(originalExpression, context, importableFqName)
}) {
firstChild as? KtDotQualifiedExpression
} ?: return
@@ -78,13 +84,18 @@ private fun KtDotQualifiedExpression.applicableExpression(
val expressionText = originalExpression.text.substring(lastChild.startOffset - originalExpression.startOffset)
val newExpression = KtPsiFactory(originalExpression).createExpressionIfPossible(expressionText) ?: return null
val newContext = newExpression.analyzeAsReplacement(originalExpression, oldContext)
val newDescriptor = newExpression.getQualifiedElementSelector()?.getResolvedCall(newContext)?.resultingDescriptor ?: return null
val newDescriptor = newExpression.selector()
?.mainReference?.resolveToDescriptors(newContext)
?.firstOrNull() ?: return null
return takeIf {
importableFqName == newDescriptor.importableFqName
}
}
private fun KtExpression.selector(): KtElement? = if (this is KtClassLiteralExpression) receiverExpression?.getQualifiedElementSelector()
else getQualifiedElementSelector()
private fun KtExpression.isApplicableReceiver(context: BindingContext): Boolean {
if (this is KtInstanceExpressionWithLabel) return false
@@ -0,0 +1,8 @@
// WITH_RUNTIME
package foo
class Foo
fun bar() {
foo<caret>.Foo::class
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
package foo
class Foo
fun bar() {
Foo::class
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
package foo
class Foo
fun bar() {
foo<caret>.Foo::class.java
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
package foo
class Foo
fun bar() {
Foo::class.java
}
@@ -0,0 +1,17 @@
// WITH_RUNTIME
// DISABLE-ERRORS
package foo.www.ddd
class Check {
class BBD {
class Bwd {
fun dad() {
val Bwd = 42
class BBD
val a = foo.www.ddd<caret>.Check.BBD.Bwd::class.java.annotatedInterfaces.size
}
}
}
}
@@ -0,0 +1,17 @@
// WITH_RUNTIME
// DISABLE-ERRORS
package foo.www.ddd
class Check {
class BBD {
class Bwd {
fun dad() {
val Bwd = 42
class BBD
val a = Check.BBD.Bwd::class.java.annotatedInterfaces.size
}
}
}
}
@@ -0,0 +1,14 @@
// WITH_RUNTIME
// DISABLE-ERRORS
package foo.www.ddd
class Check {
class BBD {
class Bwd {
fun dad() {
fun Bwd(): String = ""
val a = foo.www.ddd.<caret>Check.BBD.Bwd::class.java.annotatedInterfaces.size
}
}
}
}
@@ -0,0 +1,14 @@
// WITH_RUNTIME
// DISABLE-ERRORS
package foo.www.ddd
class Check {
class BBD {
class Bwd {
fun dad() {
fun Bwd(): String = ""
val a = Bwd::class.java.annotatedInterfaces.size
}
}
}
}
@@ -0,0 +1,14 @@
// WITH_RUNTIME
// DISABLE-ERRORS
package foo.www.ddd
class Check {
class BBD {
class Bwd {
fun dad() {
class Bwd
val a = foo.www.ddd.<caret>Check.BBD.Bwd::class.java.annotatedInterfaces.size
}
}
}
}
@@ -0,0 +1,14 @@
// WITH_RUNTIME
// DISABLE-ERRORS
package foo.www.ddd
class Check {
class BBD {
class Bwd {
fun dad() {
class Bwd
val a = BBD.Bwd::class.java.annotatedInterfaces.size
}
}
}
}
@@ -7631,6 +7631,31 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/asReceiverProperty.kt");
}
@TestMetadata("classLiteral.kt")
public void testClassLiteral() throws Exception {
runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/classLiteral.kt");
}
@TestMetadata("classLiteral2.kt")
public void testClassLiteral2() throws Exception {
runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/classLiteral2.kt");
}
@TestMetadata("classLiteral3.kt")
public void testClassLiteral3() throws Exception {
runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/classLiteral3.kt");
}
@TestMetadata("classLiteral4.kt")
public void testClassLiteral4() throws Exception {
runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/classLiteral4.kt");
}
@TestMetadata("classLiteral5.kt")
public void testClassLiteral5() throws Exception {
runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/classLiteral5.kt");
}
@TestMetadata("companionCollision.kt")
public void testCompanionCollision() throws Exception {
runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/companionCollision.kt");