[kotlin] Add 'Fully qualified name can be replaced with existing import alias' inspection

#KTIJ-13716 Fixed

https://github.com/JetBrains/intellij-community/pull/1612 close

GitOrigin-RevId: e518cd95dff8ab345932f422fd8083b370d11cf3
This commit is contained in:
Toshiaki Kameyama
2021-07-21 13:37:54 +00:00
committed by intellij-monorepo-bot
parent 68cb15940b
commit 30129e9db3
20 changed files with 254 additions and 0 deletions
@@ -0,0 +1,19 @@
<html>
<body>
Reports fully qualified names that can be replaced with an existing import alias.
<p><b>Example:</b></p>
<pre><code>
import foo.Foo as Bar
fun main() {
foo.Foo()
}
</code></pre>
<p>After the quick-fix is applied:</p>
<pre><code>
import foo.Foo as Bar
fun main() {
Bar()
}
</code></pre>
</body>
</html>
@@ -2375,3 +2375,6 @@ floating.point.literal.precision.inspection=Floating-point literal cannot be rep
inspection.replace.mapIndexed.with.list.generator.display.name=Replace 'mapIndexed' with List generator
should.be.replaced.with.list.generator=Should be replaced with List generator
replace.with.list.generator.fix.text=Replace with List generator
inspection.replace.with.import.alias.display.name=Fully qualified name can be replaced with existing import alias
replace.with.import.alias=Replace with import alias
@@ -2672,6 +2672,14 @@
language="kotlin"
key="inspection.replace.mapIndexed.with.list.generator.display.name" bundle="messages.KotlinBundle"/>
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.ReplaceWithImportAliasInspection"
groupPath="Kotlin"
groupName="Style issues"
enabledByDefault="true"
level="INFORMATION"
language="kotlin"
key="inspection.replace.with.import.alias.display.name" bundle="messages.KotlinBundle"/>
</extensions>
</idea-plugin>
@@ -0,0 +1,51 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.SmartPsiElementPointer
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
import org.jetbrains.kotlin.psi.psiUtil.isInImportDirective
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class ReplaceWithImportAliasInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = simpleNameExpressionVisitor (fun(expression) {
if (expression !is KtNameReferenceExpression || expression.getIdentifier() == null || expression.isInImportDirective()) return
val qualifiedElement = expression.getQualifiedElement()
if (qualifiedElement !is KtDotQualifiedExpression && qualifiedElement !is KtUserType) return
val aliasNameIdentifier = expression.aliasNameIdentifier() ?: return
holder.registerProblem(
expression,
KotlinBundle.message("replace.with.import.alias"),
ReplaceWithImportAliasFix(aliasNameIdentifier.createSmartPointer(), aliasNameIdentifier.text)
)
})
private fun KtNameReferenceExpression.aliasNameIdentifier(): PsiElement? {
val fqName = resolveMainReferenceToDescriptors().firstOrNull()?.importableFqName ?: return null
return containingKtFile.findAliasByFqName(fqName)?.nameIdentifier
}
private class ReplaceWithImportAliasFix(
private val aliasNameIdentifierPointer: SmartPsiElementPointer<PsiElement>,
private val aliasName: String
): LocalQuickFix {
override fun getName() = KotlinBundle.message("replace.with.0", aliasName)
override fun getFamilyName() = name
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val expression = descriptor.psiElement as? KtNameReferenceExpression ?: return
val aliasNameIdentifier = aliasNameIdentifierPointer.element ?: return
expression.getIdentifier()?.replace(aliasNameIdentifier.copy())
expression.getQualifiedElement().replace(expression.parent.safeAs<KtCallExpression>() ?: expression)
}
}
}
@@ -12978,6 +12978,54 @@ public abstract class LocalInspectionTestGenerated extends AbstractLocalInspecti
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("testData/inspectionsLocal/replaceWithImportAlias")
public static class ReplaceWithImportAlias extends AbstractLocalInspectionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("class.kt")
public void testClass() throws Exception {
runTest("testData/inspectionsLocal/replaceWithImportAlias/class.kt");
}
@TestMetadata("extension.kt")
public void testExtension() throws Exception {
runTest("testData/inspectionsLocal/replaceWithImportAlias/extension.kt");
}
@TestMetadata("function.kt")
public void testFunction() throws Exception {
runTest("testData/inspectionsLocal/replaceWithImportAlias/function.kt");
}
@TestMetadata("inImport.kt")
public void testInImport() throws Exception {
runTest("testData/inspectionsLocal/replaceWithImportAlias/inImport.kt");
}
@TestMetadata("multipleAliases.kt")
public void testMultipleAliases() throws Exception {
runTest("testData/inspectionsLocal/replaceWithImportAlias/multipleAliases.kt");
}
@TestMetadata("notQualifed.kt")
public void testNotQualifed() throws Exception {
runTest("testData/inspectionsLocal/replaceWithImportAlias/notQualifed.kt");
}
@TestMetadata("property.kt")
public void testProperty() throws Exception {
runTest("testData/inspectionsLocal/replaceWithImportAlias/property.kt");
}
@TestMetadata("type.kt")
public void testType() throws Exception {
runTest("testData/inspectionsLocal/replaceWithImportAlias/type.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("testData/inspectionsLocal/replaceWithOperatorAssignment")
public static class ReplaceWithOperatorAssignment extends AbstractLocalInspectionTest {
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.inspections.ReplaceWithImportAliasInspection
@@ -0,0 +1,10 @@
package foo
import foo.Foo as Bar
class Foo
fun main() {
foo.<caret>Foo()
foo.Foo()
}
@@ -0,0 +1,10 @@
package foo
import foo.Foo as Bar
class Foo
fun main() {
Bar()
foo.Foo()
}
@@ -0,0 +1,7 @@
package foo
import foo.Foo as Bar
class Foo
fun foo.<caret>Foo.test() {}
@@ -0,0 +1,7 @@
package foo
import foo.Foo as Bar
class Foo
fun Bar.test() {}
@@ -0,0 +1,10 @@
package foo
import foo.foo as bar
fun foo() {}
fun main() {
foo.<caret>foo()
foo.foo()
}
@@ -0,0 +1,10 @@
package foo
import foo.foo as bar
fun foo() {}
fun main() {
bar()
foo.foo()
}
@@ -0,0 +1,6 @@
// PROBLEM: none
package foo
import foo.Foo<caret> as Bar
class Foo
@@ -0,0 +1,10 @@
package foo
import foo.Foo as Bar
import foo.Foo as Baz
class Foo
fun main() {
foo.<caret>Foo()
}
@@ -0,0 +1,10 @@
package foo
import foo.Foo as Bar
import foo.Foo as Baz
class Foo
fun main() {
Bar()
}
@@ -0,0 +1,10 @@
// PROBLEM: none
package foo
import foo.Foo as Bar
class Foo
fun main() {
<caret>Bar()
}
@@ -0,0 +1,10 @@
package foo
import foo.foo as bar
val foo = 1
fun main() {
foo.foo
foo.<caret>foo
}
@@ -0,0 +1,10 @@
package foo
import foo.foo as bar
val foo = 1
fun main() {
foo.foo
bar
}
@@ -0,0 +1,7 @@
package foo
import foo.Foo as Bar
class Foo
fun test(): foo.<caret>Foo? = null
@@ -0,0 +1,7 @@
package foo
import foo.Foo as Bar
class Foo
fun test(): Bar? = null