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
|
||||
|
||||
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)
|
||||
|
||||
;
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
|
||||
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
|
||||
}
|
||||
|
||||
+2
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<LocalQuickFix>()
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ class ReplaceGetOrSetInspection : AbstractApplicabilityBasedInspection<KtDotQual
|
||||
|
||||
override fun isApplicable(element: KtDotQualifiedExpression): Boolean {
|
||||
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
|
||||
if (!resolvedCall.isReallySuccess()) return false
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class AddForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(
|
||||
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
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ class ConvertAssertToIfWithThrowIntention : SelfTargetingIntention<KtCallExpress
|
||||
val args = element.valueArguments
|
||||
val conditionText = args[0]?.getArgumentExpression()?.text ?: return
|
||||
val functionLiteralArgument = element.lambdaArguments.singleOrNull()
|
||||
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
||||
val bindingContext = element.analyze(BodyResolveMode.PARTIAL_WITH_CFA)
|
||||
val psiFactory = KtPsiFactory(element)
|
||||
|
||||
val messageFunctionExpr = when {
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ class RemoveExplicitSuperQualifierIntention : SelfTargetingRangeIntention<KtSupe
|
||||
val qualifiedExpression = element.getQualifiedExpressionForReceiver() ?: 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
|
||||
|
||||
val newQualifiedExpression = KtPsiFactory(element).createExpressionByPattern(
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ class RemoveExplicitTypeArgumentsIntention : SelfTargetingOffsetIndependentInten
|
||||
if (callExpression.typeArguments.isEmpty()) return false
|
||||
|
||||
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 (contextExpression, expectedType) = findContextToAnalyze(callExpression, bindingContext)
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
class IfThenToElvisInspection : IntentionBasedInspection<KtIfExpression>(
|
||||
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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -61,7 +61,7 @@ class SurroundWithNullCheckFix(
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val element = diagnostic.psiElement
|
||||
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 nullableExpression =
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ object CreateFunctionFromCallableReferenceActionFactory : CreateCallableMemberFr
|
||||
override fun extractFixData(element: KtCallableReferenceExpression, diagnostic: Diagnostic): List<CallableInfo> {
|
||||
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
|
||||
|
||||
+1
-1
@@ -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}"
|
||||
|
||||
Reference in New Issue
Block a user