From 9170aa06747509aaf1fa136ff2bc3b06508a2729 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 27 Mar 2018 10:43:14 +0200 Subject: [PATCH] Distinguish PARTIAL_WITH_CFA resolve mode from just PARTIAL So #KT-23182 Fixed --- .../kotlin/resolve/lazy/BodyResolveMode.kt | 16 +++++++++++----- .../kotlin/idea/project/ResolveElementCache.kt | 15 +++++++++------ .../kotlin/idea/core/ShortenReferences.kt | 2 +- .../CallableUsageReplacementStrategy.kt | 2 +- .../codeInsight/KotlinExpressionTypeProvider.kt | 2 +- .../surroundWith/KotlinSurrounderUtils.java | 4 ++-- .../inspections/ConstantConditionIfInspection.kt | 2 +- .../ReplaceWithOperatorAssignmentInspection.kt | 2 +- .../UnusedLambdaExpressionBodyInspection.kt | 2 +- .../ReplaceGetOrSetInspection.kt | 2 +- .../intentions/AddForLoopIndicesIntention.kt | 2 +- .../ConvertAssertToIfWithThrowIntention.kt | 2 +- .../RemoveExplicitSuperQualifierIntention.kt | 2 +- .../RemoveExplicitTypeArgumentsIntention.kt | 2 +- .../intentions/IfThenToElvisIntention.kt | 2 +- .../idea/intentions/loopToCallChain/utils.kt | 2 +- .../quickfix/RenameUnresolvedReferenceFix.kt | 2 +- .../idea/quickfix/SurroundWithNullCheckFix.kt | 2 +- ...FunctionFromCallableReferenceActionFactory.kt | 2 +- .../klint/AddTargetVersionCheckQuickFix.kt | 2 +- 20 files changed, 39 insertions(+), 30 deletions(-) diff --git a/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt b/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt index a11c7cdb4b3..cd0ce553238 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt @@ -18,11 +18,17 @@ package org.jetbrains.kotlin.resolve.lazy import org.jetbrains.kotlin.resolve.BindingTraceFilter -enum class BodyResolveMode(val bindingTraceFilter: BindingTraceFilter) { - FULL(BindingTraceFilter.ACCEPT_ALL), - PARTIAL_FOR_COMPLETION(BindingTraceFilter.NO_DIAGNOSTICS), - PARTIAL_WITH_DIAGNOSTICS(BindingTraceFilter.ACCEPT_ALL), - PARTIAL(BindingTraceFilter.NO_DIAGNOSTICS) +enum class BodyResolveMode(val bindingTraceFilter: BindingTraceFilter, val doControlFlowAnalysis: Boolean) { + // All body statements are analyzed, diagnostics included + FULL(BindingTraceFilter.ACCEPT_ALL, doControlFlowAnalysis = true), + // Analyzes only dependent statements, including all declaration statements (difference from PARTIAL_WITH_CFA) + PARTIAL_FOR_COMPLETION(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = true), + // Analyzes only dependent statements, diagnostics included + PARTIAL_WITH_DIAGNOSTICS(BindingTraceFilter.ACCEPT_ALL, doControlFlowAnalysis = true), + // Analyzes only dependent statements, performs control flow analysis (mostly needed for isUsedAsExpression / AsStatement) + PARTIAL_WITH_CFA(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = true), + // Analyzes only dependent statements, including only used declaration statements, does not perform control flow analysis + PARTIAL(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = false) ; diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt index 7a3e802fafe..6303bee5564 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt @@ -409,12 +409,15 @@ class ResolveElementCache( } } - val controlFlowTrace = - DelegatingBindingTrace(trace.bindingContext, "Element control flow resolve", resolveElement, allowSliceRewrite = true) - ControlFlowInformationProvider( - resolveElement, controlFlowTrace, resolveElement.languageVersionSettings, resolveSession.platformDiagnosticSuppressor - ).checkDeclaration() - controlFlowTrace.addOwnDataTo(trace, null, false) + if (bodyResolveMode.doControlFlowAnalysis) { + val controlFlowTrace = DelegatingBindingTrace( + trace.bindingContext, "Element control flow resolve", resolveElement, allowSliceRewrite = true + ) + ControlFlowInformationProvider( + resolveElement, controlFlowTrace, resolveElement.languageVersionSettings, resolveSession.platformDiagnosticSuppressor + ).checkDeclaration() + controlFlowTrace.addOwnDataTo(trace, null, false) + } return Pair(trace.bindingContext, statementFilterUsed) } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ShortenReferences.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ShortenReferences.kt index 8ecae87ef17..95b5ecf1fd1 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ShortenReferences.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ShortenReferences.kt @@ -173,7 +173,7 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT // step 2: analyze collected elements with resolve and decide which can be shortened now and which need descriptors to be imported before shortening val allElementsToAnalyze = visitors.flatMap { it.getElementsToAnalyze().map { it.element } } - val bindingContext = file.getResolutionFacade().analyze(allElementsToAnalyze, BodyResolveMode.PARTIAL) + val bindingContext = file.getResolutionFacade().analyze(allElementsToAnalyze, BodyResolveMode.PARTIAL_WITH_CFA) processors.forEach { it.analyzeCollectedElements(bindingContext) } // step 3: shorten elements that can be shortened right now diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CallableUsageReplacementStrategy.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CallableUsageReplacementStrategy.kt index fc4eb338c4a..d5231983a51 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CallableUsageReplacementStrategy.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CallableUsageReplacementStrategy.kt @@ -29,7 +29,7 @@ class CallableUsageReplacementStrategy( private val inlineSetter: Boolean = false ) : UsageReplacementStrategy { override fun createReplacer(usage: KtSimpleNameExpression): (() -> KtElement?)? { - val bindingContext = usage.analyze(BodyResolveMode.PARTIAL) + val bindingContext = usage.analyze(BodyResolveMode.PARTIAL_WITH_CFA) val resolvedCall = usage.getResolvedCall(bindingContext) ?: return null if (!resolvedCall.status.isSuccess) return null diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt index 6d811c34f11..b4e94e374e9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinExpressionTypeProvider.kt @@ -84,7 +84,7 @@ class KotlinExpressionTypeProvider : ExpressionTypeProvider() { private fun KtExpression.shouldShowStatementType(): Boolean { if (parent !is KtBlockExpression) return true if (parent.children.lastOrNull() == this) { - return analyze(BodyResolveMode.PARTIAL)[BindingContext.USED_AS_EXPRESSION, this] ?: false + return analyze(BodyResolveMode.PARTIAL_WITH_CFA)[BindingContext.USED_AS_EXPRESSION, this] ?: false } return false } diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/KotlinSurrounderUtils.java b/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/KotlinSurrounderUtils.java index 22096e11a02..4773724e10e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/KotlinSurrounderUtils.java +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/KotlinSurrounderUtils.java @@ -49,12 +49,12 @@ public class KotlinSurrounderUtils { } public static boolean isUsedAsStatement(@NotNull KtExpression expression) { - BindingContext context = ResolutionUtils.analyze(expression, BodyResolveMode.PARTIAL); + BindingContext context = ResolutionUtils.analyze(expression, BodyResolveMode.PARTIAL_WITH_CFA); return BindingContextUtilsKt.isUsedAsStatement(expression, context); } public static boolean isUsedAsExpression(@NotNull KtExpression expression) { - BindingContext context = ResolutionUtils.analyze(expression, BodyResolveMode.PARTIAL); + BindingContext context = ResolutionUtils.analyze(expression, BodyResolveMode.PARTIAL_WITH_CFA); return BindingContextUtilsKt.isUsedAsExpression(expression, context); } } diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt index a9e40eb1574..159478f0e4f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ConstantConditionIfInspection.kt @@ -29,7 +29,7 @@ class ConstantConditionIfInspection : AbstractKotlinInspection() { return ifExpressionVisitor(fun(expression) { val condition = expression.condition ?: return - val context = condition.analyze(BodyResolveMode.PARTIAL) + val context = condition.analyze(BodyResolveMode.PARTIAL_WITH_CFA) val constantValue = condition.constantBooleanValue(context) ?: return val fixes = mutableListOf() diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceWithOperatorAssignmentInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceWithOperatorAssignmentInspection.kt index d12b6de844a..66127c9f9a2 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceWithOperatorAssignmentInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceWithOperatorAssignmentInspection.kt @@ -40,7 +40,7 @@ class ReplaceWithOperatorAssignmentInspection : AbstractApplicabilityBasedInspec val right = element.right as? KtBinaryExpression ?: return false if (right.left == null || right.right == null) return false - val bindingContext = right.analyze(BodyResolveMode.PARTIAL) + val bindingContext = right.analyze(BodyResolveMode.PARTIAL_WITH_CFA) if (!checkExpressionRepeat(left, right, bindingContext)) return false // now check that the resulting operator assignment will be resolved diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedLambdaExpressionBodyInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedLambdaExpressionBodyInspection.kt index ff3116d26f7..164445c6957 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedLambdaExpressionBodyInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedLambdaExpressionBodyInspection.kt @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.resolve.source.getPsi class UnusedLambdaExpressionBodyInspection : AbstractKotlinInspection() { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { return callExpressionVisitor(fun(expression) { - val context = expression.analyze(BodyResolveMode.PARTIAL) + val context = expression.analyze(BodyResolveMode.PARTIAL_WITH_CFA) if (expression.used(context)) { return } diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/conventionNameCalls/ReplaceGetOrSetInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/conventionNameCalls/ReplaceGetOrSetInspection.kt index 21dae20b812..4ded9a68b36 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/conventionNameCalls/ReplaceGetOrSetInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/conventionNameCalls/ReplaceGetOrSetInspection.kt @@ -55,7 +55,7 @@ class ReplaceGetOrSetInspection : AbstractApplicabilityBasedInspection( if (element.loopParameter == null) return null val loopRange = element.loopRange ?: return null - val bindingContext = element.analyze(BodyResolveMode.PARTIAL) + val bindingContext = element.analyze(BodyResolveMode.PARTIAL_WITH_CFA) val resolvedCall = loopRange.getResolvedCall(bindingContext) if (resolvedCall?.resultingDescriptor?.fqNameUnsafe?.asString() in WITH_INDEX_FQ_NAMES) return null // already withIndex() call diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertAssertToIfWithThrowIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertAssertToIfWithThrowIntention.kt index 3d6b9cffa0c..b64a545f2ec 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertAssertToIfWithThrowIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertAssertToIfWithThrowIntention.kt @@ -50,7 +50,7 @@ class ConvertAssertToIfWithThrowIntention : SelfTargetingIntention( IfThenToElvisIntention::class, - { it -> it.isUsedAsExpression(it.analyze(BodyResolveMode.PARTIAL)) } + { it -> it.isUsedAsExpression(it.analyze(BodyResolveMode.PARTIAL_WITH_CFA)) } ) { override fun inspectionTarget(element: KtIfExpression) = element.ifKeyword diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt index 35fbec3b81b..8b8ce352107 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt @@ -390,7 +390,7 @@ private fun isEmbeddedBreakOrContinue(expression: KtExpressionWithLabel): Boolea is KtContainerNode -> { val containerExpression = parent.parent as KtExpression - containerExpression.isUsedAsExpression(containerExpression.analyze(BodyResolveMode.PARTIAL)) + containerExpression.isUsedAsExpression(containerExpression.analyze(BodyResolveMode.PARTIAL_WITH_CFA)) } else -> true diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/RenameUnresolvedReferenceFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/RenameUnresolvedReferenceFix.kt index 61cdb380a2a..53bbc9fc5bc 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/RenameUnresolvedReferenceFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/RenameUnresolvedReferenceFix.kt @@ -96,7 +96,7 @@ class RenameUnresolvedReferenceFix(element: KtNameReferenceExpression): KotlinQu } val resolutionFacade = element.getResolutionFacade() - val context = resolutionFacade.analyze(element, BodyResolveMode.PARTIAL) + val context = resolutionFacade.analyze(element, BodyResolveMode.PARTIAL_WITH_CFA) val moduleDescriptor = resolutionFacade.moduleDescriptor val variantsHelper = ReferenceVariantsHelper(context, resolutionFacade, moduleDescriptor, { it !is DeclarationDescriptorWithVisibility || it.isVisible(element, null, context, resolutionFacade) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/SurroundWithNullCheckFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/SurroundWithNullCheckFix.kt index 2f651fdc7f2..34cfc4c1b4e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/SurroundWithNullCheckFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/SurroundWithNullCheckFix.kt @@ -61,7 +61,7 @@ class SurroundWithNullCheckFix( override fun createAction(diagnostic: Diagnostic): IntentionAction? { val element = diagnostic.psiElement val expressionParent = element.getParentOfType(strict = element is KtOperationReferenceExpression) ?: return null - val context = expressionParent.analyze(BodyResolveMode.PARTIAL) + val context = expressionParent.analyze(BodyResolveMode.PARTIAL_WITH_CFA) val parent = element.parent val nullableExpression = diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateFunctionFromCallableReferenceActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateFunctionFromCallableReferenceActionFactory.kt index 53e7359bb2d..d07e0dd1598 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateFunctionFromCallableReferenceActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateFunctionFromCallableReferenceActionFactory.kt @@ -42,7 +42,7 @@ object CreateFunctionFromCallableReferenceActionFactory : CreateCallableMemberFr override fun extractFixData(element: KtCallableReferenceExpression, diagnostic: Diagnostic): List { val name = element.callableReference.getReferencedName() val resolutionFacade = element.getResolutionFacade() - val context = resolutionFacade.analyze(element, BodyResolveMode.PARTIAL) + val context = resolutionFacade.analyze(element, BodyResolveMode.PARTIAL_WITH_CFA) return element .guessTypes(context, resolutionFacade.moduleDescriptor) .ifEmpty { element.guessTypes(context, resolutionFacade.moduleDescriptor, allowErrorTypes = true) } // approximate with Any diff --git a/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AddTargetVersionCheckQuickFix.kt b/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AddTargetVersionCheckQuickFix.kt index 347a402f1b1..ec8ebadf849 100644 --- a/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AddTargetVersionCheckQuickFix.kt +++ b/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AddTargetVersionCheckQuickFix.kt @@ -80,7 +80,7 @@ class AddTargetVersionCheckQuickFix(val api: Int) : AndroidLintQuickFix { } private fun getSurrounder(element: KtElement, todoText: String?): KotlinIfSurrounder { - val used = element.analyze(BodyResolveMode.PARTIAL)[BindingContext.USED_AS_EXPRESSION, element] ?: false + val used = element.analyze(BodyResolveMode.PARTIAL_WITH_CFA)[BindingContext.USED_AS_EXPRESSION, element] ?: false return if (used) { object : KotlinIfSurrounder() { override fun getCodeTemplate(): String = "if (a) { \n} else {\nTODO(${todoText ?: ""})\n}"