New J2K: do not analyze code for post-processings in edt thread

This commit is contained in:
Ilya Kirillov
2019-09-18 20:26:09 +03:00
parent e6f2e0041c
commit 74ba5b210a
18 changed files with 289 additions and 333 deletions
@@ -5,7 +5,8 @@
package org.jetbrains.kotlin.nj2k.inference.common 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.KtElement
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
@@ -19,15 +20,19 @@ class InferenceFacade(
private val printDebugConstraints: Boolean = false private val printDebugConstraints: Boolean = false
) { ) {
fun runOn(elements: List<KtElement>) { fun runOn(elements: List<KtElement>) {
val inferenceContext = typeVariablesCollector.collectTypeVariables(elements) val inferenceContext = runReadAction { typeVariablesCollector.collectTypeVariables(elements) }
val constraints = constraintsCollectorAggregator.collectConstraints(boundTypeCalculator, inferenceContext, elements) val constraints = runReadAction {
constraintsCollectorAggregator.collectConstraints(boundTypeCalculator, inferenceContext, elements)
}
val initialConstraints = if (renderDebugTypes) constraints.map { it.copy() } else null 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) { if (renderDebugTypes) {
with(DebugPrinter(inferenceContext)) { with(DebugPrinter(inferenceContext)) {
runWriteAction { runUndoTransparentActionInEdt(inWriteAction = true) {
for ((expression, boundType) in boundTypeCalculator.expressionsWithBoundType()) { for ((expression, boundType) in boundTypeCalculator.expressionsWithBoundType()) {
val comment = KtPsiFactory(expression.project).createComment("/*${boundType.asString()}*/") val comment = KtPsiFactory(expression.project).createComment("/*${boundType.asString()}*/")
expression.parent.addAfter(comment, expression) expression.parent.addAfter(comment, expression)
@@ -46,7 +51,7 @@ class InferenceFacade(
} }
} }
} }
runWriteAction { runUndoTransparentActionInEdt(inWriteAction = true) {
stateUpdater.updateStates(inferenceContext) stateUpdater.updateStates(inferenceContext)
} }
} }
@@ -5,17 +5,11 @@
package org.jetbrains.kotlin.nj2k.postProcessing 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.diagnostic.Logger
import com.intellij.openapi.editor.RangeMarker import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProcessCanceledException
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference 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.formatter.commitAndUnblockDocument
import org.jetbrains.kotlin.idea.inspections.* import org.jetbrains.kotlin.idea.inspections.*
import org.jetbrains.kotlin.idea.inspections.branchedTransformations.IfThenToElvisInspection 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.intentions.branchedTransformations.isTrivialStatementBody
import org.jetbrains.kotlin.idea.quickfix.* import org.jetbrains.kotlin.idea.quickfix.*
import org.jetbrains.kotlin.idea.util.ImportInsertHelper 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.ConverterContext
import org.jetbrains.kotlin.j2k.PostProcessor import org.jetbrains.kotlin.j2k.PostProcessor
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
@@ -41,11 +34,9 @@ class NewJ2kPostProcessor : PostProcessor {
private val LOG = Logger.getInstance("@org.jetbrains.kotlin.nj2k.postProcessing.NewJ2kPostProcessor") private val LOG = Logger.getInstance("@org.jetbrains.kotlin.nj2k.postProcessing.NewJ2kPostProcessor")
override fun insertImport(file: KtFile, fqName: FqName) { override fun insertImport(file: KtFile, fqName: FqName) {
ApplicationManager.getApplication().invokeAndWait { runUndoTransparentActionInEdt(inWriteAction = true) {
runWriteAction { val descriptors = file.resolveImportReference(fqName)
val descriptors = file.resolveImportReference(fqName) descriptors.firstOrNull()?.let { ImportInsertHelper.getInstance(file.project).importDescriptor(file, it) }
descriptors.firstOrNull()?.let { ImportInsertHelper.getInstance(file.project).importDescriptor(file, it) }
}
} }
} }
@@ -57,31 +48,25 @@ class NewJ2kPostProcessor : PostProcessor {
rangeMarker: RangeMarker?, rangeMarker: RangeMarker?,
onPhaseChanged: ((Int, String) -> Unit)? onPhaseChanged: ((Int, String) -> Unit)?
) { ) {
runBlocking(EDT.ModalityStateElement(ModalityState.defaultModalityState())) { for ((i, group) in processings.withIndex()) {
for ((i, group) in processings.withIndex()) { onPhaseChanged?.invoke(i + 1, group.description)
onPhaseChanged?.invoke(i + 1, group.description) for (processing in group.processings) {
for (processing in group.processings) { try {
try { processing.runProcessing(file, rangeMarker, converterContext as NewJ2kConverterContext)
processing.runProcessing(file, rangeMarker, converterContext as NewJ2kConverterContext) } catch (e: ProcessCanceledException) {
} catch (e: ProcessCanceledException) { throw e
throw e } catch (t: Throwable) {
} catch (t: Throwable) { LOG.error(t)
LOG.error(t) } finally {
} finally { commitFile(file)
commitFile(file)
}
} }
} }
} }
} }
private suspend fun commitFile(file: KtFile) { private fun commitFile(file: KtFile) {
withContext(EDT) { runUndoTransparentActionInEdt(inWriteAction = true) {
CommandProcessor.getInstance().runUndoTransparentAction { file.commitAndUnblockDocument()
runWriteAction {
file.commitAndUnblockDocument()
}
}
} }
} }
} }
@@ -151,7 +136,7 @@ private val addOrRemoveModifiersProcessingGroup =
processings = listOf( processings = listOf(
RemoveRedundantVisibilityModifierProcessing(), RemoveRedundantVisibilityModifierProcessing(),
RemoveRedundantModalityModifierProcessing(), RemoveRedundantModalityModifierProcessing(),
inspectionBasedProcessing(AddOperatorModifierInspection()), inspectionBasedProcessing(AddOperatorModifierInspection(), writeActionNeeded = false),
RemoveExplicitUnitTypeProcessing() RemoveExplicitUnitTypeProcessing()
) )
) )
@@ -183,24 +168,24 @@ private val inspectionLikePostProcessingGroup =
RemoveRedundantConstructorKeywordProcessing(), RemoveRedundantConstructorKeywordProcessing(),
RemoveExplicitOpenInInterfaceProcessing(), RemoveExplicitOpenInInterfaceProcessing(),
RemoveRedundantOverrideVisibilityProcessing(), RemoveRedundantOverrideVisibilityProcessing(),
inspectionBasedProcessing(MoveLambdaOutsideParenthesesInspection()), MoveLambdaOutsideParenthesesProcessing(),
intentionBasedProcessing(ConvertToStringTemplateIntention()) { intentionBasedProcessing(ConvertToStringTemplateIntention(), writeActionNeeded = false) {
ConvertToStringTemplateIntention.shouldSuggestToConvert(it) ConvertToStringTemplateIntention.shouldSuggestToConvert(it)
}, },
intentionBasedProcessing(UsePropertyAccessSyntaxIntention()), intentionBasedProcessing(UsePropertyAccessSyntaxIntention(), writeActionNeeded = false),
UninitializedVariableReferenceFromInitializerToThisReferenceProcessing(), UninitializedVariableReferenceFromInitializerToThisReferenceProcessing(),
UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing(), UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing(),
RemoveRedundantSamAdaptersProcessing(), RemoveRedundantSamAdaptersProcessing(),
RemoveRedundantCastToNullableProcessing(), RemoveRedundantCastToNullableProcessing(),
inspectionBasedProcessing(ReplacePutWithAssignmentInspection()), inspectionBasedProcessing(ReplacePutWithAssignmentInspection()),
UseExpressionBodyProcessing(), ReplaceGetterBodyWithSingleReturnStatementWithExpressionBody(),
inspectionBasedProcessing(UnnecessaryVariableInspection()), inspectionBasedProcessing(UnnecessaryVariableInspection(), writeActionNeeded = false),
RedundantExplicitTypeInspectionBasedProcessing(), RedundantExplicitTypeInspectionBasedProcessing(),
JavaObjectEqualsToEqOperatorProcessing(), JavaObjectEqualsToEqOperatorProcessing(),
RemoveExplicitPropertyTypeProcessing(), RemoveExplicitPropertyTypeProcessing(),
RemoveRedundantNullabilityProcessing(), RemoveRedundantNullabilityProcessing(),
CanBeValInspectionBasedProcessing(), CanBeValInspectionBasedProcessing(),
inspectionBasedProcessing(FoldInitializerAndIfToElvisInspection()), inspectionBasedProcessing(FoldInitializerAndIfToElvisInspection(), writeActionNeeded = false),
intentionBasedProcessing(RemoveRedundantCallsOfConversionMethodsIntention()), intentionBasedProcessing(RemoveRedundantCallsOfConversionMethodsIntention()),
inspectionBasedProcessing(JavaMapForEachInspection()), inspectionBasedProcessing(JavaMapForEachInspection()),
intentionBasedProcessing(FoldIfToReturnIntention()) { it.then.isTrivialStatementBody() && it.`else`.isTrivialStatementBody() }, intentionBasedProcessing(FoldIfToReturnIntention()) { it.then.isTrivialStatementBody() && it.`else`.isTrivialStatementBody() },
@@ -209,14 +194,13 @@ private val inspectionLikePostProcessingGroup =
it it
) as KtReturnExpression).returnedExpression.isTrivialStatementBody() ) as KtReturnExpression).returnedExpression.isTrivialStatementBody()
}, },
inspectionBasedProcessing(IfThenToSafeAccessInspection()), inspectionBasedProcessing(IfThenToSafeAccessInspection(), writeActionNeeded = false),
inspectionBasedProcessing(IfThenToElvisInspection(highlightStatement = true)), inspectionBasedProcessing(IfThenToElvisInspection(highlightStatement = true), writeActionNeeded = false),
inspectionBasedProcessing(SimplifyNegatedBinaryExpressionInspection()), inspectionBasedProcessing(SimplifyNegatedBinaryExpressionInspection()),
inspectionBasedProcessing(ReplaceGetOrSetInspection()), inspectionBasedProcessing(ReplaceGetOrSetInspection()),
intentionBasedProcessing(ObjectLiteralToLambdaIntention()), intentionBasedProcessing(ObjectLiteralToLambdaIntention(), writeActionNeeded = true),
intentionBasedProcessing(AnonymousFunctionToLambdaIntention()),
intentionBasedProcessing(RemoveUnnecessaryParenthesesIntention()), intentionBasedProcessing(RemoveUnnecessaryParenthesesIntention()),
intentionBasedProcessing(DestructureIntention()), intentionBasedProcessing(DestructureIntention(), writeActionNeeded = false),
inspectionBasedProcessing(SimplifyAssertNotNullInspection()), inspectionBasedProcessing(SimplifyAssertNotNullInspection()),
intentionBasedProcessing(RemoveRedundantCallsOfConversionMethodsIntention()), intentionBasedProcessing(RemoveRedundantCallsOfConversionMethodsIntention()),
LiftReturnInspectionBasedProcessing(), LiftReturnInspectionBasedProcessing(),
@@ -250,12 +234,12 @@ private val processings: List<NamedPostProcessingGroup> = listOf(
), ),
NullabilityInferenceProcessing(), NullabilityInferenceProcessing(),
MutabilityInferenceProcessing(), MutabilityInferenceProcessing(),
clearUnknownLabelsProcessing ClearUnknownLabelsProcessing()
) )
), ),
NamedPostProcessingGroup( NamedPostProcessingGroup(
"Formatting code", "Formatting code",
listOf(formatCodeProcessing) listOf(FormatCodeProcessing())
), ),
NamedPostProcessingGroup( NamedPostProcessingGroup(
"Shortening fully-qualified references", "Shortening fully-qualified references",
@@ -288,12 +272,12 @@ private val processings: List<NamedPostProcessingGroup> = listOf(
NamedPostProcessingGroup( NamedPostProcessingGroup(
"Optimizing imports", "Optimizing imports",
listOf( listOf(
optimizeImportsProcessing, OptimizeImportsProcessing(),
ShortenReferenceProcessing() ShortenReferenceProcessing()
) )
), ),
NamedPostProcessingGroup( NamedPostProcessingGroup(
"Formatting code", "Formatting code",
listOf(formatCodeProcessing) listOf(FormatCodeProcessing())
) )
) )
@@ -6,19 +6,16 @@
package org.jetbrains.kotlin.nj2k.postProcessing package org.jetbrains.kotlin.nj2k.postProcessing
import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.editor.RangeMarker import com.intellij.openapi.editor.RangeMarker
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import kotlinx.coroutines.withContext
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade 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.core.util.range
import org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix import org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix
import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory 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.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
@@ -36,17 +33,15 @@ class DiagnosticBasedPostProcessingGroup(diagnosticBasedProcessings: List<Diagno
list.map { it.second } list.map { it.second }
} }
override suspend fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
withContext(EDT) { val diagnostics = runReadAction { analyzeFileRange(file, rangeMarker).all() }
CommandProcessor.getInstance().runUndoTransparentAction { runUndoTransparentActionInEdt(inWriteAction = true) {
val diagnostics = runWriteAction { analyzeFileRange(file, rangeMarker) } for (diagnostic in diagnostics) {
for (diagnostic in diagnostics.all()) { val range = rangeMarker?.range ?: file.textRange
val range = rangeMarker?.range ?: file.textRange if (diagnostic.psiElement.isInRange(range)) {
if (diagnostic.psiElement.isInRange(range)) { diagnosticToFix[diagnostic.factory]?.forEach { fix ->
diagnosticToFix[diagnostic.factory]?.forEach { fix -> if (diagnostic.psiElement.isValid) {
if (diagnostic.psiElement.isValid) { fix(diagnostic)
runWriteAction { fix(diagnostic) }
}
} }
} }
} }
@@ -5,29 +5,19 @@
package org.jetbrains.kotlin.nj2k.postProcessing 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.command.CommandProcessor
import com.intellij.openapi.editor.RangeMarker import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiRecursiveElementVisitor import com.intellij.psi.PsiRecursiveElementVisitor
import kotlinx.coroutines.withContext
import org.jetbrains.kotlin.idea.core.util.EDT
import org.jetbrains.kotlin.idea.inspections.AbstractApplicabilityBasedInspection 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.intentions.SelfTargetingRangeIntention
import org.jetbrains.kotlin.idea.quickfix.QuickFixActionBase
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.j2k.ConverterSettings import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile 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 org.jetbrains.kotlin.utils.mapToIndex
import java.util.* import java.util.*
import kotlin.reflect.KClass import kotlin.reflect.KClass
@@ -39,7 +29,6 @@ class InspectionLikeProcessingGroup(
private val acceptNonKtElements: Boolean = false, private val acceptNonKtElements: Boolean = false,
private val processings: List<InspectionLikeProcessing> private val processings: List<InspectionLikeProcessing>
) : ProcessingGroup { ) : ProcessingGroup {
constructor(vararg processings: InspectionLikeProcessing) : this( constructor(vararg processings: InspectionLikeProcessing) : this(
runSingleTime = false, runSingleTime = false,
acceptNonKtElements = false, acceptNonKtElements = false,
@@ -49,49 +38,45 @@ class InspectionLikeProcessingGroup(
private val processingsToPriorityMap = processings.mapToIndex() private val processingsToPriorityMap = processings.mapToIndex()
fun priority(processing: InspectionLikeProcessing): Int = processingsToPriorityMap.getValue(processing) 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 { do {
var modificationStamp: Long? = file.modificationStamp var modificationStamp: Long? = file.modificationStamp
val elementToActions = runReadAction { val elementToActions = runReadAction {
collectAvailableActions(file, converterContext, rangeMarker) collectAvailableActions(file, converterContext, rangeMarker)
} }
withContext(EDT) {
CommandProcessor.getInstance().runUndoTransparentAction { for ((processing, element, _) in elementToActions) {
for ((element, action, _, writeActionNeeded) in elementToActions) { val needRun = runReadAction {
if (element.isValid) { element.isValid && processing.isApplicableToElement(element, converterContext.converter.settings)
if (writeActionNeeded) { }
runWriteAction { if (needRun) runUndoTransparentActionInEdt(inWriteAction = processing.writeActionNeeded) {
action() processing.applyToElement(element)
} } else {
} else { modificationStamp = null
action()
}
} else {
modificationStamp = null
}
}
} }
} }
if (runSingleTime) break if (runSingleTime) break
} while (modificationStamp != file.modificationStamp && elementToActions.isNotEmpty()) } while (modificationStamp != file.modificationStamp && elementToActions.isNotEmpty())
} }
private enum class RangeFilterResult { private enum class RangeFilterResult {
SKIP, SKIP,
GO_INSIDE, GO_INSIDE,
PROCESS PROCESS
} }
private data class ProcessingData(
private data class ActionData(val element: PsiElement, val action: () -> Unit, val priority: Int, val writeActionNeeded: Boolean) val processing: InspectionLikeProcessing,
val element: PsiElement,
val priority: Int
)
private fun collectAvailableActions( private fun collectAvailableActions(
file: KtFile, file: KtFile,
context: NewJ2kConverterContext, context: NewJ2kConverterContext,
rangeMarker: RangeMarker? rangeMarker: RangeMarker?
): List<ActionData> { ): List<ProcessingData> {
val availableActions = ArrayList<ActionData>() val availableActions = ArrayList<ProcessingData>()
file.accept(object : PsiRecursiveElementVisitor() { file.accept(object : PsiRecursiveElementVisitor() {
override fun visitElement(element: PsiElement) { override fun visitElement(element: PsiElement) {
@@ -102,15 +87,10 @@ class InspectionLikeProcessingGroup(
super.visitElement(element) super.visitElement(element)
if (rangeResult == RangeFilterResult.PROCESS) { if (rangeResult == RangeFilterResult.PROCESS) {
processings.forEach { processing -> for (processing in processings) {
val action = processing.createAction(element, context.converter.settings) if (processing.isApplicableToElement(element, context.converter.settings)) {
if (action != null) {
availableActions.add( availableActions.add(
ActionData( ProcessingData(processing, element, priority(processing))
element, action,
priority(processing),
processing.writeActionNeeded
)
) )
} }
} }
@@ -136,71 +116,63 @@ class InspectionLikeProcessingGroup(
} }
} }
interface InspectionLikeProcessing { abstract class InspectionLikeProcessing {
fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? 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<E : PsiElement>(private val classTag: KClass<E>) : InspectionLikeProcessing { abstract class InspectionLikeProcessingForElement<E : PsiElement>(private val classTag: KClass<E>) : InspectionLikeProcessing() {
protected abstract fun isApplicableTo(element: E, settings: ConverterSettings?): Boolean protected abstract fun isApplicableTo(element: E, settings: ConverterSettings?): Boolean
protected abstract fun apply(element: E) 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")
@Suppress("UNCHECKED_CAST") final override fun isApplicableToElement(element: PsiElement, settings: ConverterSettings?): Boolean {
if (!isApplicableTo(element as E, settings)) return null if (!element::class.isSubclassOf(classTag)) return false
return { if (!element.isValid) return false
if (element.isValid && isApplicableTo(element, settings)) { @Suppress("UNCHECKED_CAST") return isApplicableTo(element as E, settings)
apply(element)
}
}
} }
final override val writeActionNeeded: Boolean = true 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 <reified TElement : PsiElement, TIntention : SelfTargetingRangeIntention<TElement>> 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)
}
}
} }
} }
inline fun <reified TElement : PsiElement, TInspection : AbstractApplicabilityBasedInspection<TElement>> inline fun <reified E : PsiElement, I : SelfTargetingRangeIntention<E>> intentionBasedProcessing(
inspectionBasedProcessing(inspection: TInspection, acceptInformationLevel: Boolean = false) = intention: I,
object : InspectionLikeProcessing { writeActionNeeded: Boolean = true,
// Inspection can either need or not need write apply noinline additionalChecker: (E) -> Boolean = { true }
override val writeActionNeeded = inspection.startFixInWriteAction ) = object : InspectionLikeProcessingForElement<E>(E::class) {
override fun isApplicableTo(element: E, settings: ConverterSettings?): Boolean =
intention.applicabilityRange(element) != null
&& additionalChecker(element)
fun isApplicable(element: TElement): Boolean { override fun apply(element: E) {
if (!inspection.isApplicable(element)) return false intention.applyTo(element, null)
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 val writeActionNeeded = writeActionNeeded
}
inline fun <reified E : PsiElement, I : AbstractApplicabilityBasedInspection<E>> inspectionBasedProcessing(
inspection: I,
writeActionNeeded: Boolean = true
) = object : InspectionLikeProcessingForElement<E>(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
}
@@ -5,43 +5,28 @@
package org.jetbrains.kotlin.nj2k.postProcessing package org.jetbrains.kotlin.nj2k.postProcessing
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.editor.RangeMarker import com.intellij.openapi.editor.RangeMarker
import com.intellij.psi.PsiElement 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.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.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
interface GeneralPostProcessing { 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 : GeneralPostProcessing {
} final override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
val elements = runReadAction {
abstract class ElementsBasedPostProcessing() : SimplePostProcessing() {
final override fun applySimpleProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
val elements =
rangeMarker?.let { marker -> rangeMarker?.let { marker ->
val range = marker.range ?: return@let emptyList() val range = marker.range ?: return@let emptyList()
file.elementsInRange(range) file.elementsInRange(range)
} ?: listOf(file) } ?: listOf(file)
}
runProcessing(elements, converterContext) runProcessing(elements, converterContext)
} }
@@ -54,13 +39,3 @@ data class NamedPostProcessingGroup(
val description: String, val description: String,
val processings: List<GeneralPostProcessing> val processings: List<GeneralPostProcessing>
) )
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)
}
}
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.references.readWriteAccess import org.jetbrains.kotlin.idea.references.readWriteAccess
import org.jetbrains.kotlin.idea.util.CommentSaver import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers 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.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
@@ -272,15 +272,20 @@ class ConvertGettersAndSettersToPropertyProcessing : ElementsBasedPostProcessing
override fun runProcessing(elements: List<PsiElement>, converterContext: NewJ2kConverterContext) { override fun runProcessing(elements: List<PsiElement>, converterContext: NewJ2kConverterContext) {
val classes = elements
.descendantsOfType<KtClassOrObject>()
.sortedByInheritance()
val collectingState = CollectingState() val collectingState = CollectingState()
val classesWithPropertiesData = classes.map { klass -> val classesWithPropertiesData = runReadAction {
klass to klass.collectPropertiesData(collectingState) elements
.descendantsOfType<KtClassOrObject>()
.sortedByInheritance()
.map { klass ->
klass to klass.collectPropertiesData(collectingState)
}
} }
for ((klass, propertiesData) in classesWithPropertiesData) { if (classesWithPropertiesData.isEmpty()) return
convertClass(klass, propertiesData) runUndoTransparentActionInEdt(inWriteAction = true) {
for ((klass, propertiesData) in classesWithPropertiesData) {
convertClass(klass, propertiesData)
}
} }
} }
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.idea.core.setVisibility import org.jetbrains.kotlin.idea.core.setVisibility
import org.jetbrains.kotlin.idea.intentions.addUseSiteTarget import org.jetbrains.kotlin.idea.intentions.addUseSiteTarget
import org.jetbrains.kotlin.idea.util.CommentSaver 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.NewJ2kConverterContext
import org.jetbrains.kotlin.nj2k.escaped import org.jetbrains.kotlin.nj2k.escaped
import org.jetbrains.kotlin.nj2k.postProcessing.* import org.jetbrains.kotlin.nj2k.postProcessing.*
@@ -122,24 +123,28 @@ class ConvertToDataClassProcessing : ElementsBasedPostProcessing() {
} }
private fun convertClass(klass: KtClass) { private fun convertClass(klass: KtClass) {
for (initialization in collectInitializations(klass)) { val initialisations = runReadAction { collectInitializations(klass) }
val statementCommentSaver = CommentSaver(initialization.statement, saveLineBreaks = true) if (initialisations.isEmpty()) return
val restoreStatementCommentsTarget: KtExpression runUndoTransparentActionInEdt(inWriteAction = true) {
when (initialization) { for (initialization in initialisations) {
is ConstructorParameterInitialization -> { val statementCommentSaver = CommentSaver(initialization.statement, saveLineBreaks = true)
initialization.mergePropertyAndConstructorParameter() val restoreStatementCommentsTarget: KtExpression
restoreStatementCommentsTarget = initialization.initializer when (initialization) {
} is ConstructorParameterInitialization -> {
is LiteralInitialization -> { initialization.mergePropertyAndConstructorParameter()
val (property, initializer, _) = initialization restoreStatementCommentsTarget = initialization.initializer
property.initializer = initializer }
restoreStatementCommentsTarget = property is LiteralInitialization -> {
val (property, initializer, _) = initialization
property.initializer = initializer
restoreStatementCommentsTarget = property
}
} }
initialization.statement.delete()
statementCommentSaver.restore(restoreStatementCommentsTarget, forceAdjustIndent = false)
} }
initialization.statement.delete() klass.removeEmptyInitBlocks()
statementCommentSaver.restore(restoreStatementCommentsTarget, forceAdjustIndent = false)
} }
klass.removeEmptyInitBlocks()
} }
} }
@@ -5,11 +5,8 @@
package org.jetbrains.kotlin.nj2k.postProcessing.processings package org.jetbrains.kotlin.nj2k.postProcessing.processings
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.editor.RangeMarker import com.intellij.openapi.editor.RangeMarker
import kotlinx.coroutines.withContext
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.util.EDT
import org.jetbrains.kotlin.idea.core.util.range import org.jetbrains.kotlin.idea.core.util.range
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.application.runReadAction 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 import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
abstract class InferenceProcessing : GeneralPostProcessing { 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 elements = if (rangeMarker != null) {
val range = rangeMarker.range ?: return val range = rangeMarker.range ?: return
runReadAction { file.elementsInRange(range) }.filterIsInstance<KtElement>() runReadAction { file.elementsInRange(range) }.filterIsInstance<KtElement>()
} else listOf(file) } else listOf(file)
val resolutionFacade = runReadAction { file.getResolutionFacade() } val resolutionFacade = runReadAction { file.getResolutionFacade() }
createInferenceFacade(resolutionFacade, converterContext).runOn(elements)
withContext(EDT) {
CommandProcessor.getInstance().runUndoTransparentAction {
createInferenceFacade(resolutionFacade, converterContext).runOn(elements)
}
}
} }
abstract fun createInferenceFacade( abstract fun createInferenceFacade(
@@ -8,34 +8,33 @@ package org.jetbrains.kotlin.nj2k.postProcessing.processings
import com.intellij.openapi.editor.RangeMarker import com.intellij.openapi.editor.RangeMarker
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.core.ShortenReferences 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.ImportStorage
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext 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.KtFile
import org.jetbrains.kotlin.psi.KtQualifiedExpression import org.jetbrains.kotlin.psi.KtQualifiedExpression
class ShortenReferenceProcessing : SimplePostProcessing() { class ShortenReferenceProcessing : GeneralPostProcessing {
private val filter = filter@{ element: PsiElement -> private val filter = filter@{ element: PsiElement ->
when (element) { when (element) {
is KtQualifiedExpression -> { is KtQualifiedExpression -> when {
val fqName = element.selectorExpression?.mainReference?.resolve()?.getKotlinFqName() ImportStorage.isImportNeededForCall(element) -> ShortenReferences.FilterResult.PROCESS
?: return@filter ShortenReferences.FilterResult.PROCESS else -> ShortenReferences.FilterResult.SKIP
if (ImportStorage.isImportNeeded(fqName)) ShortenReferences.FilterResult.PROCESS
else ShortenReferences.FilterResult.SKIP
} }
else -> ShortenReferences.FilterResult.PROCESS else -> ShortenReferences.FilterResult.PROCESS
} }
} }
override fun applySimpleProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) { override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
if (rangeMarker != null) { runUndoTransparentActionInEdt(inWriteAction = false) {
if (rangeMarker.isValid) { if (rangeMarker != null) {
ShortenReferences.DEFAULT.process(file, rangeMarker.startOffset, rangeMarker.endOffset, filter) if (rangeMarker.isValid) {
ShortenReferences.DEFAULT.process(file, rangeMarker.startOffset, rangeMarker.endOffset, filter)
}
} else {
ShortenReferences.DEFAULT.process(file, filter)
} }
} else {
ShortenReferences.DEFAULT.process(file, filter)
} }
} }
} }
@@ -13,10 +13,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.idea.analysis.analyzeInContext import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.core.implicitModality import org.jetbrains.kotlin.idea.core.*
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.debugger.sequence.psi.callName import org.jetbrains.kotlin.idea.debugger.sequence.psi.callName
import org.jetbrains.kotlin.idea.inspections.* import org.jetbrains.kotlin.idea.inspections.*
import org.jetbrains.kotlin.idea.inspections.collections.isCalling 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.j2k.ConverterSettings
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName 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.*
import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -42,7 +39,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class RemoveExplicitPropertyTypeProcessing : ApplicabilityBasedInspectionLikeProcessing<KtProperty>(KtProperty::class) { class RemoveExplicitPropertyTypeProcessing : InspectionLikeProcessingForElement<KtProperty>(KtProperty::class) {
override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean { override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean {
val needFieldTypes = settings?.specifyFieldTypeByDefault == true val needFieldTypes = settings?.specifyFieldTypeByDefault == true
val needLocalVariablesTypes = settings?.specifyLocalVariableTypeByDefault == true val needLocalVariablesTypes = settings?.specifyLocalVariableTypeByDefault == true
@@ -61,7 +58,7 @@ class RemoveExplicitPropertyTypeProcessing : ApplicabilityBasedInspectionLikePro
} }
} }
class RemoveRedundantNullabilityProcessing : ApplicabilityBasedInspectionLikeProcessing<KtProperty>(KtProperty::class) { class RemoveRedundantNullabilityProcessing : InspectionLikeProcessingForElement<KtProperty>(KtProperty::class) {
override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean { override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean {
if (!element.isLocal) return false if (!element.isLocal) return false
val typeReference = element.typeReference val typeReference = element.typeReference
@@ -87,7 +84,7 @@ class RemoveRedundantNullabilityProcessing : ApplicabilityBasedInspectionLikePro
} }
} }
class RemoveExplicitTypeArgumentsProcessing : ApplicabilityBasedInspectionLikeProcessing<KtTypeArgumentList>(KtTypeArgumentList::class) { class RemoveExplicitTypeArgumentsProcessing : InspectionLikeProcessingForElement<KtTypeArgumentList>(KtTypeArgumentList::class) {
override fun isApplicableTo(element: KtTypeArgumentList, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtTypeArgumentList, settings: ConverterSettings?): Boolean =
RemoveExplicitTypeArgumentsIntention.isApplicableTo(element, approximateFlexible = true) 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 // 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 // but we need them in nullability inference, so we remove it here
class RemoveJavaStreamsCollectCallTypeArgumentsProcessing : class RemoveJavaStreamsCollectCallTypeArgumentsProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtCallExpression>(KtCallExpression::class) { InspectionLikeProcessingForElement<KtCallExpression>(KtCallExpression::class) {
override fun isApplicableTo(element: KtCallExpression, settings: ConverterSettings?): Boolean { override fun isApplicableTo(element: KtCallExpression, settings: ConverterSettings?): Boolean {
if (element.typeArgumentList == null) return false if (element.typeArgumentList == null) return false
if (element.callName() != COLLECT_FQ_NAME.shortName().identifier) return false if (element.callName() != COLLECT_FQ_NAME.shortName().identifier) return false
@@ -117,7 +114,7 @@ class RemoveJavaStreamsCollectCallTypeArgumentsProcessing :
class RemoveRedundantOverrideVisibilityProcessing : class RemoveRedundantOverrideVisibilityProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtCallableDeclaration>(KtCallableDeclaration::class) { InspectionLikeProcessingForElement<KtCallableDeclaration>(KtCallableDeclaration::class) {
override fun isApplicableTo(element: KtCallableDeclaration, settings: ConverterSettings?): Boolean { override fun isApplicableTo(element: KtCallableDeclaration, settings: ConverterSettings?): Boolean {
if (!element.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return false if (!element.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return false
@@ -130,7 +127,7 @@ class RemoveRedundantOverrideVisibilityProcessing :
} }
} }
class UseExpressionBodyProcessing : ApplicabilityBasedInspectionLikeProcessing<KtPropertyAccessor>(KtPropertyAccessor::class) { class UseExpressionBodyProcessing : InspectionLikeProcessingForElement<KtPropertyAccessor>(KtPropertyAccessor::class) {
private val inspection = UseExpressionBodyInspection(convertEmptyToUnit = false) private val inspection = UseExpressionBodyInspection(convertEmptyToUnit = false)
override fun isApplicableTo(element: KtPropertyAccessor, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtPropertyAccessor, settings: ConverterSettings?): Boolean =
inspection.isActiveFor(element) inspection.isActiveFor(element)
@@ -141,7 +138,7 @@ class UseExpressionBodyProcessing : ApplicabilityBasedInspectionLikeProcessing<K
} }
class RemoveRedundantCastToNullableProcessing : class RemoveRedundantCastToNullableProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtBinaryExpressionWithTypeRHS>(KtBinaryExpressionWithTypeRHS::class) { InspectionLikeProcessingForElement<KtBinaryExpressionWithTypeRHS>(KtBinaryExpressionWithTypeRHS::class) {
override fun isApplicableTo(element: KtBinaryExpressionWithTypeRHS, settings: ConverterSettings?): Boolean { override fun isApplicableTo(element: KtBinaryExpressionWithTypeRHS, settings: ConverterSettings?): Boolean {
if (element.right?.typeElement !is KtNullableType) return false if (element.right?.typeElement !is KtNullableType) return false
@@ -158,7 +155,7 @@ class RemoveRedundantCastToNullableProcessing :
} }
class RemoveRedundantSamAdaptersProcessing : class RemoveRedundantSamAdaptersProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtCallExpression>(KtCallExpression::class) { InspectionLikeProcessingForElement<KtCallExpression>(KtCallExpression::class) {
override fun isApplicableTo(element: KtCallExpression, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtCallExpression, settings: ConverterSettings?): Boolean =
RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element).isNotEmpty() RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element).isNotEmpty()
@@ -171,7 +168,7 @@ class RemoveRedundantSamAdaptersProcessing :
} }
class UninitializedVariableReferenceFromInitializerToThisReferenceProcessing : class UninitializedVariableReferenceFromInitializerToThisReferenceProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtSimpleNameExpression>(KtSimpleNameExpression::class) { InspectionLikeProcessingForElement<KtSimpleNameExpression>(KtSimpleNameExpression::class) {
override fun isApplicableTo(element: KtSimpleNameExpression, settings: ConverterSettings?): Boolean { override fun isApplicableTo(element: KtSimpleNameExpression, settings: ConverterSettings?): Boolean {
val anonymousObject = element.getStrictParentOfType<KtClassOrObject>()?.takeIf { it.name == null } ?: return false val anonymousObject = element.getStrictParentOfType<KtClassOrObject>()?.takeIf { it.name == null } ?: return false
@@ -192,7 +189,7 @@ class UninitializedVariableReferenceFromInitializerToThisReferenceProcessing :
} }
class UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing : class UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtSimpleNameExpression>(KtSimpleNameExpression::class) { InspectionLikeProcessingForElement<KtSimpleNameExpression>(KtSimpleNameExpression::class) {
override fun isApplicableTo(element: KtSimpleNameExpression, settings: ConverterSettings?): Boolean { override fun isApplicableTo(element: KtSimpleNameExpression, settings: ConverterSettings?): Boolean {
val anonymousObject = element.getStrictParentOfType<KtClassOrObject>() ?: return false val anonymousObject = element.getStrictParentOfType<KtClassOrObject>() ?: return false
@@ -207,7 +204,7 @@ class UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing :
} }
} }
class VarToValProcessing : ApplicabilityBasedInspectionLikeProcessing<KtProperty>(KtProperty::class) { class VarToValProcessing : InspectionLikeProcessingForElement<KtProperty>(KtProperty::class) {
private fun KtProperty.hasWriteUsages(): Boolean = private fun KtProperty.hasWriteUsages(): Boolean =
ReferencesSearch.search(this, useScope).any { usage -> ReferencesSearch.search(this, useScope).any { usage ->
(usage as? KtSimpleNameReference)?.element?.let { nameReference -> (usage as? KtSimpleNameReference)?.element?.let { nameReference ->
@@ -233,7 +230,7 @@ class VarToValProcessing : ApplicabilityBasedInspectionLikeProcessing<KtProperty
} }
} }
class JavaObjectEqualsToEqOperatorProcessing : ApplicabilityBasedInspectionLikeProcessing<KtCallExpression>(KtCallExpression::class) { class JavaObjectEqualsToEqOperatorProcessing : InspectionLikeProcessingForElement<KtCallExpression>(KtCallExpression::class) {
companion object { companion object {
val CALL_FQ_NAME = FqName("java.util.Objects.equals") val CALL_FQ_NAME = FqName("java.util.Objects.equals")
} }
@@ -259,7 +256,7 @@ class JavaObjectEqualsToEqOperatorProcessing : ApplicabilityBasedInspectionLikeP
class RemoveForExpressionLoopParameterTypeProcessing : class RemoveForExpressionLoopParameterTypeProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtForExpression>(KtForExpression::class) { InspectionLikeProcessingForElement<KtForExpression>(KtForExpression::class) {
override fun isApplicableTo(element: KtForExpression, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtForExpression, settings: ConverterSettings?): Boolean =
element.loopParameter?.typeReference?.typeElement != null element.loopParameter?.typeReference?.typeElement != null
&& settings?.specifyLocalVariableTypeByDefault != true && settings?.specifyLocalVariableTypeByDefault != true
@@ -270,7 +267,7 @@ class RemoveForExpressionLoopParameterTypeProcessing :
} }
class RemoveRedundantConstructorKeywordProcessing : class RemoveRedundantConstructorKeywordProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtPrimaryConstructor>(KtPrimaryConstructor::class) { InspectionLikeProcessingForElement<KtPrimaryConstructor>(KtPrimaryConstructor::class) {
override fun isApplicableTo(element: KtPrimaryConstructor, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtPrimaryConstructor, settings: ConverterSettings?): Boolean =
element.containingClassOrObject is KtClass element.containingClassOrObject is KtClass
&& element.getConstructorKeyword() != null && element.getConstructorKeyword() != null
@@ -283,7 +280,7 @@ class RemoveRedundantConstructorKeywordProcessing :
} }
} }
class RemoveRedundantModalityModifierProcessing : ApplicabilityBasedInspectionLikeProcessing<KtDeclaration>(KtDeclaration::class) { class RemoveRedundantModalityModifierProcessing : InspectionLikeProcessingForElement<KtDeclaration>(KtDeclaration::class) {
override fun isApplicableTo(element: KtDeclaration, settings: ConverterSettings?): Boolean { override fun isApplicableTo(element: KtDeclaration, settings: ConverterSettings?): Boolean {
if (element.hasModifier(KtTokens.FINAL_KEYWORD)) { if (element.hasModifier(KtTokens.FINAL_KEYWORD)) {
return !element.hasModifier(KtTokens.OVERRIDE_KEYWORD) return !element.hasModifier(KtTokens.OVERRIDE_KEYWORD)
@@ -298,7 +295,7 @@ class RemoveRedundantModalityModifierProcessing : ApplicabilityBasedInspectionLi
} }
class RemoveRedundantVisibilityModifierProcessing : ApplicabilityBasedInspectionLikeProcessing<KtDeclaration>(KtDeclaration::class) { class RemoveRedundantVisibilityModifierProcessing : InspectionLikeProcessingForElement<KtDeclaration>(KtDeclaration::class) {
override fun isApplicableTo(element: KtDeclaration, settings: ConverterSettings?) = when { override fun isApplicableTo(element: KtDeclaration, settings: ConverterSettings?) = when {
element.hasModifier(KtTokens.PUBLIC_KEYWORD) && element.hasModifier(KtTokens.OVERRIDE_KEYWORD) -> element.hasModifier(KtTokens.PUBLIC_KEYWORD) && element.hasModifier(KtTokens.OVERRIDE_KEYWORD) ->
false false
@@ -314,7 +311,7 @@ class RemoveRedundantVisibilityModifierProcessing : ApplicabilityBasedInspection
} }
} }
class RemoveExplicitOpenInInterfaceProcessing : ApplicabilityBasedInspectionLikeProcessing<KtClass>(KtClass::class) { class RemoveExplicitOpenInInterfaceProcessing : InspectionLikeProcessingForElement<KtClass>(KtClass::class) {
override fun isApplicableTo(element: KtClass, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtClass, settings: ConverterSettings?): Boolean =
element.isValid element.isValid
&& element.isInterface() && element.isInterface()
@@ -325,7 +322,7 @@ class RemoveExplicitOpenInInterfaceProcessing : ApplicabilityBasedInspectionLike
} }
} }
class MoveGetterAndSetterAnnotationsToPropertyProcessing : ApplicabilityBasedInspectionLikeProcessing<KtProperty>(KtProperty::class) { class MoveGetterAndSetterAnnotationsToPropertyProcessing : InspectionLikeProcessingForElement<KtProperty>(KtProperty::class) {
override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean =
element.accessors.isNotEmpty() element.accessors.isNotEmpty()
@@ -345,16 +342,17 @@ class MoveGetterAndSetterAnnotationsToPropertyProcessing : ApplicabilityBasedIns
} }
} }
class RedundantExplicitTypeInspectionBasedProcessing : ApplicabilityBasedInspectionLikeProcessing<KtProperty>(KtProperty::class) { class RedundantExplicitTypeInspectionBasedProcessing : InspectionLikeProcessingForElement<KtProperty>(KtProperty::class) {
override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean =
RedundantExplicitTypeInspection.hasRedundantType(element) RedundantExplicitTypeInspection.hasRedundantType(element)
override fun apply(element: KtProperty) { override fun apply(element: KtProperty) {
element.typeReference = null
RemoveExplicitTypeIntention.removeExplicitType(element) RemoveExplicitTypeIntention.removeExplicitType(element)
} }
} }
class CanBeValInspectionBasedProcessing : ApplicabilityBasedInspectionLikeProcessing<KtDeclaration>(KtDeclaration::class) { class CanBeValInspectionBasedProcessing : InspectionLikeProcessingForElement<KtDeclaration>(KtDeclaration::class) {
override fun isApplicableTo(element: KtDeclaration, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtDeclaration, settings: ConverterSettings?): Boolean =
CanBeValInspection.canBeVal(element, ignoreNotUsedVals = false) CanBeValInspection.canBeVal(element, ignoreNotUsedVals = false)
@@ -365,7 +363,7 @@ class CanBeValInspectionBasedProcessing : ApplicabilityBasedInspectionLikeProces
} }
class MayBeConstantInspectionBasedProcessing : ApplicabilityBasedInspectionLikeProcessing<KtProperty>(KtProperty::class) { class MayBeConstantInspectionBasedProcessing : InspectionLikeProcessingForElement<KtProperty>(KtProperty::class) {
override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean =
with(MayBeConstantInspection) { with(MayBeConstantInspection) {
val status = element.getStatus() val status = element.getStatus()
@@ -378,7 +376,7 @@ class MayBeConstantInspectionBasedProcessing : ApplicabilityBasedInspectionLikeP
} }
} }
class RemoveExplicitUnitTypeProcessing : ApplicabilityBasedInspectionLikeProcessing<KtNamedFunction>(KtNamedFunction::class) { class RemoveExplicitUnitTypeProcessing : InspectionLikeProcessingForElement<KtNamedFunction>(KtNamedFunction::class) {
override fun isApplicableTo(element: KtNamedFunction, settings: ConverterSettings?): Boolean { override fun isApplicableTo(element: KtNamedFunction, settings: ConverterSettings?): Boolean {
val typeReference = element.typeReference?.typeElement ?: return false val typeReference = element.typeReference?.typeElement ?: return false
if (!typeReference.textMatches("Unit")) return false if (!typeReference.textMatches("Unit")) return false
@@ -386,13 +384,13 @@ class RemoveExplicitUnitTypeProcessing : ApplicabilityBasedInspectionLikeProcess
} }
override fun apply(element: KtNamedFunction) { override fun apply(element: KtNamedFunction) {
RemoveExplicitTypeIntention.removeExplicitType(element) element.typeReference = null
} }
} }
class RemoveExplicitGetterInspectionBasedProcessing : class RemoveExplicitGetterInspectionBasedProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtPropertyAccessor>(KtPropertyAccessor::class) { InspectionLikeProcessingForElement<KtPropertyAccessor>(KtPropertyAccessor::class) {
override fun isApplicableTo(element: KtPropertyAccessor, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtPropertyAccessor, settings: ConverterSettings?): Boolean =
element.isRedundantGetter() element.isRedundantGetter()
@@ -402,7 +400,7 @@ class RemoveExplicitGetterInspectionBasedProcessing :
} }
class RemoveExplicitSetterInspectionBasedProcessing : class RemoveExplicitSetterInspectionBasedProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtPropertyAccessor>(KtPropertyAccessor::class) { InspectionLikeProcessingForElement<KtPropertyAccessor>(KtPropertyAccessor::class) {
override fun isApplicableTo(element: KtPropertyAccessor, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtPropertyAccessor, settings: ConverterSettings?): Boolean =
element.isRedundantSetter() element.isRedundantSetter()
@@ -413,7 +411,7 @@ class RemoveExplicitSetterInspectionBasedProcessing :
class RedundantSemicolonInspectionBasedProcessing : class RedundantSemicolonInspectionBasedProcessing :
ApplicabilityBasedInspectionLikeProcessing<PsiElement>(PsiElement::class) { InspectionLikeProcessingForElement<PsiElement>(PsiElement::class) {
override fun isApplicableTo(element: PsiElement, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: PsiElement, settings: ConverterSettings?): Boolean =
element.node.elementType == KtTokens.SEMICOLON element.node.elementType == KtTokens.SEMICOLON
&& RedundantSemicolonInspection.isRedundantSemicolon(element) && RedundantSemicolonInspection.isRedundantSemicolon(element)
@@ -425,7 +423,7 @@ class RedundantSemicolonInspectionBasedProcessing :
class RedundantCompanionReferenceInspectionBasedProcessing : class RedundantCompanionReferenceInspectionBasedProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtReferenceExpression>(KtReferenceExpression::class) { InspectionLikeProcessingForElement<KtReferenceExpression>(KtReferenceExpression::class) {
override fun isApplicableTo(element: KtReferenceExpression, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtReferenceExpression, settings: ConverterSettings?): Boolean =
RedundantCompanionReferenceInspection.isRedundantCompanionReference(element) RedundantCompanionReferenceInspection.isRedundantCompanionReference(element)
@@ -435,7 +433,7 @@ class RedundantCompanionReferenceInspectionBasedProcessing :
} }
class ExplicitThisInspectionBasedProcessing : class ExplicitThisInspectionBasedProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtExpression>(KtExpression::class) { InspectionLikeProcessingForElement<KtExpression>(KtExpression::class) {
override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean =
ExplicitThisInspection.hasExplicitThis(element) ExplicitThisInspection.hasExplicitThis(element)
@@ -449,7 +447,7 @@ class ExplicitThisInspectionBasedProcessing :
} }
class LiftReturnInspectionBasedProcessing : class LiftReturnInspectionBasedProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtExpression>(KtExpression::class) { InspectionLikeProcessingForElement<KtExpression>(KtExpression::class) {
override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean =
LiftReturnOrAssignmentInspection.getState(element, false)?.any { LiftReturnOrAssignmentInspection.getState(element, false)?.any {
it.liftType == LiftReturnOrAssignmentInspection.Companion.LiftType.LIFT_RETURN_OUT it.liftType == LiftReturnOrAssignmentInspection.Companion.LiftType.LIFT_RETURN_OUT
@@ -461,7 +459,7 @@ class LiftReturnInspectionBasedProcessing :
} }
class LiftAssignmentInspectionBasedProcessing : class LiftAssignmentInspectionBasedProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtExpression>(KtExpression::class) { InspectionLikeProcessingForElement<KtExpression>(KtExpression::class) {
override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean = override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean =
LiftReturnOrAssignmentInspection.getState(element, false)?.any { LiftReturnOrAssignmentInspection.getState(element, false)?.any {
it.liftType == LiftReturnOrAssignmentInspection.Companion.LiftType.LIFT_ASSIGNMENT_OUT it.liftType == LiftReturnOrAssignmentInspection.Companion.LiftType.LIFT_ASSIGNMENT_OUT
@@ -471,3 +469,13 @@ class LiftAssignmentInspectionBasedProcessing :
BranchedFoldingUtils.foldToAssignment(element) BranchedFoldingUtils.foldToAssignment(element)
} }
} }
class MoveLambdaOutsideParenthesesProcessing :
InspectionLikeProcessingForElement<KtCallExpression>(KtCallExpression::class) {
override fun isApplicableTo(element: KtCallExpression, settings: ConverterSettings?): Boolean =
element.canMoveLambdaOutsideParentheses()
override fun apply(element: KtCallExpression) {
element.moveFunctionLiteralOutsideParentheses()
}
}
@@ -6,58 +6,66 @@
package org.jetbrains.kotlin.nj2k.postProcessing.processings package org.jetbrains.kotlin.nj2k.postProcessing.processings
import com.intellij.codeInsight.actions.OptimizeImportsProcessor import com.intellij.codeInsight.actions.OptimizeImportsProcessor
import com.intellij.openapi.editor.RangeMarker
import com.intellij.psi.PsiComment import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.kotlin.idea.core.util.range 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.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.*
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
val formatCodeProcessing =
postProcessing { file, rangeMarker, _ -> class FormatCodeProcessing : GeneralPostProcessing {
file.commitAndUnblockDocument() override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
val codeStyleManager = CodeStyleManager.getInstance(file.project) val codeStyleManager = CodeStyleManager.getInstance(file.project)
if (rangeMarker != null) { runUndoTransparentActionInEdt(inWriteAction = true) {
if (rangeMarker.isValid) { if (rangeMarker != null) {
codeStyleManager.reformatRange(file, rangeMarker.startOffset, rangeMarker.endOffset) if (rangeMarker.isValid) {
} codeStyleManager.reformatRange(file, rangeMarker.startOffset, rangeMarker.endOffset)
} else { }
codeStyleManager.reformat(file) } else {
} codeStyleManager.reformat(file)
}
val clearUnknownLabelsProcessing =
postProcessing { file, _, _ ->
file.clearUndefinedLabels()
}
private fun KtFile.clearUndefinedLabels() {
val comments = mutableListOf<PsiComment>()
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() }
} }
val optimizeImportsProcessing = class ClearUnknownLabelsProcessing : GeneralPostProcessing {
postProcessing { file, rangeMarker, _ -> override fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
val elements = when { val comments = mutableListOf<PsiComment>()
rangeMarker != null && rangeMarker.isValid -> file.elementsInRange(rangeMarker.range!!) runUndoTransparentActionInEdt(inWriteAction = true) {
rangeMarker != null && !rangeMarker.isValid -> emptyList() file.accept(object : PsiElementVisitor() {
else -> file.children.asList() 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 -> val needFormat = elements.any { element ->
element is KtElement element is KtElement
@@ -65,7 +73,8 @@ val optimizeImportsProcessing =
&& element !is KtImportList && element !is KtImportList
&& element !is KtPackageDirective && element !is KtPackageDirective
} }
if (needFormat) { if (needFormat) runUndoTransparentActionInEdt(inWriteAction = false) {
OptimizeImportsProcessor(file.project, file).run() OptimizeImportsProcessor(file.project, file).run()
} }
} }
}
@@ -5,6 +5,9 @@
package org.jetbrains.kotlin.nj2k.postProcessing 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.openapi.util.TextRange
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.LocalSearchScope
@@ -80,3 +83,15 @@ inline fun <reified T : PsiElement> List<PsiElement>.descendantsOfType(): List<T
fun PsiElement.isInRange(outerRange: TextRange) = fun PsiElement.isInRange(outerRange: TextRange) =
outerRange.contains(range) outerRange.contains(range)
internal fun runUndoTransparentActionInEdt(inWriteAction: Boolean, action: () -> Unit) {
ApplicationManager.getApplication().invokeAndWait {
CommandProcessor.getInstance().runUndoTransparentAction {
if (inWriteAction) {
runWriteAction(action)
} else {
action()
}
}
}
}
@@ -5,8 +5,6 @@ internal interface I {
internal class C { internal class C {
fun foo(i: I) { fun foo(i: I) {
val result = i.string val result = i.string
if (result != null) { result?.let { print(it) }
print(result)
}
} }
} }
@@ -5,8 +5,6 @@ internal interface I {
internal class C { internal class C {
fun foo(i: I) { fun foo(i: I) {
val result = i.string val result = i.string
if (result != null) { result?.let { print(it) }
print(result)
}
} }
} }
@@ -6,8 +6,6 @@ internal class C {
fun foo(i: I, b: Boolean) { fun foo(i: I, b: Boolean) {
var result = i.string var result = i.string
if (b) result = null if (b) result = null
if (result != null) { result?.let { print(it) }
print(result)
}
} }
} }
@@ -1,5 +1,3 @@
fun foo(s: String?) { fun foo(s: String?) {
if (s != null) { s?.let { zoo(it) }
zoo(s)
}
} }
@@ -1,10 +1,10 @@
// !specifyLocalVariableTypeByDefault: true // !specifyLocalVariableTypeByDefault: true
fun bar(): String? { fun bar(): String? {
return null return null
} }
fun foo() { fun foo() {
val s: String? = bar() val s: String? = bar()
if (s != null) { s?.let { zoo(it) }
zoo(s)
}
} }
+1 -1
View File
@@ -21,6 +21,6 @@ internal class C {
} }
fun foo(javaClass: JavaClass): Int { fun foo(javaClass: JavaClass): Int {
return javaClass.get(0) return javaClass[0]
} }
} }