Refactoring: SelfTargetingIntention / IntentionBasedInspection

Remove complex logic which disables intention when bound inspection on
Add much simpler logic in SelfTargetingIntention.equals
This commit is contained in:
Mikhail Glukhikh
2017-05-10 18:22:16 +03:00
parent 1900b20e6e
commit 0361ed8c68
3 changed files with 9 additions and 53 deletions
@@ -147,8 +147,8 @@ abstract class IntentionBasedInspection<TElement : PsiElement>(
}
/* we implement IntentionAction to provide isAvailable which will be used to hide outdated items and make sure we never call 'invoke' for such item */
private open inner class IntentionBasedQuickFix(
private val intention: SelfTargetingRangeIntention<TElement>,
internal open inner class IntentionBasedQuickFix(
val intention: SelfTargetingRangeIntention<TElement>,
private val additionalChecker: (TElement, IntentionBasedInspection<TElement>) -> Boolean,
targetElement: TElement
) : LocalQuickFixOnPsiElement(targetElement), IntentionAction {
@@ -17,15 +17,11 @@
package org.jetbrains.kotlin.idea.intentions
import com.intellij.codeInsight.FileModificationService
import com.intellij.codeInsight.daemon.HighlightDisplayKey
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInspection.IntentionWrapper
import com.intellij.codeInspection.LocalInspectionEP
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
import com.intellij.profile.codeInspection.InspectionProjectProfileManager
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
@@ -35,8 +31,6 @@ import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.psiUtil.containsInside
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import java.util.*
import kotlin.reflect.KClass
@Suppress("EqualsOrHashCode")
abstract class SelfTargetingIntention<TElement : PsiElement>(
@@ -88,25 +82,11 @@ abstract class SelfTargetingIntention<TElement : PsiElement>(
protected open fun allowCaretInsideElement(element: PsiElement): Boolean =
element !is KtBlockExpression
final override fun isAvailable(project: Project, editor: Editor, file: PsiFile): Boolean {
val target = getTarget(editor, file) ?: return false
return !isIntentionBaseInspectionEnabled(project, target)
}
final override fun isAvailable(project: Project, editor: Editor, file: PsiFile) = getTarget(editor, file) != null
var inspection: IntentionBasedInspection<TElement>? = null
internal set
protected fun isIntentionBaseInspectionEnabled(project: Project, target: TElement): Boolean {
val inspection = inspection ?: findInspection(this::class.java.kotlin) ?: return false
val key = HighlightDisplayKey.find(inspection.shortName)
if (!InspectionProjectProfileManager.getInstance(project).inspectionProfile.isToolEnabled(key, target)) {
return false
}
return inspection.intentionInfos.single { it.intention == this::class.java.kotlin }.additionalChecker(target, inspection)
}
final override fun invoke(project: Project, editor: Editor, file: PsiFile): Unit {
PsiDocumentManager.getInstance(project).commitAllDocuments()
val target = getTarget(editor, file) ?: return
@@ -121,32 +101,11 @@ abstract class SelfTargetingIntention<TElement : PsiElement>(
override fun equals(other: Any?): Boolean {
// Nasty code because IntentionWrapper itself does not override equals
if (other is IntentionWrapper) return this == other.action
if (other is IntentionBasedInspection<*>.IntentionBasedQuickFix) return this == other.intention
return other is SelfTargetingIntention<*> && javaClass == other.javaClass && text == other.text
}
// Intentionally missed hashCode (IntentionWrapper does not override it)
companion object {
private val intentionBasedInspections = HashMap<KClass<out SelfTargetingIntention<*>>, IntentionBasedInspection<*>?>()
fun <TElement : PsiElement> findInspection(intentionClass: KClass<out SelfTargetingIntention<TElement>>): IntentionBasedInspection<TElement>? {
if (intentionBasedInspections.containsKey(intentionClass)) {
@Suppress("UNCHECKED_CAST")
return intentionBasedInspections[intentionClass] as IntentionBasedInspection<TElement>?
}
for (extension in Extensions.getExtensions(LocalInspectionEP.LOCAL_INSPECTION)) {
val inspection = extension.instance as? IntentionBasedInspection<*> ?: continue
if (inspection.intentionInfos.any { it.intention == intentionClass }) {
intentionBasedInspections[intentionClass] = inspection
@Suppress("UNCHECKED_CAST")
return inspection as IntentionBasedInspection<TElement>
}
}
return null
}
}
}
abstract class SelfTargetingRangeIntention<TElement : PsiElement>(
@@ -32,15 +32,12 @@ class ChangePackageToMatchDirectoryIntention : SelfTargetingOffsetIndependentInt
if (file.isInjectedFragment || file.packageMatchesDirectory()) return false
val fqNameByDirectory = file.getFqNameByDirectory()
if (!fqNameByDirectory.hasIdentifiersOnly()) {
if (isIntentionBaseInspectionEnabled(file.project, element)) {
text = "File package doesn't match directory"
return true
}
return false
text = if (!fqNameByDirectory.hasIdentifiersOnly()) {
"File package doesn't match directory (cannot fix)"
}
else {
"Change file's package to '${fqNameByDirectory.asString()}'"
}
text = "Change file's package to '${fqNameByDirectory.asString()}'"
return true
}