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,31 +63,12 @@ class NewJ2kPostProcessor(
PROCESS PROCESS
} }
private fun List<NewJ2kPostProcessing>.runProcessings(file: KtFile, rangeMarker: RangeMarker?): Boolean {
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()
val groupsOfProcessings = NewJ2KPostProcessingRegistrar.mainProcessings.flattenToGroups()
runBlocking(EDT.ModalityStateElement(ModalityState.defaultModalityState())) {
for (processings in groupsOfProcessings) {
do {
var modificationStamp: Long? = file.modificationStamp var modificationStamp: Long? = file.modificationStamp
val elementToActions = runReadAction { val elementToActions = runReadAction {
collectAvailableActions(processings, file, rangeMarker) collectAvailableActions(this, file, rangeMarker)
} }
withContext(EDT) {
for ((element, action, _, writeActionNeeded) in elementToActions) { for ((element, action, _, writeActionNeeded) in elementToActions) {
if (element.isValid) { if (element.isValid) {
if (writeActionNeeded) { if (writeActionNeeded) {
@@ -101,11 +82,29 @@ class NewJ2kPostProcessor(
modificationStamp = null modificationStamp = null
} }
} }
return modificationStamp != file.modificationStamp && elementToActions.isNotEmpty()
} }
if (modificationStamp == file.modificationStamp) break private fun Processing.runProcessings(file: KtFile, rangeMarker: RangeMarker?) {
} while (elementToActions.isNotEmpty()) 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?) {
OptimizeImportsProcessor(file.project, file.containingKtFile).run()
runBlocking(EDT.ModalityStateElement(ModalityState.defaultModalityState())) {
NewJ2KPostProcessingRegistrar.mainProcessings.runProcessings(file, rangeMarker)
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,34 +87,31 @@ 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 { object : NewJ2kPostProcessing {
override val writeActionNeeded: Boolean = true override val writeActionNeeded: Boolean = true
private val processing = registerGeneralInspectionBasedProcessing(RedundantExplicitTypeInspection()) private val processing = registerGeneralInspectionBasedProcessing(RedundantExplicitTypeInspection())
@@ -119,14 +119,14 @@ object NewJ2KPostProcessingRegistrar {
override fun createAction(element: KtElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? { override fun createAction(element: KtElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
if (settings?.specifyLocalVariableTypeByDefault == true) return null if (settings?.specifyLocalVariableTypeByDefault == true) return null
return processing.processing.createAction(element, diagnostics) 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)
@@ -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,
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 {
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 {