From 14d1d8e1dcec7b6bc05b100253b2ac8389d268f0 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Tue, 19 May 2015 18:38:36 +0300 Subject: [PATCH] Inspections: Create single diagnostic for inspections based on multiple intentions #KT-7784 Fixed --- .../inspections/IntentionBasedInspection.kt | 61 +++++++++++-------- .../PackageDirectoryMismatchInspection.kt | 1 + .../expected.xml | 11 +--- 3 files changed, 39 insertions(+), 34 deletions(-) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/inspections/IntentionBasedInspection.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/inspections/IntentionBasedInspection.kt index e15e3c60241..d94a7e20236 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/inspections/IntentionBasedInspection.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/inspections/IntentionBasedInspection.kt @@ -21,48 +21,61 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.EditorFactory import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.project.Project +import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import com.intellij.psi.PsiElementVisitor import org.jetbrains.kotlin.idea.intentions.JetSelfTargetingRangeIntention import org.jetbrains.kotlin.psi.JetElement -public abstract class IntentionBasedInspection( +public abstract class IntentionBasedInspection( protected val intentions: List>, + protected val problemText: String?, protected val elementType: Class ) : AbstractKotlinInspection() { - constructor(intention: JetSelfTargetingRangeIntention): this(listOf(intention), intention.elementType) + constructor(intention: JetSelfTargetingRangeIntention) : this(listOf(intention), null, intention.elementType) override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { - return object: PsiElementVisitor() { + class IntentionBasedQuickFix( + val intention: JetSelfTargetingRangeIntention, + val targetElement: T + ): LocalQuickFix { + private val text = intention.getText() + + override fun getFamilyName() = getName() + + override fun getName() = text + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + targetElement.getOrCreateEditor()?.let { editor -> + editor.getCaretModel().moveToOffset(targetElement.getTextOffset()) + intention.applyTo(targetElement, editor) + } + } + } + + return object : PsiElementVisitor() { override fun visitElement(element: PsiElement) { if (!elementType.isInstance(element) || element.getTextLength() == 0) return - [suppress("UNCHECKED_CAST")] + @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() - - override fun getFamilyName() = getName() - - override fun getName() = text - - override fun applyFix(project: Project, descriptor: ProblemDescriptor) { - targetElement.getOrCreateEditor()?.let { editor -> - editor.getCaretModel().moveToOffset(targetElement.getTextOffset()) - intention.applyTo(targetElement, editor) + 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 - holder.registerProblem(targetElement, intention.getText(), problemHighlightType, rangeInElement, fix) - } + 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) } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/changePackage/PackageDirectoryMismatchInspection.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/changePackage/PackageDirectoryMismatchInspection.kt index 9567a8cd137..b2bd93faab0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/changePackage/PackageDirectoryMismatchInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/changePackage/PackageDirectoryMismatchInspection.kt @@ -21,5 +21,6 @@ import org.jetbrains.kotlin.psi.JetPackageDirective public class PackageDirectoryMismatchInspection: IntentionBasedInspection( listOf(MoveFileToPackageMatchingDirectoryIntention(), ChangePackageToMatchDirectoryIntention()), + "Package directive doesn't match file location", javaClass() ) \ No newline at end of file diff --git a/idea/testData/multiFileInspections/mismatchedProjectAndDirectory/expected.xml b/idea/testData/multiFileInspections/mismatchedProjectAndDirectory/expected.xml index 0d2e90f1bad..07ba13421c8 100644 --- a/idea/testData/multiFileInspections/mismatchedProjectAndDirectory/expected.xml +++ b/idea/testData/multiFileInspections/mismatchedProjectAndDirectory/expected.xml @@ -5,15 +5,6 @@ testPackageDirectoryMismatch_PackageDirectoryMismatch_0 Package name does not match containing directory - Move file to 'bar' - - - - barPackageMismatched.kt - 1 - testPackageDirectoryMismatch_PackageDirectoryMismatch_0 - - Package name does not match containing directory - Change file's package to 'foo' + Package directive doesn't match file location \ No newline at end of file