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:
+18
-16
@@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
+24
-3
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports an if expression checking variable being null right after initializing it that can be converted into an elvis operator in the initializer
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports any 'when' expression that can be simplified by introducing subject argument
|
||||
</body>
|
||||
</html>
|
||||
@@ -924,6 +924,13 @@
|
||||
level="WEAK WARNING"
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.IntroduceWhenSubjectInspection"
|
||||
displayName="Introduce argument to 'when'"
|
||||
groupName="Kotlin"
|
||||
enabledByDefault="true"
|
||||
level="WEAK WARNING"
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.UnusedSymbolInspection"
|
||||
displayName="Unused Symbol"
|
||||
groupName="Kotlin"
|
||||
|
||||
+7
-6
@@ -17,16 +17,17 @@
|
||||
package org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import org.jetbrains.kotlin.idea.intentions.JetSelfTargetingOffsetIndependentIntention
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import org.jetbrains.kotlin.idea.intentions.JetSelfTargetingRangeIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.getSubjectToIntroduce
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.introduceSubject
|
||||
import org.jetbrains.kotlin.psi.JetWhenExpression
|
||||
|
||||
public class IntroduceWhenSubjectIntention : JetSelfTargetingOffsetIndependentIntention<JetWhenExpression>(javaClass(), "Introduce argument to 'when'") {
|
||||
override fun isApplicableTo(element: JetWhenExpression): Boolean {
|
||||
val subject = element.getSubjectToIntroduce() ?: return false
|
||||
setText("Introduce '$subject' as argument to 'when'")
|
||||
return true
|
||||
public class IntroduceWhenSubjectIntention : JetSelfTargetingRangeIntention<JetWhenExpression>(javaClass(), "Introduce argument to 'when'") {
|
||||
override fun applicabilityRange(element: JetWhenExpression): TextRange? {
|
||||
val subject = element.getSubjectToIntroduce() ?: return null
|
||||
setText("Introduce '${subject.getText()}' as argument to 'when'")
|
||||
return element.getWhenKeywordElement().getTextRange()
|
||||
}
|
||||
|
||||
override fun applyTo(element: JetWhenExpression, editor: Editor) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
||||
import org.jetbrains.kotlin.idea.intentions.attributeCallReplacements.ReplaceGetIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToElvisIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToSafeAccessIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IntroduceWhenSubjectIntention
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
public class ExplicitGetInspection : IntentionBasedInspection<JetDotQualifiedExpression>(ReplaceGetIntention())
|
||||
@@ -40,3 +41,5 @@ public class SimplifyBinaryNegationInspection : IntentionBasedInspection<JetPref
|
||||
|
||||
public class ReplaceWithOperatorAssignmentInspection : IntentionBasedInspection<JetBinaryExpression>(ReplaceWithOperatorAssignmentIntention())
|
||||
|
||||
public class IntroduceWhenSubjectInspection : IntentionBasedInspection<JetWhenExpression>(IntroduceWhenSubjectIntention())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user