New J2K: do not analyze code for post-processings in edt thread
This commit is contained in:
+11
-6
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-48
@@ -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())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
+10
-15
@@ -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) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+66
-94
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
+13
-8
@@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-15
@@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-10
@@ -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(
|
||||||
|
|||||||
+14
-15
@@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+43
-35
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+47
-38
@@ -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
@@ -21,6 +21,6 @@ internal class C {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun foo(javaClass: JavaClass): Int {
|
fun foo(javaClass: JavaClass): Int {
|
||||||
return javaClass.get(0)
|
return javaClass[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user