New J2K: Add repeatable post processing groups

This commit is contained in:
Ilya Kirillov
2019-02-05 22:32:43 +03:00
committed by Ilya Kirillov
parent c827247272
commit 9c71d5ca25
2 changed files with 95 additions and 97 deletions
@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.idea.nj2k package org.jetbrains.kotlin.nj2k
import com.intellij.codeInsight.actions.OptimizeImportsProcessor import com.intellij.codeInsight.actions.OptimizeImportsProcessor
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
@@ -24,13 +24,13 @@ import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiRecursiveElementVisitor import com.intellij.psi.PsiRecursiveElementVisitor
import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.codeStyle.CodeStyleManager
import kotlinx.coroutines.experimental.withContext
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.conversion.copy.range import org.jetbrains.kotlin.idea.conversion.copy.range
import org.jetbrains.kotlin.idea.core.util.EDT 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.ImportInsertHelper
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
@@ -63,49 +63,48 @@ class NewJ2kPostProcessor(
PROCESS PROCESS
} }
private fun List<NewJ2kPostProcessing>.runProcessings(file: KtFile, rangeMarker: RangeMarker?): Boolean {
var modificationStamp: Long? = file.modificationStamp
val elementToActions = runReadAction {
collectAvailableActions(this, file, rangeMarker)
}
for ((element, action, _, writeActionNeeded) in elementToActions) {
if (element.isValid) {
if (writeActionNeeded) {
runWriteAction {
action()
}
} else {
action()
}
} else {
modificationStamp = null
}
}
return modificationStamp != file.modificationStamp && elementToActions.isNotEmpty()
}
private fun Processing.runProcessings(file: KtFile, rangeMarker: RangeMarker?) {
when (this) {
is SingleOneTimeProcessing -> listOf(processing).runProcessings(file, rangeMarker)
is RepeatableProcessingGroup ->
do {
val needContinue = processings.runProcessings(file, rangeMarker)
} while (needContinue)
is OneTimeProcessingGroup ->
processings.forEach { it.runProcessings(file, rangeMarker) }
}
}
override fun doAdditionalProcessing(file: KtFile, rangeMarker: RangeMarker?) { override fun doAdditionalProcessing(file: KtFile, rangeMarker: RangeMarker?) {
fun Processing.flattenToGroups(): List<List<NewJ2kPostProcessing>> =
when (this) {
is SingleProcessing -> listOf(listOf(this.processing))
is ProcessingGroup ->
if (processings.all { it is SingleProcessing }) {
listOf(processings.map { (it as SingleProcessing).processing })
} else {
processings.flatMap { it.flattenToGroups() }
}
else -> error("Processing tree is corrupted")
}
OptimizeImportsProcessor(file.project, file.containingKtFile).run() OptimizeImportsProcessor(file.project, file.containingKtFile).run()
val groupsOfProcessings = NewJ2KPostProcessingRegistrar.mainProcessings.flattenToGroups()
runBlocking(EDT.ModalityStateElement(ModalityState.defaultModalityState())) { runBlocking(EDT.ModalityStateElement(ModalityState.defaultModalityState())) {
for (processings in groupsOfProcessings) { NewJ2KPostProcessingRegistrar.mainProcessings.runProcessings(file, rangeMarker)
do {
var modificationStamp: Long? = file.modificationStamp
val elementToActions = runReadAction {
collectAvailableActions(processings, file, rangeMarker)
}
withContext(EDT) {
for ((element, action, _, writeActionNeeded) in elementToActions) {
if (element.isValid) {
if (writeActionNeeded) {
runWriteAction {
action()
}
} else {
action()
}
} else {
modificationStamp = null
}
}
}
if (modificationStamp == file.modificationStamp) break
} while (elementToActions.isNotEmpty())
}
if (formatCode) { if (formatCode) {
withContext(EDT) { withContext(EDT) {
@@ -5,11 +5,9 @@
package org.jetbrains.kotlin.nj2k package org.jetbrains.kotlin.nj2k
import com.intellij.codeInsight.actions.OptimizeImportsProcessor
import com.intellij.codeInspection.* import com.intellij.codeInspection.*
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.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
@@ -65,8 +63,12 @@ interface NewJ2kPostProcessing {
} }
interface Processing interface Processing
data class SingleProcessing(val processing: NewJ2kPostProcessing) : Processing data class SingleOneTimeProcessing(val processing: NewJ2kPostProcessing) : Processing
data class ProcessingGroup(val processings: List<Processing>) : Processing { data class RepeatableProcessingGroup(val processings: List<NewJ2kPostProcessing>) : Processing {
constructor(vararg processings: NewJ2kPostProcessing) : this(processings.toList())
}
data class OneTimeProcessingGroup(val processings: List<Processing>) : Processing {
constructor(vararg processings: Processing) : this(processings.toList()) constructor(vararg processings: Processing) : this(processings.toList())
} }
@@ -74,8 +76,9 @@ object NewJ2KPostProcessingRegistrar {
private fun Processing.processings(): Sequence<NewJ2kPostProcessing> = private fun Processing.processings(): Sequence<NewJ2kPostProcessing> =
when (this) { when (this) {
is SingleProcessing -> sequenceOf(processing) is SingleOneTimeProcessing -> sequenceOf(processing)
is ProcessingGroup -> processings.asSequence().flatMap { it.processings() } is RepeatableProcessingGroup -> processings.asSequence()
is OneTimeProcessingGroup -> processings.asSequence().flatMap { it.processings() }
else -> sequenceOf() else -> sequenceOf()
} }
@@ -84,49 +87,46 @@ object NewJ2KPostProcessingRegistrar {
fun priority(processing: NewJ2kPostProcessing): Int = processingsToPriorityMap[processing]!! fun priority(processing: NewJ2kPostProcessing): Int = processingsToPriorityMap[processing]!!
val mainProcessings = ProcessingGroup( val mainProcessings = OneTimeProcessingGroup(
SingleProcessing(VarToVal()), SingleOneTimeProcessing(VarToVal()),
ProcessingGroup( SingleOneTimeProcessing(ConvertGettersAndSetters()),
SingleProcessing(ConvertGettersAndSetters()), SingleOneTimeProcessing(registerGeneralInspectionBasedProcessing(RedundantModalityModifierInspection())),
registerGeneralInspectionBasedProcessing(RedundantModalityModifierInspection()), SingleOneTimeProcessing(registerGeneralInspectionBasedProcessing(RedundantVisibilityModifierInspection())),
registerGeneralInspectionBasedProcessing(RedundantVisibilityModifierInspection()), SingleOneTimeProcessing(registerGeneralInspectionBasedProcessing(RedundantGetterInspection())),
registerGeneralInspectionBasedProcessing(RedundantGetterInspection()), SingleOneTimeProcessing(registerGeneralInspectionBasedProcessing(RedundantSetterInspection())),
registerGeneralInspectionBasedProcessing(RedundantSetterInspection()) SingleOneTimeProcessing(ConvertDataClass()),
), RepeatableProcessingGroup(
SingleProcessing(ConvertDataClass()),
ProcessingGroup(
registerGeneralInspectionBasedProcessing(ExplicitThisInspection()), registerGeneralInspectionBasedProcessing(ExplicitThisInspection()),
RemoveExplicitTypeArgumentsProcessing(),
SingleProcessing(RemoveExplicitTypeArgumentsProcessing()), RemoveRedundantOverrideVisibilityProcessing(),
SingleProcessing(RemoveRedundantOverrideVisibilityProcessing()),
registerInspectionBasedProcessing(MoveLambdaOutsideParenthesesInspection()), registerInspectionBasedProcessing(MoveLambdaOutsideParenthesesInspection()),
registerGeneralInspectionBasedProcessing(RedundantCompanionReferenceInspection()), registerGeneralInspectionBasedProcessing(RedundantCompanionReferenceInspection()),
SingleProcessing(FixObjectStringConcatenationProcessing()), FixObjectStringConcatenationProcessing(),
SingleProcessing(ConvertToStringTemplateProcessing()), ConvertToStringTemplateProcessing(),
SingleProcessing(UsePropertyAccessSyntaxProcessing()), UsePropertyAccessSyntaxProcessing(),
SingleProcessing(UninitializedVariableReferenceFromInitializerToThisReferenceProcessing()), UninitializedVariableReferenceFromInitializerToThisReferenceProcessing(),
SingleProcessing(UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing()), UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing(),
SingleProcessing(RemoveRedundantSamAdaptersProcessing()), RemoveRedundantSamAdaptersProcessing(),
SingleProcessing(RemoveRedundantCastToNullableProcessing()), RemoveRedundantCastToNullableProcessing(),
registerInspectionBasedProcessing(ReplacePutWithAssignmentInspection()), registerInspectionBasedProcessing(ReplacePutWithAssignmentInspection()),
SingleProcessing(UseExpressionBodyProcessing()), UseExpressionBodyProcessing(),
registerInspectionBasedProcessing(UnnecessaryVariableInspection()), registerInspectionBasedProcessing(UnnecessaryVariableInspection()),
SingleProcessing(
object : NewJ2kPostProcessing {
override val writeActionNeeded: Boolean = true
private val processing = registerGeneralInspectionBasedProcessing(RedundantExplicitTypeInspection())
override fun createAction(element: KtElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? { object : NewJ2kPostProcessing {
if (settings?.specifyLocalVariableTypeByDefault == true) return null override val writeActionNeeded: Boolean = true
private val processing = registerGeneralInspectionBasedProcessing(RedundantExplicitTypeInspection())
return processing.processing.createAction(element, diagnostics) override fun createAction(element: KtElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
} if (settings?.specifyLocalVariableTypeByDefault == true) return null
return processing.createAction(element, diagnostics)
} }
), }
,
registerGeneralInspectionBasedProcessing(RedundantUnitReturnTypeInspection()), registerGeneralInspectionBasedProcessing(RedundantUnitReturnTypeInspection()),
SingleProcessing(RemoveExplicitPropertyType()), RemoveExplicitPropertyType(),
SingleProcessing(RemoveRedundantNullability()), RemoveRedundantNullability(),
registerGeneralInspectionBasedProcessing(CanBeValInspection(ignoreNotUsedVals = false)), registerGeneralInspectionBasedProcessing(CanBeValInspection(ignoreNotUsedVals = false)),
@@ -142,7 +142,6 @@ object NewJ2KPostProcessingRegistrar {
) as KtReturnExpression).returnedExpression.isTrivialStatementBody() ) as KtReturnExpression).returnedExpression.isTrivialStatementBody()
}, },
registerInspectionBasedProcessing(IfThenToSafeAccessInspection()), registerInspectionBasedProcessing(IfThenToSafeAccessInspection()),
registerInspectionBasedProcessing(IfThenToSafeAccessInspection()), registerInspectionBasedProcessing(IfThenToSafeAccessInspection()),
registerIntentionBasedProcessing(IfThenToElvisIntention()), registerIntentionBasedProcessing(IfThenToElvisIntention()),
@@ -170,8 +169,8 @@ object NewJ2KPostProcessingRegistrar {
action.invoke(element.project, null, element.containingKtFile) action.invoke(element.project, null, element.containingKtFile)
}, },
SingleProcessing(RemoveRedundantTypeQualifierProcessing()), RemoveRedundantTypeQualifierProcessing(),
SingleProcessing(RemoveRedundantExpressionQualifierProcessing()), RemoveRedundantExpressionQualifierProcessing(),
registerDiagnosticBasedProcessing<KtBinaryExpressionWithTypeRHS>(Errors.USELESS_CAST) { element, _ -> registerDiagnosticBasedProcessing<KtBinaryExpressionWithTypeRHS>(Errors.USELESS_CAST) { element, _ ->
val expression = RemoveUselessCastFix.invoke(element) val expression = RemoveUselessCastFix.invoke(element)
@@ -215,7 +214,7 @@ object NewJ2KPostProcessingRegistrar {
}, },
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) {
@@ -253,7 +252,7 @@ object NewJ2KPostProcessingRegistrar {
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 }
) = SingleProcessing(object : NewJ2kPostProcessing { ) = object : NewJ2kPostProcessing {
// Intention can either need or not need write action // Intention can either need or not need write action
override val writeActionNeeded = intention.startInWriteAction() override val writeActionNeeded = intention.startInWriteAction()
@@ -269,13 +268,12 @@ object NewJ2KPostProcessingRegistrar {
} }
} }
} }
)
private inline fun <TInspection : AbstractKotlinInspection> registerGeneralInspectionBasedProcessing( private inline fun <TInspection : AbstractKotlinInspection> registerGeneralInspectionBasedProcessing(
inspection: TInspection, inspection: TInspection,
acceptInformationLevel: Boolean = false acceptInformationLevel: Boolean = false
) = SingleProcessing(object : NewJ2kPostProcessing { ) = (object : NewJ2kPostProcessing {
override val writeActionNeeded = false override val writeActionNeeded = false
fun <D : CommonProblemDescriptor> QuickFix<D>.applyFixSmart(project: Project, descriptor: D) { fun <D : CommonProblemDescriptor> QuickFix<D>.applyFixSmart(project: Project, descriptor: D) {
@@ -347,7 +345,7 @@ object NewJ2KPostProcessingRegistrar {
inspection: TInspection, inspection: TInspection,
acceptInformationLevel: Boolean = false acceptInformationLevel: Boolean = false
) = SingleProcessing(object : NewJ2kPostProcessing { ) = object : NewJ2kPostProcessing {
// 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
@@ -366,27 +364,28 @@ object NewJ2KPostProcessingRegistrar {
} }
} }
} }
}) }
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 -> ) = object : NewJ2kPostProcessing {
{ override val writeActionNeeded = true
fix(
element, override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
diagnostic if (!TElement::class.java.isInstance(element)) return null
) val diagnostic = diagnostics.forElement(element).firstOrNull { it.factory in diagnosticFactory } ?: return null
return {
fix(element as TElement, 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 : NewJ2kPostProcessing { ) = object : NewJ2kPostProcessing {
// ???
override val writeActionNeeded = true override val writeActionNeeded = true
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? { override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
@@ -394,7 +393,7 @@ object NewJ2KPostProcessingRegistrar {
val diagnostic = diagnostics.forElement(element).firstOrNull { it.factory in diagnosticFactory } ?: return null val diagnostic = diagnostics.forElement(element).firstOrNull { it.factory in diagnosticFactory } ?: return null
return fixFactory(element as TElement, diagnostic) return fixFactory(element as TElement, diagnostic)
} }
}) }
private class RemoveExplicitPropertyType : NewJ2kPostProcessing { private class RemoveExplicitPropertyType : NewJ2kPostProcessing {