From 509a8adae56e2b25ccda075c3187d9c97579b79b Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Fri, 26 Dec 2014 18:16:33 +0300 Subject: [PATCH] Refactoring: moved capturing in closure check to call resolver extension --- .../jet/lang/resolve/calls/CallResolver.java | 7 +- .../CallResolverExtensionProvider.java | 6 +- .../extensions/CapturingInClosureExtension.kt | 77 +++++++++++++++++++ .../BasicExpressionTypingVisitor.java | 1 - .../expressions/ExpressionTypingUtils.java | 45 ----------- .../VariablesHighlightingVisitor.java | 3 +- 6 files changed, 84 insertions(+), 55 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/extensions/CapturingInClosureExtension.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index d96c96d795f..763c7fbb739 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -301,12 +301,7 @@ public class CallResolver { } TracingStrategy tracing = TracingStrategyImpl.create(functionReference, context.call); - OverloadResolutionResultsImpl results = doResolveCallOrGetCachedResults( - context, prioritizedTasks, CallTransformer.FUNCTION_CALL_TRANSFORMER, tracing); - if (calleeExpression instanceof JetSimpleNameExpression) { - ExpressionTypingUtils.checkCapturingInClosure((JetSimpleNameExpression) calleeExpression, context.trace, context.scope); - } - return results; + return doResolveCallOrGetCachedResults(context, prioritizedTasks, CallTransformer.FUNCTION_CALL_TRANSFORMER, tracing); } public OverloadResolutionResults resolveCallWithKnownCandidate( diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/extensions/CallResolverExtensionProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/extensions/CallResolverExtensionProvider.java index 8c0aae4df14..2751a5f4ea3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/extensions/CallResolverExtensionProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/extensions/CallResolverExtensionProvider.java @@ -27,7 +27,11 @@ import java.util.*; public class CallResolverExtensionProvider { private final static CompositeExtension DEFAULT = - new CompositeExtension(Arrays.asList(new NeedSyntheticCallResolverExtension(), new ReifiedTypeParameterSubstitutionCheck())); + new CompositeExtension(Arrays.asList( + new NeedSyntheticCallResolverExtension(), + new ReifiedTypeParameterSubstitutionCheck(), + new CapturingInClosureExtension() + )); private WeakReference>> extensionsCache; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/extensions/CapturingInClosureExtension.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/extensions/CapturingInClosureExtension.kt new file mode 100644 index 00000000000..f92b2977313 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/extensions/CapturingInClosureExtension.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2010-2014 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.jet.lang.resolve.calls.extensions + +import org.jetbrains.jet.lang.descriptors.CallableDescriptor +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall +import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext +import org.jetbrains.jet.lang.resolve.BindingTrace +import org.jetbrains.jet.lang.resolve.scopes.JetScope +import org.jetbrains.jet.lang.descriptors.VariableDescriptor +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.resolve.BindingContext.CAPTURED_IN_CLOSURE +import org.jetbrains.jet.lang.types.expressions.CaptureKind +import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils +import org.jetbrains.jet.lang.psi.JetFunctionLiteral +import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression +import org.jetbrains.jet.lang.resolve.calls.callUtil.* +import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor +import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall + +class CapturingInClosureExtension : CallResolverExtension { + override fun run(resolvedCall: ResolvedCall, context: BasicCallResolutionContext) { + val variableResolvedCall = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.variableCall else resolvedCall + val variableDescriptor = variableResolvedCall.getResultingDescriptor() as? VariableDescriptor + if (variableDescriptor != null) { + checkCapturingInClosure(variableDescriptor, context.trace, context.scope) + } + } + + private fun checkCapturingInClosure(variable: VariableDescriptor, trace: BindingTrace, scope: JetScope) { + val variableParent = variable.getContainingDeclaration() + val scopeContainer = scope.getContainingDeclaration() + if (scopeContainer != variableParent && variableParent is CallableDescriptor) { + if (trace.get(CAPTURED_IN_CLOSURE, variable) != CaptureKind.NOT_INLINE) { + val inline = isCapturedInInline(trace.getBindingContext(), scopeContainer, variableParent) + trace.record(CAPTURED_IN_CLOSURE, variable, if (inline) CaptureKind.INLINE_ONLY else CaptureKind.NOT_INLINE) + } + } + } + + private fun isCapturedInInline( + context: BindingContext, scopeContainer: DeclarationDescriptor, variableParent: DeclarationDescriptor + ): Boolean { + val scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer) + if (scopeDeclaration !is JetFunctionLiteral) return false + + val parent = scopeDeclaration.getParent() + assert(parent is JetFunctionLiteralExpression) { "parent of JetFunctionLiteral is " + parent } + val resolvedCall = (parent as JetFunctionLiteralExpression).getParentResolvedCall(context, true) + if (resolvedCall == null) return false + + val callable = resolvedCall.getResultingDescriptor() + if (callable is SimpleFunctionDescriptor && callable.getInlineStrategy().isInline()) { + val scopeContainerParent = scopeContainer.getContainingDeclaration() + assert(scopeContainerParent != null) { "parent is null for " + scopeContainer } + return scopeContainerParent == variableParent || isCapturedInInline(context, scopeContainerParent, variableParent) + } + return false + } +} + + diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 896804cb055..85d83645860 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -101,7 +101,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { CallExpressionResolver callExpressionResolver = components.expressionTypingServices.getCallExpressionResolver(); JetTypeInfo typeInfo = callExpressionResolver.getSimpleNameExpressionTypeInfo(expression, NO_RECEIVER, null, context); JetType type = DataFlowUtils.checkType(typeInfo.getType(), expression, context); - ExpressionTypingUtils.checkCapturingInClosure(expression, context.trace, context.scope); return JetTypeInfo.create(type, typeInfo.getDataFlowInfo()); // TODO : Extensions to this } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java index 423d2d71a83..abf9a7f066f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java @@ -32,13 +32,10 @@ import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.calls.CallResolver; -import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage; -import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; import org.jetbrains.jet.lang.resolve.dataClassUtils.DataClassUtilsPackage; import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver; @@ -169,48 +166,6 @@ public class ExpressionTypingUtils { } } - private static boolean isCapturedInInline( - @NotNull BindingContext context, - @NotNull DeclarationDescriptor scopeContainer, - @NotNull DeclarationDescriptor variableParent - ) { - PsiElement scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer); - if (!(scopeDeclaration instanceof JetFunctionLiteral)) { - return false; - } - - PsiElement parent = scopeDeclaration.getParent(); - assert parent instanceof JetFunctionLiteralExpression : "parent of JetFunctionLiteral is " + parent; - ResolvedCall resolvedCall = CallUtilPackage.getParentResolvedCall((JetFunctionLiteralExpression) parent, context, true); - if (resolvedCall == null) { - return false; - } - - CallableDescriptor callable = resolvedCall.getResultingDescriptor(); - if (callable instanceof SimpleFunctionDescriptor && ((SimpleFunctionDescriptor) callable).getInlineStrategy().isInline()) { - DeclarationDescriptor scopeContainerParent = scopeContainer.getContainingDeclaration(); - assert scopeContainerParent != null : "parent is null for " + scopeContainer; - return scopeContainerParent == variableParent || isCapturedInInline(context, scopeContainerParent, variableParent); - } - else { - return false; - } - } - - public static void checkCapturingInClosure(JetSimpleNameExpression expression, BindingTrace trace, JetScope scope) { - VariableDescriptor variable = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), expression, true); - if (variable != null) { - DeclarationDescriptor variableParent = variable.getContainingDeclaration(); - DeclarationDescriptor scopeContainer = scope.getContainingDeclaration(); - if (scopeContainer != variableParent && variableParent instanceof CallableDescriptor) { - if (trace.get(CAPTURED_IN_CLOSURE, variable) != CaptureKind.NOT_INLINE) { - boolean inline = isCapturedInInline(trace.getBindingContext(), scopeContainer, variableParent); - trace.record(CAPTURED_IN_CLOSURE, variable, inline ? CaptureKind.INLINE_ONLY : CaptureKind.NOT_INLINE); - } - } - } - } - @NotNull public OverloadResolutionResults resolveFakeCall( @NotNull ExpressionTypingContext context, diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/highlighter/VariablesHighlightingVisitor.java b/idea/idea-analysis/src/org/jetbrains/jet/plugin/highlighter/VariablesHighlightingVisitor.java index 1172f2b07a3..42cb008a53a 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/highlighter/VariablesHighlightingVisitor.java +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/highlighter/VariablesHighlightingVisitor.java @@ -102,8 +102,7 @@ class VariablesHighlightingVisitor extends AfterAnalysisHighlightingVisitor { String msg = ((VariableDescriptor) descriptor).isVar() ? "Wrapped into a reference object to be modified when captured in a closure" : "Value captured in a closure"; - holder.createInfoAnnotation(elementToHighlight, msg).setTextAttributes( - JetHighlightingColors.WRAPPED_INTO_REF); + holder.createInfoAnnotation(elementToHighlight, msg).setTextAttributes(JetHighlightingColors.WRAPPED_INTO_REF); } if (descriptor instanceof LocalVariableDescriptor) {