Inspections: Create single diagnostic for inspections based on multiple intentions

#KT-7784 Fixed
This commit is contained in:
Alexey Sedunov
2015-05-19 18:38:36 +03:00
parent 5166cdbc96
commit 14d1d8e1dc
3 changed files with 39 additions and 34 deletions
@@ -21,32 +21,24 @@ import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorFactory 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.openapi.util.TextRange
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
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
public abstract class IntentionBasedInspection<T: JetElement>( public abstract class IntentionBasedInspection<T : JetElement>(
protected val intentions: List<JetSelfTargetingRangeIntention<T>>, protected val intentions: List<JetSelfTargetingRangeIntention<T>>,
protected val problemText: String?,
protected val elementType: Class<T> protected val elementType: Class<T>
) : AbstractKotlinInspection() { ) : AbstractKotlinInspection() {
constructor(intention: JetSelfTargetingRangeIntention<T>): this(listOf(intention), intention.elementType) constructor(intention: JetSelfTargetingRangeIntention<T>) : this(listOf(intention), null, intention.elementType)
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object: PsiElementVisitor() { class IntentionBasedQuickFix(
override fun visitElement(element: PsiElement) { val intention: JetSelfTargetingRangeIntention<T>,
if (!elementType.isInstance(element) || element.getTextLength() == 0) return val targetElement: T
): LocalQuickFix {
[suppress("UNCHECKED_CAST")]
val targetElement = element as T
for (intention in intentions) {
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() private val text = intention.getText()
override fun getFamilyName() = getName() override fun getFamilyName() = getName()
@@ -61,8 +53,29 @@ public abstract class IntentionBasedInspection<T: JetElement>(
} }
} }
holder.registerProblem(targetElement, intention.getText(), problemHighlightType, rangeInElement, fix) return object : PsiElementVisitor() {
override fun visitElement(element: PsiElement) {
if (!elementType.isInstance(element) || element.getTextLength() == 0) return
@suppress("UNCHECKED_CAST")
val targetElement = element as T
val ranges = intentions
.map {
val range = it.applicabilityRange(targetElement)
if (range != null) {
val elementRange = targetElement.getTextRange()
assert(range in elementRange, "Wrong applicabilityRange() result for $it - should be within element's range")
range.shiftRight(-elementRange.getStartOffset())
} }
else null
}
.filterNotNull()
if (ranges.isEmpty()) return
val fixes = intentions.map { IntentionBasedQuickFix(it, targetElement) }.toTypedArray()
val rangeInElement = ranges.fold(TextRange.EMPTY_RANGE) { a, b -> a union b }
holder.registerProblem(targetElement, problemText ?: fixes.first().getName(), problemHighlightType, rangeInElement, *fixes)
} }
} }
} }
@@ -21,5 +21,6 @@ import org.jetbrains.kotlin.psi.JetPackageDirective
public class PackageDirectoryMismatchInspection: IntentionBasedInspection<JetPackageDirective>( public class PackageDirectoryMismatchInspection: IntentionBasedInspection<JetPackageDirective>(
listOf(MoveFileToPackageMatchingDirectoryIntention(), ChangePackageToMatchDirectoryIntention()), listOf(MoveFileToPackageMatchingDirectoryIntention(), ChangePackageToMatchDirectoryIntention()),
"Package directive doesn't match file location",
javaClass() javaClass()
) )
@@ -5,15 +5,6 @@
<module>testPackageDirectoryMismatch_PackageDirectoryMismatch_0</module> <module>testPackageDirectoryMismatch_PackageDirectoryMismatch_0</module>
<entry_point TYPE="file" FQNAME="barPackageMismatched.kt" /> <entry_point TYPE="file" FQNAME="barPackageMismatched.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Package name does not match containing directory</problem_class> <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Package name does not match containing directory</problem_class>
<description>Move file to 'bar'</description> <description>Package directive doesn't match file location</description>
</problem>
<problem>
<file>barPackageMismatched.kt</file>
<line>1</line>
<module>testPackageDirectoryMismatch_PackageDirectoryMismatch_0</module>
<entry_point TYPE="file" FQNAME="barPackageMismatched.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Package name does not match containing directory</problem_class>
<description>Change file's package to 'foo'</description>
</problem> </problem>
</problems> </problems>