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
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<KtElement>) {
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)
}
}
@@ -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<NamedPostProcessingGroup> = 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<NamedPostProcessingGroup> = listOf(
NamedPostProcessingGroup(
"Optimizing imports",
listOf(
optimizeImportsProcessing,
OptimizeImportsProcessing(),
ShortenReferenceProcessing()
)
),
NamedPostProcessingGroup(
"Formatting code",
listOf(formatCodeProcessing)
listOf(FormatCodeProcessing())
)
)
@@ -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<Diagno
list.map { it.second }
}
override suspend fun runProcessing(file: KtFile, rangeMarker: RangeMarker?, converterContext: NewJ2kConverterContext) {
withContext(EDT) {
CommandProcessor.getInstance().runUndoTransparentAction {
val diagnostics = runWriteAction { analyzeFileRange(file, rangeMarker) }
for (diagnostic in diagnostics.all()) {
val range = rangeMarker?.range ?: file.textRange
if (diagnostic.psiElement.isInRange(range)) {
diagnosticToFix[diagnostic.factory]?.forEach { fix ->
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)
}
}
}
@@ -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<InspectionLikeProcessing>
) : 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<ActionData> {
val availableActions = ArrayList<ActionData>()
): List<ProcessingData> {
val availableActions = ArrayList<ProcessingData>()
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<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 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 <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)
}
}
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, TInspection : AbstractApplicabilityBasedInspection<TElement>>
inspectionBasedProcessing(inspection: TInspection, acceptInformationLevel: Boolean = false) =
object : InspectionLikeProcessing {
// Inspection can either need or not need write apply
override val writeActionNeeded = inspection.startFixInWriteAction
inline fun <reified E : PsiElement, I : SelfTargetingRangeIntention<E>> intentionBasedProcessing(
intention: I,
writeActionNeeded: Boolean = true,
noinline additionalChecker: (E) -> Boolean = { true }
) = object : InspectionLikeProcessingForElement<E>(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 <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
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<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.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<PsiElement>, converterContext: NewJ2kConverterContext) {
val classes = elements
.descendantsOfType<KtClassOrObject>()
.sortedByInheritance()
val collectingState = CollectingState()
val classesWithPropertiesData = classes.map { klass ->
klass to klass.collectPropertiesData(collectingState)
val classesWithPropertiesData = runReadAction {
elements
.descendantsOfType<KtClassOrObject>()
.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)
}
}
}
@@ -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()
}
}
@@ -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<KtElement>()
} 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(
@@ -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)
}
}
}
}
@@ -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>(KtProperty::class) {
class RemoveExplicitPropertyTypeProcessing : InspectionLikeProcessingForElement<KtProperty>(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>(KtProperty::class) {
class RemoveRedundantNullabilityProcessing : InspectionLikeProcessingForElement<KtProperty>(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>(KtTypeArgumentList::class) {
class RemoveExplicitTypeArgumentsProcessing : InspectionLikeProcessingForElement<KtTypeArgumentList>(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>(KtCallExpression::class) {
InspectionLikeProcessingForElement<KtCallExpression>(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>(KtCallableDeclaration::class) {
InspectionLikeProcessingForElement<KtCallableDeclaration>(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>(KtPropertyAccessor::class) {
class UseExpressionBodyProcessing : InspectionLikeProcessingForElement<KtPropertyAccessor>(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<K
}
class RemoveRedundantCastToNullableProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtBinaryExpressionWithTypeRHS>(KtBinaryExpressionWithTypeRHS::class) {
InspectionLikeProcessingForElement<KtBinaryExpressionWithTypeRHS>(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>(KtCallExpression::class) {
InspectionLikeProcessingForElement<KtCallExpression>(KtCallExpression::class) {
override fun isApplicableTo(element: KtCallExpression, settings: ConverterSettings?): Boolean =
RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element).isNotEmpty()
@@ -171,7 +168,7 @@ class RemoveRedundantSamAdaptersProcessing :
}
class UninitializedVariableReferenceFromInitializerToThisReferenceProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtSimpleNameExpression>(KtSimpleNameExpression::class) {
InspectionLikeProcessingForElement<KtSimpleNameExpression>(KtSimpleNameExpression::class) {
override fun isApplicableTo(element: KtSimpleNameExpression, settings: ConverterSettings?): Boolean {
val anonymousObject = element.getStrictParentOfType<KtClassOrObject>()?.takeIf { it.name == null } ?: return false
@@ -192,7 +189,7 @@ class UninitializedVariableReferenceFromInitializerToThisReferenceProcessing :
}
class UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtSimpleNameExpression>(KtSimpleNameExpression::class) {
InspectionLikeProcessingForElement<KtSimpleNameExpression>(KtSimpleNameExpression::class) {
override fun isApplicableTo(element: KtSimpleNameExpression, settings: ConverterSettings?): Boolean {
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 =
ReferencesSearch.search(this, useScope).any { usage ->
(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 {
val CALL_FQ_NAME = FqName("java.util.Objects.equals")
}
@@ -259,7 +256,7 @@ class JavaObjectEqualsToEqOperatorProcessing : ApplicabilityBasedInspectionLikeP
class RemoveForExpressionLoopParameterTypeProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtForExpression>(KtForExpression::class) {
InspectionLikeProcessingForElement<KtForExpression>(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>(KtPrimaryConstructor::class) {
InspectionLikeProcessingForElement<KtPrimaryConstructor>(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>(KtDeclaration::class) {
class RemoveRedundantModalityModifierProcessing : InspectionLikeProcessingForElement<KtDeclaration>(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>(KtDeclaration::class) {
class RemoveRedundantVisibilityModifierProcessing : InspectionLikeProcessingForElement<KtDeclaration>(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>(KtClass::class) {
class RemoveExplicitOpenInInterfaceProcessing : InspectionLikeProcessingForElement<KtClass>(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>(KtProperty::class) {
class MoveGetterAndSetterAnnotationsToPropertyProcessing : InspectionLikeProcessingForElement<KtProperty>(KtProperty::class) {
override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean =
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 =
RedundantExplicitTypeInspection.hasRedundantType(element)
override fun apply(element: KtProperty) {
element.typeReference = null
RemoveExplicitTypeIntention.removeExplicitType(element)
}
}
class CanBeValInspectionBasedProcessing : ApplicabilityBasedInspectionLikeProcessing<KtDeclaration>(KtDeclaration::class) {
class CanBeValInspectionBasedProcessing : InspectionLikeProcessingForElement<KtDeclaration>(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>(KtProperty::class) {
class MayBeConstantInspectionBasedProcessing : InspectionLikeProcessingForElement<KtProperty>(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>(KtNamedFunction::class) {
class RemoveExplicitUnitTypeProcessing : InspectionLikeProcessingForElement<KtNamedFunction>(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>(KtPropertyAccessor::class) {
InspectionLikeProcessingForElement<KtPropertyAccessor>(KtPropertyAccessor::class) {
override fun isApplicableTo(element: KtPropertyAccessor, settings: ConverterSettings?): Boolean =
element.isRedundantGetter()
@@ -402,7 +400,7 @@ class RemoveExplicitGetterInspectionBasedProcessing :
}
class RemoveExplicitSetterInspectionBasedProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtPropertyAccessor>(KtPropertyAccessor::class) {
InspectionLikeProcessingForElement<KtPropertyAccessor>(KtPropertyAccessor::class) {
override fun isApplicableTo(element: KtPropertyAccessor, settings: ConverterSettings?): Boolean =
element.isRedundantSetter()
@@ -413,7 +411,7 @@ class RemoveExplicitSetterInspectionBasedProcessing :
class RedundantSemicolonInspectionBasedProcessing :
ApplicabilityBasedInspectionLikeProcessing<PsiElement>(PsiElement::class) {
InspectionLikeProcessingForElement<PsiElement>(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>(KtReferenceExpression::class) {
InspectionLikeProcessingForElement<KtReferenceExpression>(KtReferenceExpression::class) {
override fun isApplicableTo(element: KtReferenceExpression, settings: ConverterSettings?): Boolean =
RedundantCompanionReferenceInspection.isRedundantCompanionReference(element)
@@ -435,7 +433,7 @@ class RedundantCompanionReferenceInspectionBasedProcessing :
}
class ExplicitThisInspectionBasedProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtExpression>(KtExpression::class) {
InspectionLikeProcessingForElement<KtExpression>(KtExpression::class) {
override fun isApplicableTo(element: KtExpression, settings: ConverterSettings?): Boolean =
ExplicitThisInspection.hasExplicitThis(element)
@@ -449,7 +447,7 @@ class ExplicitThisInspectionBasedProcessing :
}
class LiftReturnInspectionBasedProcessing :
ApplicabilityBasedInspectionLikeProcessing<KtExpression>(KtExpression::class) {
InspectionLikeProcessingForElement<KtExpression>(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>(KtExpression::class) {
InspectionLikeProcessingForElement<KtExpression>(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>(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
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<PsiComment>()
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<PsiComment>()
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()
}
}
}
@@ -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 <reified T : PsiElement> List<PsiElement>.descendantsOfType(): List<T
flatMap { it.collectDescendantsOfType() }
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 {
fun foo(i: I) {
val result = i.string
if (result != null) {
print(result)
}
result?.let { print(it) }
}
}
@@ -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) }
}
}
@@ -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) }
}
}
@@ -1,5 +1,3 @@
fun foo(s: String?) {
if (s != null) {
zoo(s)
}
s?.let { zoo(it) }
}
@@ -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) }
}
+1 -1
View File
@@ -21,6 +21,6 @@ internal class C {
}
fun foo(javaClass: JavaClass): Int {
return javaClass.get(0)
return javaClass[0]
}
}