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.application.ModalityState
|
||||||
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.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.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
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.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
|
||||||
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.core.util.EDT
|
||||||
import org.jetbrains.kotlin.idea.formatter.commitAndUnblockDocument
|
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.*
|
||||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FoldIfToReturnAsymmetricallyIntention
|
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.intentions.FoldIfToReturnIntention
|
||||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isNullExpression
|
|
||||||
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.references.mainReference
|
|
||||||
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.idea.util.application.runWriteAction
|
||||||
import org.jetbrains.kotlin.j2k.ConverterContext
|
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.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
|
||||||
import org.jetbrains.kotlin.nj2k.postProcessing.processings.*
|
import org.jetbrains.kotlin.nj2k.postProcessing.processings.*
|
||||||
import org.jetbrains.kotlin.psi.*
|
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 {
|
class NewJ2kPostProcessor : PostProcessor {
|
||||||
override fun insertImport(file: KtFile, fqName: FqName) {
|
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(
|
private val processings: List<NamedPostProcessingGroup> = listOf(
|
||||||
NamedPostProcessingGroup(
|
NamedPostProcessingGroup(
|
||||||
"Inferring declarations nullability",
|
"Inferring declarations nullability",
|
||||||
@@ -119,188 +221,9 @@ private val processings: List<NamedPostProcessingGroup> = listOf(
|
|||||||
NamedPostProcessingGroup(
|
NamedPostProcessingGroup(
|
||||||
"Cleaning up Kotlin code",
|
"Cleaning up Kotlin code",
|
||||||
listOf(
|
listOf(
|
||||||
InspectionLikeProcessingGroup(
|
errorsFixingDiagnosticBasedPostProcessingGroup,
|
||||||
RemoveRedundantVisibilityModifierProcessing(),
|
inspectionLikePostProcessingGroup,
|
||||||
RemoveRedundantModalityModifierProcessing(),
|
cleaningUpDiagnosticBasedPostProcessingGroup
|
||||||
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()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
NamedPostProcessingGroup(
|
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,
|
context: NewJ2kConverterContext,
|
||||||
rangeMarker: RangeMarker?
|
rangeMarker: RangeMarker?
|
||||||
): List<ActionData> {
|
): List<ActionData> {
|
||||||
val diagnostics = analyzeFileRange(file, rangeMarker)
|
|
||||||
|
|
||||||
val availableActions = ArrayList<ActionData>()
|
val availableActions = ArrayList<ActionData>()
|
||||||
|
|
||||||
file.accept(object : PsiRecursiveElementVisitor() {
|
file.accept(object : PsiRecursiveElementVisitor() {
|
||||||
@@ -101,7 +99,7 @@ class InspectionLikeProcessingGroup(val inspectionLikeProcessings: List<Inspecti
|
|||||||
|
|
||||||
if (rangeResult == RangeFilterResult.PROCESS) {
|
if (rangeResult == RangeFilterResult.PROCESS) {
|
||||||
inspectionLikeProcessings.forEach { processing ->
|
inspectionLikeProcessings.forEach { processing ->
|
||||||
val action = processing.createAction(element, diagnostics, context.converter.settings)
|
val action = processing.createAction(element, context.converter.settings)
|
||||||
if (action != null) {
|
if (action != null) {
|
||||||
availableActions.add(
|
availableActions.add(
|
||||||
ActionData(
|
ActionData(
|
||||||
@@ -119,17 +117,6 @@ class InspectionLikeProcessingGroup(val inspectionLikeProcessings: List<Inspecti
|
|||||||
return availableActions
|
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 {
|
private fun rangeFilter(element: PsiElement, rangeMarker: RangeMarker?): RangeFilterResult {
|
||||||
if (rangeMarker == null) return RangeFilterResult.PROCESS
|
if (rangeMarker == null) return RangeFilterResult.PROCESS
|
||||||
@@ -145,7 +132,7 @@ class InspectionLikeProcessingGroup(val inspectionLikeProcessings: List<Inspecti
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface InspectionLikeProcessing {
|
interface InspectionLikeProcessing {
|
||||||
fun createAction(element: PsiElement, diagnostics: Diagnostics, settings: ConverterSettings?): (() -> Unit)?
|
fun createAction(element: PsiElement, settings: ConverterSettings?): (() -> Unit)?
|
||||||
|
|
||||||
val writeActionNeeded: Boolean
|
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 isApplicableTo(element: E, settings: ConverterSettings?): Boolean
|
||||||
protected abstract fun apply(element: E)
|
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
|
if (!element::class.isSubclassOf(classTag)) return null
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
if (!isApplicableTo(element as E, settings)) return null
|
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
|
// Intention can either need or not need write apply
|
||||||
override val writeActionNeeded = intention.startInWriteAction()
|
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
|
if (!TElement::class.java.isInstance(element)) return null
|
||||||
val tElement = element as TElement
|
val tElement = element as TElement
|
||||||
if (intention.applicabilityRange(tElement) == null) return null
|
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 holder = ProblemsHolder(InspectionManager.getInstance(element.project), element.containingFile, false)
|
||||||
val visitor = inspection.buildVisitor(
|
val visitor = inspection.buildVisitor(
|
||||||
holder,
|
holder,
|
||||||
@@ -271,7 +258,7 @@ inline fun <reified TElement : PsiElement, TInspection : AbstractApplicabilityBa
|
|||||||
return acceptInformationLevel || inspection.inspectionHighlightType(element) != ProblemHighlightType.INFORMATION
|
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
|
if (!TElement::class.java.isInstance(element)) return null
|
||||||
val tElement = element as TElement
|
val tElement = element as TElement
|
||||||
if (!isApplicable(tElement)) return null
|
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.PsiElement
|
||||||
import com.intellij.psi.search.searches.ReferencesSearch
|
import com.intellij.psi.search.searches.ReferencesSearch
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
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.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
|
||||||
@@ -19,8 +17,13 @@ import org.jetbrains.kotlin.idea.core.implicitModality
|
|||||||
import org.jetbrains.kotlin.idea.core.implicitVisibility
|
import org.jetbrains.kotlin.idea.core.implicitVisibility
|
||||||
import org.jetbrains.kotlin.idea.core.replaced
|
import org.jetbrains.kotlin.idea.core.replaced
|
||||||
import org.jetbrains.kotlin.idea.core.setVisibility
|
import org.jetbrains.kotlin.idea.core.setVisibility
|
||||||
import org.jetbrains.kotlin.idea.inspections.*
|
import org.jetbrains.kotlin.idea.inspections.RedundantExplicitTypeInspection
|
||||||
import org.jetbrains.kotlin.idea.intentions.*
|
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.refactoring.fqName.getKotlinFqName
|
||||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
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.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||||
import org.jetbrains.kotlin.nj2k.parentsOfType
|
import org.jetbrains.kotlin.nj2k.postProcessing.ApplicabilityBasedInspectionLikeProcessing
|
||||||
import org.jetbrains.kotlin.nj2k.postProcessing.*
|
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.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
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.isNullable
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
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 {
|
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
|
||||||
@@ -101,7 +105,7 @@ class RemoveExplicitTypeArgumentsProcessing : ApplicabilityBasedInspectionLikePr
|
|||||||
class RemoveRedundantOverrideVisibilityProcessing : InspectionLikeProcessing {
|
class RemoveRedundantOverrideVisibilityProcessing : InspectionLikeProcessing {
|
||||||
override val writeActionNeeded = true
|
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
|
if (element !is KtCallableDeclaration || !element.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return null
|
||||||
val modifier = element.visibilityModifierType() ?: return null
|
val modifier = element.visibilityModifierType() ?: return null
|
||||||
return { element.setVisibility(modifier) }
|
return { element.setVisibility(modifier) }
|
||||||
@@ -113,7 +117,7 @@ class ConvertToStringTemplateProcessing : InspectionLikeProcessing {
|
|||||||
|
|
||||||
val intention = ConvertToStringTemplateIntention()
|
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(
|
if (element is KtBinaryExpression && intention.isApplicableTo(element) && ConvertToStringTemplateIntention.shouldSuggestToConvert(
|
||||||
element
|
element
|
||||||
)
|
)
|
||||||
@@ -130,7 +134,7 @@ class UsePropertyAccessSyntaxProcessing : InspectionLikeProcessing {
|
|||||||
|
|
||||||
val intention = UsePropertyAccessSyntaxIntention()
|
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
|
if (element !is KtCallExpression) return null
|
||||||
val propertyName = intention.detectPropertyNameToUse(element) ?: return null
|
val propertyName = intention.detectPropertyNameToUse(element) ?: return null
|
||||||
return { intention.applyTo(element, propertyName, reformat = true) }
|
return { intention.applyTo(element, propertyName, reformat = true) }
|
||||||
@@ -140,7 +144,7 @@ class UsePropertyAccessSyntaxProcessing : InspectionLikeProcessing {
|
|||||||
class RemoveRedundantSamAdaptersProcessing : InspectionLikeProcessing {
|
class RemoveRedundantSamAdaptersProcessing : InspectionLikeProcessing {
|
||||||
override val writeActionNeeded = true
|
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
|
if (element !is KtCallExpression) return null
|
||||||
|
|
||||||
val expressions = RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element)
|
val expressions = RedundantSamConstructorInspection.samConstructorCallsToBeConverted(element)
|
||||||
@@ -156,7 +160,7 @@ class RemoveRedundantSamAdaptersProcessing : InspectionLikeProcessing {
|
|||||||
class UseExpressionBodyProcessing : InspectionLikeProcessing {
|
class UseExpressionBodyProcessing : InspectionLikeProcessing {
|
||||||
override val writeActionNeeded = true
|
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
|
if (element !is KtPropertyAccessor) return null
|
||||||
|
|
||||||
val inspection = UseExpressionBodyInspection(convertEmptyToUnit = false)
|
val inspection = UseExpressionBodyInspection(convertEmptyToUnit = false)
|
||||||
@@ -173,7 +177,7 @@ class UseExpressionBodyProcessing : InspectionLikeProcessing {
|
|||||||
class RemoveRedundantCastToNullableProcessing : InspectionLikeProcessing {
|
class RemoveRedundantCastToNullableProcessing : InspectionLikeProcessing {
|
||||||
override val writeActionNeeded = true
|
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
|
if (element !is KtBinaryExpressionWithTypeRHS) return null
|
||||||
|
|
||||||
val context = element.analyze()
|
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 :
|
class UninitializedVariableReferenceFromInitializerToThisReferenceProcessing :
|
||||||
InspectionLikeProcessing {
|
InspectionLikeProcessing {
|
||||||
override val writeActionNeeded = true
|
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 KtSimpleNameExpression || diagnostics.forElement(element).none { it.factory == Errors.UNINITIALIZED_VARIABLE }) return null
|
if (element !is KtSimpleNameExpression || element.mainReference.resolve() == null) return null
|
||||||
|
|
||||||
val resolved = element.mainReference.resolve() ?: return null
|
val resolved = element.mainReference.resolve() ?: return null
|
||||||
if (resolved.isAncestor(element, strict = true)) {
|
if (resolved.isAncestor(element, strict = true)) {
|
||||||
@@ -246,8 +220,8 @@ class UnresolvedVariableReferenceFromInitializerToThisReferenceProcessing :
|
|||||||
InspectionLikeProcessing {
|
InspectionLikeProcessing {
|
||||||
override val writeActionNeeded = true
|
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 KtSimpleNameExpression || diagnostics.forElement(element).none { it.factory == Errors.UNRESOLVED_REFERENCE }) return null
|
if (element !is KtSimpleNameExpression || element.mainReference.resolve() != null) return null
|
||||||
|
|
||||||
val anonymousObject = element.getParentOfType<KtClassOrObject>(true) ?: return null
|
val anonymousObject = element.getParentOfType<KtClassOrObject>(true) ?: return null
|
||||||
|
|
||||||
@@ -381,10 +355,10 @@ class RemoveExplicitPropertyTypeWithInspectionProcessing :
|
|||||||
private val processing =
|
private val processing =
|
||||||
generalInspectionBasedProcessing(RedundantExplicitTypeInspection())
|
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
|
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 {
|
internal class Test {
|
||||||
val int: Int
|
val int: Int
|
||||||
get() = 10
|
get() {
|
||||||
|
val b: Byte = 10
|
||||||
|
return b.toInt()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
internal class C {
|
internal class C {
|
||||||
fun foo(o: Any?) {
|
fun foo(o: Any?) {
|
||||||
if (o is String) {
|
if (o is String) {
|
||||||
val l = o.length
|
val s = o
|
||||||
val substring = o.substring(l - 2)
|
val l = s.length
|
||||||
|
val substring = s.substring(l - 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user