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.
*/
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<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?) {
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
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) {
@@ -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>) : Processing {
data class SingleOneTimeProcessing(val processing: NewJ2kPostProcessing) : 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())
}
@@ -74,8 +76,9 @@ object NewJ2KPostProcessingRegistrar {
private fun Processing.processings(): Sequence<NewJ2kPostProcessing> =
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<KtBinaryExpressionWithTypeRHS>(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 <reified TElement : KtElement, TIntention : SelfTargetingRangeIntention<TElement>> 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 <TInspection : AbstractKotlinInspection> registerGeneralInspectionBasedProcessing(
inspection: TInspection,
acceptInformationLevel: Boolean = false
) = SingleProcessing(object : NewJ2kPostProcessing {
) = (object : NewJ2kPostProcessing {
override val writeActionNeeded = false
fun <D : CommonProblemDescriptor> QuickFix<D>.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 <reified TElement : KtElement> 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 <reified TElement : KtElement> 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 {