diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/J2kPostProcessor.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/J2kPostProcessor.kt index fe0208c22a4..589e8f7f11b 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/J2kPostProcessor.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/J2kPostProcessor.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jetbrains.kotlin.idea.nj2k +package org.jetbrains.kotlin.nj2k import com.intellij.codeInsight.actions.OptimizeImportsProcessor 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.PsiRecursiveElementVisitor import com.intellij.psi.codeStyle.CodeStyleManager -import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext 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 @@ -63,49 +63,48 @@ class NewJ2kPostProcessor( PROCESS } + private fun List.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?) { - fun Processing.flattenToGroups(): List> = - 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 - val elementToActions = runReadAction { - collectAvailableActions(processings, file, rangeMarker) - } + NewJ2KPostProcessingRegistrar.mainProcessings.runProcessings(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) { withContext(EDT) { diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/NewJ2kPostProcessings.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/NewJ2kPostProcessings.kt index 15d02d6d6cf..023e19755cf 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/NewJ2kPostProcessings.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/NewJ2kPostProcessings.kt @@ -5,11 +5,9 @@ package org.jetbrains.kotlin.nj2k -import com.intellij.codeInsight.actions.OptimizeImportsProcessor import com.intellij.codeInspection.* import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.Project -import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.searches.ReferencesSearch @@ -65,8 +63,12 @@ interface NewJ2kPostProcessing { } interface Processing -data class SingleProcessing(val processing: NewJ2kPostProcessing) : Processing -data class ProcessingGroup(val processings: List) : Processing { +data class SingleOneTimeProcessing(val processing: NewJ2kPostProcessing) : Processing +data class RepeatableProcessingGroup(val processings: List) : Processing { + constructor(vararg processings: NewJ2kPostProcessing) : this(processings.toList()) +} + +data class OneTimeProcessingGroup(val processings: List) : Processing { constructor(vararg processings: Processing) : this(processings.toList()) } @@ -74,8 +76,9 @@ object NewJ2KPostProcessingRegistrar { private fun Processing.processings(): Sequence = when (this) { - is SingleProcessing -> sequenceOf(processing) - is ProcessingGroup -> processings.asSequence().flatMap { it.processings() } + is SingleOneTimeProcessing -> sequenceOf(processing) + is RepeatableProcessingGroup -> processings.asSequence() + is OneTimeProcessingGroup -> processings.asSequence().flatMap { it.processings() } else -> sequenceOf() } @@ -84,49 +87,46 @@ object NewJ2KPostProcessingRegistrar { fun priority(processing: NewJ2kPostProcessing): Int = processingsToPriorityMap[processing]!! - val mainProcessings = ProcessingGroup( - SingleProcessing(VarToVal()), - ProcessingGroup( - SingleProcessing(ConvertGettersAndSetters()), - registerGeneralInspectionBasedProcessing(RedundantModalityModifierInspection()), - registerGeneralInspectionBasedProcessing(RedundantVisibilityModifierInspection()), - registerGeneralInspectionBasedProcessing(RedundantGetterInspection()), - registerGeneralInspectionBasedProcessing(RedundantSetterInspection()) - ), - SingleProcessing(ConvertDataClass()), - ProcessingGroup( + val mainProcessings = OneTimeProcessingGroup( + SingleOneTimeProcessing(VarToVal()), + SingleOneTimeProcessing(ConvertGettersAndSetters()), + SingleOneTimeProcessing(registerGeneralInspectionBasedProcessing(RedundantModalityModifierInspection())), + SingleOneTimeProcessing(registerGeneralInspectionBasedProcessing(RedundantVisibilityModifierInspection())), + SingleOneTimeProcessing(registerGeneralInspectionBasedProcessing(RedundantGetterInspection())), + SingleOneTimeProcessing(registerGeneralInspectionBasedProcessing(RedundantSetterInspection())), + SingleOneTimeProcessing(ConvertDataClass()), + RepeatableProcessingGroup( registerGeneralInspectionBasedProcessing(ExplicitThisInspection()), - - SingleProcessing(RemoveExplicitTypeArgumentsProcessing()), - SingleProcessing(RemoveRedundantOverrideVisibilityProcessing()), + RemoveExplicitTypeArgumentsProcessing(), + RemoveRedundantOverrideVisibilityProcessing(), registerInspectionBasedProcessing(MoveLambdaOutsideParenthesesInspection()), registerGeneralInspectionBasedProcessing(RedundantCompanionReferenceInspection()), - SingleProcessing(FixObjectStringConcatenationProcessing()), - SingleProcessing(ConvertToStringTemplateProcessing()), - SingleProcessing(UsePropertyAccessSyntaxProcessing()), - SingleProcessing(UninitializedVariableReferenceFromInitializerToThisReferenceProcessing()), - SingleProcessing(UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing()), - SingleProcessing(RemoveRedundantSamAdaptersProcessing()), - SingleProcessing(RemoveRedundantCastToNullableProcessing()), + FixObjectStringConcatenationProcessing(), + ConvertToStringTemplateProcessing(), + UsePropertyAccessSyntaxProcessing(), + UninitializedVariableReferenceFromInitializerToThisReferenceProcessing(), + UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing(), + RemoveRedundantSamAdaptersProcessing(), + RemoveRedundantCastToNullableProcessing(), registerInspectionBasedProcessing(ReplacePutWithAssignmentInspection()), - SingleProcessing(UseExpressionBodyProcessing()), + UseExpressionBodyProcessing(), 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)? { - if (settings?.specifyLocalVariableTypeByDefault == true) return null + object : NewJ2kPostProcessing { + 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()), - SingleProcessing(RemoveExplicitPropertyType()), - SingleProcessing(RemoveRedundantNullability()), + RemoveExplicitPropertyType(), + RemoveRedundantNullability(), registerGeneralInspectionBasedProcessing(CanBeValInspection(ignoreNotUsedVals = false)), @@ -142,7 +142,6 @@ object NewJ2KPostProcessingRegistrar { ) as KtReturnExpression).returnedExpression.isTrivialStatementBody() }, - registerInspectionBasedProcessing(IfThenToSafeAccessInspection()), registerInspectionBasedProcessing(IfThenToSafeAccessInspection()), registerIntentionBasedProcessing(IfThenToElvisIntention()), @@ -170,8 +169,8 @@ object NewJ2KPostProcessingRegistrar { action.invoke(element.project, null, element.containingKtFile) }, - SingleProcessing(RemoveRedundantTypeQualifierProcessing()), - SingleProcessing(RemoveRedundantExpressionQualifierProcessing()), + RemoveRedundantTypeQualifierProcessing(), + RemoveRedundantExpressionQualifierProcessing(), registerDiagnosticBasedProcessing(Errors.USELESS_CAST) { element, _ -> val expression = RemoveUselessCastFix.invoke(element) @@ -215,7 +214,7 @@ object NewJ2KPostProcessingRegistrar { }, 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 -> val property = element.mainReference.resolve() as? KtProperty if (property == null) { @@ -253,7 +252,7 @@ object NewJ2KPostProcessingRegistrar { private inline fun > registerIntentionBasedProcessing( intention: TIntention, noinline additionalChecker: (TElement) -> Boolean = { true } - ) = SingleProcessing(object : NewJ2kPostProcessing { + ) = object : NewJ2kPostProcessing { // Intention can either need or not need write action override val writeActionNeeded = intention.startInWriteAction() @@ -269,13 +268,12 @@ object NewJ2KPostProcessingRegistrar { } } } - ) private inline fun registerGeneralInspectionBasedProcessing( inspection: TInspection, acceptInformationLevel: Boolean = false - ) = SingleProcessing(object : NewJ2kPostProcessing { + ) = (object : NewJ2kPostProcessing { override val writeActionNeeded = false fun QuickFix.applyFixSmart(project: Project, descriptor: D) { @@ -347,7 +345,7 @@ object NewJ2KPostProcessingRegistrar { inspection: TInspection, acceptInformationLevel: Boolean = false - ) = SingleProcessing(object : NewJ2kPostProcessing { + ) = object : NewJ2kPostProcessing { // Inspection can either need or not need write action override val writeActionNeeded = inspection.startFixInWriteAction @@ -366,27 +364,28 @@ object NewJ2KPostProcessingRegistrar { } } } - }) + } private inline fun registerDiagnosticBasedProcessing( vararg diagnosticFactory: DiagnosticFactory<*>, crossinline fix: (TElement, Diagnostic) -> Unit - ) = registerDiagnosticBasedProcessingFactory(*diagnosticFactory) { element: TElement, diagnostic: Diagnostic -> - { - fix( - element, - diagnostic - ) + ) = object : NewJ2kPostProcessing { + 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 { + fix(element as TElement, diagnostic) + } } } - private inline fun registerDiagnosticBasedProcessingFactory( vararg diagnosticFactory: DiagnosticFactory<*>, crossinline fixFactory: (TElement, Diagnostic) -> (() -> Unit)? - ) = SingleProcessing(object : NewJ2kPostProcessing { - // ??? + ) = object : NewJ2kPostProcessing { override val writeActionNeeded = true 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 return fixFactory(element as TElement, diagnostic) } - }) + } private class RemoveExplicitPropertyType : NewJ2kPostProcessing {