Refactoring: move similar part for obtaining scope for codeFragment to JetCodeFragment

This commit is contained in:
Natalia Ukhorskaya
2015-06-23 15:04:31 +03:00
parent fdfabebcce
commit 9a53142b26
3 changed files with 87 additions and 75 deletions
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.context.withProject
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.frontend.di.createContainerForBodyResolve
import org.jetbrains.kotlin.resolve.util.getScopeAndDataFlowForAnalyzeFragment
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
@@ -206,53 +207,22 @@ public abstract class ElementResolver protected constructor(
val trace = createDelegatingTrace(codeFragment)
val codeFragmentExpression = codeFragment.getContentElement() as? JetExpression ?: return trace
val contextElement = codeFragment.correctedContext
val scopeForContextElement: JetScope?
val dataFlowInfoForContextElement: DataFlowInfo
when (contextElement) {
is JetClassOrObject -> {
val descriptor = resolveSession.resolveToDescriptor(contextElement) as LazyClassDescriptor
scopeForContextElement = descriptor.getScopeForMemberDeclarationResolution()
dataFlowInfoForContextElement = DataFlowInfo.EMPTY
}
val (scopeForContextElement, dataFlowInfoForContextElement) = codeFragment.getScopeAndDataFlowForAnalyzeFragment(resolveSession) {
val contextResolveMode = if (bodyResolveMode == BodyResolveMode.PARTIAL)
BodyResolveMode.PARTIAL_FOR_COMPLETION
else
bodyResolveMode
is JetExpression -> {
// do not use PARTIAL body resolve mode because because it does not know about names used in our fragment
val contextResolveMode = if (bodyResolveMode == BodyResolveMode.PARTIAL)
BodyResolveMode.PARTIAL_FOR_COMPLETION
else
bodyResolveMode
val contextForElement = resolveToElement(contextElement, contextResolveMode)
scopeForContextElement = contextForElement[BindingContext.RESOLUTION_SCOPE, contextElement]
dataFlowInfoForContextElement = contextForElement.getDataFlowInfo(contextElement)
}
resolveToElement(it, contextResolveMode)
} ?: return trace
else -> return trace
}
if (scopeForContextElement == null) return trace
val codeFragmentScope = resolveSession.getFileScopeProvider().getFileScope(codeFragment)
val chainedScope = ChainedScope(scopeForContextElement.getContainingDeclaration(),
"Scope for resolve code fragment", scopeForContextElement, codeFragmentScope)
codeFragmentExpression.computeTypeInContext(chainedScope, trace, dataFlowInfoForContextElement,
codeFragmentExpression.computeTypeInContext(scopeForContextElement, trace, dataFlowInfoForContextElement,
TypeUtils.NO_EXPECTED_TYPE, resolveSession.getModuleDescriptor())
return trace
}
//TODO: this code should be moved into debugger which should set correct context for its code fragment
private val JetCodeFragment.correctedContext: PsiElement?
get() {
val context = getContext()
if (context is JetBlockExpression) {
return context.getStatements().lastOrNull() ?: context
}
return context
}
private fun annotationAdditionalResolve(resolveSession: ResolveSession, jetAnnotationEntry: JetAnnotationEntry): BindingTrace {
val modifierList = jetAnnotationEntry.getParentOfType<JetModifierList>(true)
val declaration = modifierList?.getParentOfType<JetDeclaration>(true)
@@ -397,7 +367,7 @@ public abstract class ElementResolver protected constructor(
val bodyResolver = createBodyResolver(resolveSession, trace, file, statementFilter)
bodyResolver.resolveAnonymousInitializer(DataFlowInfo.EMPTY, classInitializer, classOrObjectDescriptor)
return trace
}
@@ -0,0 +1,72 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.util
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
import org.jetbrains.kotlin.resolve.scopes.ChainedScope
import org.jetbrains.kotlin.resolve.scopes.JetScope
//TODO: this code should be moved into debugger which should set correct context for its code fragment
private fun correctContext(oldContext: PsiElement?): PsiElement? {
if (oldContext is JetBlockExpression) {
return oldContext.getStatements().lastOrNull() ?: oldContext
}
return oldContext
}
public fun JetCodeFragment.getScopeAndDataFlowForAnalyzeFragment(
resolveSession: KotlinCodeAnalyzer,
resolveToElement: (JetElement) -> BindingContext
): Pair<JetScope, DataFlowInfo>? {
val context = correctContext(getContext())
if (context !is JetExpression) return null
val scopeForContextElement: JetScope?
val dataFlowInfo: DataFlowInfo
when (context) {
is JetClassOrObject -> {
val descriptor = resolveSession.getClassDescriptor(context) as ClassDescriptorWithResolutionScopes
scopeForContextElement = descriptor.getScopeForMemberDeclarationResolution()
dataFlowInfo = DataFlowInfo.EMPTY
}
is JetExpression -> {
val contextForElement = resolveToElement(context)
scopeForContextElement = contextForElement[BindingContext.RESOLUTION_SCOPE, context]
dataFlowInfo = contextForElement.getDataFlowInfo(context)
}
else -> return null
}
if (scopeForContextElement == null) return null
val codeFragmentScope = resolveSession.getFileScopeProvider().getFileScope(this)
val chainedScope = ChainedScope(
scopeForContextElement.getContainingDeclaration(),
"Scope for resolve code fragment",
scopeForContextElement, codeFragmentScope)
return chainedScope to dataFlowInfo
}
@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
import org.jetbrains.kotlin.resolve.scopes.ChainedScope
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.resolve.util.getScopeAndDataFlowForAnalyzeFragment
import org.jetbrains.kotlin.types.TypeUtils
import java.util.HashMap
@@ -270,44 +271,13 @@ private object KotlinResolveDataProvider {
val codeFragmentExpression = codeFragment.getContentElement()
if (codeFragmentExpression !is JetExpression) return BindingContext.EMPTY
val contextElement = codeFragment.getContext()
val (scopeForContextElement, dataFlowInfo) = codeFragment.getScopeAndDataFlowForAnalyzeFragment(resolveSession) {
resolveSession.resolveToElement(it, BodyResolveMode.PARTIAL_FOR_COMPLETION) //TODO: discuss it
} ?: return BindingContext.EMPTY
val scopeForContextElement: JetScope?
val dataFlowInfo: DataFlowInfo
if (contextElement is JetClassOrObject) {
val descriptor = resolveSession.resolveToDescriptor(contextElement) as LazyClassDescriptor
scopeForContextElement = descriptor.getScopeForMemberDeclarationResolution()
dataFlowInfo = DataFlowInfo.EMPTY
}
else if (contextElement is JetBlockExpression) {
val newContextElement = contextElement.getStatements().lastOrNull()
if (newContextElement !is JetExpression) return BindingContext.EMPTY
val contextForElement = newContextElement.getResolutionFacade().analyze(newContextElement, BodyResolveMode.FULL)
scopeForContextElement = contextForElement[BindingContext.RESOLUTION_SCOPE, newContextElement]
dataFlowInfo = contextForElement.getDataFlowInfo(newContextElement)
}
else {
if (contextElement !is JetExpression) return BindingContext.EMPTY
val contextForElement = contextElement.getResolutionFacade().analyze(contextElement, BodyResolveMode.PARTIAL_FOR_COMPLETION) //TODO: discuss it
scopeForContextElement = contextForElement[BindingContext.RESOLUTION_SCOPE, contextElement]
dataFlowInfo = contextForElement.getDataFlowInfo(contextElement)
}
if (scopeForContextElement == null) return BindingContext.EMPTY
val codeFragmentScope = resolveSession.getFileScopeProvider().getFileScope(codeFragment)
val chainedScope = ChainedScope(
scopeForContextElement.getContainingDeclaration(),
"Scope for resolve code fragment",
scopeForContextElement, codeFragmentScope)
return codeFragmentExpression.analyzeInContext(
chainedScope,
scopeForContextElement,
BindingTraceContext(),
dataFlowInfo,
TypeUtils.NO_EXPECTED_TYPE,