Don't invoke applicabilityRange twice for each highlighting
This commit is contained in:
+29
-23
@@ -26,9 +26,11 @@ import com.intellij.openapi.editor.EditorFactory
|
|||||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.psi.PsiDocumentManager
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiElementVisitor
|
import com.intellij.psi.PsiElementVisitor
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.util.SmartList
|
||||||
import org.jetbrains.kotlin.idea.intentions.JetSelfTargetingRangeIntention
|
import org.jetbrains.kotlin.idea.intentions.JetSelfTargetingRangeIntention
|
||||||
import org.jetbrains.kotlin.psi.JetElement
|
import org.jetbrains.kotlin.psi.JetElement
|
||||||
|
|
||||||
@@ -54,21 +56,30 @@ public abstract class IntentionBasedInspection<TElement : JetElement>(
|
|||||||
@suppress("UNCHECKED_CAST")
|
@suppress("UNCHECKED_CAST")
|
||||||
val targetElement = element as TElement
|
val targetElement = element as TElement
|
||||||
|
|
||||||
val ranges = intentions
|
var problemRange: TextRange? = null
|
||||||
.map {
|
var fixes: SmartList<IntentionBasedQuickFix<*>>? = null
|
||||||
val range = it.intention.applicabilityRange(targetElement)?.let { range ->
|
|
||||||
val elementRange = targetElement.getTextRange()
|
|
||||||
assert(range in elementRange) { "Wrong applicabilityRange() result for $it - should be within element's range" }
|
|
||||||
range.shiftRight(-elementRange.getStartOffset())
|
|
||||||
}
|
|
||||||
if (range != null && it.additionalChecker(targetElement)) range else null
|
|
||||||
}
|
|
||||||
.filterNotNull()
|
|
||||||
if (ranges.isEmpty()) return
|
|
||||||
|
|
||||||
val fixes = intentions.map { IntentionBasedQuickFix(it.intention, it.additionalChecker, targetElement) }.toTypedArray()
|
for ((intention, additionalChecker) in intentions) {
|
||||||
val rangeInElement = ranges.fold(ranges.first()) { result, range -> result.union(range) }
|
synchronized(intention) {
|
||||||
holder.registerProblem(targetElement, problemText ?: fixes.first().getName(), problemHighlightType, rangeInElement, *fixes)
|
val range = intention.applicabilityRange(targetElement)?.let { range ->
|
||||||
|
val elementRange = targetElement.getTextRange()
|
||||||
|
assert(range in elementRange) { "Wrong applicabilityRange() result for $intention - should be within element's range" }
|
||||||
|
range.shiftRight(-elementRange.getStartOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (range != null && additionalChecker(targetElement)) {
|
||||||
|
problemRange = problemRange?.union(range) ?: range
|
||||||
|
if (fixes == null) {
|
||||||
|
fixes = SmartList<IntentionBasedQuickFix<*>>()
|
||||||
|
}
|
||||||
|
fixes!!.add(IntentionBasedQuickFix(intention, intention.text, additionalChecker, targetElement))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (problemRange != null) {
|
||||||
|
holder.registerProblem(targetElement, problemText ?: fixes!!.first().name, problemHighlightType, problemRange, *fixes!!.toTypedArray())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,21 +89,16 @@ public abstract class IntentionBasedInspection<TElement : JetElement>(
|
|||||||
|
|
||||||
/* we implement IntentionAction to provide isAvailable which will be used to hide outdated items and make sure we never call 'invoke' for such item */
|
/* 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 class IntentionBasedQuickFix<TElement : JetElement>(
|
private class IntentionBasedQuickFix<TElement : JetElement>(
|
||||||
val intention: JetSelfTargetingRangeIntention<TElement>,
|
private val intention: JetSelfTargetingRangeIntention<TElement>,
|
||||||
val additionalChecker: (TElement) -> Boolean,
|
private val text: String,
|
||||||
|
private val additionalChecker: (TElement) -> Boolean,
|
||||||
targetElement: TElement
|
targetElement: TElement
|
||||||
) : LocalQuickFixOnPsiElement(targetElement), IntentionAction {
|
) : LocalQuickFixOnPsiElement(targetElement), IntentionAction {
|
||||||
|
|
||||||
// store text into variable because intention instance is shared and may change its text later
|
// store text into variable because intention instance is shared and may change its text later
|
||||||
private val _text = synchronized(intention) {
|
|
||||||
// Ensure that text will be valid for current element in multithreaded environment
|
|
||||||
intention.applicabilityRange(targetElement)
|
|
||||||
intention.getText()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getFamilyName() = intention.getFamilyName()
|
override fun getFamilyName() = intention.getFamilyName()
|
||||||
|
|
||||||
override fun getText(): String = _text
|
override fun getText(): String = text
|
||||||
|
|
||||||
override fun startInWriteAction() = true
|
override fun startInWriteAction() = true
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user