Introduced KtExpression.analyzeAsReplacement() utility

This commit is contained in:
Valentin Kipyatkov
2016-11-03 13:10:01 +03:00
parent e850446f17
commit 869b177823
8 changed files with 49 additions and 45 deletions
@@ -17,11 +17,16 @@
package org.jetbrains.kotlin.idea.analysis
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
@@ -68,3 +73,31 @@ import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
): KotlinType? {
return computeTypeInfoInContext(scope, contextExpression, trace, dataFlowInfo, expectedType).type
}
@JvmOverloads fun KtExpression.analyzeAsReplacement(
expressionToBeReplaced: KtExpression,
bindingContext: BindingContext,
scope: LexicalScope,
trace: BindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace for analyzeAsReplacement()"),
contextDependency: ContextDependency = ContextDependency.INDEPENDENT
): BindingContext {
return analyzeInContext(scope,
expressionToBeReplaced,
dataFlowInfo = bindingContext.getDataFlowInfoBefore(expressionToBeReplaced),
expectedType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, expressionToBeReplaced] ?: TypeUtils.NO_EXPECTED_TYPE,
isStatement = expressionToBeReplaced.isUsedAsStatement(bindingContext),
trace = trace,
contextDependency = contextDependency)
}
@JvmOverloads fun KtExpression.analyzeAsReplacement(
expressionToBeReplaced: KtExpression,
bindingContext: BindingContext,
resolutionFacade: ResolutionFacade = expressionToBeReplaced.getResolutionFacade(),
trace: BindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace for analyzeAsReplacement()"),
contextDependency: ContextDependency = ContextDependency.INDEPENDENT
): BindingContext {
val scope = expressionToBeReplaced.getResolutionScope(bindingContext, resolutionFacade)
return analyzeAsReplacement(expressionToBeReplaced, bindingContext, scope, trace, contextDependency)
}
@@ -20,7 +20,7 @@ import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.analysis.analyzeAsReplacement
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider
import org.jetbrains.kotlin.resolve.scopes.ImportingScope
@@ -188,7 +189,7 @@ class OptimizedImportsBuilder(
val bindingContext = element.analyze()
val expressionToAnalyze = getExpressionToAnalyze(element) ?: continue
val newScope = element.getResolutionScope(bindingContext, file.getResolutionFacade()).replaceImportingScopes(newFileScope)
val newBindingContext = expressionToAnalyze.analyzeInContext(newScope, expressionToAnalyze)
val newBindingContext = expressionToAnalyze.analyzeAsReplacement(expressionToAnalyze, bindingContext, newScope, trace = BindingTraceContext())
testLog?.append("Additional checking of reference $ref\n")
@@ -22,7 +22,7 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.PostprocessReformattingAspect
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.analysis.analyzeAsReplacement
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.ShortenReferences.Options
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
@@ -432,9 +432,8 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
val varAsFunResolvedCall = callee.getResolvedCall(bindingContext) as? VariableAsFunctionResolvedCall
if (targets.isEmpty()) return Skip
val scope = element.getResolutionScope(bindingContext, resolutionFacade)
val selectorCopy = selector.copy() as KtReferenceExpression
val newContext = selectorCopy.analyzeInContext(scope, selector)
val newContext = selectorCopy.analyzeAsReplacement(element, bindingContext, resolutionFacade)
val newCallee = selectorCopy.getCalleeExpressionIfAny() as KtReferenceExpression
val targetsWhenShort = newCallee.targets(newContext)
val varAsFunResolvedCallWhenShort = newCallee.getResolvedCall(newContext) as? VariableAsFunctionResolvedCall
@@ -505,8 +504,7 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
override fun analyzeQualifiedElement(element: KtThisExpression, bindingContext: BindingContext): AnalyzeQualifiedElementResult {
val targetBefore = element.instanceReference.targets(bindingContext).singleOrNull() ?: return Skip
val scope = element.getResolutionScope(bindingContext, resolutionFacade)
val newContext = simpleThis.analyzeInContext(scope, element)
val newContext = simpleThis.analyzeAsReplacement(element, bindingContext, resolutionFacade)
val targetAfter = simpleThis.instanceReference.targets(newContext).singleOrNull()
return if (targetBefore == targetAfter) ShortenNow else Skip
}
@@ -21,11 +21,9 @@ import com.intellij.codeInsight.template.TemplateBuilderImpl
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiDocumentManager
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.analysis.analyzeAsReplacement
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
@@ -46,10 +44,9 @@ class AddForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(
val resolvedCall = loopRange.getResolvedCall(bindingContext)
if (resolvedCall?.resultingDescriptor?.fqNameUnsafe?.asString() in WITH_INDEX_FQ_NAMES) return null // already withIndex() call
val resolutionScope = element.getResolutionScope(bindingContext, element.getResolutionFacade())
val potentialExpression = createWithIndexExpression(loopRange)
val newBindingContext = potentialExpression.analyzeInContext(resolutionScope, loopRange)
val newBindingContext = potentialExpression.analyzeAsReplacement(loopRange, bindingContext)
val newResolvedCall = potentialExpression.getResolvedCall(newBindingContext) ?: return null
if (newResolvedCall.resultingDescriptor.fqNameUnsafe.asString() !in WITH_INDEX_FQ_NAMES) return null
@@ -20,11 +20,9 @@ import com.intellij.codeInspection.CleanupLocalInspectionTool
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.analysis.analyzeAsReplacement
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtQualifiedExpression
import org.jetbrains.kotlin.psi.KtSuperExpression
@@ -32,13 +30,9 @@ import org.jetbrains.kotlin.psi.createExpressionByPattern
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiver
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoAfter
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.TypeUtils
class RemoveExplicitSuperQualifierInspection : IntentionBasedInspection<KtSuperExpression>(RemoveExplicitSuperQualifierIntention::class), CleanupLocalInspectionTool {
override val problemHighlightType: ProblemHighlightType
@@ -54,12 +48,9 @@ class RemoveExplicitSuperQualifierIntention : SelfTargetingRangeIntention<KtSupe
val bindingContext = selector.analyze(BodyResolveMode.PARTIAL)
if (selector.getResolvedCall(bindingContext) == null) return null
val resolutionScope = qualifiedExpression.getResolutionScope(bindingContext, selector.getResolutionFacade())
val dataFlowInfo = bindingContext.getDataFlowInfoBefore(element)
val expectedType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, qualifiedExpression] ?: TypeUtils.NO_EXPECTED_TYPE
val newQualifiedExpression = KtPsiFactory(element).createExpressionByPattern("$0.$1", toNonQualified(element), selector) as KtQualifiedExpression
val newBindingContext = newQualifiedExpression.analyzeInContext(resolutionScope, qualifiedExpression, dataFlowInfo = dataFlowInfo, expectedType = expectedType, isStatement = true)
val newBindingContext = newQualifiedExpression.analyzeAsReplacement(qualifiedExpression, bindingContext)
val newResolvedCall = newQualifiedExpression.selectorExpression.getResolvedCall(newBindingContext) ?: return null
if (ErrorUtils.isError(newResolvedCall.resultingDescriptor)) return null
@@ -20,11 +20,9 @@ import com.intellij.openapi.editor.Editor
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.analysis.analyzeAsReplacement
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.idea.util.psi.patternMatching.matches
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression
@@ -32,7 +30,6 @@ import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.doNotAnalyze
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class ReplaceWithOperatorAssignmentInspection : IntentionBasedInspection<KtBinaryExpression>(ReplaceWithOperatorAssignmentIntention::class)
@@ -50,11 +47,7 @@ class ReplaceWithOperatorAssignmentIntention : SelfTargetingOffsetIndependentInt
// now check that the resulting operator assignment will be resolved
val opAssign = buildOperatorAssignment(element)
opAssign.getContainingKtFile().doNotAnalyze = null //TODO: strange hack
val resolutionScope = element.getResolutionScope(bindingContext, element.getResolutionFacade())
val newBindingContext = opAssign.analyzeInContext(resolutionScope,
contextExpression = element,
dataFlowInfo = bindingContext.getDataFlowInfoBefore(element),
isStatement = true)
val newBindingContext = opAssign.analyzeAsReplacement(element, bindingContext)
return newBindingContext.diagnostics.forElement(opAssign.operationReference).isEmpty()
}
@@ -21,21 +21,17 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeUtil
import org.jetbrains.kotlin.cfg.pseudocode.containingDeclarationForPseudocode
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.analysis.analyzeAsReplacement
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.result.*
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.sequence.*
import org.jetbrains.kotlin.idea.project.builtIns
import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils.isSubtypeOfClass
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoAfter
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.smartcasts.ExplicitSmartCasts
import org.jetbrains.kotlin.resolve.calls.smartcasts.ImplicitSmartCasts
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -270,9 +266,7 @@ private fun checkSmartCastsPreserved(loop: KtForExpression, matchResult: MatchRe
val callChain = matchResult.generateCallChain(loop)
val resolutionScope = loop.getResolutionScope(bindingContext, loop.getResolutionFacade())
val dataFlowInfo = bindingContext.getDataFlowInfoBefore(loop)
val newBindingContext = callChain.analyzeInContext(resolutionScope, loop, dataFlowInfo = dataFlowInfo)
val newBindingContext = callChain.analyzeAsReplacement(loop, bindingContext)
var preservedSmartCastCount = 0
callChain.forEachDescendantOfType<KtExpression> { expression ->
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.idea.analysis.analyzeAsReplacement
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
@@ -275,11 +276,7 @@ fun <TExpression : KtExpression> tryChangeAndCheckErrors(
performChange(expressionCopy)
val resolutionScope = block.getResolutionScope(bindingContext, block.getResolutionFacade())
val newBindingContext = blockCopy.analyzeInContext(scope = resolutionScope,
contextExpression = block,
dataFlowInfo = bindingContext.getDataFlowInfoBefore(block),
trace = DelegatingBindingTrace(bindingContext, "Temporary trace"))
val newBindingContext = blockCopy.analyzeAsReplacement(block, bindingContext)
return newBindingContext.diagnostics.none {
it.severity == Severity.ERROR
&& !scopeToExcludeCopy.isAncestor(it.psiElement)