KtExpression.analyzeInContext uses correct context when analyzing return's

This commit is contained in:
Valentin Kipyatkov
2016-04-19 18:23:44 +03:00
parent 340fe82fa0
commit c50cf13611
13 changed files with 157 additions and 57 deletions
@@ -35,15 +35,20 @@ interface CallChecker {
} }
class CallCheckerContext( class CallCheckerContext(
val resolutionContext: ResolutionContext<*>,
val trace: BindingTrace, val trace: BindingTrace,
val scope: LexicalScope, val languageFeatureSettings: LanguageFeatureSettings
val languageFeatureSettings: LanguageFeatureSettings,
val dataFlowInfo: DataFlowInfo,
val isAnnotationContext: Boolean
) { ) {
constructor(c: ResolutionContext<*>, languageFeatureSettings: LanguageFeatureSettings) : this( val scope: LexicalScope
c.trace, c.scope, languageFeatureSettings, c.dataFlowInfo, c.isAnnotationContext get() = resolutionContext.scope
)
val dataFlowInfo: DataFlowInfo
get() = resolutionContext.dataFlowInfo
val isAnnotationContext: Boolean
get() = resolutionContext.isAnnotationContext
constructor(c: ResolutionContext<*>, languageFeatureSettings: LanguageFeatureSettings) : this(c, c.trace, languageFeatureSettings)
} }
// Use this utility to avoid premature computation of deferred return type of a resolved callable descriptor. // Use this utility to avoid premature computation of deferred return type of a resolved callable descriptor.
@@ -285,7 +285,7 @@ class InlineChecker implements CallChecker {
) { ) {
if (!allowsNonLocalReturns(inlinableParameterDescriptor)) return; if (!allowsNonLocalReturns(inlinableParameterDescriptor)) return;
if (!checkNonLocalReturnUsage(descriptor, parameterUsage, context.getTrace())) { if (!checkNonLocalReturnUsage(descriptor, parameterUsage, context.getResolutionContext())) {
context.getTrace().report(NON_LOCAL_RETURN_NOT_ALLOWED.on(parameterUsage, parameterUsage)); context.getTrace().report(NON_LOCAL_RETURN_NOT_ALLOWED.on(parameterUsage, parameterUsage));
} }
} }
@@ -33,7 +33,7 @@ object CoroutineSuspendCallChecker : CallChecker {
val dispatchReceiverOwner = (resolvedCall.dispatchReceiver as? CoroutineReceiverValue)?.declarationDescriptor ?: return val dispatchReceiverOwner = (resolvedCall.dispatchReceiver as? CoroutineReceiverValue)?.declarationDescriptor ?: return
val callElement = resolvedCall.call.callElement as KtExpression val callElement = resolvedCall.call.callElement as KtExpression
if (!InlineUtil.checkNonLocalReturnUsage(dispatchReceiverOwner, callElement, context.trace)) { if (!InlineUtil.checkNonLocalReturnUsage(dispatchReceiverOwner, callElement, context.resolutionContext)) {
context.trace.report(Errors.NON_LOCAL_SUSPENSION_POINT.on(reportOn)) context.trace.report(Errors.NON_LOCAL_SUSPENSION_POINT.on(reportOn))
} }
} }
@@ -16,9 +16,11 @@
package org.jetbrains.kotlin.resolve.calls.context; package org.jetbrains.kotlin.resolve.calls.context;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.psi.Call; import org.jetbrains.kotlin.psi.Call;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments; import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
@@ -41,10 +43,12 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
boolean isAnnotationContext, boolean isAnnotationContext,
boolean isDebuggerContext, boolean isDebuggerContext,
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider
) { ) {
super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates,
callPosition, expressionContextProvider);
} }
@NotNull @NotNull
@@ -61,7 +65,7 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
return new BasicCallResolutionContext(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, return new BasicCallResolutionContext(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments,
new ResolutionResultsCacheImpl(), null, new ResolutionResultsCacheImpl(), null,
StatementFilter.NONE, isAnnotationContext, false, false, StatementFilter.NONE, isAnnotationContext, false, false,
CallPosition.Unknown.INSTANCE); CallPosition.Unknown.INSTANCE, DEFAULT_EXPRESSION_CONTEXT_PROVIDER);
} }
@NotNull @NotNull
@@ -72,7 +76,8 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
return new BasicCallResolutionContext( return new BasicCallResolutionContext(
context.trace, context.scope, call, context.expectedType, context.dataFlowInfo, context.contextDependency, checkArguments, context.trace, context.scope, call, context.expectedType, context.dataFlowInfo, context.contextDependency, checkArguments,
context.resolutionResultsCache, dataFlowInfoForArguments, context.resolutionResultsCache, dataFlowInfoForArguments,
context.statementFilter, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates, context.callPosition); context.statementFilter, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates,
context.callPosition, context.expressionContextProvider);
} }
@NotNull @NotNull
@@ -92,17 +97,20 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
@NotNull ResolutionResultsCache resolutionResultsCache, @NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider
) { ) {
return new BasicCallResolutionContext( return new BasicCallResolutionContext(
trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates,
callPosition, expressionContextProvider);
} }
@NotNull @NotNull
public BasicCallResolutionContext replaceCall(@NotNull Call newCall) { public BasicCallResolutionContext replaceCall(@NotNull Call newCall) {
return new BasicCallResolutionContext( return new BasicCallResolutionContext(
trace, scope, newCall, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, trace, scope, newCall, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates,
callPosition, expressionContextProvider);
} }
} }
@@ -16,10 +16,12 @@
package org.jetbrains.kotlin.resolve.calls.context; package org.jetbrains.kotlin.resolve.calls.context;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.psi.Call; import org.jetbrains.kotlin.psi.Call;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments; import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
@@ -54,11 +56,12 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
boolean isAnnotationContext, boolean isAnnotationContext,
boolean isDebuggerContext, boolean isDebuggerContext,
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider
) { ) {
super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext,
collectAllCandidates, callPosition); collectAllCandidates, callPosition, expressionContextProvider);
this.candidateCall = candidateCall; this.candidateCall = candidateCall;
this.tracing = tracing; this.tracing = tracing;
this.candidateResolveMode = candidateResolveMode; this.candidateResolveMode = candidateResolveMode;
@@ -74,7 +77,8 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
context.dataFlowInfo, context.contextDependency, context.checkArguments, context.dataFlowInfo, context.contextDependency, context.checkArguments,
context.resolutionResultsCache, context.dataFlowInfoForArguments, context.resolutionResultsCache, context.dataFlowInfoForArguments,
context.statementFilter, context.statementFilter,
candidateResolveMode, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates, context.callPosition); candidateResolveMode, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates,
context.callPosition, context.expressionContextProvider);
} }
@NotNull @NotNull
@@ -86,7 +90,7 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
context.dataFlowInfo, context.contextDependency, context.checkArguments, context.resolutionResultsCache, context.dataFlowInfo, context.contextDependency, context.checkArguments, context.resolutionResultsCache,
context.dataFlowInfoForArguments, context.statementFilter, context.dataFlowInfoForArguments, context.statementFilter,
CandidateResolveMode.FULLY, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates, CandidateResolveMode.FULLY, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates,
context.callPosition); context.callPosition, context.expressionContextProvider);
} }
@Override @Override
@@ -99,11 +103,12 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
@NotNull ResolutionResultsCache resolutionResultsCache, @NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider
) { ) {
return new CallCandidateResolutionContext<D>( return new CallCandidateResolutionContext<D>(
candidateCall, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, candidateCall, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments,
resolutionResultsCache, dataFlowInfoForArguments, statementFilter, resolutionResultsCache, dataFlowInfoForArguments, statementFilter,
candidateResolveMode, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); candidateResolveMode, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition, expressionContextProvider);
} }
} }
@@ -16,9 +16,11 @@
package org.jetbrains.kotlin.resolve.calls.context; package org.jetbrains.kotlin.resolve.calls.context;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.psi.Call; import org.jetbrains.kotlin.psi.Call;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl; import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl;
@@ -50,10 +52,11 @@ public abstract class CallResolutionContext<Context extends CallResolutionContex
boolean isAnnotationContext, boolean isAnnotationContext,
boolean isDebuggerContext, boolean isDebuggerContext,
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider
) { ) {
super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache, super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache,
statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition, expressionContextProvider);
this.call = call; this.call = call;
this.checkArguments = checkArguments; this.checkArguments = checkArguments;
if (dataFlowInfoForArguments != null) { if (dataFlowInfoForArguments != null) {
@@ -16,8 +16,12 @@
package org.jetbrains.kotlin.resolve.calls.context; package org.jetbrains.kotlin.resolve.calls.context;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
@@ -56,6 +60,23 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
@NotNull @NotNull
public final CallPosition callPosition; public final CallPosition callPosition;
/**
* Used for analyzing expression in the given context.
* Should be used for going through parents to find containing function, loop etc.
* The provider should return specific context expression (which can be used instead of parent)
* for the given expression or null otherwise.
* @see #getContextParentOfType
*/
@NotNull
public final Function1<KtExpression, KtExpression> expressionContextProvider;
public static final Function1<KtExpression, KtExpression> DEFAULT_EXPRESSION_CONTEXT_PROVIDER = new Function1<KtExpression, KtExpression>() {
@Override
public KtExpression invoke(KtExpression expression) {
return null;
}
};
protected ResolutionContext( protected ResolutionContext(
@NotNull BindingTrace trace, @NotNull BindingTrace trace,
@NotNull LexicalScope scope, @NotNull LexicalScope scope,
@@ -67,7 +88,8 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
boolean isAnnotationContext, boolean isAnnotationContext,
boolean isDebuggerContext, boolean isDebuggerContext,
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider
) { ) {
this.trace = trace; this.trace = trace;
this.scope = scope; this.scope = scope;
@@ -80,6 +102,7 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
this.isDebuggerContext = isDebuggerContext; this.isDebuggerContext = isDebuggerContext;
this.collectAllCandidates = collectAllCandidates; this.collectAllCandidates = collectAllCandidates;
this.callPosition = callPosition; this.callPosition = callPosition;
this.expressionContextProvider = expressionContextProvider;
} }
protected abstract Context create( protected abstract Context create(
@@ -91,7 +114,8 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
@NotNull ResolutionResultsCache resolutionResultsCache, @NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider
); );
@NotNull @NotNull
@@ -104,14 +128,14 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
public Context replaceBindingTrace(@NotNull BindingTrace trace) { public Context replaceBindingTrace(@NotNull BindingTrace trace) {
if (this.trace == trace) return self(); if (this.trace == trace) return self();
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition); collectAllCandidates, callPosition, expressionContextProvider);
} }
@NotNull @NotNull
public Context replaceDataFlowInfo(@NotNull DataFlowInfo newDataFlowInfo) { public Context replaceDataFlowInfo(@NotNull DataFlowInfo newDataFlowInfo) {
if (newDataFlowInfo == dataFlowInfo) return self(); if (newDataFlowInfo == dataFlowInfo) return self();
return create(trace, scope, newDataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, newDataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition); collectAllCandidates, callPosition, expressionContextProvider);
} }
@NotNull @NotNull
@@ -119,28 +143,28 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
if (newExpectedType == null) return replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); if (newExpectedType == null) return replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
if (expectedType == newExpectedType) return self(); if (expectedType == newExpectedType) return self();
return create(trace, scope, dataFlowInfo, newExpectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, newExpectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition); collectAllCandidates, callPosition, expressionContextProvider);
} }
@NotNull @NotNull
public Context replaceScope(@NotNull LexicalScope newScope) { public Context replaceScope(@NotNull LexicalScope newScope) {
if (newScope == scope) return self(); if (newScope == scope) return self();
return create(trace, newScope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, newScope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition); collectAllCandidates, callPosition, expressionContextProvider);
} }
@NotNull @NotNull
public Context replaceContextDependency(@NotNull ContextDependency newContextDependency) { public Context replaceContextDependency(@NotNull ContextDependency newContextDependency) {
if (newContextDependency == contextDependency) return self(); if (newContextDependency == contextDependency) return self();
return create(trace, scope, dataFlowInfo, expectedType, newContextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, newContextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition); collectAllCandidates, callPosition, expressionContextProvider);
} }
@NotNull @NotNull
public Context replaceResolutionResultsCache(@NotNull ResolutionResultsCache newResolutionResultsCache) { public Context replaceResolutionResultsCache(@NotNull ResolutionResultsCache newResolutionResultsCache) {
if (newResolutionResultsCache == resolutionResultsCache) return self(); if (newResolutionResultsCache == resolutionResultsCache) return self();
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, newResolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, newResolutionResultsCache, statementFilter,
collectAllCandidates, callPosition); collectAllCandidates, callPosition, expressionContextProvider);
} }
@NotNull @NotNull
@@ -151,18 +175,50 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
@NotNull @NotNull
public Context replaceCollectAllCandidates(boolean newCollectAllCandidates) { public Context replaceCollectAllCandidates(boolean newCollectAllCandidates) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
newCollectAllCandidates, callPosition); newCollectAllCandidates, callPosition, expressionContextProvider);
} }
@NotNull @NotNull
public Context replaceStatementFilter(@NotNull StatementFilter statementFilter) { public Context replaceStatementFilter(@NotNull StatementFilter statementFilter) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition); collectAllCandidates, callPosition, expressionContextProvider);
} }
@NotNull @NotNull
public Context replaceCallPosition(@NotNull CallPosition callPosition) { public Context replaceCallPosition(@NotNull CallPosition callPosition) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition); collectAllCandidates, callPosition, expressionContextProvider);
}
@NotNull
public Context replaceExpressionContextProvider(@NotNull Function1<KtExpression, KtExpression> expressionContextProvider) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider);
}
@Nullable
public <T extends PsiElement> T getContextParentOfType(@NotNull KtExpression expression, @NotNull Class<? extends T>... classes) {
PsiElement current = expression.getParent();
while (current != null) {
for (Class<? extends T> klass : classes) {
if (klass.isInstance(current)) {
//noinspection unchecked
return (T) current;
}
}
if (current instanceof PsiFile) return null;
if (current instanceof KtExpression) {
KtExpression context = expressionContextProvider.invoke((KtExpression) current);
if (context != null) {
current = context;
continue;
}
}
current = current.getParent();
}
return null;
} }
} }
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.resolve.inline; package org.jetbrains.kotlin.resolve.inline;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.FunctionTypesKt; import org.jetbrains.kotlin.builtins.FunctionTypesKt;
@@ -25,9 +24,9 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMapping; import org.jetbrains.kotlin.resolve.calls.model.ArgumentMapping;
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch; import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
@@ -81,19 +80,19 @@ public class InlineUtil {
public static boolean checkNonLocalReturnUsage( public static boolean checkNonLocalReturnUsage(
@NotNull DeclarationDescriptor fromFunction, @NotNull DeclarationDescriptor fromFunction,
@NotNull KtExpression startExpression, @NotNull KtExpression startExpression,
@NotNull BindingTrace trace @NotNull ResolutionContext<?> context
) { ) {
PsiElement containingFunction = PsiTreeUtil.getParentOfType(startExpression, KtClassOrObject.class, KtDeclarationWithBody.class); PsiElement containingFunction = context.getContextParentOfType(startExpression, KtClassOrObject.class, KtDeclarationWithBody.class);
if (containingFunction == null) { if (containingFunction == null) {
return false; return false;
} }
DeclarationDescriptor containingFunctionDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, containingFunction); DeclarationDescriptor containingFunctionDescriptor = context.trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, containingFunction);
if (containingFunctionDescriptor == null) { if (containingFunctionDescriptor == null) {
return false; return false;
} }
BindingContext bindingContext = trace.getBindingContext(); BindingContext bindingContext = context.trace.getBindingContext();
while (canBeInlineArgument(containingFunction) && fromFunction != containingFunctionDescriptor) { while (canBeInlineArgument(containingFunction) && fromFunction != containingFunctionDescriptor) {
if (!isInlinedArgument((KtFunction) containingFunction, bindingContext, true)) { if (!isInlinedArgument((KtFunction) containingFunction, bindingContext, true)) {
@@ -909,9 +909,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (resolvedCall != null) { if (resolvedCall != null) {
// Call must be validated with the actual, not temporary trace in order to report operator diagnostic // Call must be validated with the actual, not temporary trace in order to report operator diagnostic
// Only unary assignment expressions (++, --) and +=/... must be checked, normal assignments have the proper trace // Only unary assignment expressions (++, --) and +=/... must be checked, normal assignments have the proper trace
CallCheckerContext callCheckerContext = new CallCheckerContext( CallCheckerContext callCheckerContext = new CallCheckerContext(context, trace, components.languageFeatureSettings);
trace, context.scope, components.languageFeatureSettings, context.dataFlowInfo, context.isAnnotationContext
);
for (CallChecker checker : components.callCheckers) { for (CallChecker checker : components.callCheckers) {
checker.check(resolvedCall, expression, callCheckerContext); checker.check(resolvedCall, expression, callCheckerContext);
} }
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.types.expressions;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
@@ -555,7 +554,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
KotlinType expectedType = NO_EXPECTED_TYPE; KotlinType expectedType = NO_EXPECTED_TYPE;
KotlinType resultType = components.builtIns.getNothingType(); KotlinType resultType = components.builtIns.getNothingType();
KtDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, KtDeclaration.class); KtDeclaration parentDeclaration = context.getContextParentOfType(expression, KtDeclaration.class);
if (parentDeclaration instanceof KtParameter) { if (parentDeclaration instanceof KtParameter) {
// In a default value for parameter // In a default value for parameter
@@ -565,7 +564,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
if (expression.getTargetLabel() == null) { if (expression.getTargetLabel() == null) {
while (parentDeclaration instanceof KtDestructuringDeclaration) { while (parentDeclaration instanceof KtDestructuringDeclaration) {
//TODO: It's hacking fix for KT-5100: Strange "Return is not allowed here" for multi-declaration initializer with elvis expression //TODO: It's hacking fix for KT-5100: Strange "Return is not allowed here" for multi-declaration initializer with elvis expression
parentDeclaration = PsiTreeUtil.getParentOfType(parentDeclaration, KtDeclaration.class); parentDeclaration = context.getContextParentOfType(parentDeclaration, KtDeclaration.class);
} }
// Parent declaration can be null in code fragments or in some bad error expressions // Parent declaration can be null in code fragments or in some bad error expressions
@@ -576,7 +575,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
FunctionDescriptor containingFunctionDescriptor = containingFunInfo.getFirst(); FunctionDescriptor containingFunctionDescriptor = containingFunInfo.getFirst();
if (containingFunctionDescriptor != null) { if (containingFunctionDescriptor != null) {
if (!InlineUtil.checkNonLocalReturnUsage(containingFunctionDescriptor, expression, context.trace) || if (!InlineUtil.checkNonLocalReturnUsage(containingFunctionDescriptor, expression, context) ||
isClassInitializer(containingFunInfo)) { isClassInitializer(containingFunInfo)) {
// Unqualified, in a function literal // Unqualified, in a function literal
context.trace.report(RETURN_NOT_ALLOWED.on(expression)); context.trace.report(RETURN_NOT_ALLOWED.on(expression));
@@ -595,7 +594,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
SimpleFunctionDescriptor functionDescriptor = context.trace.get(FUNCTION, labelTargetElement); SimpleFunctionDescriptor functionDescriptor = context.trace.get(FUNCTION, labelTargetElement);
if (functionDescriptor != null) { if (functionDescriptor != null) {
expectedType = getFunctionExpectedReturnType(functionDescriptor, labelTargetElement, context); expectedType = getFunctionExpectedReturnType(functionDescriptor, labelTargetElement, context);
if (!InlineUtil.checkNonLocalReturnUsage(functionDescriptor, expression, context.trace)) { if (!InlineUtil.checkNonLocalReturnUsage(functionDescriptor, expression, context)) {
// Qualified, non-local // Qualified, non-local
context.trace.report(RETURN_NOT_ALLOWED.on(expression)); context.trace.report(RETURN_NOT_ALLOWED.on(expression));
resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE); resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE);
@@ -16,7 +16,9 @@
package org.jetbrains.kotlin.types.expressions; package org.jetbrains.kotlin.types.expressions;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.resolve.calls.context.*; import org.jetbrains.kotlin.resolve.calls.context.*;
@@ -45,7 +47,7 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
context.contextDependency, context.resolutionResultsCache, context.contextDependency, context.resolutionResultsCache,
context.statementFilter, context.statementFilter,
context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates,
context.callPosition); context.callPosition, context.expressionContextProvider);
} }
@NotNull @NotNull
@@ -55,7 +57,7 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
context.contextDependency, context.resolutionResultsCache, context.contextDependency, context.resolutionResultsCache,
context.statementFilter, context.statementFilter,
context.isAnnotationContext, isDebuggerContext, context.collectAllCandidates, context.isAnnotationContext, isDebuggerContext, context.collectAllCandidates,
context.callPosition); context.callPosition, context.expressionContextProvider);
} }
@NotNull @NotNull
@@ -71,7 +73,7 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
) { ) {
return new ExpressionTypingContext( return new ExpressionTypingContext(
trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache,
statementFilter, isAnnotationContext, false, false, CallPosition.Unknown.INSTANCE); statementFilter, isAnnotationContext, false, false, CallPosition.Unknown.INSTANCE, DEFAULT_EXPRESSION_CONTEXT_PROVIDER);
} }
private ExpressionTypingContext( private ExpressionTypingContext(
@@ -85,10 +87,11 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
boolean isAnnotationContext, boolean isAnnotationContext,
boolean isDebuggerContext, boolean isDebuggerContext,
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider
) { ) {
super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache, super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache,
statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition, expressionContextProvider);
} }
@Override @Override
@@ -101,10 +104,12 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
@NotNull ResolutionResultsCache resolutionResultsCache, @NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider
) { ) {
return new ExpressionTypingContext(trace, scope, dataFlowInfo, return new ExpressionTypingContext(trace, scope, dataFlowInfo,
expectedType, contextDependency, resolutionResultsCache, expectedType, contextDependency, resolutionResultsCache,
statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition); statementFilter, isAnnotationContext, isDebuggerContext,
collectAllCandidates, callPosition, expressionContextProvider);
} }
} }
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.types.expressions; package org.jetbrains.kotlin.types.expressions;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
@@ -91,10 +92,31 @@ public class ExpressionTypingServices {
@NotNull DataFlowInfo dataFlowInfo, @NotNull DataFlowInfo dataFlowInfo,
@NotNull BindingTrace trace, @NotNull BindingTrace trace,
boolean isStatement boolean isStatement
) {
return getTypeInfo(scope, expression, expectedType, dataFlowInfo, trace, isStatement, expression);
}
@NotNull
public KotlinTypeInfo getTypeInfo(
@NotNull LexicalScope scope,
@NotNull final KtExpression expression,
@NotNull KotlinType expectedType,
@NotNull DataFlowInfo dataFlowInfo,
@NotNull BindingTrace trace,
boolean isStatement,
@NotNull final KtExpression contextExpression
) { ) {
ExpressionTypingContext context = ExpressionTypingContext.newContext( ExpressionTypingContext context = ExpressionTypingContext.newContext(
trace, scope, dataFlowInfo, expectedType trace, scope, dataFlowInfo, expectedType
); );
if (contextExpression != expression) {
context = context.replaceExpressionContextProvider(new Function1<KtExpression, KtExpression>() {
@Override
public KtExpression invoke(KtExpression arg) {
return arg == expression ? contextExpression : null;
}
});
}
return expressionTypingFacade.getTypeInfo(expression, context, isStatement); return expressionTypingFacade.getTypeInfo(expression, context, isStatement);
} }
@@ -40,7 +40,7 @@ import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
): KotlinTypeInfo { ): KotlinTypeInfo {
PreliminaryDeclarationVisitor.createForExpression(this, trace) PreliminaryDeclarationVisitor.createForExpression(this, trace)
return contextExpression.getResolutionFacade().frontendService<ExpressionTypingServices>() return contextExpression.getResolutionFacade().frontendService<ExpressionTypingServices>()
.getTypeInfo(scope, this, expectedType, dataFlowInfo, trace, isStatement) .getTypeInfo(scope, this, expectedType, dataFlowInfo, trace, isStatement, contextExpression)
} }
@JvmOverloads fun KtExpression.analyzeInContext( @JvmOverloads fun KtExpression.analyzeInContext(