001 /*
002 * Copyright 2010-2016 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.resolve.calls.context;
018
019 import com.intellij.psi.PsiElement;
020 import com.intellij.psi.PsiFile;
021 import kotlin.jvm.functions.Function1;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.kotlin.psi.KtExpression;
025 import org.jetbrains.kotlin.resolve.BindingTrace;
026 import org.jetbrains.kotlin.resolve.StatementFilter;
027 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
028 import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
029 import org.jetbrains.kotlin.types.KotlinType;
030 import org.jetbrains.kotlin.types.TypeUtils;
031
032 /**
033 * This class together with its descendants is intended to transfer data flow analysis information
034 * in top-down direction, from AST parents to children.
035 *
036 * NB: all descendants must be immutable!
037 */
038 public abstract class ResolutionContext<Context extends ResolutionContext<Context>> {
039 @NotNull
040 public final BindingTrace trace;
041 @NotNull
042 public final LexicalScope scope;
043 @NotNull
044 public final KotlinType expectedType;
045 @NotNull
046 public final DataFlowInfo dataFlowInfo;
047 @NotNull
048 public final ContextDependency contextDependency;
049 @NotNull
050 public final ResolutionResultsCache resolutionResultsCache;
051 @NotNull
052 public final StatementFilter statementFilter;
053
054 public final boolean isAnnotationContext;
055
056 public final boolean isDebuggerContext;
057
058 public final boolean collectAllCandidates;
059
060 @NotNull
061 public final CallPosition callPosition;
062
063 /**
064 * Used for analyzing expression in the given context.
065 * Should be used for going through parents to find containing function, loop etc.
066 * The provider should return specific context expression (which can be used instead of parent)
067 * for the given expression or null otherwise.
068 * @see #getContextParentOfType
069 */
070 @NotNull
071 public final Function1<KtExpression, KtExpression> expressionContextProvider;
072
073 public static final Function1<KtExpression, KtExpression> DEFAULT_EXPRESSION_CONTEXT_PROVIDER = new Function1<KtExpression, KtExpression>() {
074 @Override
075 public KtExpression invoke(KtExpression expression) {
076 return null;
077 }
078 };
079
080 protected ResolutionContext(
081 @NotNull BindingTrace trace,
082 @NotNull LexicalScope scope,
083 @NotNull KotlinType expectedType,
084 @NotNull DataFlowInfo dataFlowInfo,
085 @NotNull ContextDependency contextDependency,
086 @NotNull ResolutionResultsCache resolutionResultsCache,
087 @NotNull StatementFilter statementFilter,
088 boolean isAnnotationContext,
089 boolean isDebuggerContext,
090 boolean collectAllCandidates,
091 @NotNull CallPosition callPosition,
092 @NotNull Function1<KtExpression, KtExpression> expressionContextProvider
093 ) {
094 this.trace = trace;
095 this.scope = scope;
096 this.expectedType = expectedType;
097 this.dataFlowInfo = dataFlowInfo;
098 this.contextDependency = contextDependency;
099 this.resolutionResultsCache = resolutionResultsCache;
100 this.statementFilter = statementFilter;
101 this.isAnnotationContext = isAnnotationContext;
102 this.isDebuggerContext = isDebuggerContext;
103 this.collectAllCandidates = collectAllCandidates;
104 this.callPosition = callPosition;
105 this.expressionContextProvider = expressionContextProvider;
106 }
107
108 protected abstract Context create(
109 @NotNull BindingTrace trace,
110 @NotNull LexicalScope scope,
111 @NotNull DataFlowInfo dataFlowInfo,
112 @NotNull KotlinType expectedType,
113 @NotNull ContextDependency contextDependency,
114 @NotNull ResolutionResultsCache resolutionResultsCache,
115 @NotNull StatementFilter statementFilter,
116 boolean collectAllCandidates,
117 @NotNull CallPosition callPosition,
118 @NotNull Function1<KtExpression, KtExpression> expressionContextProvider
119 );
120
121 @NotNull
122 private Context self() {
123 //noinspection unchecked
124 return (Context) this;
125 }
126
127 @NotNull
128 public Context replaceBindingTrace(@NotNull BindingTrace trace) {
129 if (this.trace == trace) return self();
130 return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
131 collectAllCandidates, callPosition, expressionContextProvider);
132 }
133
134 @NotNull
135 public Context replaceDataFlowInfo(@NotNull DataFlowInfo newDataFlowInfo) {
136 if (newDataFlowInfo == dataFlowInfo) return self();
137 return create(trace, scope, newDataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
138 collectAllCandidates, callPosition, expressionContextProvider);
139 }
140
141 @NotNull
142 public Context replaceExpectedType(@Nullable KotlinType newExpectedType) {
143 if (newExpectedType == null) return replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
144 if (expectedType == newExpectedType) return self();
145 return create(trace, scope, dataFlowInfo, newExpectedType, contextDependency, resolutionResultsCache, statementFilter,
146 collectAllCandidates, callPosition, expressionContextProvider);
147 }
148
149 @NotNull
150 public Context replaceScope(@NotNull LexicalScope newScope) {
151 if (newScope == scope) return self();
152 return create(trace, newScope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
153 collectAllCandidates, callPosition, expressionContextProvider);
154 }
155
156 @NotNull
157 public Context replaceContextDependency(@NotNull ContextDependency newContextDependency) {
158 if (newContextDependency == contextDependency) return self();
159 return create(trace, scope, dataFlowInfo, expectedType, newContextDependency, resolutionResultsCache, statementFilter,
160 collectAllCandidates, callPosition, expressionContextProvider);
161 }
162
163 @NotNull
164 public Context replaceResolutionResultsCache(@NotNull ResolutionResultsCache newResolutionResultsCache) {
165 if (newResolutionResultsCache == resolutionResultsCache) return self();
166 return create(trace, scope, dataFlowInfo, expectedType, contextDependency, newResolutionResultsCache, statementFilter,
167 collectAllCandidates, callPosition, expressionContextProvider);
168 }
169
170 @NotNull
171 public Context replaceTraceAndCache(@NotNull TemporaryTraceAndCache traceAndCache) {
172 return replaceBindingTrace(traceAndCache.trace).replaceResolutionResultsCache(traceAndCache.cache);
173 }
174
175 @NotNull
176 public Context replaceCollectAllCandidates(boolean newCollectAllCandidates) {
177 return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
178 newCollectAllCandidates, callPosition, expressionContextProvider);
179 }
180
181 @NotNull
182 public Context replaceStatementFilter(@NotNull StatementFilter statementFilter) {
183 return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
184 collectAllCandidates, callPosition, expressionContextProvider);
185 }
186
187 @NotNull
188 public Context replaceCallPosition(@NotNull CallPosition callPosition) {
189 return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
190 collectAllCandidates, callPosition, expressionContextProvider);
191 }
192
193 @NotNull
194 public Context replaceExpressionContextProvider(@NotNull Function1<KtExpression, KtExpression> expressionContextProvider) {
195 return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
196 collectAllCandidates, callPosition, expressionContextProvider);
197 }
198
199 @Nullable
200 public <T extends PsiElement> T getContextParentOfType(@NotNull KtExpression expression, @NotNull Class<? extends T>... classes) {
201 PsiElement current = expression.getParent();
202 while (current != null) {
203 for (Class<? extends T> klass : classes) {
204 if (klass.isInstance(current)) {
205 //noinspection unchecked
206 return (T) current;
207 }
208 }
209
210 if (current instanceof PsiFile) return null;
211
212 if (current instanceof KtExpression) {
213 KtExpression context = expressionContextProvider.invoke((KtExpression) current);
214 if (context != null) {
215 current = context;
216 continue;
217 }
218 }
219
220 current = current.getParent();
221 }
222 return null;
223 }
224 }