Intention based intentions: added ability to highlight partial range, used it in new inspection based on IntroduceWhenSubjectIntention + added missing description

This commit is contained in:
Valentin Kipyatkov
2015-05-06 13:06:37 +03:00
parent 45c5454e39
commit 07a89b38e1
7 changed files with 69 additions and 25 deletions
@@ -23,15 +23,14 @@ import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.idea.intentions.JetSelfTargetingOffsetIndependentIntention
import org.jetbrains.kotlin.idea.intentions.JetSelfTargetingRangeIntention
import org.jetbrains.kotlin.psi.JetElement
import java.util.*
public abstract class IntentionBasedInspection<T: JetElement>(
protected val intentions: List<JetSelfTargetingOffsetIndependentIntention<T>>,
protected val intentions: List<JetSelfTargetingRangeIntention<T>>,
protected val elementType: Class<T>
) : AbstractKotlinInspection() {
constructor(intention: JetSelfTargetingOffsetIndependentIntention<T>): this(listOf(intention), intention.elementType)
constructor(intention: JetSelfTargetingRangeIntention<T>): this(listOf(intention), intention.elementType)
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object: PsiElementVisitor() {
@@ -42,7 +41,10 @@ public abstract class IntentionBasedInspection<T: JetElement>(
val targetElement = element as T
for (intention in intentions) {
if (!intention.isApplicableTo(targetElement)) continue
val range = intention.applicabilityRange(targetElement) ?: continue
val elementRange = targetElement.getTextRange()
assert(range in elementRange, "Wrong applicabilityRange() result for $intention - should be within element's range")
val rangeInElement = range.shiftRight(-elementRange.getStartOffset())
val fix = object: LocalQuickFix {
private val text = intention.getText()
@@ -59,7 +61,7 @@ public abstract class IntentionBasedInspection<T: JetElement>(
}
}
holder.registerProblem(targetElement, intention.getText(), problemHighlightType, fix)
holder.registerProblem(targetElement, intention.getText(), problemHighlightType, rangeInElement, fix)
}
}
}
@@ -67,14 +69,14 @@ public abstract class IntentionBasedInspection<T: JetElement>(
protected open val problemHighlightType: ProblemHighlightType
get() = ProblemHighlightType.GENERIC_ERROR_OR_WARNING
}
private fun PsiElement.getOrCreateEditor(): Editor? {
val file = getContainingFile()?.getVirtualFile() ?: return null
val document = FileDocumentManager.getInstance().getDocument(file) ?: return null
val editorFactory = EditorFactory.getInstance()!!
val editors = editorFactory.getEditors(document)
return if (editors.isEmpty()) editorFactory.createEditor(document) else editors[0]
private fun PsiElement.getOrCreateEditor(): Editor? {
val file = getContainingFile()?.getVirtualFile() ?: return null
val document = FileDocumentManager.getInstance().getDocument(file) ?: return null
val editorFactory = EditorFactory.getInstance()
val editors = editorFactory.getEditors(document)
return if (editors.isEmpty()) editorFactory.createEditor(document) else editors[0]
}
}
@@ -19,12 +19,12 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.JetBundle
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypesAndPredicate
import org.jetbrains.kotlin.psi.psiUtil.parents
public abstract class JetSelfTargetingIntention<TElement : JetElement>(
@@ -88,7 +88,7 @@ public abstract class JetSelfTargetingIntention<TElement : JetElement>(
override fun toString(): String = getText()
}
public abstract class JetSelfTargetingOffsetIndependentIntention<TElement : JetElement>(
public abstract class JetSelfTargetingRangeIntention<TElement : JetElement>(
elementType: Class<TElement>,
text: String,
familyName: String = text,
@@ -99,7 +99,28 @@ public abstract class JetSelfTargetingOffsetIndependentIntention<TElement : JetE
public constructor(key: String, elementType: Class<TElement>) : this(elementType, JetBundle.message(key), JetBundle.message(key + ".family")) {
}
public abstract fun applicabilityRange(element: TElement): TextRange?
override final fun isApplicableTo(element: TElement, caretOffset: Int): Boolean {
val range = applicabilityRange(element) ?: return false
return range.containsOffset(caretOffset)
}
}
public abstract class JetSelfTargetingOffsetIndependentIntention<TElement : JetElement>(
elementType: Class<TElement>,
text: String,
familyName: String = text,
firstElementOfTypeOnly: Boolean = false
) : JetSelfTargetingRangeIntention<TElement>(elementType, text, familyName, firstElementOfTypeOnly) {
deprecated("Use primary constructor, no need to use i18n")
public constructor(key: String, elementType: Class<TElement>) : this(elementType, JetBundle.message(key), JetBundle.message(key + ".family")) {
}
public abstract fun isApplicableTo(element: TElement): Boolean
override final fun isApplicableTo(element: TElement, caretOffset: Int): Boolean = isApplicableTo(element)
override final fun applicabilityRange(element: TElement): TextRange? {
return if (isApplicableTo(element)) element.getTextRange() else null
}
}