New J2K: Add support of diagnostic based inspections on arbitrary PsiElements

This commit is contained in:
Ilya Kirillov
2019-03-12 14:25:34 +03:00
committed by Ilya Kirillov
parent 47e722854c
commit deb4129a16
5 changed files with 54 additions and 52 deletions
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.nj2k
import com.intellij.codeInsight.actions.OptimizeImportsProcessor
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.command.CommandProcessor
@@ -31,13 +30,15 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.conversion.copy.range
import org.jetbrains.kotlin.idea.core.util.EDT
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessing
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.PostProcessor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.nj2k.nullabilityAnalysis.AnalysisContext
import org.jetbrains.kotlin.nj2k.nullabilityAnalysis.NullabilityAnalysisFacade
import org.jetbrains.kotlin.nj2k.nullabilityAnalysis.nullabilityByUndefinedNullabilityComment
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.nj2k.nullabilityAnalysis.AnalysisScope
import org.jetbrains.kotlin.nj2k.nullabilityAnalysis.NullabilityAnalysisFacade
@@ -134,7 +135,7 @@ class NewJ2kPostProcessor(
}
private data class ActionData(val element: KtElement, val action: () -> Unit, val priority: Int, val writeActionNeeded: Boolean)
private data class ActionData(val element: PsiElement, val action: () -> Unit, val priority: Int, val writeActionNeeded: Boolean)
private fun collectAvailableActions(
processings: Collection<NewJ2kPostProcessing>,
@@ -147,24 +148,22 @@ class NewJ2kPostProcessor(
file.accept(object : PsiRecursiveElementVisitor() {
override fun visitElement(element: PsiElement) {
if (element is KtElement) {
val rangeResult = rangeFilter(element, rangeMarker)
if (rangeResult == RangeFilterResult.SKIP) return
val rangeResult = rangeFilter(element, rangeMarker)
if (rangeResult == RangeFilterResult.SKIP) return
super.visitElement(element)
super.visitElement(element)
if (rangeResult == RangeFilterResult.PROCESS) {
processings.forEach { processing ->
val action = processing.createAction(element, diagnostics, settings)
if (action != null) {
availableActions.add(
ActionData(
element, action,
NewJ2KPostProcessingRegistrar.priority(processing),
processing.writeActionNeeded
)
if (rangeResult == RangeFilterResult.PROCESS) {
processings.forEach { processing ->
val action = processing.createAction(element, diagnostics, settings)
if (action != null) {
availableActions.add(
ActionData(
element, action,
NewJ2KPostProcessingRegistrar.priority(processing),
processing.writeActionNeeded
)
}
)
}
}
}
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters2
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.caches.resolve.analyze
@@ -46,6 +47,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.isNullable
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -53,10 +55,10 @@ import org.jetbrains.kotlin.utils.mapToIndex
import java.util.*
interface NewJ2kPostProcessing {
fun createAction(element: KtElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? =
fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? =
createAction(element, diagnostics)
fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? =
fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? =
createAction(element, diagnostics, null)
val writeActionNeeded: Boolean
@@ -91,8 +93,6 @@ object NewJ2KPostProcessingRegistrar {
SingleOneTimeProcessing(VarToVal()),
SingleOneTimeProcessing(ConvertGettersAndSetters()),
SingleOneTimeProcessing(MoveGetterAndSetterAnnotationsToProperty()),
SingleOneTimeProcessing(registerGeneralInspectionBasedProcessing(RedundantModalityModifierInspection())),
SingleOneTimeProcessing(registerGeneralInspectionBasedProcessing(RedundantVisibilityModifierInspection())),
SingleOneTimeProcessing(registerGeneralInspectionBasedProcessing(RedundantGetterInspection())),
SingleOneTimeProcessing(registerGeneralInspectionBasedProcessing(RedundantSetterInspection())),
SingleOneTimeProcessing(ConvertDataClass()),
@@ -105,7 +105,7 @@ object NewJ2KPostProcessingRegistrar {
object : NewJ2kPostProcessing {
override val writeActionNeeded: Boolean = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtClass) return null
fun check(klass: KtClass): Boolean {
@@ -143,7 +143,7 @@ object NewJ2KPostProcessingRegistrar {
override val writeActionNeeded: Boolean = true
private val processing = registerGeneralInspectionBasedProcessing(RedundantExplicitTypeInspection())
override fun createAction(element: KtElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
if (settings?.specifyLocalVariableTypeByDefault == true) return null
return processing.createAction(element, diagnostics)
@@ -169,6 +169,7 @@ object NewJ2KPostProcessingRegistrar {
) as KtReturnExpression).returnedExpression.isTrivialStatementBody()
},
registerInspectionBasedProcessing(IfThenToSafeAccessInspection()),
registerInspectionBasedProcessing(IfThenToSafeAccessInspection()),
registerIntentionBasedProcessing(IfThenToElvisIntention()),
@@ -283,14 +284,14 @@ object NewJ2KPostProcessingRegistrar {
}
private inline fun <reified TElement : KtElement, TIntention : SelfTargetingRangeIntention<TElement>> registerIntentionBasedProcessing(
private inline fun <reified TElement : PsiElement, TIntention : SelfTargetingRangeIntention<TElement>> registerIntentionBasedProcessing(
intention: TIntention,
noinline additionalChecker: (TElement) -> Boolean = { true }
) = object : NewJ2kPostProcessing {
// Intention can either need or not need write action
override val writeActionNeeded = intention.startInWriteAction()
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (!TElement::class.java.isInstance(element)) return null
val tElement = element as TElement
if (intention.applicabilityRange(tElement) == null) return null
@@ -351,7 +352,7 @@ object NewJ2KPostProcessingRegistrar {
}
}
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
val holder = ProblemsHolder(InspectionManager.getInstance(element.project), element.containingFile, false)
val visitor = inspection.buildVisitor(
holder,
@@ -374,7 +375,7 @@ object NewJ2KPostProcessingRegistrar {
private inline fun
<reified TElement : KtElement,
<reified TElement : PsiElement,
TInspection : AbstractApplicabilityBasedInspection<TElement>> registerInspectionBasedProcessing(
inspection: TInspection,
@@ -388,7 +389,7 @@ object NewJ2KPostProcessingRegistrar {
return acceptInformationLevel || inspection.inspectionHighlightType(element) != ProblemHighlightType.INFORMATION
}
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (!TElement::class.java.isInstance(element)) return null
val tElement = element as TElement
if (!isApplicable(tElement)) return null
@@ -401,13 +402,13 @@ object NewJ2KPostProcessingRegistrar {
}
private inline fun <reified TElement : KtElement> registerDiagnosticBasedProcessing(
private inline fun <reified TElement : PsiElement> registerDiagnosticBasedProcessing(
vararg diagnosticFactory: DiagnosticFactory<*>,
crossinline fix: (TElement, Diagnostic) -> Unit
) = object : NewJ2kPostProcessing {
override val writeActionNeeded = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (!TElement::class.java.isInstance(element)) return null
val diagnostic = diagnostics.forElement(element).firstOrNull { it.factory in diagnosticFactory } ?: return null
return {
@@ -416,13 +417,13 @@ object NewJ2KPostProcessingRegistrar {
}
}
private inline fun <reified TElement : KtElement> registerDiagnosticBasedProcessingFactory(
private inline fun <reified TElement : PsiElement> registerDiagnosticBasedProcessingFactory(
vararg diagnosticFactory: DiagnosticFactory<*>,
crossinline fixFactory: (TElement, Diagnostic) -> (() -> Unit)?
) = object : NewJ2kPostProcessing {
override val writeActionNeeded = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (!TElement::class.java.isInstance(element)) return null
val diagnostic = diagnostics.forElement(element).firstOrNull { it.factory in diagnosticFactory } ?: return null
return fixFactory(element as TElement, diagnostic)
@@ -433,7 +434,7 @@ object NewJ2KPostProcessingRegistrar {
private class RemoveExplicitPropertyType : NewJ2kPostProcessing {
override val writeActionNeeded = true
override fun createAction(element: KtElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
if (element !is KtProperty) return null
val needFieldTypes = settings?.specifyFieldTypeByDefault == true
val needLocalVariablesTypes = settings?.specifyLocalVariableTypeByDefault == true
@@ -467,7 +468,7 @@ object NewJ2KPostProcessingRegistrar {
private class RemoveRedundantNullability : NewJ2kPostProcessing {
override val writeActionNeeded: Boolean = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtProperty) return null
fun check(element: KtProperty): Boolean {
@@ -505,7 +506,7 @@ object NewJ2KPostProcessingRegistrar {
private class RemoveExplicitTypeArgumentsProcessing : NewJ2kPostProcessing {
override val writeActionNeeded = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtTypeArgumentList || !RemoveExplicitTypeArgumentsIntention.isApplicableTo(
element,
approximateFlexible = true
@@ -523,7 +524,7 @@ object NewJ2KPostProcessingRegistrar {
private class RemoveRedundantOverrideVisibilityProcessing : NewJ2kPostProcessing {
override val writeActionNeeded = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtCallableDeclaration || !element.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return null
val modifier = element.visibilityModifierType() ?: return null
return { element.setVisibility(modifier) }
@@ -535,7 +536,7 @@ object NewJ2KPostProcessingRegistrar {
private val intention = ConvertToStringTemplateIntention()
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element is KtBinaryExpression && intention.isApplicableTo(element) && ConvertToStringTemplateIntention.shouldSuggestToConvert(
element
)
@@ -552,7 +553,7 @@ object NewJ2KPostProcessingRegistrar {
private val intention = UsePropertyAccessSyntaxIntention()
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtCallExpression) return null
val propertyName = intention.detectPropertyNameToUse(element) ?: return null
return { intention.applyTo(element, propertyName, reformat = true) }
@@ -562,7 +563,7 @@ object NewJ2KPostProcessingRegistrar {
private class RemoveRedundantSamAdaptersProcessing : NewJ2kPostProcessing {
override val writeActionNeeded = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtCallExpression) return null
val expressions = RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element)
@@ -578,7 +579,7 @@ object NewJ2KPostProcessingRegistrar {
private class UseExpressionBodyProcessing : NewJ2kPostProcessing {
override val writeActionNeeded = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtPropertyAccessor) return null
val inspection = UseExpressionBodyInspection(convertEmptyToUnit = false)
@@ -595,7 +596,7 @@ object NewJ2KPostProcessingRegistrar {
private class RemoveRedundantCastToNullableProcessing : NewJ2kPostProcessing {
override val writeActionNeeded = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtBinaryExpressionWithTypeRHS) return null
val context = element.analyze()
@@ -616,7 +617,7 @@ object NewJ2KPostProcessingRegistrar {
private class FixObjectStringConcatenationProcessing : NewJ2kPostProcessing {
override val writeActionNeeded = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtBinaryExpression ||
element.operationToken != KtTokens.PLUS ||
diagnostics.forElement(element.operationReference).none {
@@ -646,7 +647,7 @@ object NewJ2KPostProcessingRegistrar {
private class UninitializedVariableReferenceFromInitializerToThisReferenceProcessing : NewJ2kPostProcessing {
override val writeActionNeeded = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtSimpleNameExpression || diagnostics.forElement(element).none { it.factory == Errors.UNINITIALIZED_VARIABLE }) return null
val resolved = element.mainReference.resolve() ?: return null
@@ -666,7 +667,7 @@ object NewJ2KPostProcessingRegistrar {
private class UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing : NewJ2kPostProcessing {
override val writeActionNeeded = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtSimpleNameExpression || diagnostics.forElement(element).none { it.factory == Errors.UNRESOLVED_REFERENCE }) return null
val anonymousObject = element.getParentOfType<KtClassOrObject>(true) ?: return null
@@ -694,7 +695,7 @@ object NewJ2KPostProcessingRegistrar {
} == true
}
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtProperty) return null
fun check(element: KtProperty): Boolean {
@@ -726,7 +727,7 @@ object NewJ2KPostProcessingRegistrar {
return topLevelClass == qualifier
}
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtQualifiedExpression) return null
if (!check(element)) return null
return {
@@ -748,7 +749,7 @@ object NewJ2KPostProcessingRegistrar {
return topLevelClass.isAncestor(qualifierClass)
}
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtUserType) return null
if (!check(element)) return null
return {
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.nj2k.postProcessing
import com.intellij.psi.PsiElement
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
@@ -63,7 +64,7 @@ class ConvertDataClass : NewJ2kPostProcessing {
DataClassInfo(constructorParameter, property, statement)
}.toList()
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtClass) return null
return {
val factory = KtPsiFactory(element)
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.nj2k.postProcessing
import com.intellij.psi.PsiElement
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.psi.util.parentOfType
@@ -363,7 +364,7 @@ class ConvertGettersAndSetters : NewJ2kPostProcessing {
this.add(setter) as KtPropertyAccessor
}
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtClassOrObject) return null
return {
val factory = KtPsiFactory(element)
@@ -5,17 +5,17 @@
package org.jetbrains.kotlin.nj2k.postProcessing
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.idea.intentions.addUseSiteTarget
import org.jetbrains.kotlin.nj2k.NewJ2kPostProcessing
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
class MoveGetterAndSetterAnnotationsToProperty : NewJ2kPostProcessing {
override val writeActionNeeded: Boolean = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
override fun createAction(element: PsiElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element !is KtProperty) return null
if (element.accessors.isEmpty()) return null
return {