Code cleanup to remove deprecated symbol imports that have ReplaceWith

This commit is contained in:
Valentin Kipyatkov
2015-08-28 21:37:56 +03:00
parent c020189ad0
commit e98edbcbac
9 changed files with 76 additions and 38 deletions
@@ -19,11 +19,15 @@ package org.jetbrains.kotlin.idea.core
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getFileTopLevelScope
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstanceToExpression
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.JetScope
@@ -102,3 +106,8 @@ public fun PsiElement.getResolutionScope(bindingContext: BindingContext, resolut
}
error("Not in JetFile")
}
public fun JetImportDirective.targetDescriptors(): Collection<DeclarationDescriptor> {
val nameExpression = importedReference?.getQualifiedElementSelector() as? JetSimpleNameExpression ?: return emptyList()
return nameExpression.mainReference.resolveToDescriptors(nameExpression.analyze())
}
@@ -29,16 +29,17 @@ import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.highlighter.JetPsiChecker
import org.jetbrains.kotlin.idea.quickfix.CleanupFix
import org.jetbrains.kotlin.idea.quickfix.DeprecatedSymbolUsageFix
import org.jetbrains.kotlin.idea.quickfix.JetIntentionAction
import org.jetbrains.kotlin.idea.quickfix.ReplaceObsoleteLabelSyntaxFix
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.psi.JetAnnotationEntry
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.JetImportDirective
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
import kotlin.properties.Delegates
public class KotlinCleanupInspection(): LocalInspectionTool(), CleanupLocalInspectionTool {
// required to simplify the inspection registration in tests
@@ -61,6 +62,14 @@ public class KotlinCleanupInspection(): LocalInspectionTool(), CleanupLocalInspe
}
val problems = arrayListOf<ProblemData>()
val importsToRemove = file.importDirectives.filter { DeprecatedSymbolUsageFix.isImportToBeRemoved(it) }
for (import in importsToRemove) {
val removeImportFix = RemoveImportFix(import)
val problemDescriptor = createProblemDescriptor(import, removeImportFix.text, listOf(removeImportFix), file, manager)
problems.add(ProblemData(problemDescriptor, import))
}
file.forEachDescendantOfType<PsiElement> { element ->
for (diagnostic in diagnostics.forElement(element)) {
if (diagnostic.isCleanup()) {
@@ -111,10 +120,23 @@ public class KotlinCleanupInspection(): LocalInspectionTool(), CleanupLocalInspe
}
private fun Diagnostic.toProblemDescriptor(fixes: Collection<CleanupFix>, file: JetFile, manager: InspectionManager): ProblemDescriptor {
return manager.createProblemDescriptor(getPsiElement(),
DefaultErrorMessages.render(this),
false,
fixes.map { Wrapper(it, file) }.toTypedArray(),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING)
return createProblemDescriptor(psiElement, DefaultErrorMessages.render(this), fixes, file, manager)
}
private fun createProblemDescriptor(element: PsiElement, message: String, fixes: Collection<CleanupFix>, file: JetFile, manager: InspectionManager): ProblemDescriptor {
return manager.createProblemDescriptor(element,
message,
false,
fixes.map { Wrapper(it, file) }.toTypedArray(),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING)
}
private class RemoveImportFix(import: JetImportDirective) : JetIntentionAction<JetImportDirective>(import), CleanupFix {
override fun getFamilyName() = "Remove deprecated symbol import"
override fun getText() = familyName
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
element.delete()
}
}
}
@@ -41,15 +41,12 @@ import com.intellij.psi.PsiFile
import com.intellij.util.DocumentUtil
import com.intellij.util.Processor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.targetDescriptors
import org.jetbrains.kotlin.idea.imports.KotlinImportOptimizer
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
import java.util.*
class UnusedImportInspection : AbstractKotlinInspection() {
@@ -104,8 +101,7 @@ class UnusedImportInspection : AbstractKotlinInspection() {
}
if (!isUsed) {
val nameExpression = directive.importedReference?.getQualifiedElementSelector() as? JetSimpleNameExpression
if (nameExpression == null || nameExpression.getReferenceTargets(nameExpression.analyze()).isEmpty()) continue // do not highlight unresolved imports as unused
if (directive.targetDescriptors().isEmpty()) continue // do not highlight unresolved imports as unused
val fixes = arrayListOf<LocalQuickFix>()
fixes.add(OptimizeImportsQuickFix(file))
@@ -24,6 +24,7 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.core.targetDescriptors
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
@@ -72,5 +73,9 @@ public class DeprecatedSymbolUsageFix(
return DeprecatedSymbolUsageFix(nameExpression, replacement)
}
public fun isImportToBeRemoved(import: JetImportDirective): Boolean {
return !import.isAllUnder
&& import.targetDescriptors().all { DeprecatedSymbolUsageFixBase.replaceWithPattern(it, import.project) != null }
}
}
}
@@ -17,31 +17,16 @@
package org.jetbrains.kotlin.idea.refactoring.safeDelete
import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteReferenceSimpleDeleteUsageInfo
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.core.targetDescriptors
import org.jetbrains.kotlin.psi.JetDeclaration
import org.jetbrains.kotlin.psi.JetImportDirective
public class SafeDeleteImportDirectiveUsageInfo(
importDirective: JetImportDirective, declaration: JetDeclaration
) : SafeDeleteReferenceSimpleDeleteUsageInfo(importDirective, declaration, importDirective.isSafeToDelete(declaration))
fun JetImportDirective.isSafeToDelete(declaration: JetDeclaration): Boolean {
val importExpr = getImportedReference()
val importReference: JetReferenceExpression? = when (importExpr) {
is JetSimpleNameExpression ->
importExpr
is JetDotQualifiedExpression ->
importExpr.getSelectorExpression()?.let { selector ->
if (selector is JetSimpleNameExpression) selector else null
}
else -> null
}
if (importReference != null) {
val bindingContext = importReference.analyze()
val referenceDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, importReference)
val declarationDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration)
return referenceDescriptor == declarationDescriptor
}
return false
private fun JetImportDirective.isSafeToDelete(declaration: JetDeclaration): Boolean {
val referencedDescriptor = targetDescriptors().singleOrNull() ?: return false
return referencedDescriptor == declaration.resolveToDescriptor()
}
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.getFileTopLevelScope
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.formatter.JetCodeStyleSettings
import org.jetbrains.kotlin.idea.core.targetDescriptors
import org.jetbrains.kotlin.idea.imports.getImportableTargets
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
@@ -299,9 +300,8 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert
val importsToCheck = ArrayList<FqName>()
for (import in dropCandidates) {
val importedReference = import.getImportedReference() ?: continue
val refExpr = (importedReference as JetDotQualifiedExpression).getSelectorExpression() as JetSimpleNameExpression
val targets = refExpr.resolveTargets()
if (import.importedReference == null) continue
val targets = import.targetDescriptors()
if (targets.any { it is PackageViewDescriptor }) continue // do not drop import of package
val classDescriptor = targets.filterIsInstance<ClassDescriptor>().firstOrNull()
importsToCheck.addIfNotNull(classDescriptor?.importableFqName)
+6
View File
@@ -1,3 +1,7 @@
import pack.oldFun1
import pack.oldFun2 // should not be removed for non-deprecated overload used
import pack.oldFun3
trait Foo {
}
@@ -16,6 +20,8 @@ fun foo() {
}
oldFun1(oldFun2(10))
oldFun2()
}
fun unnecessarySafeCall(x: String) {
+5
View File
@@ -1,3 +1,6 @@
import pack.bar
import pack.oldFun2 // should not be removed for non-deprecated overload used
interface Foo {
}
@@ -16,6 +19,8 @@ fun foo() {
}
bar(bar(10 + 2) + 1)
oldFun2()
}
fun unnecessarySafeCall(x: String) {
+10
View File
@@ -1,7 +1,17 @@
package pack
@deprecated("", ReplaceWith("bar(p + 1)"))
public fun oldFun1(p: Int): Int = 0
@deprecated("", ReplaceWith("bar(-1)"))
public fun oldFun1(): Int = 0
@deprecated("", ReplaceWith("bar(p + 2)"))
public fun oldFun2(p: Int): Int = 0
public fun oldFun2(): Int = 0
@deprecated("", ReplaceWith("bar(p)"))
public fun oldFun3(p: Int): Int = 0
public fun bar(p: Int): Int = p