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:
Ilya Kirillov
2019-06-11 11:56:23 +03:00
parent 2f8e83d6b9
commit 59f66d5882
7 changed files with 343 additions and 308 deletions
@@ -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(
@@ -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)
}
}
@@ -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)
}
}
@@ -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)
}
}
@@ -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
View File
@@ -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)
} }
} }
} }