Do not drop analysis results for the code fragment context, allow to re-use it
Otherwise labels declared in the expression context become unresolved. This is needed for the `this@label` expression evaluation support (KT-28134).
This commit is contained in:
@@ -41,7 +41,7 @@ object LabelResolver {
|
|||||||
if (name != null && name == labelName) {
|
if (name != null && name == labelName) {
|
||||||
elements.add(getExpressionUnderLabel(parent as KtExpression))
|
elements.add(getExpressionUnderLabel(parent as KtExpression))
|
||||||
}
|
}
|
||||||
parent = parent.parent
|
parent = if (parent is KtCodeFragment) parent.context else parent.parent
|
||||||
}
|
}
|
||||||
return elements
|
return elements
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-29
@@ -40,21 +40,22 @@ class CodeFragmentAnalyzer(
|
|||||||
private val expressionTypingServices: ExpressionTypingServices,
|
private val expressionTypingServices: ExpressionTypingServices,
|
||||||
private val typeResolver: TypeResolver
|
private val typeResolver: TypeResolver
|
||||||
) {
|
) {
|
||||||
// component dependency cycle
|
@set:Inject // component dependency cycle
|
||||||
var resolveElementCache: ResolveElementCache? = null
|
lateinit var resolveElementCache: ResolveElementCache
|
||||||
@Inject set
|
|
||||||
|
|
||||||
fun analyzeCodeFragment(codeFragment: KtCodeFragment, trace: BindingTrace, bodyResolveMode: BodyResolveMode) {
|
fun analyzeCodeFragment(codeFragment: KtCodeFragment, trace: BindingTrace, bodyResolveMode: BodyResolveMode): BindingTrace {
|
||||||
val codeFragmentElement = codeFragment.getContentElement()
|
val codeFragmentElement = codeFragment.getContentElement()
|
||||||
|
|
||||||
val (scopeForContextElement, dataFlowInfo) = getScopeAndDataFlowForAnalyzeFragment(codeFragment) {
|
val (scopeForContextElement, dataFlowInfo, newBindingContext) = doAnalyzeCoreFragment(codeFragment) {
|
||||||
resolveElementCache!!.resolveToElements(listOf(it), bodyResolveMode)
|
resolveElementCache!!.resolveToElements(listOf(it), bodyResolveMode)
|
||||||
} ?: return
|
} ?: return trace
|
||||||
|
|
||||||
|
val newBindingTrace = DelegatingBindingTrace(newBindingContext, "For code fragment analysis")
|
||||||
|
|
||||||
when (codeFragmentElement) {
|
when (codeFragmentElement) {
|
||||||
is KtExpression -> {
|
is KtExpression -> {
|
||||||
PreliminaryDeclarationVisitor.createForExpression(
|
PreliminaryDeclarationVisitor.createForExpression(
|
||||||
codeFragmentElement, trace,
|
codeFragmentElement, newBindingTrace,
|
||||||
expressionTypingServices.languageVersionSettings
|
expressionTypingServices.languageVersionSettings
|
||||||
)
|
)
|
||||||
expressionTypingServices.getTypeInfo(
|
expressionTypingServices.getTypeInfo(
|
||||||
@@ -62,7 +63,7 @@ class CodeFragmentAnalyzer(
|
|||||||
codeFragmentElement,
|
codeFragmentElement,
|
||||||
TypeUtils.NO_EXPECTED_TYPE,
|
TypeUtils.NO_EXPECTED_TYPE,
|
||||||
dataFlowInfo,
|
dataFlowInfo,
|
||||||
trace,
|
newBindingTrace,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -70,7 +71,7 @@ class CodeFragmentAnalyzer(
|
|||||||
is KtTypeReference -> {
|
is KtTypeReference -> {
|
||||||
val context = TypeResolutionContext(
|
val context = TypeResolutionContext(
|
||||||
scopeForContextElement,
|
scopeForContextElement,
|
||||||
trace,
|
newBindingTrace,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
codeFragment.suppressDiagnosticsInDebugMode()
|
codeFragment.suppressDiagnosticsInDebugMode()
|
||||||
@@ -78,6 +79,8 @@ class CodeFragmentAnalyzer(
|
|||||||
typeResolver.resolvePossiblyBareType(context, codeFragmentElement)
|
typeResolver.resolvePossiblyBareType(context, codeFragmentElement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return newBindingTrace
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: this code should be moved into debugger which should set correct context for its code fragment
|
//TODO: this code should be moved into debugger which should set correct context for its code fragment
|
||||||
@@ -91,56 +94,63 @@ class CodeFragmentAnalyzer(
|
|||||||
} ?: this
|
} ?: this
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getScopeAndDataFlowForAnalyzeFragment(
|
private fun doAnalyzeCoreFragment(
|
||||||
codeFragment: KtCodeFragment,
|
codeFragment: KtCodeFragment,
|
||||||
resolveToElement: (KtElement) -> BindingContext
|
resolveToElement: (KtElement) -> BindingContext
|
||||||
): Pair<LexicalScope, DataFlowInfo>? {
|
): Triple<LexicalScope, DataFlowInfo, BindingContext>? {
|
||||||
val context = codeFragment.context
|
val context = codeFragment.context
|
||||||
|
|
||||||
val scopeForContextElement: LexicalScope?
|
val scopeForContextElement: LexicalScope?
|
||||||
val dataFlowInfo: DataFlowInfo
|
val dataFlowInfo: DataFlowInfo
|
||||||
|
|
||||||
fun getClassDescriptor(classOrObject: KtClassOrObject): ClassDescriptor? {
|
fun getClassDescriptor(classOrObject: KtClassOrObject): Pair<BindingContext, ClassDescriptorWithResolutionScopes>? {
|
||||||
|
val bindingContext: BindingContext
|
||||||
|
val classDescriptor: ClassDescriptor?
|
||||||
|
|
||||||
if (!KtPsiUtil.isLocal(classOrObject)) {
|
if (!KtPsiUtil.isLocal(classOrObject)) {
|
||||||
return resolveSession.getClassDescriptor(classOrObject, NoLookupLocation.FROM_IDE)
|
bindingContext = resolveSession.bindingContext
|
||||||
|
classDescriptor = resolveSession.getClassDescriptor(classOrObject, NoLookupLocation.FROM_IDE)
|
||||||
|
} else {
|
||||||
|
bindingContext = resolveToElement(classOrObject)
|
||||||
|
classDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject] as ClassDescriptor?
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolveToElement(classOrObject)[BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject] as ClassDescriptor?
|
return (classDescriptor as? ClassDescriptorWithResolutionScopes)?.let { Pair(bindingContext, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val bindingContextForContext: BindingContext
|
||||||
when (context) {
|
when (context) {
|
||||||
is KtPrimaryConstructor -> {
|
is KtPrimaryConstructor -> {
|
||||||
val descriptor =
|
val (bindingContext, classDescriptor) = getClassDescriptor(context.getContainingClassOrObject()) ?: return null
|
||||||
(getClassDescriptor(context.getContainingClassOrObject()) as? ClassDescriptorWithResolutionScopes) ?: return null
|
|
||||||
|
|
||||||
scopeForContextElement = descriptor.scopeForInitializerResolution
|
scopeForContextElement = classDescriptor.scopeForInitializerResolution
|
||||||
dataFlowInfo = DataFlowInfo.EMPTY
|
dataFlowInfo = DataFlowInfo.EMPTY
|
||||||
|
bindingContextForContext = bindingContext
|
||||||
}
|
}
|
||||||
is KtSecondaryConstructor -> {
|
is KtSecondaryConstructor -> {
|
||||||
val correctedContext = context.getDelegationCall().calleeExpression!!
|
val correctedContext = context.getDelegationCall().calleeExpression!!
|
||||||
|
bindingContextForContext = resolveToElement(correctedContext)
|
||||||
|
|
||||||
val contextForElement = resolveToElement(correctedContext)
|
scopeForContextElement = bindingContextForContext[BindingContext.LEXICAL_SCOPE, correctedContext]
|
||||||
|
|
||||||
scopeForContextElement = contextForElement[BindingContext.LEXICAL_SCOPE, correctedContext]
|
|
||||||
dataFlowInfo = DataFlowInfo.EMPTY
|
dataFlowInfo = DataFlowInfo.EMPTY
|
||||||
}
|
}
|
||||||
is KtClassOrObject -> {
|
is KtClassOrObject -> {
|
||||||
val descriptor = (getClassDescriptor(context) as? ClassDescriptorWithResolutionScopes) ?: return null
|
val (bindingContext, classDescriptor) = getClassDescriptor(context) ?: return null
|
||||||
|
scopeForContextElement = classDescriptor.scopeForMemberDeclarationResolution
|
||||||
scopeForContextElement = descriptor.scopeForMemberDeclarationResolution
|
|
||||||
dataFlowInfo = DataFlowInfo.EMPTY
|
dataFlowInfo = DataFlowInfo.EMPTY
|
||||||
|
bindingContextForContext = bindingContext
|
||||||
}
|
}
|
||||||
is KtFile -> {
|
is KtFile -> {
|
||||||
scopeForContextElement = resolveSession.fileScopeProvider.getFileResolutionScope(context)
|
scopeForContextElement = resolveSession.fileScopeProvider.getFileResolutionScope(context)
|
||||||
dataFlowInfo = DataFlowInfo.EMPTY
|
dataFlowInfo = DataFlowInfo.EMPTY
|
||||||
|
bindingContextForContext = BindingContext.EMPTY
|
||||||
}
|
}
|
||||||
is KtElement -> {
|
is KtElement -> {
|
||||||
val correctedContext = context.correctContextForElement()
|
val correctedContext = context.correctContextForElement()
|
||||||
|
bindingContextForContext = resolveToElement(correctedContext)
|
||||||
|
|
||||||
val contextForElement = resolveToElement(correctedContext)
|
scopeForContextElement = bindingContextForContext[BindingContext.LEXICAL_SCOPE, correctedContext]
|
||||||
|
dataFlowInfo = bindingContextForContext.getDataFlowInfoAfter(correctedContext)
|
||||||
scopeForContextElement = contextForElement[BindingContext.LEXICAL_SCOPE, correctedContext]
|
|
||||||
dataFlowInfo = contextForElement.getDataFlowInfoAfter(correctedContext)
|
|
||||||
}
|
}
|
||||||
else -> return null
|
else -> return null
|
||||||
}
|
}
|
||||||
@@ -149,7 +159,7 @@ class CodeFragmentAnalyzer(
|
|||||||
|
|
||||||
val importList = codeFragment.importsAsImportList()
|
val importList = codeFragment.importsAsImportList()
|
||||||
if (importList == null || importList.imports.isEmpty()) {
|
if (importList == null || importList.imports.isEmpty()) {
|
||||||
return scopeForContextElement to dataFlowInfo
|
return Triple(scopeForContextElement, dataFlowInfo, bindingContextForContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
val importScopes = importList.imports.mapNotNull {
|
val importScopes = importList.imports.mapNotNull {
|
||||||
@@ -159,6 +169,6 @@ class CodeFragmentAnalyzer(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return scopeForContextElement.addImportingScopes(importScopes) to dataFlowInfo
|
return Triple(scopeForContextElement.addImportingScopes(importScopes), dataFlowInfo, bindingContextForContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-4
@@ -219,12 +219,17 @@ private object KotlinResolveDataProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun analyzeExpressionCodeFragment(codeFragmentAnalyzer: CodeFragmentAnalyzer, codeFragment: KtCodeFragment): BindingContext {
|
private fun analyzeExpressionCodeFragment(codeFragmentAnalyzer: CodeFragmentAnalyzer, codeFragment: KtCodeFragment): BindingContext {
|
||||||
val trace = BindingTraceContext()
|
val contextElement = codeFragment.getContentElement()
|
||||||
codeFragmentAnalyzer.analyzeCodeFragment(
|
val trace = if (contextElement != null) {
|
||||||
|
DelegatingBindingTrace(contextElement.analyze(BodyResolveMode.PARTIAL_FOR_COMPLETION), "Trace for code fragment resolution")
|
||||||
|
} else {
|
||||||
|
BindingTraceContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
return codeFragmentAnalyzer.analyzeCodeFragment(
|
||||||
codeFragment,
|
codeFragment,
|
||||||
trace,
|
trace,
|
||||||
BodyResolveMode.PARTIAL_FOR_COMPLETION //TODO: discuss it
|
BodyResolveMode.PARTIAL_FOR_COMPLETION //TODO: discuss it
|
||||||
)
|
).bindingContext
|
||||||
return trace.bindingContext
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -463,9 +463,8 @@ class ResolveElementCache(
|
|||||||
BodyResolveMode.PARTIAL_FOR_COMPLETION
|
BodyResolveMode.PARTIAL_FOR_COMPLETION
|
||||||
else
|
else
|
||||||
bodyResolveMode
|
bodyResolveMode
|
||||||
codeFragmentAnalyzer.analyzeCodeFragment(codeFragment, trace, contextResolveMode)
|
|
||||||
|
|
||||||
return trace
|
return codeFragmentAnalyzer.analyzeCodeFragment(codeFragment, trace, contextResolveMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun annotationAdditionalResolve(resolveSession: ResolveSession, ktAnnotationEntry: KtAnnotationEntry): BindingTrace {
|
private fun annotationAdditionalResolve(resolveSession: ResolveSession, ktAnnotationEntry: KtAnnotationEntry): BindingTrace {
|
||||||
|
|||||||
Reference in New Issue
Block a user