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,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<T: JetElement>(
public abstract class IntentionBasedInspection<T : JetElement>(
protected val intentions: List<JetSelfTargetingRangeIntention<T>>,
protected val problemText: String?,
protected val elementType: Class<T>
) : 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 {
return object: PsiElementVisitor() {
class IntentionBasedQuickFix(
val intention: JetSelfTargetingRangeIntention<T>,
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)
}
}
}
@@ -21,5 +21,6 @@ import org.jetbrains.kotlin.psi.JetPackageDirective
public class PackageDirectoryMismatchInspection: IntentionBasedInspection<JetPackageDirective>(
listOf(MoveFileToPackageMatchingDirectoryIntention(), ChangePackageToMatchDirectoryIntention()),
"Package directive doesn't match file location",
javaClass()
)
@@ -5,15 +5,6 @@
<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>Move file to 'bar'</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>
<description>Package directive doesn't match file location</description>
</problem>
</problems>