From 9a53142b26a945633f3bbf24137b2364ba8f6700 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Tue, 23 Jun 2015 15:04:31 +0300 Subject: [PATCH] Refactoring: move similar part for obtaining scope for codeFragment to JetCodeFragment --- .../kotlin/resolve/lazy/ElementResolver.kt | 50 +++---------- .../resolve/util/codeFragmentResolveUtils.kt | 72 +++++++++++++++++++ .../idea/caches/resolve/KotlinResolveCache.kt | 40 ++--------- 3 files changed, 87 insertions(+), 75 deletions(-) create mode 100644 idea/ide-common/src/org/jetbrains/kotlin/resolve/util/codeFragmentResolveUtils.kt diff --git a/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/ElementResolver.kt b/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/ElementResolver.kt index ad87d432aef..0610a5ec0c3 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/ElementResolver.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/ElementResolver.kt @@ -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(true) val declaration = modifierList?.getParentOfType(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 } diff --git a/idea/ide-common/src/org/jetbrains/kotlin/resolve/util/codeFragmentResolveUtils.kt b/idea/ide-common/src/org/jetbrains/kotlin/resolve/util/codeFragmentResolveUtils.kt new file mode 100644 index 00000000000..77afac95010 --- /dev/null +++ b/idea/ide-common/src/org/jetbrains/kotlin/resolve/util/codeFragmentResolveUtils.kt @@ -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? { + 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 +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinResolveCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinResolveCache.kt index 5e5d613a099..bea4defa543 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinResolveCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinResolveCache.kt @@ -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,