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);
|
||||
OverloadResolutionResultsImpl<FunctionDescriptor> 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<FunctionDescriptor> resolveCallWithKnownCandidate(
|
||||
|
||||
+5
-1
@@ -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<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();
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
-45
@@ -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<FunctionDescriptor> resolveFakeCall(
|
||||
@NotNull ExpressionTypingContext context,
|
||||
|
||||
+1
-2
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user