Distinguish PARTIAL_WITH_CFA resolve mode from just PARTIAL
So #KT-23182 Fixed
This commit is contained in:
@@ -18,11 +18,17 @@ package org.jetbrains.kotlin.resolve.lazy
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingTraceFilter
|
import org.jetbrains.kotlin.resolve.BindingTraceFilter
|
||||||
|
|
||||||
enum class BodyResolveMode(val bindingTraceFilter: BindingTraceFilter) {
|
enum class BodyResolveMode(val bindingTraceFilter: BindingTraceFilter, val doControlFlowAnalysis: Boolean) {
|
||||||
FULL(BindingTraceFilter.ACCEPT_ALL),
|
// All body statements are analyzed, diagnostics included
|
||||||
PARTIAL_FOR_COMPLETION(BindingTraceFilter.NO_DIAGNOSTICS),
|
FULL(BindingTraceFilter.ACCEPT_ALL, doControlFlowAnalysis = true),
|
||||||
PARTIAL_WITH_DIAGNOSTICS(BindingTraceFilter.ACCEPT_ALL),
|
// Analyzes only dependent statements, including all declaration statements (difference from PARTIAL_WITH_CFA)
|
||||||
PARTIAL(BindingTraceFilter.NO_DIAGNOSTICS)
|
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)
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -409,12 +409,15 @@ class ResolveElementCache(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val controlFlowTrace =
|
if (bodyResolveMode.doControlFlowAnalysis) {
|
||||||
DelegatingBindingTrace(trace.bindingContext, "Element control flow resolve", resolveElement, allowSliceRewrite = true)
|
val controlFlowTrace = DelegatingBindingTrace(
|
||||||
ControlFlowInformationProvider(
|
trace.bindingContext, "Element control flow resolve", resolveElement, allowSliceRewrite = true
|
||||||
resolveElement, controlFlowTrace, resolveElement.languageVersionSettings, resolveSession.platformDiagnosticSuppressor
|
)
|
||||||
).checkDeclaration()
|
ControlFlowInformationProvider(
|
||||||
controlFlowTrace.addOwnDataTo(trace, null, false)
|
resolveElement, controlFlowTrace, resolveElement.languageVersionSettings, resolveSession.platformDiagnosticSuppressor
|
||||||
|
).checkDeclaration()
|
||||||
|
controlFlowTrace.addOwnDataTo(trace, null, false)
|
||||||
|
}
|
||||||
|
|
||||||
return Pair(trace.bindingContext, statementFilterUsed)
|
return Pair(trace.bindingContext, statementFilterUsed)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// 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 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) }
|
processors.forEach { it.analyzeCollectedElements(bindingContext) }
|
||||||
|
|
||||||
// step 3: shorten elements that can be shortened right now
|
// step 3: shorten elements that can be shortened right now
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class CallableUsageReplacementStrategy(
|
|||||||
private val inlineSetter: Boolean = false
|
private val inlineSetter: Boolean = false
|
||||||
) : UsageReplacementStrategy {
|
) : UsageReplacementStrategy {
|
||||||
override fun createReplacer(usage: KtSimpleNameExpression): (() -> KtElement?)? {
|
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
|
val resolvedCall = usage.getResolvedCall(bindingContext) ?: return null
|
||||||
if (!resolvedCall.status.isSuccess) return null
|
if (!resolvedCall.status.isSuccess) return null
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
|
|||||||
private fun KtExpression.shouldShowStatementType(): Boolean {
|
private fun KtExpression.shouldShowStatementType(): Boolean {
|
||||||
if (parent !is KtBlockExpression) return true
|
if (parent !is KtBlockExpression) return true
|
||||||
if (parent.children.lastOrNull() == this) {
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -49,12 +49,12 @@ public class KotlinSurrounderUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isUsedAsStatement(@NotNull KtExpression expression) {
|
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);
|
return BindingContextUtilsKt.isUsedAsStatement(expression, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isUsedAsExpression(@NotNull KtExpression expression) {
|
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);
|
return BindingContextUtilsKt.isUsedAsExpression(expression, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class ConstantConditionIfInspection : AbstractKotlinInspection() {
|
|||||||
return ifExpressionVisitor(fun(expression) {
|
return ifExpressionVisitor(fun(expression) {
|
||||||
val condition = expression.condition ?: return
|
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 constantValue = condition.constantBooleanValue(context) ?: return
|
||||||
|
|
||||||
val fixes = mutableListOf<LocalQuickFix>()
|
val fixes = mutableListOf<LocalQuickFix>()
|
||||||
|
|||||||
+1
-1
@@ -40,7 +40,7 @@ class ReplaceWithOperatorAssignmentInspection : AbstractApplicabilityBasedInspec
|
|||||||
val right = element.right as? KtBinaryExpression ?: return false
|
val right = element.right as? KtBinaryExpression ?: return false
|
||||||
if (right.left == null || right.right == null) 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
|
if (!checkExpressionRepeat(left, right, bindingContext)) return false
|
||||||
|
|
||||||
// now check that the resulting operator assignment will be resolved
|
// now check that the resulting operator assignment will be resolved
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.resolve.source.getPsi
|
|||||||
class UnusedLambdaExpressionBodyInspection : AbstractKotlinInspection() {
|
class UnusedLambdaExpressionBodyInspection : AbstractKotlinInspection() {
|
||||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||||
return callExpressionVisitor(fun(expression) {
|
return callExpressionVisitor(fun(expression) {
|
||||||
val context = expression.analyze(BodyResolveMode.PARTIAL)
|
val context = expression.analyze(BodyResolveMode.PARTIAL_WITH_CFA)
|
||||||
if (expression.used(context)) {
|
if (expression.used(context)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -55,7 +55,7 @@ class ReplaceGetOrSetInspection : AbstractApplicabilityBasedInspection<KtDotQual
|
|||||||
|
|
||||||
override fun isApplicable(element: KtDotQualifiedExpression): Boolean {
|
override fun isApplicable(element: KtDotQualifiedExpression): Boolean {
|
||||||
val callExpression = element.callExpression ?: return false
|
val callExpression = element.callExpression ?: return false
|
||||||
val bindingContext = callExpression.analyze(BodyResolveMode.PARTIAL)
|
val bindingContext = callExpression.analyze(BodyResolveMode.PARTIAL_WITH_CFA)
|
||||||
val resolvedCall = callExpression.getResolvedCall(bindingContext) ?: return false
|
val resolvedCall = callExpression.getResolvedCall(bindingContext) ?: return false
|
||||||
if (!resolvedCall.isReallySuccess()) return false
|
if (!resolvedCall.isReallySuccess()) return false
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class AddForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(
|
|||||||
if (element.loopParameter == null) return null
|
if (element.loopParameter == null) return null
|
||||||
val loopRange = element.loopRange ?: 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)
|
val resolvedCall = loopRange.getResolvedCall(bindingContext)
|
||||||
if (resolvedCall?.resultingDescriptor?.fqNameUnsafe?.asString() in WITH_INDEX_FQ_NAMES) return null // already withIndex() call
|
if (resolvedCall?.resultingDescriptor?.fqNameUnsafe?.asString() in WITH_INDEX_FQ_NAMES) return null // already withIndex() call
|
||||||
|
|||||||
+1
-1
@@ -50,7 +50,7 @@ class ConvertAssertToIfWithThrowIntention : SelfTargetingIntention<KtCallExpress
|
|||||||
val args = element.valueArguments
|
val args = element.valueArguments
|
||||||
val conditionText = args[0]?.getArgumentExpression()?.text ?: return
|
val conditionText = args[0]?.getArgumentExpression()?.text ?: return
|
||||||
val functionLiteralArgument = element.lambdaArguments.singleOrNull()
|
val functionLiteralArgument = element.lambdaArguments.singleOrNull()
|
||||||
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
val bindingContext = element.analyze(BodyResolveMode.PARTIAL_WITH_CFA)
|
||||||
val psiFactory = KtPsiFactory(element)
|
val psiFactory = KtPsiFactory(element)
|
||||||
|
|
||||||
val messageFunctionExpr = when {
|
val messageFunctionExpr = when {
|
||||||
|
|||||||
+1
-1
@@ -48,7 +48,7 @@ class RemoveExplicitSuperQualifierIntention : SelfTargetingRangeIntention<KtSupe
|
|||||||
val qualifiedExpression = element.getQualifiedExpressionForReceiver() ?: return null
|
val qualifiedExpression = element.getQualifiedExpressionForReceiver() ?: return null
|
||||||
val selector = qualifiedExpression.selectorExpression ?: return null
|
val selector = qualifiedExpression.selectorExpression ?: return null
|
||||||
|
|
||||||
val bindingContext = selector.analyze(BodyResolveMode.PARTIAL)
|
val bindingContext = selector.analyze(BodyResolveMode.PARTIAL_WITH_CFA)
|
||||||
if (selector.getResolvedCall(bindingContext) == null) return null
|
if (selector.getResolvedCall(bindingContext) == null) return null
|
||||||
|
|
||||||
val newQualifiedExpression = KtPsiFactory(element).createExpressionByPattern(
|
val newQualifiedExpression = KtPsiFactory(element).createExpressionByPattern(
|
||||||
|
|||||||
+1
-1
@@ -55,7 +55,7 @@ class RemoveExplicitTypeArgumentsIntention : SelfTargetingOffsetIndependentInten
|
|||||||
if (callExpression.typeArguments.isEmpty()) return false
|
if (callExpression.typeArguments.isEmpty()) return false
|
||||||
|
|
||||||
val resolutionFacade = callExpression.getResolutionFacade()
|
val resolutionFacade = callExpression.getResolutionFacade()
|
||||||
val bindingContext = resolutionFacade.analyze(callExpression, BodyResolveMode.PARTIAL)
|
val bindingContext = resolutionFacade.analyze(callExpression, BodyResolveMode.PARTIAL_WITH_CFA)
|
||||||
val originalCall = callExpression.getResolvedCall(bindingContext) ?: return false
|
val originalCall = callExpression.getResolvedCall(bindingContext) ?: return false
|
||||||
|
|
||||||
val (contextExpression, expectedType) = findContextToAnalyze(callExpression, bindingContext)
|
val (contextExpression, expectedType) = findContextToAnalyze(callExpression, bindingContext)
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
|||||||
|
|
||||||
class IfThenToElvisInspection : IntentionBasedInspection<KtIfExpression>(
|
class IfThenToElvisInspection : IntentionBasedInspection<KtIfExpression>(
|
||||||
IfThenToElvisIntention::class,
|
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
|
override fun inspectionTarget(element: KtIfExpression) = element.ifKeyword
|
||||||
|
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ private fun isEmbeddedBreakOrContinue(expression: KtExpressionWithLabel): Boolea
|
|||||||
|
|
||||||
is KtContainerNode -> {
|
is KtContainerNode -> {
|
||||||
val containerExpression = parent.parent as KtExpression
|
val containerExpression = parent.parent as KtExpression
|
||||||
containerExpression.isUsedAsExpression(containerExpression.analyze(BodyResolveMode.PARTIAL))
|
containerExpression.isUsedAsExpression(containerExpression.analyze(BodyResolveMode.PARTIAL_WITH_CFA))
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> true
|
else -> true
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ class RenameUnresolvedReferenceFix(element: KtNameReferenceExpression): KotlinQu
|
|||||||
}
|
}
|
||||||
|
|
||||||
val resolutionFacade = element.getResolutionFacade()
|
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 moduleDescriptor = resolutionFacade.moduleDescriptor
|
||||||
val variantsHelper = ReferenceVariantsHelper(context, resolutionFacade, moduleDescriptor, {
|
val variantsHelper = ReferenceVariantsHelper(context, resolutionFacade, moduleDescriptor, {
|
||||||
it !is DeclarationDescriptorWithVisibility || it.isVisible(element, null, context, resolutionFacade)
|
it !is DeclarationDescriptorWithVisibility || it.isVisible(element, null, context, resolutionFacade)
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class SurroundWithNullCheckFix(
|
|||||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||||
val element = diagnostic.psiElement
|
val element = diagnostic.psiElement
|
||||||
val expressionParent = element.getParentOfType<KtExpression>(strict = element is KtOperationReferenceExpression) ?: return null
|
val expressionParent = element.getParentOfType<KtExpression>(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 parent = element.parent
|
||||||
val nullableExpression =
|
val nullableExpression =
|
||||||
|
|||||||
+1
-1
@@ -42,7 +42,7 @@ object CreateFunctionFromCallableReferenceActionFactory : CreateCallableMemberFr
|
|||||||
override fun extractFixData(element: KtCallableReferenceExpression, diagnostic: Diagnostic): List<CallableInfo> {
|
override fun extractFixData(element: KtCallableReferenceExpression, diagnostic: Diagnostic): List<CallableInfo> {
|
||||||
val name = element.callableReference.getReferencedName()
|
val name = element.callableReference.getReferencedName()
|
||||||
val resolutionFacade = element.getResolutionFacade()
|
val resolutionFacade = element.getResolutionFacade()
|
||||||
val context = resolutionFacade.analyze(element, BodyResolveMode.PARTIAL)
|
val context = resolutionFacade.analyze(element, BodyResolveMode.PARTIAL_WITH_CFA)
|
||||||
return element
|
return element
|
||||||
.guessTypes(context, resolutionFacade.moduleDescriptor)
|
.guessTypes(context, resolutionFacade.moduleDescriptor)
|
||||||
.ifEmpty { element.guessTypes(context, resolutionFacade.moduleDescriptor, allowErrorTypes = true) } // approximate with Any
|
.ifEmpty { element.guessTypes(context, resolutionFacade.moduleDescriptor, allowErrorTypes = true) } // approximate with Any
|
||||||
|
|||||||
+1
-1
@@ -80,7 +80,7 @@ class AddTargetVersionCheckQuickFix(val api: Int) : AndroidLintQuickFix {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getSurrounder(element: KtElement, todoText: String?): KotlinIfSurrounder {
|
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) {
|
return if (used) {
|
||||||
object : KotlinIfSurrounder() {
|
object : KotlinIfSurrounder() {
|
||||||
override fun getCodeTemplate(): String = "if (a) { \n} else {\nTODO(${todoText ?: ""})\n}"
|
override fun getCodeTemplate(): String = "if (a) { \n} else {\nTODO(${todoText ?: ""})\n}"
|
||||||
|
|||||||
Reference in New Issue
Block a user