New J2K: split diagnostic based processing from inspection ones
Analysing file file with diagnostics on each step of post-processings is rather expensive operation so the inspection-like post-processings which don't require diagnostic information was separated from ones that need it Related to #KT-31848
This commit is contained in:
+121
-198
@@ -9,16 +9,9 @@ import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.command.CommandProcessor
|
||||
import com.intellij.openapi.editor.RangeMarker
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import com.intellij.psi.search.LocalSearchScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters2
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
|
||||
import org.jetbrains.kotlin.idea.core.util.EDT
|
||||
import org.jetbrains.kotlin.idea.formatter.commitAndUnblockDocument
|
||||
@@ -29,10 +22,8 @@ import org.jetbrains.kotlin.idea.inspections.conventionNameCalls.ReplaceGetOrSet
|
||||
import org.jetbrains.kotlin.idea.intentions.*
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FoldIfToReturnAsymmetricallyIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FoldIfToReturnIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isNullExpression
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isTrivialStatementBody
|
||||
import org.jetbrains.kotlin.idea.quickfix.*
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.j2k.ConverterContext
|
||||
@@ -40,15 +31,8 @@ import org.jetbrains.kotlin.j2k.PostProcessor
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
import org.jetbrains.kotlin.nj2k.postProcessing.processings.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.isNullable
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSignedOrUnsignedNumberType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
|
||||
class NewJ2kPostProcessor : PostProcessor {
|
||||
override fun insertImport(file: KtFile, fqName: FqName) {
|
||||
@@ -90,6 +74,124 @@ class NewJ2kPostProcessor : PostProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private val errorsFixingDiagnosticBasedPostProcessingGroup =
|
||||
DiagnosticBasedPostProcessingGroup(
|
||||
diagnosticBasedProcessing(Errors.REDUNDANT_OPEN_IN_INTERFACE) { element: KtModifierListOwner, _ ->
|
||||
element.removeModifier(KtTokens.OPEN_KEYWORD)
|
||||
},
|
||||
diagnosticBasedProcessing(Errors.PLATFORM_CLASS_MAPPED_TO_KOTLIN) { element: KtDotQualifiedExpression, _ ->
|
||||
val parent = element.parent as? KtImportDirective ?: return@diagnosticBasedProcessing
|
||||
parent.delete()
|
||||
},
|
||||
|
||||
diagnosticBasedProcessing(
|
||||
addExclExclFactoryNoImplicitReceiver(AddExclExclCallFix),
|
||||
Errors.UNSAFE_CALL,
|
||||
Errors.UNSAFE_INFIX_CALL,
|
||||
Errors.UNSAFE_OPERATOR_CALL
|
||||
),
|
||||
diagnosticBasedProcessing(
|
||||
addExclExclFactoryNoImplicitReceiver(MissingIteratorExclExclFixFactory),
|
||||
Errors.ITERATOR_ON_NULLABLE
|
||||
),
|
||||
diagnosticBasedProcessing(
|
||||
SmartCastImpossibleExclExclFixFactory,
|
||||
Errors.SMARTCAST_IMPOSSIBLE
|
||||
),
|
||||
|
||||
diagnosticBasedProcessing(
|
||||
ReplacePrimitiveCastWithNumberConversionFix,
|
||||
Errors.CAST_NEVER_SUCCEEDS
|
||||
),
|
||||
diagnosticBasedProcessing(
|
||||
ChangeCallableReturnTypeFix.ReturnTypeMismatchOnOverrideFactory,
|
||||
Errors.RETURN_TYPE_MISMATCH_ON_OVERRIDE
|
||||
),
|
||||
|
||||
diagnosticBasedProcessing(
|
||||
RemoveModifierFix.createRemoveProjectionFactory(true),
|
||||
Errors.REDUNDANT_PROJECTION
|
||||
),
|
||||
diagnosticBasedProcessing(
|
||||
AddModifierFix.createFactory(KtTokens.OVERRIDE_KEYWORD),
|
||||
Errors.VIRTUAL_MEMBER_HIDDEN
|
||||
),
|
||||
diagnosticBasedProcessing(
|
||||
RemoveModifierFix.createRemoveModifierFromListOwnerFactory(KtTokens.OPEN_KEYWORD),
|
||||
Errors.NON_FINAL_MEMBER_IN_FINAL_CLASS, Errors.NON_FINAL_MEMBER_IN_OBJECT
|
||||
),
|
||||
diagnosticBasedProcessing(
|
||||
MakeVisibleFactory,
|
||||
Errors.INVISIBLE_MEMBER
|
||||
),
|
||||
fixValToVarDiagnosticBasedProcessing,
|
||||
fixTypeMismatchDiagnosticBasedProcessing
|
||||
)
|
||||
|
||||
|
||||
private val inspectionLikePostProcessingGroup =
|
||||
InspectionLikeProcessingGroup(
|
||||
RemoveRedundantVisibilityModifierProcessing(),
|
||||
RemoveRedundantModalityModifierProcessing(),
|
||||
RemoveRedundantConstructorKeywordProcessing(),
|
||||
RemoveExplicitOpenInInterfaceProcessing(),
|
||||
generalInspectionBasedProcessing(ExplicitThisInspection()),
|
||||
RemoveExplicitTypeArgumentsProcessing(),
|
||||
RemoveRedundantOverrideVisibilityProcessing(),
|
||||
inspectionBasedProcessing(MoveLambdaOutsideParenthesesInspection()),
|
||||
generalInspectionBasedProcessing(RedundantCompanionReferenceInspection()),
|
||||
ConvertToStringTemplateProcessing(),
|
||||
UsePropertyAccessSyntaxProcessing(),
|
||||
UninitializedVariableReferenceFromInitializerToThisReferenceProcessing(),
|
||||
UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing(),
|
||||
RemoveRedundantSamAdaptersProcessing(),
|
||||
RemoveRedundantCastToNullableProcessing(),
|
||||
inspectionBasedProcessing(ReplacePutWithAssignmentInspection()),
|
||||
UseExpressionBodyProcessing(),
|
||||
inspectionBasedProcessing(UnnecessaryVariableInspection()),
|
||||
RemoveExplicitPropertyTypeWithInspectionProcessing(),
|
||||
generalInspectionBasedProcessing(RedundantUnitReturnTypeInspection()),
|
||||
JavaObjectEqualsToEqOperatorProcessing(),
|
||||
RemoveExplicitPropertyTypeProcessing(),
|
||||
RemoveRedundantNullabilityProcessing(),
|
||||
generalInspectionBasedProcessing(CanBeValInspection(ignoreNotUsedVals = false)),
|
||||
inspectionBasedProcessing(FoldInitializerAndIfToElvisInspection()),
|
||||
generalInspectionBasedProcessing(RedundantSemicolonInspection()),
|
||||
intentionBasedProcessing(RemoveEmptyClassBodyIntention()),
|
||||
intentionBasedProcessing(RemoveRedundantCallsOfConversionMethodsIntention()),
|
||||
inspectionBasedProcessing(JavaMapForEachInspection()),
|
||||
intentionBasedProcessing(FoldIfToReturnIntention()) { it.then.isTrivialStatementBody() && it.`else`.isTrivialStatementBody() },
|
||||
intentionBasedProcessing(FoldIfToReturnAsymmetricallyIntention()) {
|
||||
it.then.isTrivialStatementBody() && (KtPsiUtil.skipTrailingWhitespacesAndComments(
|
||||
it
|
||||
) as KtReturnExpression).returnedExpression.isTrivialStatementBody()
|
||||
},
|
||||
inspectionBasedProcessing(IfThenToSafeAccessInspection()),
|
||||
inspectionBasedProcessing(IfThenToElvisInspection(highlightStatement = true)),
|
||||
inspectionBasedProcessing(SimplifyNegatedBinaryExpressionInspection()),
|
||||
inspectionBasedProcessing(ReplaceGetOrSetInspection()),
|
||||
inspectionBasedProcessing(AddOperatorModifierInspection()),
|
||||
intentionBasedProcessing(ObjectLiteralToLambdaIntention()),
|
||||
intentionBasedProcessing(AnonymousFunctionToLambdaIntention()),
|
||||
intentionBasedProcessing(RemoveUnnecessaryParenthesesIntention()),
|
||||
intentionBasedProcessing(DestructureIntention()),
|
||||
inspectionBasedProcessing(SimplifyAssertNotNullInspection()),
|
||||
intentionBasedProcessing(RemoveRedundantCallsOfConversionMethodsIntention()),
|
||||
generalInspectionBasedProcessing(LiftReturnOrAssignmentInspection(skipLongExpressions = false)),
|
||||
intentionBasedProcessing(RemoveEmptyPrimaryConstructorIntention()),
|
||||
generalInspectionBasedProcessing(MayBeConstantInspection()),
|
||||
RemoveForExpressionLoopParameterTypeProcessing()
|
||||
)
|
||||
|
||||
|
||||
private val cleaningUpDiagnosticBasedPostProcessingGroup =
|
||||
DiagnosticBasedPostProcessingGroup(
|
||||
removeUselessCastDiagnosticBasedProcessing,
|
||||
removeInnecessaryNotNullAssertionDiagnosticBasedProcessing,
|
||||
fixValToVarDiagnosticBasedProcessing
|
||||
)
|
||||
|
||||
|
||||
private val processings: List<NamedPostProcessingGroup> = listOf(
|
||||
NamedPostProcessingGroup(
|
||||
"Inferring declarations nullability",
|
||||
@@ -119,188 +221,9 @@ private val processings: List<NamedPostProcessingGroup> = listOf(
|
||||
NamedPostProcessingGroup(
|
||||
"Cleaning up Kotlin code",
|
||||
listOf(
|
||||
InspectionLikeProcessingGroup(
|
||||
RemoveRedundantVisibilityModifierProcessing(),
|
||||
RemoveRedundantModalityModifierProcessing(),
|
||||
RemoveRedundantConstructorKeywordProcessing(),
|
||||
diagnosticBasedProcessing(Errors.REDUNDANT_OPEN_IN_INTERFACE) { element: KtDeclaration, _ ->
|
||||
element.removeModifier(KtTokens.OPEN_KEYWORD)
|
||||
},
|
||||
RemoveExplicitOpenInInterfaceProcessing(),
|
||||
generalInspectionBasedProcessing(ExplicitThisInspection()),
|
||||
RemoveExplicitTypeArgumentsProcessing(),
|
||||
RemoveRedundantOverrideVisibilityProcessing(),
|
||||
inspectionBasedProcessing(MoveLambdaOutsideParenthesesInspection()),
|
||||
generalInspectionBasedProcessing(RedundantCompanionReferenceInspection()),
|
||||
FixObjectStringConcatenationProcessing(),
|
||||
ConvertToStringTemplateProcessing(),
|
||||
UsePropertyAccessSyntaxProcessing(),
|
||||
UninitializedVariableReferenceFromInitializerToThisReferenceProcessing(),
|
||||
UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing(),
|
||||
RemoveRedundantSamAdaptersProcessing(),
|
||||
RemoveRedundantCastToNullableProcessing(),
|
||||
inspectionBasedProcessing(ReplacePutWithAssignmentInspection()),
|
||||
UseExpressionBodyProcessing(),
|
||||
inspectionBasedProcessing(UnnecessaryVariableInspection()),
|
||||
RemoveExplicitPropertyTypeWithInspectionProcessing(),
|
||||
generalInspectionBasedProcessing(RedundantUnitReturnTypeInspection()),
|
||||
JavaObjectEqualsToEqOperatorProcessing(),
|
||||
RemoveExplicitPropertyTypeProcessing(),
|
||||
RemoveRedundantNullabilityProcessing(),
|
||||
generalInspectionBasedProcessing(CanBeValInspection(ignoreNotUsedVals = false)),
|
||||
inspectionBasedProcessing(FoldInitializerAndIfToElvisInspection()),
|
||||
generalInspectionBasedProcessing(RedundantSemicolonInspection()),
|
||||
intentionBasedProcessing(RemoveEmptyClassBodyIntention()),
|
||||
intentionBasedProcessing(
|
||||
RemoveRedundantCallsOfConversionMethodsIntention()
|
||||
),
|
||||
inspectionBasedProcessing(JavaMapForEachInspection()),
|
||||
|
||||
intentionBasedProcessing(FoldIfToReturnIntention()) { it.then.isTrivialStatementBody() && it.`else`.isTrivialStatementBody() },
|
||||
intentionBasedProcessing(FoldIfToReturnAsymmetricallyIntention()) {
|
||||
it.then.isTrivialStatementBody() && (KtPsiUtil.skipTrailingWhitespacesAndComments(
|
||||
it
|
||||
) as KtReturnExpression).returnedExpression.isTrivialStatementBody()
|
||||
},
|
||||
|
||||
inspectionBasedProcessing(IfThenToSafeAccessInspection()),
|
||||
inspectionBasedProcessing(IfThenToSafeAccessInspection()),
|
||||
inspectionBasedProcessing(IfThenToElvisInspection(true)),
|
||||
inspectionBasedProcessing(SimplifyNegatedBinaryExpressionInspection()),
|
||||
inspectionBasedProcessing(ReplaceGetOrSetInspection()),
|
||||
inspectionBasedProcessing(AddOperatorModifierInspection()),
|
||||
intentionBasedProcessing(ObjectLiteralToLambdaIntention()),
|
||||
intentionBasedProcessing(AnonymousFunctionToLambdaIntention()),
|
||||
intentionBasedProcessing(RemoveUnnecessaryParenthesesIntention()),
|
||||
intentionBasedProcessing(DestructureIntention()),
|
||||
inspectionBasedProcessing(SimplifyAssertNotNullInspection()),
|
||||
intentionBasedProcessing(
|
||||
RemoveRedundantCallsOfConversionMethodsIntention()
|
||||
),
|
||||
generalInspectionBasedProcessing(LiftReturnOrAssignmentInspection(skipLongExpressions = false)),
|
||||
generalInspectionBasedProcessing(MayBeConstantInspection()),
|
||||
intentionBasedProcessing(RemoveEmptyPrimaryConstructorIntention()),
|
||||
diagnosticBasedProcessing(Errors.PLATFORM_CLASS_MAPPED_TO_KOTLIN) { element: KtDotQualifiedExpression, _ ->
|
||||
val parent = element.parent as? KtImportDirective ?: return@diagnosticBasedProcessing
|
||||
parent.delete()
|
||||
},
|
||||
|
||||
diagnosticBasedProcessing(
|
||||
Errors.UNSAFE_CALL,
|
||||
Errors.UNSAFE_INFIX_CALL,
|
||||
Errors.UNSAFE_OPERATOR_CALL
|
||||
) { element: PsiElement, diagnostic ->
|
||||
val action =
|
||||
AddExclExclCallFix.createActions(diagnostic).singleOrNull()
|
||||
?: return@diagnosticBasedProcessing
|
||||
action.invoke(element.project, null, element.containingFile)
|
||||
},
|
||||
|
||||
diagnosticBasedProcessingWithFixFactory(
|
||||
MissingIteratorExclExclFixFactory,
|
||||
Errors.ITERATOR_ON_NULLABLE
|
||||
),
|
||||
diagnosticBasedProcessingWithFixFactory(
|
||||
SmartCastImpossibleExclExclFixFactory,
|
||||
Errors.SMARTCAST_IMPOSSIBLE
|
||||
),
|
||||
diagnosticBasedProcessing(Errors.TYPE_MISMATCH) { element: PsiElement, diagnostic ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val diagnosticWithParameters =
|
||||
diagnostic as? DiagnosticWithParameters2<KtExpression, KotlinType, KotlinType>
|
||||
?: return@diagnosticBasedProcessing
|
||||
val expectedType = diagnosticWithParameters.a
|
||||
val realType = diagnosticWithParameters.b
|
||||
when {
|
||||
realType.makeNotNullable().isSubtypeOf(expectedType.makeNotNullable())
|
||||
&& realType.isNullable()
|
||||
&& !expectedType.isNullable()
|
||||
-> {
|
||||
val factory = KtPsiFactory(element)
|
||||
element.replace(factory.createExpressionByPattern("($0)!!", element.text))
|
||||
}
|
||||
element is KtExpression
|
||||
&& realType.isSignedOrUnsignedNumberType()
|
||||
&& expectedType.isSignedOrUnsignedNumberType() -> {
|
||||
val fix = NumberConversionFix(element, expectedType, disableIfAvailable = null)
|
||||
fix.invoke(element.project, null, element.containingFile)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
diagnosticBasedProcessingWithFixFactory(
|
||||
ReplacePrimitiveCastWithNumberConversionFix,
|
||||
Errors.CAST_NEVER_SUCCEEDS
|
||||
),
|
||||
diagnosticBasedProcessingWithFixFactory(
|
||||
ChangeCallableReturnTypeFix.ReturnTypeMismatchOnOverrideFactory,
|
||||
Errors.RETURN_TYPE_MISMATCH_ON_OVERRIDE
|
||||
),
|
||||
|
||||
diagnosticBasedProcessing<KtBinaryExpressionWithTypeRHS>(Errors.USELESS_CAST) { element, _ ->
|
||||
if (element.left.isNullExpression()) return@diagnosticBasedProcessing
|
||||
val expression = RemoveUselessCastFix.invoke(element)
|
||||
|
||||
val variable = expression.parent as? KtProperty
|
||||
if (variable != null && expression == variable.initializer && variable.isLocal) {
|
||||
val ref = ReferencesSearch.search(variable, LocalSearchScope(variable.containingFile)).findAll().singleOrNull()
|
||||
if (ref != null && ref.element is KtSimpleNameExpression) {
|
||||
ref.element.replace(expression)
|
||||
variable.delete()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
diagnosticBasedProcessingWithFixFactory(
|
||||
RemoveModifierFix.createRemoveProjectionFactory(true),
|
||||
Errors.REDUNDANT_PROJECTION
|
||||
),
|
||||
diagnosticBasedProcessingWithFixFactory(
|
||||
AddModifierFix.createFactory(KtTokens.OVERRIDE_KEYWORD),
|
||||
Errors.VIRTUAL_MEMBER_HIDDEN
|
||||
),
|
||||
diagnosticBasedProcessingWithFixFactory(
|
||||
RemoveModifierFix.createRemoveModifierFromListOwnerFactory(KtTokens.OPEN_KEYWORD),
|
||||
Errors.NON_FINAL_MEMBER_IN_FINAL_CLASS, Errors.NON_FINAL_MEMBER_IN_OBJECT
|
||||
),
|
||||
diagnosticBasedProcessingWithFixFactory(
|
||||
MakeVisibleFactory,
|
||||
Errors.INVISIBLE_MEMBER
|
||||
),
|
||||
|
||||
diagnosticBasedProcessingFactory(
|
||||
Errors.VAL_REASSIGNMENT, Errors.CAPTURED_VAL_INITIALIZATION, Errors.CAPTURED_MEMBER_VAL_INITIALIZATION
|
||||
) { element: KtSimpleNameExpression, _: Diagnostic ->
|
||||
val property = element.mainReference.resolve() as? KtProperty
|
||||
if (property == null) {
|
||||
null
|
||||
} else {
|
||||
val action = {
|
||||
if (!property.isVar) {
|
||||
property.valOrVarKeyword.replace(KtPsiFactory(element.project).createVarKeyword())
|
||||
}
|
||||
}
|
||||
action
|
||||
}
|
||||
},
|
||||
|
||||
diagnosticBasedProcessing<KtSimpleNameExpression>(Errors.UNNECESSARY_NOT_NULL_ASSERTION) { element, _ ->
|
||||
val exclExclExpr = element.parent as KtUnaryExpression
|
||||
val baseExpression = exclExclExpr.baseExpression!!
|
||||
val context = baseExpression.analyze(BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS)
|
||||
if (context.diagnostics.forElement(element).any { it.factory == Errors.UNNECESSARY_NOT_NULL_ASSERTION }) {
|
||||
exclExclExpr.replace(baseExpression)
|
||||
}
|
||||
},
|
||||
diagnosticBasedProcessing<LeafPsiElement>(
|
||||
Errors.WRONG_MODIFIER_TARGET
|
||||
) { element, _ ->
|
||||
if (element.elementType == KtTokens.OPEN_KEYWORD) {
|
||||
element.parentOfType<KtModifierListOwner>()?.removeModifier(KtTokens.OPEN_KEYWORD)
|
||||
}
|
||||
},
|
||||
RemoveForExpressionLoopParameterTypeProcessing()
|
||||
)
|
||||
errorsFixingDiagnosticBasedPostProcessingGroup,
|
||||
inspectionLikePostProcessingGroup,
|
||||
cleaningUpDiagnosticBasedPostProcessingGroup
|
||||
)
|
||||
),
|
||||
NamedPostProcessingGroup(
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
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.nj2k.NewJ2kConverterContext
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class DiagnosticBasedPostProcessingGroup(diagnosticBasedProcessings: List<DiagnosticBasedProcessing>) : ProcessingGroup {
|
||||
constructor(vararg diagnosticBasedProcessings: DiagnosticBasedProcessing) : this(diagnosticBasedProcessings.toList())
|
||||
|
||||
private val diagnosticToFix =
|
||||
diagnosticBasedProcessings.asSequence().flatMap { processing ->
|
||||
processing.diagnosticFactories.asSequence().map { it to processing::fix }
|
||||
}.groupBy { it.first }.mapValues { (_, list) ->
|
||||
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()) {
|
||||
diagnosticToFix[diagnostic.factory]?.forEach { fix ->
|
||||
runWriteAction { fix(diagnostic) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun analyzeFileRange(file: KtFile, rangeMarker: RangeMarker?): Diagnostics {
|
||||
val elements =
|
||||
if (rangeMarker == null) listOf(file)
|
||||
else file.elementsInRange(rangeMarker.range!!).filterIsInstance<KtElement>()
|
||||
|
||||
return if (elements.isNotEmpty())
|
||||
file.getResolutionFacade().analyzeWithAllCompilerChecks(elements).bindingContext.diagnostics
|
||||
else Diagnostics.EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
interface DiagnosticBasedProcessing {
|
||||
val diagnosticFactories: List<DiagnosticFactory<*>>
|
||||
fun fix(diagnostic: Diagnostic)
|
||||
}
|
||||
|
||||
inline fun <reified T : PsiElement> diagnosticBasedProcessing(
|
||||
vararg diagnosticFactory: DiagnosticFactory<*>,
|
||||
crossinline fix: (T, Diagnostic) -> Unit
|
||||
) =
|
||||
object : DiagnosticBasedProcessing {
|
||||
override val diagnosticFactories = diagnosticFactory.toList()
|
||||
override fun fix(diagnostic: Diagnostic) {
|
||||
val element = diagnostic.psiElement as? T
|
||||
if (element != null) {
|
||||
fix(element, diagnostic)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun diagnosticBasedProcessing(fixFactory: KotlinIntentionActionsFactory, vararg diagnosticFactory: DiagnosticFactory<*>) =
|
||||
object : DiagnosticBasedProcessing {
|
||||
override val diagnosticFactories = diagnosticFactory.toList()
|
||||
override fun fix(diagnostic: Diagnostic) {
|
||||
val fix = fixFactory.createActions(diagnostic).singleOrNull()
|
||||
fix?.invoke(diagnostic.psiElement.project, null, diagnostic.psiFile)
|
||||
}
|
||||
}
|
||||
|
||||
fun addExclExclFactoryNoImplicitReceiver(initialFactory: KotlinSingleIntentionActionFactory) =
|
||||
object : KotlinSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? =
|
||||
initialFactory.createActions(diagnostic).singleOrNull()
|
||||
?.safeAs<AddExclExclCallFix>()
|
||||
?.let {
|
||||
AddExclExclCallFix(diagnostic.psiElement, checkImplicitReceivers = false)
|
||||
}
|
||||
}
|
||||
|
||||
+6
-57
@@ -88,8 +88,6 @@ class InspectionLikeProcessingGroup(val inspectionLikeProcessings: List<Inspecti
|
||||
context: NewJ2kConverterContext,
|
||||
rangeMarker: RangeMarker?
|
||||
): List<ActionData> {
|
||||
val diagnostics = analyzeFileRange(file, rangeMarker)
|
||||
|
||||
val availableActions = ArrayList<ActionData>()
|
||||
|
||||
file.accept(object : PsiRecursiveElementVisitor() {
|
||||
@@ -101,7 +99,7 @@ class InspectionLikeProcessingGroup(val inspectionLikeProcessings: List<Inspecti
|
||||
|
||||
if (rangeResult == RangeFilterResult.PROCESS) {
|
||||
inspectionLikeProcessings.forEach { processing ->
|
||||
val action = processing.createAction(element, diagnostics, context.converter.settings)
|
||||
val action = processing.createAction(element, context.converter.settings)
|
||||
if (action != null) {
|
||||
availableActions.add(
|
||||
ActionData(
|
||||
@@ -119,17 +117,6 @@ class InspectionLikeProcessingGroup(val inspectionLikeProcessings: List<Inspecti
|
||||
return availableActions
|
||||
}
|
||||
|
||||
private fun analyzeFileRange(file: KtFile, rangeMarker: RangeMarker?): Diagnostics {
|
||||
val elements = if (rangeMarker == null)
|
||||
listOf(file)
|
||||
else
|
||||
file.elementsInRange(rangeMarker.range!!).filterIsInstance<KtElement>()
|
||||
|
||||
return if (elements.isNotEmpty())
|
||||
file.getResolutionFacade().analyzeWithAllCompilerChecks(elements).bindingContext.diagnostics
|
||||
else
|
||||
Diagnostics.EMPTY
|
||||
}
|
||||
|
||||
private fun rangeFilter(element: PsiElement, rangeMarker: RangeMarker?): RangeFilterResult {
|
||||
if (rangeMarker == null) return RangeFilterResult.PROCESS
|
||||
@@ -145,7 +132,7 @@ class InspectionLikeProcessingGroup(val inspectionLikeProcessings: List<Inspecti
|
||||
}
|
||||
|
||||
interface InspectionLikeProcessing {
|
||||
fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)?
|
||||
fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)?
|
||||
|
||||
val writeActionNeeded: Boolean
|
||||
}
|
||||
@@ -154,7 +141,7 @@ abstract class ApplicabilityBasedInspectionLikeProcessing<E : PsiElement>(privat
|
||||
protected abstract fun isApplicableTo(element: E, settings: ConverterSettings?): Boolean
|
||||
protected abstract fun apply(element: E)
|
||||
|
||||
final override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
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
|
||||
@@ -176,7 +163,7 @@ inline fun <reified TElement : PsiElement, TIntention : SelfTargetingRangeIntent
|
||||
// Intention can either need or not need write apply
|
||||
override val writeActionNeeded = intention.startInWriteAction()
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
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
|
||||
@@ -238,7 +225,7 @@ fun <TInspection : AbstractKotlinInspection> generalInspectionBasedProcessing(
|
||||
}
|
||||
}
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
override fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? {
|
||||
val holder = ProblemsHolder(InspectionManager.getInstance(element.project), element.containingFile, false)
|
||||
val visitor = inspection.buildVisitor(
|
||||
holder,
|
||||
@@ -271,7 +258,7 @@ inline fun <reified TElement : PsiElement, TInspection : AbstractApplicabilityBa
|
||||
return acceptInformationLevel || inspection.inspectionHighlightType(element) != ProblemHighlightType.INFORMATION
|
||||
}
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
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
|
||||
@@ -282,41 +269,3 @@ inline fun <reified TElement : PsiElement, TInspection : AbstractApplicabilityBa
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun diagnosticBasedProcessingWithFixFactory(
|
||||
fixFactory: KotlinIntentionActionsFactory,
|
||||
vararg diagnosticFactory: DiagnosticFactory<*>
|
||||
): InspectionLikeProcessing =
|
||||
diagnosticBasedProcessing(*diagnosticFactory) { element: PsiElement, diagnostic: Diagnostic ->
|
||||
fixFactory.createActions(diagnostic).singleOrNull()
|
||||
?.invoke(element.project, null, element.containingFile)
|
||||
}
|
||||
|
||||
|
||||
inline fun <reified TElement : PsiElement> diagnosticBasedProcessing(
|
||||
vararg diagnosticFactory: DiagnosticFactory<*>,
|
||||
crossinline fix: (TElement, Diagnostic) -> Unit
|
||||
) = object : InspectionLikeProcessing {
|
||||
override val writeActionNeeded = true
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (!TElement::class.java.isInstance(element)) return null
|
||||
val diagnostic = diagnostics.forElement(element).firstOrNull { it.factory in diagnosticFactory } ?: return null
|
||||
return {
|
||||
fix(element as TElement, diagnostic)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified TElement : PsiElement> diagnosticBasedProcessingFactory(
|
||||
vararg diagnosticFactory: DiagnosticFactory<*>,
|
||||
crossinline fixFactory: (TElement, Diagnostic) -> (() -> Unit)?
|
||||
) = object : InspectionLikeProcessing {
|
||||
override val writeActionNeeded = true
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (!TElement::class.java.isInstance(element)) return null
|
||||
val diagnostic = diagnostics.forElement(element).firstOrNull { it.factory in diagnosticFactory } ?: return null
|
||||
return fixFactory(element as TElement, diagnostic)
|
||||
}
|
||||
}
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.nj2k.postProcessing.processings
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.search.LocalSearchScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters2
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isNullExpression
|
||||
import org.jetbrains.kotlin.idea.quickfix.NumberConversionFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.RemoveUselessCastFix
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.nj2k.postProcessing.diagnosticBasedProcessing
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.isNullable
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSignedOrUnsignedNumberType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
|
||||
val fixValToVarDiagnosticBasedProcessing =
|
||||
diagnosticBasedProcessing(
|
||||
Errors.VAL_REASSIGNMENT, Errors.CAPTURED_VAL_INITIALIZATION, Errors.CAPTURED_MEMBER_VAL_INITIALIZATION
|
||||
) { element: KtSimpleNameExpression, _ ->
|
||||
val property = element.mainReference.resolve() as? KtProperty ?: return@diagnosticBasedProcessing
|
||||
if (!property.isVar) {
|
||||
property.valOrVarKeyword.replace(KtPsiFactory(element.project).createVarKeyword())
|
||||
}
|
||||
}
|
||||
|
||||
val fixTypeMismatchDiagnosticBasedProcessing =
|
||||
diagnosticBasedProcessing(Errors.TYPE_MISMATCH) { element: PsiElement, diagnostic ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val diagnosticWithParameters =
|
||||
diagnostic as? DiagnosticWithParameters2<KtExpression, KotlinType, KotlinType>
|
||||
?: return@diagnosticBasedProcessing
|
||||
val expectedType = diagnosticWithParameters.a
|
||||
val realType = diagnosticWithParameters.b
|
||||
when {
|
||||
realType.makeNotNullable().isSubtypeOf(expectedType.makeNotNullable())
|
||||
&& realType.isNullable()
|
||||
&& !expectedType.isNullable()
|
||||
-> {
|
||||
val factory = KtPsiFactory(element)
|
||||
element.replace(factory.createExpressionByPattern("($0)!!", element.text))
|
||||
}
|
||||
element is KtExpression
|
||||
&& realType.isSignedOrUnsignedNumberType()
|
||||
&& expectedType.isSignedOrUnsignedNumberType() -> {
|
||||
val fix = NumberConversionFix(element, expectedType, disableIfAvailable = null)
|
||||
fix.invoke(element.project, null, element.containingFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val removeUselessCastDiagnosticBasedProcessing =
|
||||
diagnosticBasedProcessing<KtBinaryExpressionWithTypeRHS>(Errors.USELESS_CAST) { element, _ ->
|
||||
if (element.left.isNullExpression()) return@diagnosticBasedProcessing
|
||||
val expression = RemoveUselessCastFix.invoke(element)
|
||||
|
||||
val variable = expression.parent as? KtProperty
|
||||
if (variable != null && expression == variable.initializer && variable.isLocal) {
|
||||
val ref = ReferencesSearch.search(variable, LocalSearchScope(variable.containingFile)).findAll().singleOrNull()
|
||||
if (ref != null && ref.element is KtSimpleNameExpression) {
|
||||
ref.element.replace(expression)
|
||||
variable.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val removeInnecessaryNotNullAssertionDiagnosticBasedProcessing =
|
||||
diagnosticBasedProcessing<KtSimpleNameExpression>(Errors.UNNECESSARY_NOT_NULL_ASSERTION) { element, _ ->
|
||||
val exclExclExpr = element.parent as KtUnaryExpression
|
||||
val baseExpression = exclExclExpr.baseExpression!!
|
||||
val context = baseExpression.analyze(BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS)
|
||||
if (context.diagnostics.forElement(element).any { it.factory == Errors.UNNECESSARY_NOT_NULL_ASSERTION }) {
|
||||
exclExclExpr.replace(baseExpression)
|
||||
}
|
||||
}
|
||||
+24
-50
@@ -7,11 +7,9 @@ package org.jetbrains.kotlin.nj2k.postProcessing.processings
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
@@ -19,8 +17,13 @@ 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.inspections.*
|
||||
import org.jetbrains.kotlin.idea.intentions.*
|
||||
import org.jetbrains.kotlin.idea.inspections.RedundantExplicitTypeInspection
|
||||
import org.jetbrains.kotlin.idea.inspections.RedundantSamConstructorInspection
|
||||
import org.jetbrains.kotlin.idea.inspections.UseExpressionBodyInspection
|
||||
import org.jetbrains.kotlin.idea.intentions.ConvertToStringTemplateIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.UsePropertyAccessSyntaxIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.addUseSiteTarget
|
||||
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
@@ -30,13 +33,14 @@ import org.jetbrains.kotlin.j2k.ConverterSettings
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
import org.jetbrains.kotlin.nj2k.parentsOfType
|
||||
import org.jetbrains.kotlin.nj2k.postProcessing.*
|
||||
import org.jetbrains.kotlin.nj2k.postProcessing.ApplicabilityBasedInspectionLikeProcessing
|
||||
import org.jetbrains.kotlin.nj2k.postProcessing.InspectionLikeProcessing
|
||||
import org.jetbrains.kotlin.nj2k.postProcessing.generalInspectionBasedProcessing
|
||||
import org.jetbrains.kotlin.nj2k.postProcessing.resolve
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||
import org.jetbrains.kotlin.types.isNullable
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
@@ -63,7 +67,7 @@ class RemoveExplicitPropertyTypeProcessing : ApplicabilityBasedInspectionLikePro
|
||||
}
|
||||
}
|
||||
|
||||
class RemoveRedundantNullabilityProcessing: ApplicabilityBasedInspectionLikeProcessing<KtProperty>(KtProperty::class) {
|
||||
class RemoveRedundantNullabilityProcessing : ApplicabilityBasedInspectionLikeProcessing<KtProperty>(KtProperty::class) {
|
||||
override fun isApplicableTo(element: KtProperty, settings: ConverterSettings?): Boolean {
|
||||
if (!element.isLocal) return false
|
||||
val typeReference = element.typeReference
|
||||
@@ -101,7 +105,7 @@ class RemoveExplicitTypeArgumentsProcessing : ApplicabilityBasedInspectionLikePr
|
||||
class RemoveRedundantOverrideVisibilityProcessing : InspectionLikeProcessing {
|
||||
override val writeActionNeeded = true
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
override fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (element !is KtCallableDeclaration || !element.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return null
|
||||
val modifier = element.visibilityModifierType() ?: return null
|
||||
return { element.setVisibility(modifier) }
|
||||
@@ -113,7 +117,7 @@ class ConvertToStringTemplateProcessing : InspectionLikeProcessing {
|
||||
|
||||
val intention = ConvertToStringTemplateIntention()
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
override fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (element is KtBinaryExpression && intention.isApplicableTo(element) && ConvertToStringTemplateIntention.shouldSuggestToConvert(
|
||||
element
|
||||
)
|
||||
@@ -130,7 +134,7 @@ class UsePropertyAccessSyntaxProcessing : InspectionLikeProcessing {
|
||||
|
||||
val intention = UsePropertyAccessSyntaxIntention()
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
override fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (element !is KtCallExpression) return null
|
||||
val propertyName = intention.detectPropertyNameToUse(element) ?: return null
|
||||
return { intention.applyTo(element, propertyName, reformat = true) }
|
||||
@@ -140,7 +144,7 @@ class UsePropertyAccessSyntaxProcessing : InspectionLikeProcessing {
|
||||
class RemoveRedundantSamAdaptersProcessing : InspectionLikeProcessing {
|
||||
override val writeActionNeeded = true
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
override fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (element !is KtCallExpression) return null
|
||||
|
||||
val expressions = RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element)
|
||||
@@ -156,7 +160,7 @@ class RemoveRedundantSamAdaptersProcessing : InspectionLikeProcessing {
|
||||
class UseExpressionBodyProcessing : InspectionLikeProcessing {
|
||||
override val writeActionNeeded = true
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
override fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (element !is KtPropertyAccessor) return null
|
||||
|
||||
val inspection = UseExpressionBodyInspection(convertEmptyToUnit = false)
|
||||
@@ -173,7 +177,7 @@ class UseExpressionBodyProcessing : InspectionLikeProcessing {
|
||||
class RemoveRedundantCastToNullableProcessing : InspectionLikeProcessing {
|
||||
override val writeActionNeeded = true
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
override fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (element !is KtBinaryExpressionWithTypeRHS) return null
|
||||
|
||||
val context = element.analyze()
|
||||
@@ -191,42 +195,12 @@ class RemoveRedundantCastToNullableProcessing : InspectionLikeProcessing {
|
||||
}
|
||||
}
|
||||
|
||||
class FixObjectStringConcatenationProcessing : InspectionLikeProcessing {
|
||||
override val writeActionNeeded = true
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (element !is KtBinaryExpression ||
|
||||
element.operationToken != KtTokens.PLUS ||
|
||||
diagnostics.forElement(element.operationReference).none {
|
||||
it.factory == Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER
|
||||
|| it.factory == Errors.NONE_APPLICABLE
|
||||
}
|
||||
)
|
||||
return null
|
||||
|
||||
val bindingContext = element.analyze()
|
||||
val rightType = element.right?.getType(bindingContext) ?: return null
|
||||
|
||||
if (KotlinBuiltIns.isString(rightType)) {
|
||||
return {
|
||||
val factory = KtPsiFactory(element)
|
||||
element.left!!.replace(factory.buildExpression {
|
||||
appendFixedText("(")
|
||||
appendExpression(element.left)
|
||||
appendFixedText(").toString()")
|
||||
})
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class UninitializedVariableReferenceFromInitializerToThisReferenceProcessing :
|
||||
InspectionLikeProcessing {
|
||||
override val writeActionNeeded = true
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (element !is KtSimpleNameExpression || diagnostics.forElement(element).none { it.factory == Errors.UNINITIALIZED_VARIABLE }) return null
|
||||
override fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (element !is KtSimpleNameExpression || element.mainReference.resolve() == null) return null
|
||||
|
||||
val resolved = element.mainReference.resolve() ?: return null
|
||||
if (resolved.isAncestor(element, strict = true)) {
|
||||
@@ -246,8 +220,8 @@ class UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing :
|
||||
InspectionLikeProcessing {
|
||||
override val writeActionNeeded = true
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (element !is KtSimpleNameExpression || diagnostics.forElement(element).none { it.factory == Errors.UNRESOLVED_REFERENCE }) return null
|
||||
override fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (element !is KtSimpleNameExpression || element.mainReference.resolve() != null) return null
|
||||
|
||||
val anonymousObject = element.getParentOfType<KtClassOrObject>(true) ?: return null
|
||||
|
||||
@@ -381,10 +355,10 @@ class RemoveExplicitPropertyTypeWithInspectionProcessing :
|
||||
private val processing =
|
||||
generalInspectionBasedProcessing(RedundantExplicitTypeInspection())
|
||||
|
||||
override fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)? {
|
||||
override fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)? {
|
||||
if (settings?.specifyLocalVariableTypeByDefault == true) return null
|
||||
|
||||
return processing.createAction(element, diagnostics, settings)
|
||||
return processing.createAction(element, settings)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -1,4 +1,7 @@
|
||||
internal class Test {
|
||||
val int: Int
|
||||
get() = 10
|
||||
get() {
|
||||
val b: Byte = 10
|
||||
return b.toInt()
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
internal class C {
|
||||
fun foo(o: Any?) {
|
||||
if (o is String) {
|
||||
val l = o.length
|
||||
val substring = o.substring(l - 2)
|
||||
val s = o
|
||||
val l = s.length
|
||||
val substring = s.substring(l - 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user