org.jetbrains.kotlin.resolve.calls.context.ResolutionContext Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* Copyright 2010-2016 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.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.Nullable;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils;
/**
* This class together with its descendants is intended to transfer data flow analysis information
* in top-down direction, from AST parents to children.
*
* NB: all descendants must be immutable!
*/
public abstract class ResolutionContext> {
@NotNull
public final BindingTrace trace;
@NotNull
public final LexicalScope scope;
@NotNull
public final KotlinType expectedType;
@NotNull
public final DataFlowInfo dataFlowInfo;
@NotNull
public final ContextDependency contextDependency;
@NotNull
public final ResolutionResultsCache resolutionResultsCache;
@NotNull
public final StatementFilter statementFilter;
public final boolean isAnnotationContext;
public final boolean isDebuggerContext;
public final boolean collectAllCandidates;
@NotNull
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 expressionContextProvider;
public static final Function1 DEFAULT_EXPRESSION_CONTEXT_PROVIDER = new Function1() {
@Override
public KtExpression invoke(KtExpression expression) {
return null;
}
};
protected ResolutionContext(
@NotNull BindingTrace trace,
@NotNull LexicalScope scope,
@NotNull KotlinType expectedType,
@NotNull DataFlowInfo dataFlowInfo,
@NotNull ContextDependency contextDependency,
@NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter,
boolean isAnnotationContext,
boolean isDebuggerContext,
boolean collectAllCandidates,
@NotNull CallPosition callPosition,
@NotNull Function1 expressionContextProvider
) {
this.trace = trace;
this.scope = scope;
this.expectedType = expectedType;
this.dataFlowInfo = dataFlowInfo;
this.contextDependency = contextDependency;
this.resolutionResultsCache = resolutionResultsCache;
this.statementFilter = statementFilter;
this.isAnnotationContext = isAnnotationContext;
this.isDebuggerContext = isDebuggerContext;
this.collectAllCandidates = collectAllCandidates;
this.callPosition = callPosition;
this.expressionContextProvider = expressionContextProvider;
}
protected abstract Context create(
@NotNull BindingTrace trace,
@NotNull LexicalScope scope,
@NotNull DataFlowInfo dataFlowInfo,
@NotNull KotlinType expectedType,
@NotNull ContextDependency contextDependency,
@NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter,
boolean collectAllCandidates,
@NotNull CallPosition callPosition,
@NotNull Function1 expressionContextProvider
);
@NotNull
private Context self() {
//noinspection unchecked
return (Context) this;
}
@NotNull
public Context replaceBindingTrace(@NotNull BindingTrace trace) {
if (this.trace == trace) return self();
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider);
}
@NotNull
public Context replaceDataFlowInfo(@NotNull DataFlowInfo newDataFlowInfo) {
if (newDataFlowInfo == dataFlowInfo) return self();
return create(trace, scope, newDataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider);
}
@NotNull
public Context replaceExpectedType(@Nullable KotlinType newExpectedType) {
if (newExpectedType == null) return replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
if (expectedType == newExpectedType) return self();
return create(trace, scope, dataFlowInfo, newExpectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider);
}
@NotNull
public Context replaceScope(@NotNull LexicalScope newScope) {
if (newScope == scope) return self();
return create(trace, newScope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider);
}
@NotNull
public Context replaceContextDependency(@NotNull ContextDependency newContextDependency) {
if (newContextDependency == contextDependency) return self();
return create(trace, scope, dataFlowInfo, expectedType, newContextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider);
}
@NotNull
public Context replaceResolutionResultsCache(@NotNull ResolutionResultsCache newResolutionResultsCache) {
if (newResolutionResultsCache == resolutionResultsCache) return self();
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, newResolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider);
}
@NotNull
public Context replaceTraceAndCache(@NotNull TemporaryTraceAndCache traceAndCache) {
return replaceBindingTrace(traceAndCache.trace).replaceResolutionResultsCache(traceAndCache.cache);
}
@NotNull
public Context replaceCollectAllCandidates(boolean newCollectAllCandidates) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
newCollectAllCandidates, callPosition, expressionContextProvider);
}
@NotNull
public Context replaceStatementFilter(@NotNull StatementFilter statementFilter) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider);
}
@NotNull
public Context replaceCallPosition(@NotNull CallPosition callPosition) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider);
}
@NotNull
public Context replaceExpressionContextProvider(@NotNull Function1 expressionContextProvider) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider);
}
@Nullable
public 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;
}
}