New J2K: Add support of grouped postProcessings & introduce VarToVal inspection
This commit is contained in:
committed by
Ilya Kirillov
parent
c7df104b36
commit
49a8a8f116
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
|||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.types.isNullable
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||||
import org.jetbrains.kotlin.utils.mapToIndex
|
import org.jetbrains.kotlin.utils.mapToIndex
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -67,15 +68,20 @@ interface J2kPostProcessing {
|
|||||||
val writeActionNeeded: Boolean
|
val writeActionNeeded: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
object J2KPostProcessingRegistrar {
|
interface J2KPostProcessingRegistrar {
|
||||||
|
val processings: Collection<J2kPostProcessing>
|
||||||
|
fun priority(processing: J2kPostProcessing): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
object J2KPostProcessingRegistrarImpl : J2KPostProcessingRegistrar {
|
||||||
private val _processings = ArrayList<J2kPostProcessing>()
|
private val _processings = ArrayList<J2kPostProcessing>()
|
||||||
|
|
||||||
val processings: Collection<J2kPostProcessing>
|
override val processings: Collection<J2kPostProcessing>
|
||||||
get() = _processings
|
get() = _processings
|
||||||
|
|
||||||
private val processingsToPriorityMap = HashMap<J2kPostProcessing, Int>()
|
private val processingsToPriorityMap = HashMap<J2kPostProcessing, Int>()
|
||||||
|
|
||||||
fun priority(processing: J2kPostProcessing): Int = processingsToPriorityMap[processing]!!
|
override fun priority(processing: J2kPostProcessing): Int = processingsToPriorityMap[processing]!!
|
||||||
|
|
||||||
init {
|
init {
|
||||||
_processings.add(RemoveExplicitTypeArgumentsProcessing())
|
_processings.add(RemoveExplicitTypeArgumentsProcessing())
|
||||||
@@ -91,18 +97,8 @@ object J2KPostProcessingRegistrar {
|
|||||||
registerInspectionBasedProcessing(ReplacePutWithAssignmentInspection())
|
registerInspectionBasedProcessing(ReplacePutWithAssignmentInspection())
|
||||||
_processings.add(UseExpressionBodyProcessing())
|
_processings.add(UseExpressionBodyProcessing())
|
||||||
registerInspectionBasedProcessing(UnnecessaryVariableInspection())
|
registerInspectionBasedProcessing(UnnecessaryVariableInspection())
|
||||||
registerGeneralInspectionBasedProcessing(RedundantModalityModifierInspection())
|
|
||||||
registerGeneralInspectionBasedProcessing(RedundantVisibilityModifierInspection())
|
|
||||||
registerGeneralInspectionBasedProcessing(RedundantExplicitTypeInspection())
|
|
||||||
registerGeneralInspectionBasedProcessing(RedundantUnitReturnTypeInspection())
|
|
||||||
registerGeneralInspectionBasedProcessing(RedundantGetterInspection())
|
|
||||||
registerGeneralInspectionBasedProcessing(RedundantSetterInspection())
|
|
||||||
|
|
||||||
_processings.add(RemoveExplicitPropertyType())
|
|
||||||
registerGeneralInspectionBasedProcessing(CanBeValInspection(ignoreNotUsedVals = false))
|
|
||||||
|
|
||||||
registerIntentionBasedProcessing(FoldInitializerAndIfToElvisIntention())
|
registerIntentionBasedProcessing(FoldInitializerAndIfToElvisIntention())
|
||||||
registerIntentionBasedProcessing(RemoveEmptyClassBodyIntention())
|
|
||||||
|
|
||||||
registerIntentionBasedProcessing(FoldIfToReturnIntention()) { it.then.isTrivialStatementBody() && it.`else`.isTrivialStatementBody() }
|
registerIntentionBasedProcessing(FoldIfToReturnIntention()) { it.then.isTrivialStatementBody() && it.`else`.isTrivialStatementBody() }
|
||||||
registerIntentionBasedProcessing(FoldIfToReturnAsymmetricallyIntention()) { it.then.isTrivialStatementBody() && (KtPsiUtil.skipTrailingWhitespacesAndComments(it) as KtReturnExpression).returnedExpression.isTrivialStatementBody() }
|
registerIntentionBasedProcessing(FoldIfToReturnAsymmetricallyIntention()) { it.then.isTrivialStatementBody() && (KtPsiUtil.skipTrailingWhitespacesAndComments(it) as KtReturnExpression).returnedExpression.isTrivialStatementBody() }
|
||||||
@@ -120,15 +116,6 @@ object J2KPostProcessingRegistrar {
|
|||||||
registerIntentionBasedProcessing(RemoveRedundantCallsOfConversionMethodsIntention())
|
registerIntentionBasedProcessing(RemoveRedundantCallsOfConversionMethodsIntention())
|
||||||
registerInspectionBasedProcessing(JavaMapForEachInspection())
|
registerInspectionBasedProcessing(JavaMapForEachInspection())
|
||||||
|
|
||||||
_processings.add(object : J2kPostProcessing {
|
|
||||||
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? =
|
|
||||||
{
|
|
||||||
OptimizeImportsProcessor(element.project, element.containingKtFile).run()
|
|
||||||
PsiDocumentManager.getInstance(element.project).commitAllDocuments()
|
|
||||||
}
|
|
||||||
|
|
||||||
override val writeActionNeeded: Boolean = true
|
|
||||||
})
|
|
||||||
|
|
||||||
registerDiagnosticBasedProcessing<KtBinaryExpressionWithTypeRHS>(Errors.USELESS_CAST) { element, _ ->
|
registerDiagnosticBasedProcessing<KtBinaryExpressionWithTypeRHS>(Errors.USELESS_CAST) { element, _ ->
|
||||||
val expression = RemoveUselessCastFix.invoke(element)
|
val expression = RemoveUselessCastFix.invoke(element)
|
||||||
@@ -148,25 +135,10 @@ object J2KPostProcessingRegistrar {
|
|||||||
fix.invoke()
|
fix.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
registerDiagnosticBasedProcessing<KtModifierListOwner>(Errors.NON_FINAL_MEMBER_IN_FINAL_CLASS) { _, diagnostic ->
|
|
||||||
val fix =
|
|
||||||
RemoveModifierFix
|
|
||||||
.createRemoveModifierFromListOwnerFactory(KtTokens.OPEN_KEYWORD)
|
|
||||||
.createActions(diagnostic).single() as RemoveModifierFix
|
|
||||||
fix.invoke()
|
|
||||||
}
|
|
||||||
registerDiagnosticBasedProcessing<KtModifierListOwner>(Errors.NON_FINAL_MEMBER_IN_OBJECT) { _, diagnostic ->
|
|
||||||
val fix =
|
|
||||||
RemoveModifierFix
|
|
||||||
.createRemoveModifierFromListOwnerFactory(KtTokens.OPEN_KEYWORD)
|
|
||||||
.createActions(diagnostic).single() as RemoveModifierFix
|
|
||||||
fix.invoke()
|
|
||||||
}
|
|
||||||
|
|
||||||
registerDiagnosticBasedProcessingFactory(
|
registerDiagnosticBasedProcessingFactory(
|
||||||
Errors.VAL_REASSIGNMENT, Errors.CAPTURED_VAL_INITIALIZATION, Errors.CAPTURED_MEMBER_VAL_INITIALIZATION
|
Errors.VAL_REASSIGNMENT, Errors.CAPTURED_VAL_INITIALIZATION, Errors.CAPTURED_MEMBER_VAL_INITIALIZATION
|
||||||
) {
|
) {
|
||||||
element: KtSimpleNameExpression, _: Diagnostic ->
|
element: KtSimpleNameExpression, _: Diagnostic ->
|
||||||
val property = element.mainReference.resolve() as? KtProperty
|
val property = element.mainReference.resolve() as? KtProperty
|
||||||
if (property == null) {
|
if (property == null) {
|
||||||
null
|
null
|
||||||
@@ -193,8 +165,8 @@ object J2KPostProcessingRegistrar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified TElement : KtElement, TIntention: SelfTargetingRangeIntention<TElement>> registerIntentionBasedProcessing(
|
private inline fun <reified TElement : KtElement, TIntention: SelfTargetingRangeIntention<TElement>> registerIntentionBasedProcessing(
|
||||||
intention: TIntention,
|
intention: TIntention,
|
||||||
noinline additionalChecker: (TElement) -> Boolean = { true }
|
noinline additionalChecker: (TElement) -> Boolean = { true }
|
||||||
) {
|
) {
|
||||||
_processings.add(object : J2kPostProcessing {
|
_processings.add(object : J2kPostProcessing {
|
||||||
// Intention can either need or not need write action
|
// Intention can either need or not need write action
|
||||||
@@ -286,10 +258,10 @@ object J2KPostProcessingRegistrar {
|
|||||||
|
|
||||||
private inline fun
|
private inline fun
|
||||||
<reified TElement : KtElement,
|
<reified TElement : KtElement,
|
||||||
TInspection: AbstractApplicabilityBasedInspection<TElement>> registerInspectionBasedProcessing(
|
TInspection: AbstractApplicabilityBasedInspection<TElement>> registerInspectionBasedProcessing(
|
||||||
|
|
||||||
inspection: TInspection,
|
inspection: TInspection,
|
||||||
acceptInformationLevel: Boolean = false
|
acceptInformationLevel: Boolean = false
|
||||||
) {
|
) {
|
||||||
_processings.add(object : J2kPostProcessing {
|
_processings.add(object : J2kPostProcessing {
|
||||||
// Inspection can either need or not need write action
|
// Inspection can either need or not need write action
|
||||||
@@ -314,15 +286,15 @@ object J2KPostProcessingRegistrar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified TElement : KtElement> registerDiagnosticBasedProcessing(
|
private inline fun <reified TElement : KtElement> registerDiagnosticBasedProcessing(
|
||||||
vararg diagnosticFactory: DiagnosticFactory<*>,
|
vararg diagnosticFactory: DiagnosticFactory<*>,
|
||||||
crossinline fix: (TElement, Diagnostic) -> Unit
|
crossinline fix: (TElement, Diagnostic) -> Unit
|
||||||
) {
|
) {
|
||||||
registerDiagnosticBasedProcessingFactory(*diagnosticFactory) { element: TElement, diagnostic: Diagnostic -> { fix(element, diagnostic) } }
|
registerDiagnosticBasedProcessingFactory(*diagnosticFactory) { element: TElement, diagnostic: Diagnostic -> { fix(element, diagnostic) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified TElement : KtElement> registerDiagnosticBasedProcessingFactory(
|
private inline fun <reified TElement : KtElement> registerDiagnosticBasedProcessingFactory(
|
||||||
vararg diagnosticFactory: DiagnosticFactory<*>,
|
vararg diagnosticFactory: DiagnosticFactory<*>,
|
||||||
crossinline fixFactory: (TElement, Diagnostic) -> (() -> Unit)?
|
crossinline fixFactory: (TElement, Diagnostic) -> (() -> Unit)?
|
||||||
) {
|
) {
|
||||||
_processings.add(object : J2kPostProcessing {
|
_processings.add(object : J2kPostProcessing {
|
||||||
// ???
|
// ???
|
||||||
@@ -336,35 +308,6 @@ object J2KPostProcessingRegistrar {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RemoveExplicitPropertyType : J2kPostProcessing {
|
|
||||||
override val writeActionNeeded = true
|
|
||||||
|
|
||||||
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
|
||||||
if (element !is KtProperty) return null
|
|
||||||
|
|
||||||
fun check(element: KtProperty): Boolean {
|
|
||||||
val initializer = element.initializer ?: return false
|
|
||||||
val withoutExpectedType = initializer.analyzeInContext(initializer.getResolutionScope())
|
|
||||||
val descriptor = element.resolveToDescriptorIfAny() as? CallableDescriptor ?: return false
|
|
||||||
return when (withoutExpectedType.getType(initializer)) {
|
|
||||||
descriptor.returnType,
|
|
||||||
descriptor.returnType?.makeNotNullable() -> true
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!check(element)) {
|
|
||||||
return null
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
if (element.isValid && check(element)) {
|
|
||||||
element.typeReference = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class RemoveExplicitTypeArgumentsProcessing : J2kPostProcessing {
|
private class RemoveExplicitTypeArgumentsProcessing : J2kPostProcessing {
|
||||||
override val writeActionNeeded = true
|
override val writeActionNeeded = true
|
||||||
|
|
||||||
@@ -427,7 +370,7 @@ object J2KPostProcessingRegistrar {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element)
|
RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element)
|
||||||
.forEach { RedundantSamConstructorInspection.replaceSamConstructorCall(it) }
|
.forEach { RedundantSamConstructorInspection.replaceSamConstructorCall(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -478,7 +421,7 @@ object J2KPostProcessingRegistrar {
|
|||||||
element.operationToken != KtTokens.PLUS ||
|
element.operationToken != KtTokens.PLUS ||
|
||||||
diagnostics.forElement(element.operationReference).none {
|
diagnostics.forElement(element.operationReference).none {
|
||||||
it.factory == Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER
|
it.factory == Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER
|
||||||
|| it.factory == Errors.NONE_APPLICABLE
|
|| it.factory == Errors.NONE_APPLICABLE
|
||||||
})
|
})
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
|||||||
@@ -18,16 +18,15 @@ package org.jetbrains.kotlin.idea.j2k
|
|||||||
|
|
||||||
import com.intellij.codeInsight.actions.OptimizeImportsProcessor
|
import com.intellij.codeInsight.actions.OptimizeImportsProcessor
|
||||||
import com.intellij.codeInspection.*
|
import com.intellij.codeInspection.*
|
||||||
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.psi.PsiDocumentManager
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.search.LocalSearchScope
|
import com.intellij.psi.search.LocalSearchScope
|
||||||
import com.intellij.psi.search.searches.ReferencesSearch
|
import com.intellij.psi.search.searches.ReferencesSearch
|
||||||
|
import com.intellij.psi.util.parentOfType
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
@@ -44,11 +43,14 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.F
|
|||||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FoldIfToReturnIntention
|
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FoldIfToReturnIntention
|
||||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToElvisIntention
|
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToElvisIntention
|
||||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isTrivialStatementBody
|
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isTrivialStatementBody
|
||||||
import org.jetbrains.kotlin.idea.quickfix.ChangeVariableMutabilityFix
|
import org.jetbrains.kotlin.idea.j2k.postProcessing.ConvertDataClass
|
||||||
|
import org.jetbrains.kotlin.idea.j2k.postProcessing.ConvertGettersAndSetters
|
||||||
import org.jetbrains.kotlin.idea.quickfix.QuickFixActionBase
|
import org.jetbrains.kotlin.idea.quickfix.QuickFixActionBase
|
||||||
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
|
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
|
||||||
import org.jetbrains.kotlin.idea.quickfix.RemoveUselessCastFix
|
import org.jetbrains.kotlin.idea.quickfix.RemoveUselessCastFix
|
||||||
|
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
|
import org.jetbrains.kotlin.idea.references.readWriteAccess
|
||||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -62,276 +64,304 @@ import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
|||||||
import org.jetbrains.kotlin.utils.mapToIndex
|
import org.jetbrains.kotlin.utils.mapToIndex
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
object NewJ2KPostProcessingRegistrarImpl: J2KPostProcessingRegistrar {
|
object NewJ2KPostProcessingRegistrarImpl : J2KPostProcessingRegistrar {
|
||||||
private val _processings = ArrayList<J2kPostProcessing>()
|
|
||||||
|
private fun Processing.processings(): Sequence<J2kPostProcessing> =
|
||||||
|
when (this) {
|
||||||
|
is SingleProcessing -> sequenceOf(processing)
|
||||||
|
is ProcessingGroup -> processings.asSequence().flatMap { it.processings() }
|
||||||
|
else -> sequenceOf()
|
||||||
|
}
|
||||||
|
|
||||||
override val processings: Collection<J2kPostProcessing>
|
|
||||||
get() = _processings
|
|
||||||
|
|
||||||
private val processingsToPriorityMap = HashMap<J2kPostProcessing, Int>()
|
private val processingsToPriorityMap = HashMap<J2kPostProcessing, Int>()
|
||||||
|
|
||||||
override fun priority(processing: J2kPostProcessing): Int = processingsToPriorityMap[processing]!!
|
override fun priority(processing: J2kPostProcessing): Int = processingsToPriorityMap[processing]!!
|
||||||
|
|
||||||
init {
|
override val mainProcessings = ProcessingGroup(
|
||||||
_processings.add(RemoveExplicitTypeArgumentsProcessing())
|
SingleProcessing(VarToVal()),
|
||||||
_processings.add(RemoveRedundantOverrideVisibilityProcessing())
|
ProcessingGroup(
|
||||||
registerInspectionBasedProcessing(MoveLambdaOutsideParenthesesInspection())
|
SingleProcessing(ConvertGettersAndSetters()),
|
||||||
_processings.add(FixObjectStringConcatenationProcessing())
|
registerGeneralInspectionBasedProcessing(RedundantModalityModifierInspection()),
|
||||||
_processings.add(ConvertToStringTemplateProcessing())
|
registerGeneralInspectionBasedProcessing(RedundantVisibilityModifierInspection()),
|
||||||
_processings.add(UsePropertyAccessSyntaxProcessing())
|
registerGeneralInspectionBasedProcessing(RedundantGetterInspection()),
|
||||||
_processings.add(UninitializedVariableReferenceFromInitializerToThisReferenceProcessing())
|
registerGeneralInspectionBasedProcessing(RedundantSetterInspection())
|
||||||
_processings.add(UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing())
|
),
|
||||||
_processings.add(RemoveRedundantSamAdaptersProcessing())
|
SingleProcessing(ConvertDataClass()),
|
||||||
_processings.add(RemoveRedundantCastToNullableProcessing())
|
ProcessingGroup(
|
||||||
registerInspectionBasedProcessing(ReplacePutWithAssignmentInspection())
|
registerGeneralInspectionBasedProcessing(ExplicitThisInspection()),
|
||||||
_processings.add(UseExpressionBodyProcessing())
|
|
||||||
registerInspectionBasedProcessing(UnnecessaryVariableInspection())
|
|
||||||
registerGeneralInspectionBasedProcessing(RedundantModalityModifierInspection())
|
|
||||||
registerGeneralInspectionBasedProcessing(RedundantVisibilityModifierInspection())
|
|
||||||
registerGeneralInspectionBasedProcessing(RedundantExplicitTypeInspection())
|
|
||||||
registerGeneralInspectionBasedProcessing(RedundantUnitReturnTypeInspection())
|
|
||||||
registerGeneralInspectionBasedProcessing(RedundantGetterInspection())
|
|
||||||
registerGeneralInspectionBasedProcessing(RedundantSetterInspection())
|
|
||||||
|
|
||||||
_processings.add(RemoveExplicitPropertyType())
|
SingleProcessing(RemoveExplicitTypeArgumentsProcessing()),
|
||||||
_processings.add(RemoveRedundantNullability())
|
SingleProcessing(RemoveRedundantOverrideVisibilityProcessing()),
|
||||||
|
registerInspectionBasedProcessing(MoveLambdaOutsideParenthesesInspection()),
|
||||||
|
SingleProcessing(FixObjectStringConcatenationProcessing()),
|
||||||
|
SingleProcessing(ConvertToStringTemplateProcessing()),
|
||||||
|
SingleProcessing(UsePropertyAccessSyntaxProcessing()),
|
||||||
|
SingleProcessing(UninitializedVariableReferenceFromInitializerToThisReferenceProcessing()),
|
||||||
|
SingleProcessing(UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing()),
|
||||||
|
SingleProcessing(RemoveRedundantSamAdaptersProcessing()),
|
||||||
|
SingleProcessing(RemoveRedundantCastToNullableProcessing()),
|
||||||
|
registerInspectionBasedProcessing(ReplacePutWithAssignmentInspection()),
|
||||||
|
SingleProcessing(UseExpressionBodyProcessing()),
|
||||||
|
registerInspectionBasedProcessing(UnnecessaryVariableInspection()),
|
||||||
|
registerGeneralInspectionBasedProcessing(RedundantExplicitTypeInspection()),
|
||||||
|
registerGeneralInspectionBasedProcessing(RedundantUnitReturnTypeInspection()),
|
||||||
|
|
||||||
registerGeneralInspectionBasedProcessing(CanBeValInspection(ignoreNotUsedVals = false))
|
SingleProcessing(RemoveExplicitPropertyType()),
|
||||||
|
SingleProcessing(RemoveRedundantNullability()),
|
||||||
|
|
||||||
registerIntentionBasedProcessing(FoldInitializerAndIfToElvisIntention())
|
registerGeneralInspectionBasedProcessing(CanBeValInspection(ignoreNotUsedVals = false)),
|
||||||
registerIntentionBasedProcessing(RemoveEmptyClassBodyIntention())
|
|
||||||
|
|
||||||
registerIntentionBasedProcessing(FoldIfToReturnIntention()) { it.then.isTrivialStatementBody() && it.`else`.isTrivialStatementBody() }
|
registerIntentionBasedProcessing(FoldInitializerAndIfToElvisIntention()),
|
||||||
registerIntentionBasedProcessing(FoldIfToReturnAsymmetricallyIntention()) { it.then.isTrivialStatementBody() && (KtPsiUtil.skipTrailingWhitespacesAndComments(it) as KtReturnExpression).returnedExpression.isTrivialStatementBody() }
|
registerGeneralInspectionBasedProcessing(RedundantSemicolonInspection()),
|
||||||
|
registerIntentionBasedProcessing(RemoveEmptyClassBodyIntention()),
|
||||||
|
|
||||||
registerInspectionBasedProcessing(IfThenToSafeAccessInspection())
|
registerIntentionBasedProcessing(FoldIfToReturnIntention()) { it.then.isTrivialStatementBody() && it.`else`.isTrivialStatementBody() },
|
||||||
registerIntentionBasedProcessing(IfThenToElvisIntention())
|
registerIntentionBasedProcessing(FoldIfToReturnAsymmetricallyIntention()) {
|
||||||
registerInspectionBasedProcessing(SimplifyNegatedBinaryExpressionInspection())
|
it.then.isTrivialStatementBody() && (KtPsiUtil.skipTrailingWhitespacesAndComments(
|
||||||
registerInspectionBasedProcessing(ReplaceGetOrSetInspection())
|
it
|
||||||
registerIntentionBasedProcessing(AddOperatorModifierIntention())
|
) as KtReturnExpression).returnedExpression.isTrivialStatementBody()
|
||||||
registerIntentionBasedProcessing(ObjectLiteralToLambdaIntention())
|
},
|
||||||
registerIntentionBasedProcessing(AnonymousFunctionToLambdaIntention())
|
|
||||||
registerIntentionBasedProcessing(RemoveUnnecessaryParenthesesIntention())
|
|
||||||
registerIntentionBasedProcessing(DestructureIntention())
|
|
||||||
registerInspectionBasedProcessing(SimplifyAssertNotNullInspection())
|
|
||||||
registerIntentionBasedProcessing(RemoveRedundantCallsOfConversionMethodsIntention())
|
|
||||||
registerGeneralInspectionBasedProcessing(LiftReturnOrAssignmentInspection())
|
|
||||||
|
|
||||||
_processings.add(object : J2kPostProcessing {
|
|
||||||
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? =
|
registerInspectionBasedProcessing(IfThenToSafeAccessInspection()),
|
||||||
{
|
registerInspectionBasedProcessing(IfThenToSafeAccessInspection()),
|
||||||
OptimizeImportsProcessor(element.project, element.containingKtFile).run()
|
registerIntentionBasedProcessing(IfThenToElvisIntention()),
|
||||||
PsiDocumentManager.getInstance(element.project).commitAllDocuments()
|
registerInspectionBasedProcessing(SimplifyNegatedBinaryExpressionInspection()),
|
||||||
|
registerInspectionBasedProcessing(ReplaceGetOrSetInspection()),
|
||||||
|
registerIntentionBasedProcessing(AddOperatorModifierIntention()),
|
||||||
|
registerIntentionBasedProcessing(ObjectLiteralToLambdaIntention()),
|
||||||
|
registerIntentionBasedProcessing(AnonymousFunctionToLambdaIntention()),
|
||||||
|
registerIntentionBasedProcessing(RemoveUnnecessaryParenthesesIntention()),
|
||||||
|
registerIntentionBasedProcessing(DestructureIntention()),
|
||||||
|
registerInspectionBasedProcessing(SimplifyAssertNotNullInspection()),
|
||||||
|
registerIntentionBasedProcessing(RemoveRedundantCallsOfConversionMethodsIntention()),
|
||||||
|
registerGeneralInspectionBasedProcessing(LiftReturnOrAssignmentInspection()),
|
||||||
|
|
||||||
|
SingleProcessing(object : J2kPostProcessing {
|
||||||
|
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? =
|
||||||
|
{
|
||||||
|
OptimizeImportsProcessor(element.project, element.containingKtFile).run()
|
||||||
|
PsiDocumentManager.getInstance(element.project).commitAllDocuments()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val writeActionNeeded: Boolean = true
|
||||||
|
}),
|
||||||
|
|
||||||
|
registerDiagnosticBasedProcessing<KtBinaryExpressionWithTypeRHS>(Errors.USELESS_CAST) { element, _ ->
|
||||||
|
val expression = RemoveUselessCastFix.invoke(element)
|
||||||
|
|
||||||
|
val variable = expression.parent as? KtProperty
|
||||||
|
if (variable != null && expression == variable.initializer && variable.isLocal) {
|
||||||
|
val ref = ReferencesSearch.search(variable, LocalSearchScope(variable.containingFile)).findAll().singleOrNull()
|
||||||
|
if (ref != null && ref.element is KtSimpleNameExpression) {
|
||||||
|
ref.element.replace(expression)
|
||||||
|
variable.delete()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
override val writeActionNeeded: Boolean = true
|
registerDiagnosticBasedProcessing<KtTypeProjection>(Errors.REDUNDANT_PROJECTION) { _, diagnostic ->
|
||||||
})
|
val fix = RemoveModifierFix.createRemoveProjectionFactory(true).createActions(diagnostic).single() as RemoveModifierFix
|
||||||
|
fix.invoke()
|
||||||
|
},
|
||||||
|
|
||||||
registerDiagnosticBasedProcessing<KtBinaryExpressionWithTypeRHS>(Errors.USELESS_CAST) { element, _ ->
|
registerDiagnosticBasedProcessing<KtModifierListOwner>(Errors.NON_FINAL_MEMBER_IN_FINAL_CLASS) { _, diagnostic ->
|
||||||
val expression = RemoveUselessCastFix.invoke(element)
|
val fix =
|
||||||
|
RemoveModifierFix
|
||||||
|
.createRemoveModifierFromListOwnerFactory(KtTokens.OPEN_KEYWORD)
|
||||||
|
.createActions(diagnostic).single() as RemoveModifierFix
|
||||||
|
fix.invoke()
|
||||||
|
},
|
||||||
|
registerDiagnosticBasedProcessing<KtModifierListOwner>(Errors.NON_FINAL_MEMBER_IN_OBJECT) { _, diagnostic ->
|
||||||
|
val fix =
|
||||||
|
RemoveModifierFix
|
||||||
|
.createRemoveModifierFromListOwnerFactory(KtTokens.OPEN_KEYWORD)
|
||||||
|
.createActions(diagnostic).single() as RemoveModifierFix
|
||||||
|
fix.invoke()
|
||||||
|
},
|
||||||
|
|
||||||
val variable = expression.parent as? KtProperty
|
registerDiagnosticBasedProcessingFactory(
|
||||||
if (variable != null && expression == variable.initializer && variable.isLocal) {
|
|
||||||
val ref = ReferencesSearch.search(variable, LocalSearchScope(variable.containingFile)).findAll().singleOrNull()
|
|
||||||
if (ref != null && ref.element is KtSimpleNameExpression) {
|
|
||||||
ref.element.replace(expression)
|
|
||||||
variable.delete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registerDiagnosticBasedProcessing<KtTypeProjection>(Errors.REDUNDANT_PROJECTION) { _, diagnostic ->
|
|
||||||
val fix = RemoveModifierFix.createRemoveProjectionFactory(true).createActions(diagnostic).single() as RemoveModifierFix
|
|
||||||
fix.invoke()
|
|
||||||
}
|
|
||||||
|
|
||||||
registerDiagnosticBasedProcessing<KtModifierListOwner>(Errors.NON_FINAL_MEMBER_IN_FINAL_CLASS) { _, diagnostic ->
|
|
||||||
val fix =
|
|
||||||
RemoveModifierFix
|
|
||||||
.createRemoveModifierFromListOwnerFactory(KtTokens.OPEN_KEYWORD)
|
|
||||||
.createActions(diagnostic).single() as RemoveModifierFix
|
|
||||||
fix.invoke()
|
|
||||||
}
|
|
||||||
registerDiagnosticBasedProcessing<KtModifierListOwner>(Errors.NON_FINAL_MEMBER_IN_OBJECT) { _, diagnostic ->
|
|
||||||
val fix =
|
|
||||||
RemoveModifierFix
|
|
||||||
.createRemoveModifierFromListOwnerFactory(KtTokens.OPEN_KEYWORD)
|
|
||||||
.createActions(diagnostic).single() as RemoveModifierFix
|
|
||||||
fix.invoke()
|
|
||||||
}
|
|
||||||
|
|
||||||
registerDiagnosticBasedProcessingFactory(
|
|
||||||
Errors.VAL_REASSIGNMENT, Errors.CAPTURED_VAL_INITIALIZATION, Errors.CAPTURED_MEMBER_VAL_INITIALIZATION
|
Errors.VAL_REASSIGNMENT, Errors.CAPTURED_VAL_INITIALIZATION, Errors.CAPTURED_MEMBER_VAL_INITIALIZATION
|
||||||
) {
|
) { element: KtSimpleNameExpression, _: Diagnostic ->
|
||||||
element: KtSimpleNameExpression, _: Diagnostic ->
|
val property = element.mainReference.resolve() as? KtProperty
|
||||||
val property = element.mainReference.resolve() as? KtProperty
|
if (property == null) {
|
||||||
if (property == null) {
|
null
|
||||||
null
|
} else {
|
||||||
}
|
{
|
||||||
else {
|
if (!property.isVar) {
|
||||||
{
|
property.valOrVarKeyword.replace(KtPsiFactory(element.project).createVarKeyword())
|
||||||
if (!property.isVar) {
|
}
|
||||||
property.valOrVarKeyword.replace(KtPsiFactory(element.project).createVarKeyword())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
registerDiagnosticBasedProcessing<KtSimpleNameExpression>(Errors.UNNECESSARY_NOT_NULL_ASSERTION) { element, _ ->
|
||||||
|
val exclExclExpr = element.parent as KtUnaryExpression
|
||||||
|
val baseExpression = exclExclExpr.baseExpression!!
|
||||||
|
val context = baseExpression.analyze(BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS)
|
||||||
|
if (context.diagnostics.forElement(element).any { it.factory == Errors.UNNECESSARY_NOT_NULL_ASSERTION }) {
|
||||||
|
exclExclExpr.replace(baseExpression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
override val processings: Collection<J2kPostProcessing> =
|
||||||
|
mainProcessings.processings().toList()
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
processingsToPriorityMap.putAll(processings.mapToIndex())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private inline fun <reified TElement : KtElement, TIntention : SelfTargetingRangeIntention<TElement>> registerIntentionBasedProcessing(
|
||||||
|
intention: TIntention,
|
||||||
|
noinline additionalChecker: (TElement) -> Boolean = { true }
|
||||||
|
) = SingleProcessing(object : J2kPostProcessing {
|
||||||
|
// Intention can either need or not need write action
|
||||||
|
override val writeActionNeeded = intention.startInWriteAction()
|
||||||
|
|
||||||
|
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
||||||
|
if (!TElement::class.java.isInstance(element)) return null
|
||||||
|
val tElement = element as TElement
|
||||||
|
if (intention.applicabilityRange(tElement) == null) return null
|
||||||
|
if (!additionalChecker(tElement)) return null
|
||||||
|
return {
|
||||||
|
if (intention.applicabilityRange(tElement) != null) { // check availability of the intention again because something could change
|
||||||
|
intention.applyTo(element, null)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registerDiagnosticBasedProcessing<KtSimpleNameExpression>(Errors.UNNECESSARY_NOT_NULL_ASSERTION) { element, _ ->
|
|
||||||
val exclExclExpr = element.parent as KtUnaryExpression
|
|
||||||
val baseExpression = exclExclExpr.baseExpression!!
|
|
||||||
val context = baseExpression.analyze(BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS)
|
|
||||||
if (context.diagnostics.forElement(element).any { it.factory == Errors.UNNECESSARY_NOT_NULL_ASSERTION }) {
|
|
||||||
exclExclExpr.replace(baseExpression)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
processingsToPriorityMap.putAll(_processings.mapToIndex())
|
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
private inline fun <reified TElement : KtElement, TIntention: SelfTargetingRangeIntention<TElement>> registerIntentionBasedProcessing(
|
|
||||||
intention: TIntention,
|
|
||||||
noinline additionalChecker: (TElement) -> Boolean = { true }
|
|
||||||
) {
|
|
||||||
_processings.add(object : J2kPostProcessing {
|
|
||||||
// Intention can either need or not need write action
|
|
||||||
override val writeActionNeeded = intention.startInWriteAction()
|
|
||||||
|
|
||||||
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
|
||||||
if (!TElement::class.java.isInstance(element)) return null
|
|
||||||
val tElement = element as TElement
|
|
||||||
if (intention.applicabilityRange(tElement) == null) return null
|
|
||||||
if (!additionalChecker(tElement)) return null
|
|
||||||
return {
|
|
||||||
if (intention.applicabilityRange(tElement) != null) { // check availability of the intention again because something could change
|
|
||||||
intention.applyTo(element, null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun <TInspection : AbstractKotlinInspection> registerGeneralInspectionBasedProcessing(
|
private inline fun <TInspection : AbstractKotlinInspection> registerGeneralInspectionBasedProcessing(
|
||||||
inspection: TInspection,
|
inspection: TInspection,
|
||||||
acceptInformationLevel: Boolean = false
|
acceptInformationLevel: Boolean = false
|
||||||
) {
|
) = SingleProcessing(object : J2kPostProcessing {
|
||||||
_processings.add(object : J2kPostProcessing {
|
override val writeActionNeeded = false
|
||||||
override val writeActionNeeded = false
|
|
||||||
|
|
||||||
fun <D : CommonProblemDescriptor> QuickFix<D>.applyFixSmart(project: Project, descriptor: D) {
|
|
||||||
if (descriptor is ProblemDescriptor) {
|
|
||||||
if (this is IntentionWrapper) {
|
|
||||||
@Suppress("NOT_YET_SUPPORTED_IN_INLINE")
|
|
||||||
fun applySelfTargetingIntention(action: SelfTargetingIntention<PsiElement>) {
|
|
||||||
val target = action.getTarget(descriptor.psiElement.startOffset, descriptor.psiElement.containingFile) ?: return
|
|
||||||
if (!action.isApplicableTo(target, descriptor.psiElement.startOffset)) return
|
|
||||||
action.applyTo(target, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("NOT_YET_SUPPORTED_IN_INLINE")
|
|
||||||
fun applyQuickFixActionBase(action: QuickFixActionBase<PsiElement>) {
|
|
||||||
if (!action.isAvailable(project, null, descriptor.psiElement.containingFile)) return
|
|
||||||
action.invoke(project, null, descriptor.psiElement.containingFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Suppress("NOT_YET_SUPPORTED_IN_INLINE")
|
|
||||||
fun applyIntention() {
|
|
||||||
val action = this.action
|
|
||||||
when (action) {
|
|
||||||
is SelfTargetingIntention<*> -> applySelfTargetingIntention(action as SelfTargetingIntention<PsiElement>)
|
|
||||||
is QuickFixActionBase<*> -> applyQuickFixActionBase(action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (this.startInWriteAction()) {
|
|
||||||
ApplicationManager.getApplication().runWriteAction(::applyIntention)
|
|
||||||
} else {
|
|
||||||
applyIntention()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
fun <D : CommonProblemDescriptor> QuickFix<D>.applyFixSmart(project: Project, descriptor: D) {
|
||||||
|
if (descriptor is ProblemDescriptor) {
|
||||||
|
if (this is IntentionWrapper) {
|
||||||
|
@Suppress("NOT_YET_SUPPORTED_IN_INLINE")
|
||||||
|
fun applySelfTargetingIntention(action: SelfTargetingIntention<PsiElement>) {
|
||||||
|
val target = action.getTarget(descriptor.psiElement.startOffset, descriptor.psiElement.containingFile) ?: return
|
||||||
|
if (!action.isApplicableTo(target, descriptor.psiElement.startOffset)) return
|
||||||
|
action.applyTo(target, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("NOT_YET_SUPPORTED_IN_INLINE")
|
||||||
|
fun applyQuickFixActionBase(action: QuickFixActionBase<PsiElement>) {
|
||||||
|
if (!action.isAvailable(project, null, descriptor.psiElement.containingFile)) return
|
||||||
|
action.invoke(project, null, descriptor.psiElement.containingFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Suppress("NOT_YET_SUPPORTED_IN_INLINE")
|
||||||
|
fun applyIntention() {
|
||||||
|
val action = this.action
|
||||||
|
when (action) {
|
||||||
|
is SelfTargetingIntention<*> -> applySelfTargetingIntention(action as SelfTargetingIntention<PsiElement>)
|
||||||
|
is QuickFixActionBase<*> -> applyQuickFixActionBase(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (this.startInWriteAction()) {
|
||||||
|
ApplicationManager.getApplication().runWriteAction(::applyIntention)
|
||||||
|
} else {
|
||||||
|
applyIntention()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ApplicationManager.getApplication().runWriteAction {
|
|
||||||
this.applyFix(project, descriptor)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
ApplicationManager.getApplication().runWriteAction {
|
||||||
val holder = ProblemsHolder(InspectionManager.getInstance(element.project), element.containingFile, false)
|
this.applyFix(project, descriptor)
|
||||||
val visitor = inspection.buildVisitor(
|
}
|
||||||
holder,
|
}
|
||||||
false,
|
|
||||||
LocalInspectionToolSession(element.containingFile, 0, element.containingFile.endOffset)
|
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
||||||
)
|
val holder = ProblemsHolder(InspectionManager.getInstance(element.project), element.containingFile, false)
|
||||||
|
val visitor = inspection.buildVisitor(
|
||||||
|
holder,
|
||||||
|
false,
|
||||||
|
LocalInspectionToolSession(element.containingFile, 0, element.containingFile.endOffset)
|
||||||
|
)
|
||||||
|
element.accept(visitor)
|
||||||
|
if (!holder.hasResults()) return null
|
||||||
|
return {
|
||||||
|
holder.results.clear()
|
||||||
element.accept(visitor)
|
element.accept(visitor)
|
||||||
if (!holder.hasResults()) return null
|
if (holder.hasResults()) {
|
||||||
return {
|
holder.results
|
||||||
holder.results.clear()
|
.filter { acceptInformationLevel || it.highlightType != ProblemHighlightType.INFORMATION }
|
||||||
element.accept(visitor)
|
.forEach { it.fixes?.firstOrNull()?.applyFixSmart(element.project, it) }
|
||||||
if (holder.hasResults()) {
|
|
||||||
holder.results
|
|
||||||
.filter { acceptInformationLevel || it.highlightType != ProblemHighlightType.INFORMATION }
|
|
||||||
.forEach { it.fixes?.firstOrNull()?.applyFixSmart(element.project, it) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
|
|
||||||
private inline fun
|
private inline fun
|
||||||
<reified TElement : KtElement,
|
<reified TElement : KtElement,
|
||||||
TInspection: AbstractApplicabilityBasedInspection<TElement>> registerInspectionBasedProcessing(
|
TInspection : AbstractApplicabilityBasedInspection<TElement>> registerInspectionBasedProcessing(
|
||||||
|
|
||||||
inspection: TInspection,
|
inspection: TInspection,
|
||||||
acceptInformationLevel: Boolean = false
|
acceptInformationLevel: Boolean = false
|
||||||
) {
|
) = SingleProcessing(object : J2kPostProcessing {
|
||||||
_processings.add(object : J2kPostProcessing {
|
// Inspection can either need or not need write action
|
||||||
// Inspection can either need or not need write action
|
override val writeActionNeeded = inspection.startFixInWriteAction
|
||||||
override val writeActionNeeded = inspection.startFixInWriteAction
|
|
||||||
|
|
||||||
private fun isApplicable(element: TElement): Boolean {
|
private fun isApplicable(element: TElement): Boolean {
|
||||||
if (!inspection.isApplicable(element)) return false
|
if (!inspection.isApplicable(element)) return false
|
||||||
return acceptInformationLevel || inspection.inspectionHighlightType(element) != ProblemHighlightType.INFORMATION
|
return acceptInformationLevel || inspection.inspectionHighlightType(element) != ProblemHighlightType.INFORMATION
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
||||||
if (!TElement::class.java.isInstance(element)) return null
|
if (!TElement::class.java.isInstance(element)) return null
|
||||||
val tElement = element as TElement
|
val tElement = element as TElement
|
||||||
if (!isApplicable(tElement)) return null
|
if (!isApplicable(tElement)) return null
|
||||||
return {
|
return {
|
||||||
if (isApplicable(tElement)) { // check availability of the inspection again because something could change
|
if (isApplicable(tElement)) { // check availability of the inspection again because something could change
|
||||||
inspection.applyTo(inspection.inspectionTarget(tElement))
|
inspection.applyTo(inspection.inspectionTarget(tElement))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
|
|
||||||
private inline fun <reified TElement : KtElement> registerDiagnosticBasedProcessing(
|
private inline fun <reified TElement : KtElement> registerDiagnosticBasedProcessing(
|
||||||
vararg diagnosticFactory: DiagnosticFactory<*>,
|
vararg diagnosticFactory: DiagnosticFactory<*>,
|
||||||
crossinline fix: (TElement, Diagnostic) -> Unit
|
crossinline fix: (TElement, Diagnostic) -> Unit
|
||||||
) {
|
) = registerDiagnosticBasedProcessingFactory(*diagnosticFactory) { element: TElement, diagnostic: Diagnostic ->
|
||||||
registerDiagnosticBasedProcessingFactory(*diagnosticFactory) { element: TElement, diagnostic: Diagnostic -> { fix(element, diagnostic) } }
|
{
|
||||||
|
fix(
|
||||||
|
element,
|
||||||
|
diagnostic
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private inline fun <reified TElement : KtElement> registerDiagnosticBasedProcessingFactory(
|
private inline fun <reified TElement : KtElement> registerDiagnosticBasedProcessingFactory(
|
||||||
vararg diagnosticFactory: DiagnosticFactory<*>,
|
vararg diagnosticFactory: DiagnosticFactory<*>,
|
||||||
crossinline fixFactory: (TElement, Diagnostic) -> (() -> Unit)?
|
crossinline fixFactory: (TElement, Diagnostic) -> (() -> Unit)?
|
||||||
) {
|
) = SingleProcessing(object : J2kPostProcessing {
|
||||||
_processings.add(object : J2kPostProcessing {
|
// ???
|
||||||
// ???
|
override val writeActionNeeded = true
|
||||||
override val writeActionNeeded = true
|
|
||||||
|
override fun createAction(element: KtElement, 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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
override fun createAction(element: KtElement, 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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private class RemoveExplicitPropertyType : J2kPostProcessing {
|
private class RemoveExplicitPropertyType : J2kPostProcessing {
|
||||||
override val writeActionNeeded = true
|
override val writeActionNeeded = true
|
||||||
@@ -344,8 +374,8 @@ object NewJ2KPostProcessingRegistrarImpl: J2KPostProcessingRegistrar {
|
|||||||
val withoutExpectedType = initializer.analyzeInContext(initializer.getResolutionScope())
|
val withoutExpectedType = initializer.analyzeInContext(initializer.getResolutionScope())
|
||||||
val descriptor = element.resolveToDescriptorIfAny() as? CallableDescriptor ?: return false
|
val descriptor = element.resolveToDescriptorIfAny() as? CallableDescriptor ?: return false
|
||||||
return when (withoutExpectedType.getType(initializer)) {
|
return when (withoutExpectedType.getType(initializer)) {
|
||||||
descriptor.returnType,
|
descriptor.returnType -> true
|
||||||
descriptor.returnType?.makeNotNullable() -> true
|
descriptor.returnType?.makeNotNullable() -> !element.isVar
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,7 +431,11 @@ object NewJ2KPostProcessingRegistrarImpl: J2KPostProcessingRegistrar {
|
|||||||
override val writeActionNeeded = true
|
override val writeActionNeeded = true
|
||||||
|
|
||||||
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
||||||
if (element !is KtTypeArgumentList || !RemoveExplicitTypeArgumentsIntention.isApplicableTo(element, approximateFlexible = true)) return null
|
if (element !is KtTypeArgumentList || !RemoveExplicitTypeArgumentsIntention.isApplicableTo(
|
||||||
|
element,
|
||||||
|
approximateFlexible = true
|
||||||
|
)
|
||||||
|
) return null
|
||||||
|
|
||||||
return {
|
return {
|
||||||
if (RemoveExplicitTypeArgumentsIntention.isApplicableTo(element, approximateFlexible = true)) {
|
if (RemoveExplicitTypeArgumentsIntention.isApplicableTo(element, approximateFlexible = true)) {
|
||||||
@@ -427,10 +461,12 @@ object NewJ2KPostProcessingRegistrarImpl: J2KPostProcessingRegistrar {
|
|||||||
private val intention = ConvertToStringTemplateIntention()
|
private val intention = ConvertToStringTemplateIntention()
|
||||||
|
|
||||||
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
||||||
if (element is KtBinaryExpression && intention.isApplicableTo(element) && ConvertToStringTemplateIntention.shouldSuggestToConvert(element)) {
|
if (element is KtBinaryExpression && intention.isApplicableTo(element) && ConvertToStringTemplateIntention.shouldSuggestToConvert(
|
||||||
|
element
|
||||||
|
)
|
||||||
|
) {
|
||||||
return { intention.applyTo(element, null) }
|
return { intention.applyTo(element, null) }
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -459,7 +495,7 @@ object NewJ2KPostProcessingRegistrarImpl: J2KPostProcessingRegistrar {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element)
|
RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element)
|
||||||
.forEach { RedundantSamConstructorInspection.replaceSamConstructorCall(it) }
|
.forEach { RedundantSamConstructorInspection.replaceSamConstructorCall(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -510,8 +546,9 @@ object NewJ2KPostProcessingRegistrarImpl: J2KPostProcessingRegistrar {
|
|||||||
element.operationToken != KtTokens.PLUS ||
|
element.operationToken != KtTokens.PLUS ||
|
||||||
diagnostics.forElement(element.operationReference).none {
|
diagnostics.forElement(element.operationReference).none {
|
||||||
it.factory == Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER
|
it.factory == Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER
|
||||||
|| it.factory == Errors.NONE_APPLICABLE
|
|| it.factory == Errors.NONE_APPLICABLE
|
||||||
})
|
}
|
||||||
|
)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
val bindingContext = element.analyze()
|
val bindingContext = element.analyze()
|
||||||
@@ -562,11 +599,47 @@ object NewJ2KPostProcessingRegistrarImpl: J2KPostProcessingRegistrar {
|
|||||||
val variable = anonymousObject.getParentOfType<KtVariableDeclaration>(true) ?: return null
|
val variable = anonymousObject.getParentOfType<KtVariableDeclaration>(true) ?: return null
|
||||||
|
|
||||||
if (variable.nameAsName == element.getReferencedNameAsName() &&
|
if (variable.nameAsName == element.getReferencedNameAsName() &&
|
||||||
variable.initializer?.getChildOfType<KtClassOrObject>() == anonymousObject) {
|
variable.initializer?.getChildOfType<KtClassOrObject>() == anonymousObject
|
||||||
|
) {
|
||||||
return { element.replaced(KtPsiFactory(element).createThisExpression()) }
|
return { element.replaced(KtPsiFactory(element).createThisExpression()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class VarToVal : J2kPostProcessing {
|
||||||
|
override val writeActionNeeded = true
|
||||||
|
|
||||||
|
private fun KtProperty.hasWriteUsages(): Boolean =
|
||||||
|
ReferencesSearch.search(this, useScope).any { usage ->
|
||||||
|
(usage as? KtSimpleNameReference)?.element?.let {
|
||||||
|
it.readWriteAccess(useResolveForReadWrite = true).isWrite
|
||||||
|
&& it.parentOfType<KtAnonymousInitializer>() == null//TODO properly check
|
||||||
|
} == true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
||||||
|
if (element !is KtProperty) return null
|
||||||
|
|
||||||
|
fun check(element: KtProperty): Boolean {
|
||||||
|
if (!element.isVar) return false
|
||||||
|
if (!element.isPrivate()) return false
|
||||||
|
return !element.hasWriteUsages()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!check(element)) {
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
if (element.isValid && check(element)) {
|
||||||
|
val factory = KtPsiFactory(element)
|
||||||
|
element.valOrVarKeyword.replace(factory.createValKeyword())
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user