From 74ba5b210ac3ddde0fee8daa053e877b7c9a53c4 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 18 Sep 2019 20:26:09 +0300 Subject: [PATCH] New J2K: do not analyze code for post-processings in edt thread --- .../nj2k/inference/common/InferenceFacade.kt | 17 +- .../nj2k/postProcessing/J2kPostProcessor.kt | 80 ++++----- .../diagnosticBasedPostProcessing.kt | 25 ++- .../inspectionLikePostProcessings.kt | 160 ++++++++---------- .../nj2k/postProcessing/postProcessings.kt | 37 +--- ...rtGettersAndSettersToPropertyProcessing.kt | 21 ++- .../ConvertToDataClassProcessing.kt | 35 ++-- .../processings/InferenceProcessing.kt | 12 +- .../processings/ShortenReferenceProcessing.kt | 31 ++-- .../processings/inspeсtionLikeProcessings.kt | 78 +++++---- .../postProcessing/processings/processings.kt | 85 +++++----- .../kotlin/nj2k/postProcessing/utils.kt | 17 +- .../MethodResultComparedWithNull2.kt | 4 +- .../MethodResultComparedWithNull3.kt | 4 +- .../MethodResultComparedWithNull4.kt | 4 +- .../nullability/ParameterComparedWithNull.kt | 4 +- .../nullability/VariableComparedWithNull.kt | 6 +- .../newJ2k/postProcessing/GetOperator.kt | 2 +- 18 files changed, 289 insertions(+), 333 deletions(-) diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/InferenceFacade.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/InferenceFacade.kt index ce99c1585b6..c779a64ce4c 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/InferenceFacade.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/inference/common/InferenceFacade.kt @@ -5,7 +5,8 @@ package org.jetbrains.kotlin.nj2k.inference.common -import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.kotlin.nj2k.postProcessing.runUndoTransparentActionInEdt import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtPsiFactory @@ -19,15 +20,19 @@ class InferenceFacade( private val printDebugConstraints: Boolean = false ) { fun runOn(elements: List) { - val inferenceContext = typeVariablesCollector.collectTypeVariables(elements) - val constraints = constraintsCollectorAggregator.collectConstraints(boundTypeCalculator, inferenceContext, elements) + val inferenceContext = runReadAction { typeVariablesCollector.collectTypeVariables(elements) } + val constraints = runReadAction { + constraintsCollectorAggregator.collectConstraints(boundTypeCalculator, inferenceContext, elements) + } val initialConstraints = if (renderDebugTypes) constraints.map { it.copy() } else null - Solver(inferenceContext, printDebugConstraints, defaultStateProvider).solveConstraints(constraints) + runReadAction { + Solver(inferenceContext, printDebugConstraints, defaultStateProvider).solveConstraints(constraints) + } if (renderDebugTypes) { with(DebugPrinter(inferenceContext)) { - runWriteAction { + runUndoTransparentActionInEdt(inWriteAction = true) { for ((expression, boundType) in boundTypeCalculator.expressionsWithBoundType()) { val comment = KtPsiFactory(expression.project).createComment("/*${boundType.asString()}*/") expression.parent.addAfter(comment, expression) @@ -46,7 +51,7 @@ class InferenceFacade( } } } - runWriteAction { + runUndoTransparentActionInEdt(inWriteAction = true) { stateUpdater.updateStates(inferenceContext) } } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/J2kPostProcessor.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/J2kPostProcessor.kt index 8ca6dca9235..d0d96746458 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/J2kPostProcessor.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/J2kPostProcessor.kt @@ -5,17 +5,11 @@ package org.jetbrains.kotlin.nj2k.postProcessing -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.ModalityState -import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.editor.RangeMarker import com.intellij.openapi.progress.ProcessCanceledException -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withContext import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference -import org.jetbrains.kotlin.idea.core.util.EDT import org.jetbrains.kotlin.idea.formatter.commitAndUnblockDocument import org.jetbrains.kotlin.idea.inspections.* import org.jetbrains.kotlin.idea.inspections.branchedTransformations.IfThenToElvisInspection @@ -27,7 +21,6 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.F import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isTrivialStatementBody import org.jetbrains.kotlin.idea.quickfix.* import org.jetbrains.kotlin.idea.util.ImportInsertHelper -import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.j2k.ConverterContext import org.jetbrains.kotlin.j2k.PostProcessor import org.jetbrains.kotlin.lexer.KtTokens @@ -41,11 +34,9 @@ class NewJ2kPostProcessor : PostProcessor { private val LOG = Logger.getInstance("@org.jetbrains.kotlin.nj2k.postProcessing.NewJ2kPostProcessor") override fun insertImport(file: KtFile, fqName: FqName) { - ApplicationManager.getApplication().invokeAndWait { - runWriteAction { - val descriptors = file.resolveImportReference(fqName) - descriptors.firstOrNull()?.let { ImportInsertHelper.getInstance(file.project).importDescriptor(file, it) } - } + runUndoTransparentActionInEdt(inWriteAction = true) { + val descriptors = file.resolveImportReference(fqName) + descriptors.firstOrNull()?.let { ImportInsertHelper.getInstance(file.project).importDescriptor(file, it) } } } @@ -57,31 +48,25 @@ class NewJ2kPostProcessor : PostProcessor { rangeMarker: RangeMarker?, onPhaseChanged: ((Int, String) -> Unit)? ) { - runBlocking(EDT.ModalityStateElement(ModalityState.defaultModalityState())) { - for ((i, group) in processings.withIndex()) { - onPhaseChanged?.invoke(i + 1, group.description) - for (processing in group.processings) { - try { - processing.runProcessing(file, rangeMarker, converterContext as NewJ2kConverterContext) - } catch (e: ProcessCanceledException) { - throw e - } catch (t: Throwable) { - LOG.error(t) - } finally { - commitFile(file) - } + for ((i, group) in processings.withIndex()) { + onPhaseChanged?.invoke(i + 1, group.description) + for (processing in group.processings) { + try { + processing.runProcessing(file, rangeMarker, converterContext as NewJ2kConverterContext) + } catch (e: ProcessCanceledException) { + throw e + } catch (t: Throwable) { + LOG.error(t) + } finally { + commitFile(file) } } } } - private suspend fun commitFile(file: KtFile) { - withContext(EDT) { - CommandProcessor.getInstance().runUndoTransparentAction { - runWriteAction { - file.commitAndUnblockDocument() - } - } + private fun commitFile(file: KtFile) { + runUndoTransparentActionInEdt(inWriteAction = true) { + file.commitAndUnblockDocument() } } } @@ -151,7 +136,7 @@ private val addOrRemoveModifiersProcessingGroup = processings = listOf( RemoveRedundantVisibilityModifierProcessing(), RemoveRedundantModalityModifierProcessing(), - inspectionBasedProcessing(AddOperatorModifierInspection()), + inspectionBasedProcessing(AddOperatorModifierInspection(), writeActionNeeded = false), RemoveExplicitUnitTypeProcessing() ) ) @@ -183,24 +168,24 @@ private val inspectionLikePostProcessingGroup = RemoveRedundantConstructorKeywordProcessing(), RemoveExplicitOpenInInterfaceProcessing(), RemoveRedundantOverrideVisibilityProcessing(), - inspectionBasedProcessing(MoveLambdaOutsideParenthesesInspection()), - intentionBasedProcessing(ConvertToStringTemplateIntention()) { + MoveLambdaOutsideParenthesesProcessing(), + intentionBasedProcessing(ConvertToStringTemplateIntention(), writeActionNeeded = false) { ConvertToStringTemplateIntention.shouldSuggestToConvert(it) }, - intentionBasedProcessing(UsePropertyAccessSyntaxIntention()), + intentionBasedProcessing(UsePropertyAccessSyntaxIntention(), writeActionNeeded = false), UninitializedVariableReferenceFromInitializerToThisReferenceProcessing(), UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing(), RemoveRedundantSamAdaptersProcessing(), RemoveRedundantCastToNullableProcessing(), inspectionBasedProcessing(ReplacePutWithAssignmentInspection()), - UseExpressionBodyProcessing(), - inspectionBasedProcessing(UnnecessaryVariableInspection()), + ReplaceGetterBodyWithSingleReturnStatementWithExpressionBody(), + inspectionBasedProcessing(UnnecessaryVariableInspection(), writeActionNeeded = false), RedundantExplicitTypeInspectionBasedProcessing(), JavaObjectEqualsToEqOperatorProcessing(), RemoveExplicitPropertyTypeProcessing(), RemoveRedundantNullabilityProcessing(), CanBeValInspectionBasedProcessing(), - inspectionBasedProcessing(FoldInitializerAndIfToElvisInspection()), + inspectionBasedProcessing(FoldInitializerAndIfToElvisInspection(), writeActionNeeded = false), intentionBasedProcessing(RemoveRedundantCallsOfConversionMethodsIntention()), inspectionBasedProcessing(JavaMapForEachInspection()), intentionBasedProcessing(FoldIfToReturnIntention()) { it.then.isTrivialStatementBody() && it.`else`.isTrivialStatementBody() }, @@ -209,14 +194,13 @@ private val inspectionLikePostProcessingGroup = it ) as KtReturnExpression).returnedExpression.isTrivialStatementBody() }, - inspectionBasedProcessing(IfThenToSafeAccessInspection()), - inspectionBasedProcessing(IfThenToElvisInspection(highlightStatement = true)), + inspectionBasedProcessing(IfThenToSafeAccessInspection(), writeActionNeeded = false), + inspectionBasedProcessing(IfThenToElvisInspection(highlightStatement = true), writeActionNeeded = false), inspectionBasedProcessing(SimplifyNegatedBinaryExpressionInspection()), inspectionBasedProcessing(ReplaceGetOrSetInspection()), - intentionBasedProcessing(ObjectLiteralToLambdaIntention()), - intentionBasedProcessing(AnonymousFunctionToLambdaIntention()), + intentionBasedProcessing(ObjectLiteralToLambdaIntention(), writeActionNeeded = true), intentionBasedProcessing(RemoveUnnecessaryParenthesesIntention()), - intentionBasedProcessing(DestructureIntention()), + intentionBasedProcessing(DestructureIntention(), writeActionNeeded = false), inspectionBasedProcessing(SimplifyAssertNotNullInspection()), intentionBasedProcessing(RemoveRedundantCallsOfConversionMethodsIntention()), LiftReturnInspectionBasedProcessing(), @@ -250,12 +234,12 @@ private val processings: List = listOf( ), NullabilityInferenceProcessing(), MutabilityInferenceProcessing(), - clearUnknownLabelsProcessing + ClearUnknownLabelsProcessing() ) ), NamedPostProcessingGroup( "Formatting code", - listOf(formatCodeProcessing) + listOf(FormatCodeProcessing()) ), NamedPostProcessingGroup( "Shortening fully-qualified references", @@ -288,12 +272,12 @@ private val processings: List = listOf( NamedPostProcessingGroup( "Optimizing imports", listOf( - optimizeImportsProcessing, + OptimizeImportsProcessing(), ShortenReferenceProcessing() ) ), NamedPostProcessingGroup( "Formatting code", - listOf(formatCodeProcessing) + listOf(FormatCodeProcessing()) ) ) \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/diagnosticBasedPostProcessing.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/diagnosticBasedPostProcessing.kt index 831d3d5022f..5d4c3fdb129 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/diagnosticBasedPostProcessing.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/diagnosticBasedPostProcessing.kt @@ -6,19 +6,16 @@ package org.jetbrains.kotlin.nj2k.postProcessing import com.intellij.codeInsight.intention.IntentionAction -import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.editor.RangeMarker import com.intellij.psi.PsiElement -import kotlinx.coroutines.withContext import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticFactory import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade -import org.jetbrains.kotlin.idea.core.util.EDT import org.jetbrains.kotlin.idea.core.util.range import org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory -import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile @@ -36,17 +33,15 @@ class DiagnosticBasedPostProcessingGroup(diagnosticBasedProcessings: List - if (diagnostic.psiElement.isValid) { - runWriteAction { fix(diagnostic) } - } + override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { + val diagnostics = runReadAction { analyzeFileRange(file, rangeMarker).all() } + runUndoTransparentActionInEdt(inWriteAction = true) { + for (diagnostic in diagnostics) { + val range = rangeMarker?.range ?: file.textRange + if (diagnostic.psiElement.isInRange(range)) { + diagnosticToFix[diagnostic.factory]?.forEach { fix -> + if (diagnostic.psiElement.isValid) { + fix(diagnostic) } } } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/inspectionLikePostProcessings.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/inspectionLikePostProcessings.kt index 8158cc05025..522ef768e99 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/inspectionLikePostProcessings.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/inspectionLikePostProcessings.kt @@ -5,29 +5,19 @@ package org.jetbrains.kotlin.nj2k.postProcessing -import com.intellij.codeInspection.* -import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.editor.RangeMarker import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import com.intellij.psi.PsiRecursiveElementVisitor -import kotlinx.coroutines.withContext -import org.jetbrains.kotlin.idea.core.util.EDT import org.jetbrains.kotlin.idea.inspections.AbstractApplicabilityBasedInspection -import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection -import org.jetbrains.kotlin.idea.intentions.SelfTargetingIntention import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention -import org.jetbrains.kotlin.idea.quickfix.QuickFixActionBase import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.j2k.ConverterSettings import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtVisitorVoid -import org.jetbrains.kotlin.psi.psiUtil.endOffset -import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.utils.mapToIndex import java.util.* import kotlin.reflect.KClass @@ -39,7 +29,6 @@ class InspectionLikeProcessingGroup( private val acceptNonKtElements: Boolean = false, private val processings: List ) : ProcessingGroup { - constructor(vararg processings: InspectionLikeProcessing) : this( runSingleTime = false, acceptNonKtElements = false, @@ -49,49 +38,45 @@ class InspectionLikeProcessingGroup( private val processingsToPriorityMap = processings.mapToIndex() fun priority(processing: InspectionLikeProcessing): Int = processingsToPriorityMap.getValue(processing) - override suspend fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { + override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { do { var modificationStamp: Long? = file.modificationStamp val elementToActions = runReadAction { collectAvailableActions(file, converterContext, rangeMarker) } - withContext(EDT) { - CommandProcessor.getInstance().runUndoTransparentAction { - for ((element, action, _, writeActionNeeded) in elementToActions) { - if (element.isValid) { - if (writeActionNeeded) { - runWriteAction { - action() - } - } else { - action() - } - } else { - modificationStamp = null - } - } + + for ((processing, element, _) in elementToActions) { + val needRun = runReadAction { + element.isValid && processing.isApplicableToElement(element, converterContext.converter.settings) + } + if (needRun) runUndoTransparentActionInEdt(inWriteAction = processing.writeActionNeeded) { + processing.applyToElement(element) + } else { + modificationStamp = null } } if (runSingleTime) break } while (modificationStamp != file.modificationStamp && elementToActions.isNotEmpty()) } - private enum class RangeFilterResult { SKIP, GO_INSIDE, PROCESS } - - private data class ActionData(val element: PsiElement, val action: () -> Unit, val priority: Int, val writeActionNeeded: Boolean) + private data class ProcessingData( + val processing: InspectionLikeProcessing, + val element: PsiElement, + val priority: Int + ) private fun collectAvailableActions( file: KtFile, context: NewJ2kConverterContext, rangeMarker: RangeMarker? - ): List { - val availableActions = ArrayList() + ): List { + val availableActions = ArrayList() file.accept(object : PsiRecursiveElementVisitor() { override fun visitElement(element: PsiElement) { @@ -102,15 +87,10 @@ class InspectionLikeProcessingGroup( super.visitElement(element) if (rangeResult == RangeFilterResult.PROCESS) { - processings.forEach { processing -> - val action = processing.createAction(element, context.converter.settings) - if (action != null) { + for (processing in processings) { + if (processing.isApplicableToElement(element, context.converter.settings)) { availableActions.add( - ActionData( - element, action, - priority(processing), - processing.writeActionNeeded - ) + ProcessingData(processing, element, priority(processing)) ) } } @@ -136,71 +116,63 @@ class InspectionLikeProcessingGroup( } } -interface InspectionLikeProcessing { - fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? +abstract class InspectionLikeProcessing { + abstract fun isApplicableToElement(element: PsiElement, settings: ConverterSettings?): Boolean + abstract fun applyToElement(element: PsiElement) - val writeActionNeeded: Boolean + // Some post-processings may need to do some resolving operations when applying + // Running it in outer write action may lead to UI freezes + // So we let that post-processings to handle write actions by themselves + open val writeActionNeeded = true } -abstract class ApplicabilityBasedInspectionLikeProcessing(private val classTag: KClass) : InspectionLikeProcessing { +abstract class InspectionLikeProcessingForElement(private val classTag: KClass) : InspectionLikeProcessing() { protected abstract fun isApplicableTo(element: E, settings: ConverterSettings?): Boolean protected abstract fun apply(element: E) - final override fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? { - if (!element::class.isSubclassOf(classTag)) return null - @Suppress("UNCHECKED_CAST") - if (!isApplicableTo(element as E, settings)) return null - return { - if (element.isValid && isApplicableTo(element, settings)) { - apply(element) - } - } + + @Suppress("UNCHECKED_CAST") + final override fun isApplicableToElement(element: PsiElement, settings: ConverterSettings?): Boolean { + if (!element::class.isSubclassOf(classTag)) return false + if (!element.isValid) return false + @Suppress("UNCHECKED_CAST") return isApplicableTo(element as E, settings) } - final override val writeActionNeeded: Boolean = true -} - - -inline fun > intentionBasedProcessing( - intention: TIntention, - noinline additionalChecker: (TElement) -> Boolean = { true } -) = object : InspectionLikeProcessing { - // Intention can either need or not need write apply - override val writeActionNeeded = intention.startInWriteAction() - - override fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? { - if (!TElement::class.java.isInstance(element)) return null - val tElement = element as TElement - if (intention.applicabilityRange(tElement) == null) return null - if (!additionalChecker(tElement)) return null - return { - if (intention.applicabilityRange(tElement) != null) { // isApplicableTo availability of the intention again because something could change - intention.applyTo(element, null) - } - } + final override fun applyToElement(element: PsiElement) { + if (!element::class.isSubclassOf(classTag)) return + if (!element.isValid) return + @Suppress("UNCHECKED_CAST") apply(element as E) } } -inline fun > - inspectionBasedProcessing(inspection: TInspection, acceptInformationLevel: Boolean = false) = - object : InspectionLikeProcessing { - // Inspection can either need or not need write apply - override val writeActionNeeded = inspection.startFixInWriteAction +inline fun > intentionBasedProcessing( + intention: I, + writeActionNeeded: Boolean = true, + noinline additionalChecker: (E) -> Boolean = { true } +) = object : InspectionLikeProcessingForElement(E::class) { + override fun isApplicableTo(element: E, settings: ConverterSettings?): Boolean = + intention.applicabilityRange(element) != null + && additionalChecker(element) - fun isApplicable(element: TElement): Boolean { - if (!inspection.isApplicable(element)) return false - return acceptInformationLevel || inspection.inspectionHighlightType(element) != ProblemHighlightType.INFORMATION - } - - override fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? { - if (!TElement::class.java.isInstance(element)) return null - val tElement = element as TElement - if (!isApplicable(tElement)) return null - return { - if (isApplicable(tElement)) { // isApplicableTo availability of the inspection again because something could change - inspection.applyTo(tElement) - } - } - } + override fun apply(element: E) { + intention.applyTo(element, null) } + + override val writeActionNeeded = writeActionNeeded +} + + +inline fun > inspectionBasedProcessing( + inspection: I, + writeActionNeeded: Boolean = true +) = object : InspectionLikeProcessingForElement(E::class) { + override fun isApplicableTo(element: E, settings: ConverterSettings?): Boolean = + inspection.isApplicable(element) + + override fun apply(element: E) { + inspection.applyTo(element) + } + + override val writeActionNeeded = writeActionNeeded +} diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/postProcessings.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/postProcessings.kt index a1c323eca51..eff0ea13ce1 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/postProcessings.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/postProcessings.kt @@ -5,43 +5,28 @@ package org.jetbrains.kotlin.nj2k.postProcessing -import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.editor.RangeMarker import com.intellij.psi.PsiElement -import kotlinx.coroutines.withContext -import org.jetbrains.kotlin.idea.core.util.EDT import org.jetbrains.kotlin.idea.core.util.range -import org.jetbrains.kotlin.idea.util.application.runWriteAction +import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.psiUtil.elementsInRange interface GeneralPostProcessing { - suspend fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) + fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) } -abstract class SimplePostProcessing() : GeneralPostProcessing { - final override suspend fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { - withContext(EDT) { - CommandProcessor.getInstance().runUndoTransparentAction { - runWriteAction { - applySimpleProcessing(file, rangeMarker, converterContext) - } - } - } - } - abstract fun applySimpleProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) -} - -abstract class ElementsBasedPostProcessing() : SimplePostProcessing() { - final override fun applySimpleProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { - val elements = +abstract class ElementsBasedPostProcessing : GeneralPostProcessing { + final override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { + val elements = runReadAction { rangeMarker?.let { marker -> val range = marker.range ?: return@let emptyList() file.elementsInRange(range) } ?: listOf(file) + } runProcessing(elements, converterContext) } @@ -54,13 +39,3 @@ data class NamedPostProcessingGroup( val description: String, val processings: List ) - -fun postProcessing( - action: (file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) -> Unit -): GeneralPostProcessing = - object : SimplePostProcessing() { - override fun applySimpleProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { - action(file, rangeMarker, converterContext) - } - } - diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertGettersAndSettersToPropertyProcessing.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertGettersAndSettersToPropertyProcessing.kt index 49b593aec12..76eff2bdd13 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertGettersAndSettersToPropertyProcessing.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertGettersAndSettersToPropertyProcessing.kt @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.readWriteAccess import org.jetbrains.kotlin.idea.util.CommentSaver import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers -import org.jetbrains.kotlin.j2k.getContainingClass +import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext @@ -272,15 +272,20 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing override fun runProcessing(elements: List, converterContext: NewJ2kConverterContext) { - val classes = elements - .descendantsOfType() - .sortedByInheritance() val collectingState = CollectingState() - val classesWithPropertiesData = classes.map { klass -> - klass to klass.collectPropertiesData(collectingState) + val classesWithPropertiesData = runReadAction { + elements + .descendantsOfType() + .sortedByInheritance() + .map { klass -> + klass to klass.collectPropertiesData(collectingState) + } } - for ((klass, propertiesData) in classesWithPropertiesData) { - convertClass(klass, propertiesData) + if (classesWithPropertiesData.isEmpty()) return + runUndoTransparentActionInEdt(inWriteAction = true) { + for ((klass, propertiesData) in classesWithPropertiesData) { + convertClass(klass, propertiesData) + } } } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertToDataClassProcessing.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertToDataClassProcessing.kt index 62f5f002583..e3ba52b6ccf 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertToDataClassProcessing.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ConvertToDataClassProcessing.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.idea.core.setVisibility import org.jetbrains.kotlin.idea.intentions.addUseSiteTarget import org.jetbrains.kotlin.idea.util.CommentSaver +import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.nj2k.escaped import org.jetbrains.kotlin.nj2k.postProcessing.* @@ -122,24 +123,28 @@ class ConvertToDataClassProcessing : ElementsBasedPostProcessing() { } private fun convertClass(klass: KtClass) { - for (initialization in collectInitializations(klass)) { - val statementCommentSaver = CommentSaver(initialization.statement, saveLineBreaks = true) - val restoreStatementCommentsTarget: KtExpression - when (initialization) { - is ConstructorParameterInitialization -> { - initialization.mergePropertyAndConstructorParameter() - restoreStatementCommentsTarget = initialization.initializer - } - is LiteralInitialization -> { - val (property, initializer, _) = initialization - property.initializer = initializer - restoreStatementCommentsTarget = property + val initialisations = runReadAction { collectInitializations(klass) } + if (initialisations.isEmpty()) return + runUndoTransparentActionInEdt(inWriteAction = true) { + for (initialization in initialisations) { + val statementCommentSaver = CommentSaver(initialization.statement, saveLineBreaks = true) + val restoreStatementCommentsTarget: KtExpression + when (initialization) { + is ConstructorParameterInitialization -> { + initialization.mergePropertyAndConstructorParameter() + restoreStatementCommentsTarget = initialization.initializer + } + is LiteralInitialization -> { + val (property, initializer, _) = initialization + property.initializer = initializer + restoreStatementCommentsTarget = property + } } + initialization.statement.delete() + statementCommentSaver.restore(restoreStatementCommentsTarget, forceAdjustIndent = false) } - initialization.statement.delete() - statementCommentSaver.restore(restoreStatementCommentsTarget, forceAdjustIndent = false) + klass.removeEmptyInitBlocks() } - klass.removeEmptyInitBlocks() } } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/InferenceProcessing.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/InferenceProcessing.kt index 11308411677..fb61ae7c69c 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/InferenceProcessing.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/InferenceProcessing.kt @@ -5,11 +5,8 @@ package org.jetbrains.kotlin.nj2k.postProcessing.processings -import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.editor.RangeMarker -import kotlinx.coroutines.withContext import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade -import org.jetbrains.kotlin.idea.core.util.EDT import org.jetbrains.kotlin.idea.core.util.range import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.util.application.runReadAction @@ -29,18 +26,13 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.psiUtil.elementsInRange abstract class InferenceProcessing : GeneralPostProcessing { - final override suspend fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { + final override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { val elements = if (rangeMarker != null) { val range = rangeMarker.range ?: return runReadAction { file.elementsInRange(range) }.filterIsInstance() } else listOf(file) val resolutionFacade = runReadAction { file.getResolutionFacade() } - - withContext(EDT) { - CommandProcessor.getInstance().runUndoTransparentAction { - createInferenceFacade(resolutionFacade, converterContext).runOn(elements) - } - } + createInferenceFacade(resolutionFacade, converterContext).runOn(elements) } abstract fun createInferenceFacade( diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ShortenReferenceProcessing.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ShortenReferenceProcessing.kt index d7019f48050..fcf57ba031f 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ShortenReferenceProcessing.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/ShortenReferenceProcessing.kt @@ -8,34 +8,33 @@ package org.jetbrains.kotlin.nj2k.postProcessing.processings import com.intellij.openapi.editor.RangeMarker import com.intellij.psi.PsiElement import org.jetbrains.kotlin.idea.core.ShortenReferences -import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName -import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.nj2k.ImportStorage import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext -import org.jetbrains.kotlin.nj2k.postProcessing.SimplePostProcessing +import org.jetbrains.kotlin.nj2k.postProcessing.GeneralPostProcessing +import org.jetbrains.kotlin.nj2k.postProcessing.runUndoTransparentActionInEdt import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtQualifiedExpression -class ShortenReferenceProcessing : SimplePostProcessing() { +class ShortenReferenceProcessing : GeneralPostProcessing { private val filter = filter@{ element: PsiElement -> when (element) { - is KtQualifiedExpression -> { - val fqName = element.selectorExpression?.mainReference?.resolve()?.getKotlinFqName() - ?: return@filter ShortenReferences.FilterResult.PROCESS - if (ImportStorage.isImportNeeded(fqName)) ShortenReferences.FilterResult.PROCESS - else ShortenReferences.FilterResult.SKIP + is KtQualifiedExpression -> when { + ImportStorage.isImportNeededForCall(element) -> ShortenReferences.FilterResult.PROCESS + else -> ShortenReferences.FilterResult.SKIP } else -> ShortenReferences.FilterResult.PROCESS } } - override fun applySimpleProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { - if (rangeMarker != null) { - if (rangeMarker.isValid) { - ShortenReferences.DEFAULT.process(file, rangeMarker.startOffset, rangeMarker.endOffset, filter) + override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { + runUndoTransparentActionInEdt(inWriteAction = false) { + if (rangeMarker != null) { + if (rangeMarker.isValid) { + ShortenReferences.DEFAULT.process(file, rangeMarker.startOffset, rangeMarker.endOffset, filter) + } + } else { + ShortenReferences.DEFAULT.process(file, filter) } - } else { - ShortenReferences.DEFAULT.process(file, filter) } } -} \ No newline at end of file +} diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/inspeсtionLikeProcessings.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/inspeсtionLikeProcessings.kt index a17a4c31969..57312fa8fb5 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/inspeсtionLikeProcessings.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/inspeсtionLikeProcessings.kt @@ -13,10 +13,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.idea.analysis.analyzeInContext import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny -import org.jetbrains.kotlin.idea.core.implicitModality -import org.jetbrains.kotlin.idea.core.implicitVisibility -import org.jetbrains.kotlin.idea.core.replaced -import org.jetbrains.kotlin.idea.core.setVisibility +import org.jetbrains.kotlin.idea.core.* import org.jetbrains.kotlin.idea.debugger.sequence.psi.callName import org.jetbrains.kotlin.idea.inspections.* import org.jetbrains.kotlin.idea.inspections.collections.isCalling @@ -32,7 +29,7 @@ import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.j2k.ConverterSettings import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.nj2k.postProcessing.ApplicabilityBasedInspectionLikeProcessing +import org.jetbrains.kotlin.nj2k.postProcessing.InspectionLikeProcessingForElement import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.resolve.BindingContext @@ -42,7 +39,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.safeAs -class RemoveExplicitPropertyTypeProcessing : ApplicabilityBasedInspectionLikeProcessing(KtProperty::class) { +class RemoveExplicitPropertyTypeProcessing : InspectionLikeProcessingForElement(KtProperty::class) { override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean { val needFieldTypes = settings?.specifyFieldTypeByDefault == true val needLocalVariablesTypes = settings?.specifyLocalVariableTypeByDefault == true @@ -61,7 +58,7 @@ class RemoveExplicitPropertyTypeProcessing : ApplicabilityBasedInspectionLikePro } } -class RemoveRedundantNullabilityProcessing : ApplicabilityBasedInspectionLikeProcessing(KtProperty::class) { +class RemoveRedundantNullabilityProcessing : InspectionLikeProcessingForElement(KtProperty::class) { override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean { if (!element.isLocal) return false val typeReference = element.typeReference @@ -87,7 +84,7 @@ class RemoveRedundantNullabilityProcessing : ApplicabilityBasedInspectionLikePro } } -class RemoveExplicitTypeArgumentsProcessing : ApplicabilityBasedInspectionLikeProcessing(KtTypeArgumentList::class) { +class RemoveExplicitTypeArgumentsProcessing : InspectionLikeProcessingForElement(KtTypeArgumentList::class) { override fun isApplicableTo(element: KtTypeArgumentList, settings: ConverterSettings?): Boolean = RemoveExplicitTypeArgumentsIntention.isApplicableTo(element, approximateFlexible = true) @@ -99,7 +96,7 @@ class RemoveExplicitTypeArgumentsProcessing : ApplicabilityBasedInspectionLikePr // the types arguments for Stream.collect calls cannot be explicitly specified in Kotlin // but we need them in nullability inference, so we remove it here class RemoveJavaStreamsCollectCallTypeArgumentsProcessing : - ApplicabilityBasedInspectionLikeProcessing(KtCallExpression::class) { + InspectionLikeProcessingForElement(KtCallExpression::class) { override fun isApplicableTo(element: KtCallExpression, settings: ConverterSettings?): Boolean { if (element.typeArgumentList == null) return false if (element.callName() != COLLECT_FQ_NAME.shortName().identifier) return false @@ -117,7 +114,7 @@ class RemoveJavaStreamsCollectCallTypeArgumentsProcessing : class RemoveRedundantOverrideVisibilityProcessing : - ApplicabilityBasedInspectionLikeProcessing(KtCallableDeclaration::class) { + InspectionLikeProcessingForElement(KtCallableDeclaration::class) { override fun isApplicableTo(element: KtCallableDeclaration, settings: ConverterSettings?): Boolean { if (!element.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return false @@ -130,7 +127,7 @@ class RemoveRedundantOverrideVisibilityProcessing : } } -class UseExpressionBodyProcessing : ApplicabilityBasedInspectionLikeProcessing(KtPropertyAccessor::class) { +class UseExpressionBodyProcessing : InspectionLikeProcessingForElement(KtPropertyAccessor::class) { private val inspection = UseExpressionBodyInspection(convertEmptyToUnit = false) override fun isApplicableTo(element: KtPropertyAccessor, settings: ConverterSettings?): Boolean = inspection.isActiveFor(element) @@ -141,7 +138,7 @@ class UseExpressionBodyProcessing : ApplicabilityBasedInspectionLikeProcessing(KtBinaryExpressionWithTypeRHS::class) { + InspectionLikeProcessingForElement(KtBinaryExpressionWithTypeRHS::class) { override fun isApplicableTo(element: KtBinaryExpressionWithTypeRHS, settings: ConverterSettings?): Boolean { if (element.right?.typeElement !is KtNullableType) return false @@ -158,7 +155,7 @@ class RemoveRedundantCastToNullableProcessing : } class RemoveRedundantSamAdaptersProcessing : - ApplicabilityBasedInspectionLikeProcessing(KtCallExpression::class) { + InspectionLikeProcessingForElement(KtCallExpression::class) { override fun isApplicableTo(element: KtCallExpression, settings: ConverterSettings?): Boolean = RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element).isNotEmpty() @@ -171,7 +168,7 @@ class RemoveRedundantSamAdaptersProcessing : } class UninitializedVariableReferenceFromInitializerToThisReferenceProcessing : - ApplicabilityBasedInspectionLikeProcessing(KtSimpleNameExpression::class) { + InspectionLikeProcessingForElement(KtSimpleNameExpression::class) { override fun isApplicableTo(element: KtSimpleNameExpression, settings: ConverterSettings?): Boolean { val anonymousObject = element.getStrictParentOfType()?.takeIf { it.name == null } ?: return false @@ -192,7 +189,7 @@ class UninitializedVariableReferenceFromInitializerToThisReferenceProcessing : } class UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing : - ApplicabilityBasedInspectionLikeProcessing(KtSimpleNameExpression::class) { + InspectionLikeProcessingForElement(KtSimpleNameExpression::class) { override fun isApplicableTo(element: KtSimpleNameExpression, settings: ConverterSettings?): Boolean { val anonymousObject = element.getStrictParentOfType() ?: return false @@ -207,7 +204,7 @@ class UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing : } } -class VarToValProcessing : ApplicabilityBasedInspectionLikeProcessing(KtProperty::class) { +class VarToValProcessing : InspectionLikeProcessingForElement(KtProperty::class) { private fun KtProperty.hasWriteUsages(): Boolean = ReferencesSearch.search(this, useScope).any { usage -> (usage as? KtSimpleNameReference)?.element?.let { nameReference -> @@ -233,7 +230,7 @@ class VarToValProcessing : ApplicabilityBasedInspectionLikeProcessing(KtCallExpression::class) { +class JavaObjectEqualsToEqOperatorProcessing : InspectionLikeProcessingForElement(KtCallExpression::class) { companion object { val CALL_FQ_NAME = FqName("java.util.Objects.equals") } @@ -259,7 +256,7 @@ class JavaObjectEqualsToEqOperatorProcessing : ApplicabilityBasedInspectionLikeP class RemoveForExpressionLoopParameterTypeProcessing : - ApplicabilityBasedInspectionLikeProcessing(KtForExpression::class) { + InspectionLikeProcessingForElement(KtForExpression::class) { override fun isApplicableTo(element: KtForExpression, settings: ConverterSettings?): Boolean = element.loopParameter?.typeReference?.typeElement != null && settings?.specifyLocalVariableTypeByDefault != true @@ -270,7 +267,7 @@ class RemoveForExpressionLoopParameterTypeProcessing : } class RemoveRedundantConstructorKeywordProcessing : - ApplicabilityBasedInspectionLikeProcessing(KtPrimaryConstructor::class) { + InspectionLikeProcessingForElement(KtPrimaryConstructor::class) { override fun isApplicableTo(element: KtPrimaryConstructor, settings: ConverterSettings?): Boolean = element.containingClassOrObject is KtClass && element.getConstructorKeyword() != null @@ -283,7 +280,7 @@ class RemoveRedundantConstructorKeywordProcessing : } } -class RemoveRedundantModalityModifierProcessing : ApplicabilityBasedInspectionLikeProcessing(KtDeclaration::class) { +class RemoveRedundantModalityModifierProcessing : InspectionLikeProcessingForElement(KtDeclaration::class) { override fun isApplicableTo(element: KtDeclaration, settings: ConverterSettings?): Boolean { if (element.hasModifier(KtTokens.FINAL_KEYWORD)) { return !element.hasModifier(KtTokens.OVERRIDE_KEYWORD) @@ -298,7 +295,7 @@ class RemoveRedundantModalityModifierProcessing : ApplicabilityBasedInspectionLi } -class RemoveRedundantVisibilityModifierProcessing : ApplicabilityBasedInspectionLikeProcessing(KtDeclaration::class) { +class RemoveRedundantVisibilityModifierProcessing : InspectionLikeProcessingForElement(KtDeclaration::class) { override fun isApplicableTo(element: KtDeclaration, settings: ConverterSettings?) = when { element.hasModifier(KtTokens.PUBLIC_KEYWORD) && element.hasModifier(KtTokens.OVERRIDE_KEYWORD) -> false @@ -314,7 +311,7 @@ class RemoveRedundantVisibilityModifierProcessing : ApplicabilityBasedInspection } } -class RemoveExplicitOpenInInterfaceProcessing : ApplicabilityBasedInspectionLikeProcessing(KtClass::class) { +class RemoveExplicitOpenInInterfaceProcessing : InspectionLikeProcessingForElement(KtClass::class) { override fun isApplicableTo(element: KtClass, settings: ConverterSettings?): Boolean = element.isValid && element.isInterface() @@ -325,7 +322,7 @@ class RemoveExplicitOpenInInterfaceProcessing : ApplicabilityBasedInspectionLike } } -class MoveGetterAndSetterAnnotationsToPropertyProcessing : ApplicabilityBasedInspectionLikeProcessing(KtProperty::class) { +class MoveGetterAndSetterAnnotationsToPropertyProcessing : InspectionLikeProcessingForElement(KtProperty::class) { override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean = element.accessors.isNotEmpty() @@ -345,16 +342,17 @@ class MoveGetterAndSetterAnnotationsToPropertyProcessing : ApplicabilityBasedIns } } -class RedundantExplicitTypeInspectionBasedProcessing : ApplicabilityBasedInspectionLikeProcessing(KtProperty::class) { +class RedundantExplicitTypeInspectionBasedProcessing : InspectionLikeProcessingForElement(KtProperty::class) { override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean = RedundantExplicitTypeInspection.hasRedundantType(element) override fun apply(element: KtProperty) { + element.typeReference = null RemoveExplicitTypeIntention.removeExplicitType(element) } } -class CanBeValInspectionBasedProcessing : ApplicabilityBasedInspectionLikeProcessing(KtDeclaration::class) { +class CanBeValInspectionBasedProcessing : InspectionLikeProcessingForElement(KtDeclaration::class) { override fun isApplicableTo(element: KtDeclaration, settings: ConverterSettings?): Boolean = CanBeValInspection.canBeVal(element, ignoreNotUsedVals = false) @@ -365,7 +363,7 @@ class CanBeValInspectionBasedProcessing : ApplicabilityBasedInspectionLikeProces } -class MayBeConstantInspectionBasedProcessing : ApplicabilityBasedInspectionLikeProcessing(KtProperty::class) { +class MayBeConstantInspectionBasedProcessing : InspectionLikeProcessingForElement(KtProperty::class) { override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean = with(MayBeConstantInspection) { val status = element.getStatus() @@ -378,7 +376,7 @@ class MayBeConstantInspectionBasedProcessing : ApplicabilityBasedInspectionLikeP } } -class RemoveExplicitUnitTypeProcessing : ApplicabilityBasedInspectionLikeProcessing(KtNamedFunction::class) { +class RemoveExplicitUnitTypeProcessing : InspectionLikeProcessingForElement(KtNamedFunction::class) { override fun isApplicableTo(element: KtNamedFunction, settings: ConverterSettings?): Boolean { val typeReference = element.typeReference?.typeElement ?: return false if (!typeReference.textMatches("Unit")) return false @@ -386,13 +384,13 @@ class RemoveExplicitUnitTypeProcessing : ApplicabilityBasedInspectionLikeProcess } override fun apply(element: KtNamedFunction) { - RemoveExplicitTypeIntention.removeExplicitType(element) + element.typeReference = null } } class RemoveExplicitGetterInspectionBasedProcessing : - ApplicabilityBasedInspectionLikeProcessing(KtPropertyAccessor::class) { + InspectionLikeProcessingForElement(KtPropertyAccessor::class) { override fun isApplicableTo(element: KtPropertyAccessor, settings: ConverterSettings?): Boolean = element.isRedundantGetter() @@ -402,7 +400,7 @@ class RemoveExplicitGetterInspectionBasedProcessing : } class RemoveExplicitSetterInspectionBasedProcessing : - ApplicabilityBasedInspectionLikeProcessing(KtPropertyAccessor::class) { + InspectionLikeProcessingForElement(KtPropertyAccessor::class) { override fun isApplicableTo(element: KtPropertyAccessor, settings: ConverterSettings?): Boolean = element.isRedundantSetter() @@ -413,7 +411,7 @@ class RemoveExplicitSetterInspectionBasedProcessing : class RedundantSemicolonInspectionBasedProcessing : - ApplicabilityBasedInspectionLikeProcessing(PsiElement::class) { + InspectionLikeProcessingForElement(PsiElement::class) { override fun isApplicableTo(element: PsiElement, settings: ConverterSettings?): Boolean = element.node.elementType == KtTokens.SEMICOLON && RedundantSemicolonInspection.isRedundantSemicolon(element) @@ -425,7 +423,7 @@ class RedundantSemicolonInspectionBasedProcessing : class RedundantCompanionReferenceInspectionBasedProcessing : - ApplicabilityBasedInspectionLikeProcessing(KtReferenceExpression::class) { + InspectionLikeProcessingForElement(KtReferenceExpression::class) { override fun isApplicableTo(element: KtReferenceExpression, settings: ConverterSettings?): Boolean = RedundantCompanionReferenceInspection.isRedundantCompanionReference(element) @@ -435,7 +433,7 @@ class RedundantCompanionReferenceInspectionBasedProcessing : } class ExplicitThisInspectionBasedProcessing : - ApplicabilityBasedInspectionLikeProcessing(KtExpression::class) { + InspectionLikeProcessingForElement(KtExpression::class) { override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean = ExplicitThisInspection.hasExplicitThis(element) @@ -449,7 +447,7 @@ class ExplicitThisInspectionBasedProcessing : } class LiftReturnInspectionBasedProcessing : - ApplicabilityBasedInspectionLikeProcessing(KtExpression::class) { + InspectionLikeProcessingForElement(KtExpression::class) { override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean = LiftReturnOrAssignmentInspection.getState(element, false)?.any { it.liftType == LiftReturnOrAssignmentInspection.Companion.LiftType.LIFT_RETURN_OUT @@ -461,7 +459,7 @@ class LiftReturnInspectionBasedProcessing : } class LiftAssignmentInspectionBasedProcessing : - ApplicabilityBasedInspectionLikeProcessing(KtExpression::class) { + InspectionLikeProcessingForElement(KtExpression::class) { override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean = LiftReturnOrAssignmentInspection.getState(element, false)?.any { it.liftType == LiftReturnOrAssignmentInspection.Companion.LiftType.LIFT_ASSIGNMENT_OUT @@ -470,4 +468,14 @@ class LiftAssignmentInspectionBasedProcessing : override fun apply(element: KtExpression) { BranchedFoldingUtils.foldToAssignment(element) } +} + +class MoveLambdaOutsideParenthesesProcessing : + InspectionLikeProcessingForElement(KtCallExpression::class) { + override fun isApplicableTo(element: KtCallExpression, settings: ConverterSettings?): Boolean = + element.canMoveLambdaOutsideParentheses() + + override fun apply(element: KtCallExpression) { + element.moveFunctionLiteralOutsideParentheses() + } } \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/processings.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/processings.kt index 363cbb5f71f..d33e5f0ed8a 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/processings.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/processings/processings.kt @@ -6,58 +6,66 @@ package org.jetbrains.kotlin.nj2k.postProcessing.processings import com.intellij.codeInsight.actions.OptimizeImportsProcessor +import com.intellij.openapi.editor.RangeMarker import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement import com.intellij.psi.PsiElementVisitor import com.intellij.psi.codeStyle.CodeStyleManager import org.jetbrains.kotlin.idea.core.util.range -import org.jetbrains.kotlin.idea.formatter.commitAndUnblockDocument +import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.nj2k.asLabel -import org.jetbrains.kotlin.nj2k.postProcessing.postProcessing +import org.jetbrains.kotlin.nj2k.postProcessing.GeneralPostProcessing +import org.jetbrains.kotlin.nj2k.postProcessing.runUndoTransparentActionInEdt import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.elementsInRange -val formatCodeProcessing = - postProcessing { file, rangeMarker, _ -> - file.commitAndUnblockDocument() + +class FormatCodeProcessing : GeneralPostProcessing { + override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { val codeStyleManager = CodeStyleManager.getInstance(file.project) - if (rangeMarker != null) { - if (rangeMarker.isValid) { - codeStyleManager.reformatRange(file, rangeMarker.startOffset, rangeMarker.endOffset) - } - } else { - codeStyleManager.reformat(file) - } - } - -val clearUnknownLabelsProcessing = - postProcessing { file, _, _ -> - file.clearUndefinedLabels() - } - -private fun KtFile.clearUndefinedLabels() { - val comments = mutableListOf() - accept(object : PsiElementVisitor() { - override fun visitElement(element: PsiElement) { - element.acceptChildren(this) - } - - override fun visitComment(comment: PsiComment) { - if (comment.text.asLabel() != null) { - comments += comment + runUndoTransparentActionInEdt(inWriteAction = true) { + if (rangeMarker != null) { + if (rangeMarker.isValid) { + codeStyleManager.reformatRange(file, rangeMarker.startOffset, rangeMarker.endOffset) + } + } else { + codeStyleManager.reformat(file) } } - }) - comments.forEach { it.delete() } + } } -val optimizeImportsProcessing = - postProcessing { file, rangeMarker, _ -> - val elements = when { - rangeMarker != null && rangeMarker.isValid -> file.elementsInRange(rangeMarker.range!!) - rangeMarker != null && !rangeMarker.isValid -> emptyList() - else -> file.children.asList() +class ClearUnknownLabelsProcessing : GeneralPostProcessing { + override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { + val comments = mutableListOf() + runUndoTransparentActionInEdt(inWriteAction = true) { + file.accept(object : PsiElementVisitor() { + override fun visitElement(element: PsiElement) { + element.acceptChildren(this) + } + + override fun visitComment(comment: PsiComment) { + if (comment.text.asLabel() != null) { + comments += comment + } + } + }) + comments.forEach { it.delete() } + } + } +} + + +class OptimizeImportsProcessing : GeneralPostProcessing { + override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { + val elements = runReadAction { + when { + rangeMarker != null && rangeMarker.isValid -> file.elementsInRange(rangeMarker.range!!) + rangeMarker != null && !rangeMarker.isValid -> emptyList() + else -> file.children.asList() + } } val needFormat = elements.any { element -> element is KtElement @@ -65,7 +73,8 @@ val optimizeImportsProcessing = && element !is KtImportList && element !is KtPackageDirective } - if (needFormat) { + if (needFormat) runUndoTransparentActionInEdt(inWriteAction = false) { OptimizeImportsProcessor(file.project, file).run() } } +} diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/utils.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/utils.kt index 9f9d25b6bd5..adf7ed96831 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/utils.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/postProcessing/utils.kt @@ -5,6 +5,9 @@ package org.jetbrains.kotlin.nj2k.postProcessing +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import com.intellij.psi.search.LocalSearchScope @@ -79,4 +82,16 @@ inline fun List.descendantsOfType(): List Unit) { + ApplicationManager.getApplication().invokeAndWait { + CommandProcessor.getInstance().runUndoTransparentAction { + if (inWriteAction) { + runWriteAction(action) + } else { + action() + } + } + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/nullability/MethodResultComparedWithNull2.kt b/nj2k/testData/newJ2k/nullability/MethodResultComparedWithNull2.kt index b9bc29b02ec..030e81cd44f 100644 --- a/nj2k/testData/newJ2k/nullability/MethodResultComparedWithNull2.kt +++ b/nj2k/testData/newJ2k/nullability/MethodResultComparedWithNull2.kt @@ -5,8 +5,6 @@ internal interface I { internal class C { fun foo(i: I) { val result = i.string - if (result != null) { - print(result) - } + result?.let { print(it) } } } \ No newline at end of file diff --git a/nj2k/testData/newJ2k/nullability/MethodResultComparedWithNull3.kt b/nj2k/testData/newJ2k/nullability/MethodResultComparedWithNull3.kt index b9bc29b02ec..030e81cd44f 100644 --- a/nj2k/testData/newJ2k/nullability/MethodResultComparedWithNull3.kt +++ b/nj2k/testData/newJ2k/nullability/MethodResultComparedWithNull3.kt @@ -5,8 +5,6 @@ internal interface I { internal class C { fun foo(i: I) { val result = i.string - if (result != null) { - print(result) - } + result?.let { print(it) } } } \ No newline at end of file diff --git a/nj2k/testData/newJ2k/nullability/MethodResultComparedWithNull4.kt b/nj2k/testData/newJ2k/nullability/MethodResultComparedWithNull4.kt index 153dd631ca4..5dd087d712e 100644 --- a/nj2k/testData/newJ2k/nullability/MethodResultComparedWithNull4.kt +++ b/nj2k/testData/newJ2k/nullability/MethodResultComparedWithNull4.kt @@ -6,8 +6,6 @@ internal class C { fun foo(i: I, b: Boolean) { var result = i.string if (b) result = null - if (result != null) { - print(result) - } + result?.let { print(it) } } } \ No newline at end of file diff --git a/nj2k/testData/newJ2k/nullability/ParameterComparedWithNull.kt b/nj2k/testData/newJ2k/nullability/ParameterComparedWithNull.kt index 743fe1eedd4..3fc71b3e365 100644 --- a/nj2k/testData/newJ2k/nullability/ParameterComparedWithNull.kt +++ b/nj2k/testData/newJ2k/nullability/ParameterComparedWithNull.kt @@ -1,5 +1,3 @@ fun foo(s: String?) { - if (s != null) { - zoo(s) - } + s?.let { zoo(it) } } \ No newline at end of file diff --git a/nj2k/testData/newJ2k/nullability/VariableComparedWithNull.kt b/nj2k/testData/newJ2k/nullability/VariableComparedWithNull.kt index 538c3025006..0ec928942e5 100644 --- a/nj2k/testData/newJ2k/nullability/VariableComparedWithNull.kt +++ b/nj2k/testData/newJ2k/nullability/VariableComparedWithNull.kt @@ -1,10 +1,10 @@ // !specifyLocalVariableTypeByDefault: true + fun bar(): String? { return null } + fun foo() { val s: String? = bar() - if (s != null) { - zoo(s) - } + s?.let { zoo(it) } } \ No newline at end of file diff --git a/nj2k/testData/newJ2k/postProcessing/GetOperator.kt b/nj2k/testData/newJ2k/postProcessing/GetOperator.kt index 60c61006d1c..e4fbe070812 100644 --- a/nj2k/testData/newJ2k/postProcessing/GetOperator.kt +++ b/nj2k/testData/newJ2k/postProcessing/GetOperator.kt @@ -21,6 +21,6 @@ internal class C { } fun foo(javaClass: JavaClass): Int { - return javaClass.get(0) + return javaClass[0] } } \ No newline at end of file