Refactoring: moved capturing in closure check to call resolver extension
This commit is contained in:
@@ -301,12 +301,7 @@ public class CallResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TracingStrategy tracing = TracingStrategyImpl.create(functionReference, context.call);
|
TracingStrategy tracing = TracingStrategyImpl.create(functionReference, context.call);
|
||||||
OverloadResolutionResultsImpl<FunctionDescriptor> results = doResolveCallOrGetCachedResults(
|
return doResolveCallOrGetCachedResults(context, prioritizedTasks, CallTransformer.FUNCTION_CALL_TRANSFORMER, tracing);
|
||||||
context, prioritizedTasks, CallTransformer.FUNCTION_CALL_TRANSFORMER, tracing);
|
|
||||||
if (calleeExpression instanceof JetSimpleNameExpression) {
|
|
||||||
ExpressionTypingUtils.checkCapturingInClosure((JetSimpleNameExpression) calleeExpression, context.trace, context.scope);
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OverloadResolutionResults<FunctionDescriptor> resolveCallWithKnownCandidate(
|
public OverloadResolutionResults<FunctionDescriptor> resolveCallWithKnownCandidate(
|
||||||
|
|||||||
+5
-1
@@ -27,7 +27,11 @@ import java.util.*;
|
|||||||
public class CallResolverExtensionProvider {
|
public class CallResolverExtensionProvider {
|
||||||
|
|
||||||
private final static CompositeExtension DEFAULT =
|
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<Map<DeclarationDescriptor, List<CallResolverExtension>>> extensionsCache;
|
private WeakReference<Map<DeclarationDescriptor, List<CallResolverExtension>>> extensionsCache;
|
||||||
|
|
||||||
|
|||||||
+77
@@ -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 <F : CallableDescriptor> run(resolvedCall: ResolvedCall<F>, 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
-1
@@ -101,7 +101,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
CallExpressionResolver callExpressionResolver = components.expressionTypingServices.getCallExpressionResolver();
|
CallExpressionResolver callExpressionResolver = components.expressionTypingServices.getCallExpressionResolver();
|
||||||
JetTypeInfo typeInfo = callExpressionResolver.getSimpleNameExpressionTypeInfo(expression, NO_RECEIVER, null, context);
|
JetTypeInfo typeInfo = callExpressionResolver.getSimpleNameExpressionTypeInfo(expression, NO_RECEIVER, null, context);
|
||||||
JetType type = DataFlowUtils.checkType(typeInfo.getType(), expression, 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
|
return JetTypeInfo.create(type, typeInfo.getDataFlowInfo()); // TODO : Extensions to this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-45
@@ -32,13 +32,10 @@ import org.jetbrains.jet.lang.diagnostics.Errors;
|
|||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.*;
|
import org.jetbrains.jet.lang.resolve.*;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
|
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.results.OverloadResolutionResults;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
|
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
|
||||||
import org.jetbrains.jet.lang.resolve.dataClassUtils.DataClassUtilsPackage;
|
import org.jetbrains.jet.lang.resolve.dataClassUtils.DataClassUtilsPackage;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
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.WritableScope;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
|
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver;
|
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
|
@NotNull
|
||||||
public OverloadResolutionResults<FunctionDescriptor> resolveFakeCall(
|
public OverloadResolutionResults<FunctionDescriptor> resolveFakeCall(
|
||||||
@NotNull ExpressionTypingContext context,
|
@NotNull ExpressionTypingContext context,
|
||||||
|
|||||||
+1
-2
@@ -102,8 +102,7 @@ class VariablesHighlightingVisitor extends AfterAnalysisHighlightingVisitor {
|
|||||||
String msg = ((VariableDescriptor) descriptor).isVar()
|
String msg = ((VariableDescriptor) descriptor).isVar()
|
||||||
? "Wrapped into a reference object to be modified when captured in a closure"
|
? "Wrapped into a reference object to be modified when captured in a closure"
|
||||||
: "Value captured in a closure";
|
: "Value captured in a closure";
|
||||||
holder.createInfoAnnotation(elementToHighlight, msg).setTextAttributes(
|
holder.createInfoAnnotation(elementToHighlight, msg).setTextAttributes(JetHighlightingColors.WRAPPED_INTO_REF);
|
||||||
JetHighlightingColors.WRAPPED_INTO_REF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (descriptor instanceof LocalVariableDescriptor) {
|
if (descriptor instanceof LocalVariableDescriptor) {
|
||||||
|
|||||||
Reference in New Issue
Block a user