New J2K: Add repeatable post processing groups
This commit is contained in:
committed by
Ilya Kirillov
parent
c827247272
commit
9c71d5ca25
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user