001 /*
002 * Copyright 2010-2015 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.smartcasts;
018
019 import com.intellij.openapi.util.Pair;
020 import com.intellij.psi.PsiElement;
021 import com.intellij.psi.tree.IElementType;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.kotlin.KtNodeTypes;
025 import org.jetbrains.kotlin.descriptors.*;
026 import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
027 import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
028 import org.jetbrains.kotlin.lexer.KtTokens;
029 import org.jetbrains.kotlin.psi.*;
030 import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
031 import org.jetbrains.kotlin.resolve.BindingContext;
032 import org.jetbrains.kotlin.resolve.DescriptorUtils;
033 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
034 import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
035 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
036 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue.Kind;
037 import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
038 import org.jetbrains.kotlin.resolve.scopes.receivers.*;
039 import org.jetbrains.kotlin.types.KotlinType;
040 import org.jetbrains.kotlin.types.TypeUtils;
041 import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils;
042 import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor;
043
044 import java.util.Set;
045
046 import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableNothing;
047 import static org.jetbrains.kotlin.resolve.BindingContext.DECLARATION_TO_DESCRIPTOR;
048 import static org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET;
049 import static org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue.Kind.*;
050
051 /**
052 * This class is intended to create data flow values for different kind of expressions.
053 * Then data flow values serve as keys to obtain data flow information for these expressions.
054 */
055 public class DataFlowValueFactory {
056 private DataFlowValueFactory() {
057 }
058
059 @NotNull
060 public static DataFlowValue createDataFlowValue(
061 @NotNull KtExpression expression,
062 @NotNull KotlinType type,
063 @NotNull ResolutionContext resolutionContext
064 ) {
065 return createDataFlowValue(expression, type, resolutionContext.trace.getBindingContext(),
066 resolutionContext.scope.getOwnerDescriptor());
067 }
068
069 private static boolean isComplexExpression(@NotNull KtExpression expression) {
070 if (expression instanceof KtBlockExpression ||
071 expression instanceof KtIfExpression ||
072 expression instanceof KtWhenExpression ||
073 (expression instanceof KtBinaryExpression && ((KtBinaryExpression) expression).getOperationToken() == KtTokens.ELVIS)) {
074
075 return true;
076 }
077 if (expression instanceof KtParenthesizedExpression) {
078 KtExpression deparenthesized = KtPsiUtil.deparenthesize(expression);
079 return deparenthesized != null && isComplexExpression(deparenthesized);
080 }
081 return false;
082 }
083
084 @NotNull
085 public static DataFlowValue createDataFlowValue(
086 @NotNull KtExpression expression,
087 @NotNull KotlinType type,
088 @NotNull BindingContext bindingContext,
089 @NotNull DeclarationDescriptor containingDeclarationOrModule
090 ) {
091 if (expression instanceof KtConstantExpression) {
092 KtConstantExpression constantExpression = (KtConstantExpression) expression;
093 if (constantExpression.getNode().getElementType() == KtNodeTypes.NULL) {
094 return DataFlowValue.nullValue(DescriptorUtilsKt.getBuiltIns(containingDeclarationOrModule));
095 }
096 }
097 if (type.isError()) return DataFlowValue.ERROR;
098 if (isNullableNothing(type)) {
099 return DataFlowValue.nullValue(DescriptorUtilsKt.getBuiltIns(containingDeclarationOrModule)); // 'null' is the only inhabitant of 'Nothing?'
100 }
101
102 if (ExpressionTypingUtils.isExclExclExpression(KtPsiUtil.deparenthesize(expression))) {
103 // In most cases type of `E!!`-expression is strictly not nullable and we could get proper Nullability
104 // by calling `getImmanentNullability` (as it happens below).
105 //
106 // But there are some problem with types built on type parameters, e.g.
107 // fun <T : Any?> foo(x: T) = x!!.hashCode() // there no way in type system to denote that `x!!` is not nullable
108 return new DataFlowValue(expression,
109 type,
110 OTHER,
111 Nullability.NOT_NULL);
112 }
113
114 if (isComplexExpression(expression)) {
115 return createDataFlowValueForComplexExpression(expression, type);
116 }
117
118 IdentifierInfo result = getIdForStableIdentifier(expression, bindingContext, containingDeclarationOrModule);
119 return new DataFlowValue(result == NO_IDENTIFIER_INFO ? expression : result.id,
120 type,
121 result.kind,
122 getImmanentNullability(type));
123 }
124
125 @NotNull
126 public static DataFlowValue createDataFlowValueForStableReceiver(@NotNull ReceiverValue receiver) {
127 KotlinType type = receiver.getType();
128 return new DataFlowValue(receiver, type, STABLE_VALUE, getImmanentNullability(type));
129 }
130
131 @NotNull
132 public static DataFlowValue createDataFlowValue(
133 @NotNull ReceiverValue receiverValue,
134 @NotNull ResolutionContext resolutionContext
135 ) {
136 return createDataFlowValue(receiverValue, resolutionContext.trace.getBindingContext(),
137 resolutionContext.scope.getOwnerDescriptor());
138 }
139
140 @NotNull
141 public static DataFlowValue createDataFlowValue(
142 @NotNull ReceiverValue receiverValue,
143 @NotNull BindingContext bindingContext,
144 @NotNull DeclarationDescriptor containingDeclarationOrModule
145 ) {
146 if (receiverValue instanceof TransientReceiver || receiverValue instanceof ImplicitReceiver) {
147 return createDataFlowValueForStableReceiver(receiverValue);
148 }
149 else if (receiverValue instanceof ExpressionReceiver) {
150 return createDataFlowValue(((ExpressionReceiver) receiverValue).getExpression(),
151 receiverValue.getType(),
152 bindingContext,
153 containingDeclarationOrModule);
154 }
155 else {
156 throw new UnsupportedOperationException("Unsupported receiver value: " + receiverValue.getClass().getName());
157 }
158 }
159
160 @NotNull
161 public static DataFlowValue createDataFlowValueForProperty(
162 @NotNull KtProperty property,
163 @NotNull VariableDescriptor variableDescriptor,
164 @NotNull BindingContext bindingContext,
165 @Nullable ModuleDescriptor usageContainingModule
166 ) {
167 KotlinType type = variableDescriptor.getType();
168 return new DataFlowValue(variableDescriptor, type,
169 variableKind(variableDescriptor, usageContainingModule,
170 bindingContext, property),
171 getImmanentNullability(type));
172 }
173
174 @NotNull
175 private static DataFlowValue createDataFlowValueForComplexExpression(
176 @NotNull KtExpression expression,
177 @NotNull KotlinType type
178 ) {
179 return new DataFlowValue(expression, type, Kind.STABLE_COMPLEX_EXPRESSION, getImmanentNullability(type));
180 }
181
182 @NotNull
183 private static Nullability getImmanentNullability(@NotNull KotlinType type) {
184 return TypeUtils.isNullableType(type) ? Nullability.UNKNOWN : Nullability.NOT_NULL;
185 }
186
187 private static class IdentifierInfo {
188 public final Object id;
189 public final Kind kind;
190 public final boolean isPackage;
191
192 private IdentifierInfo(Object id, Kind kind, boolean isPackage) {
193 this.id = id;
194 this.kind = kind;
195 this.isPackage = isPackage;
196 }
197 }
198
199 private static final IdentifierInfo NO_IDENTIFIER_INFO = new IdentifierInfo(null, OTHER, false) {
200 @Override
201 public String toString() {
202 return "NO_IDENTIFIER_INFO";
203 }
204 };
205
206 @NotNull
207 private static IdentifierInfo createInfo(Object id, Kind kind) {
208 return new IdentifierInfo(id, kind, false);
209 }
210
211 @NotNull
212 private static IdentifierInfo createStableInfo(Object id) {
213 return createInfo(id, STABLE_VALUE);
214 }
215
216 @NotNull
217 private static IdentifierInfo createPackageOrClassInfo(Object id) {
218 return new IdentifierInfo(id, STABLE_VALUE, true);
219 }
220
221 @NotNull
222 private static IdentifierInfo combineInfo(@Nullable IdentifierInfo receiverInfo, @NotNull IdentifierInfo selectorInfo) {
223 if (selectorInfo.id == null || receiverInfo == NO_IDENTIFIER_INFO) {
224 return NO_IDENTIFIER_INFO;
225 }
226 if (receiverInfo == null || receiverInfo.isPackage) {
227 return selectorInfo;
228 }
229 return createInfo(Pair.create(receiverInfo.id, selectorInfo.id),
230 receiverInfo.kind.isStable() ? selectorInfo.kind : OTHER);
231 }
232
233 @NotNull
234 private static IdentifierInfo createPostfixInfo(@NotNull KtPostfixExpression expression, @NotNull IdentifierInfo argumentInfo) {
235 if (argumentInfo == NO_IDENTIFIER_INFO) {
236 return NO_IDENTIFIER_INFO;
237 }
238 return createInfo(Pair.create(expression, argumentInfo.id), argumentInfo.kind);
239 }
240
241 @NotNull
242 private static IdentifierInfo getIdForStableIdentifier(
243 @Nullable KtExpression expression,
244 @NotNull BindingContext bindingContext,
245 @NotNull DeclarationDescriptor containingDeclarationOrModule
246 ) {
247 if (expression != null) {
248 KtExpression deparenthesized = KtPsiUtil.deparenthesize(expression);
249 if (expression != deparenthesized) {
250 return getIdForStableIdentifier(deparenthesized, bindingContext, containingDeclarationOrModule);
251 }
252 }
253 if (expression instanceof KtQualifiedExpression) {
254 KtQualifiedExpression qualifiedExpression = (KtQualifiedExpression) expression;
255 KtExpression receiverExpression = qualifiedExpression.getReceiverExpression();
256 KtExpression selectorExpression = qualifiedExpression.getSelectorExpression();
257 IdentifierInfo receiverId = getIdForStableIdentifier(receiverExpression, bindingContext, containingDeclarationOrModule);
258 IdentifierInfo selectorId = getIdForStableIdentifier(selectorExpression, bindingContext, containingDeclarationOrModule);
259
260 return combineInfo(receiverId, selectorId);
261 }
262 if (expression instanceof KtSimpleNameExpression) {
263 return getIdForSimpleNameExpression((KtSimpleNameExpression) expression, bindingContext, containingDeclarationOrModule);
264 }
265 else if (expression instanceof KtThisExpression) {
266 KtThisExpression thisExpression = (KtThisExpression) expression;
267 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, thisExpression.getInstanceReference());
268
269 return getIdForThisReceiver(declarationDescriptor);
270 }
271 else if (expression instanceof KtPostfixExpression) {
272 KtPostfixExpression postfixExpression = (KtPostfixExpression) expression;
273 IElementType operationType = postfixExpression.getOperationReference().getReferencedNameElementType();
274 if (operationType == KtTokens.PLUSPLUS || operationType == KtTokens.MINUSMINUS) {
275 return createPostfixInfo(postfixExpression,
276 getIdForStableIdentifier(postfixExpression.getBaseExpression(), bindingContext, containingDeclarationOrModule));
277 }
278 }
279 return NO_IDENTIFIER_INFO;
280 }
281
282 @NotNull
283 private static IdentifierInfo getIdForSimpleNameExpression(
284 @NotNull KtSimpleNameExpression simpleNameExpression,
285 @NotNull BindingContext bindingContext,
286 @NotNull DeclarationDescriptor containingDeclarationOrModule
287 ) {
288 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, simpleNameExpression);
289 if (declarationDescriptor instanceof VariableDescriptor) {
290 ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(simpleNameExpression, bindingContext);
291
292 // todo uncomment assert
293 // KT-4113
294 // for now it fails for resolving 'invoke' convention, return it after 'invoke' algorithm changes
295 // assert resolvedCall != null : "Cannot create right identifier info if the resolved call is not known yet for
296 ModuleDescriptor usageModuleDescriptor = DescriptorUtils.getContainingModuleOrNull(containingDeclarationOrModule);
297 IdentifierInfo receiverInfo =
298 resolvedCall != null ? getIdForImplicitReceiver(resolvedCall.getDispatchReceiver(), simpleNameExpression) : null;
299
300 VariableDescriptor variableDescriptor = (VariableDescriptor) declarationDescriptor;
301 return combineInfo(receiverInfo,
302 createInfo(variableDescriptor,
303 variableKind(variableDescriptor, usageModuleDescriptor,
304 bindingContext, simpleNameExpression)));
305 }
306 if (declarationDescriptor instanceof PackageViewDescriptor || declarationDescriptor instanceof ClassDescriptor) {
307 return createPackageOrClassInfo(declarationDescriptor);
308 }
309 return NO_IDENTIFIER_INFO;
310 }
311
312 @Nullable
313 private static IdentifierInfo getIdForImplicitReceiver(@Nullable ReceiverValue receiverValue, @Nullable KtExpression expression) {
314 if (receiverValue instanceof ImplicitReceiver) {
315 return getIdForThisReceiver(((ImplicitReceiver) receiverValue).getDeclarationDescriptor());
316 }
317 else {
318 assert !(receiverValue instanceof TransientReceiver)
319 : "Transient receiver is implicit for an explicit expression: " + expression + ". Receiver: " + receiverValue;
320 // For ExpressionReceiver there is an explicit "this" expression and it was analyzed earlier
321 return null;
322 }
323 }
324
325 @NotNull
326 private static IdentifierInfo getIdForThisReceiver(@Nullable DeclarationDescriptor descriptorOfThisReceiver) {
327 if (descriptorOfThisReceiver instanceof CallableDescriptor) {
328 ReceiverParameterDescriptor receiverParameter = ((CallableDescriptor) descriptorOfThisReceiver).getExtensionReceiverParameter();
329 assert receiverParameter != null : "'This' refers to the callable member without a receiver parameter: " +
330 descriptorOfThisReceiver;
331 return createStableInfo(receiverParameter.getValue());
332 }
333 if (descriptorOfThisReceiver instanceof ClassDescriptor) {
334 return createStableInfo(((ClassDescriptor) descriptorOfThisReceiver).getThisAsReceiverParameter().getValue());
335 }
336 return NO_IDENTIFIER_INFO;
337 }
338
339 @NotNull
340 private static DeclarationDescriptor getVariableContainingDeclaration(@NotNull VariableDescriptor variableDescriptor) {
341 DeclarationDescriptor containingDeclarationDescriptor = variableDescriptor.getContainingDeclaration();
342 if (containingDeclarationDescriptor instanceof ConstructorDescriptor
343 && ((ConstructorDescriptor) containingDeclarationDescriptor).isPrimary()) {
344 // This code is necessary just because JetClassInitializer has no associated descriptor in trace
345 // Because of it we have to use class itself instead of initializer,
346 // otherwise we could not find this descriptor inside isAccessedInsideClosure below
347 containingDeclarationDescriptor = containingDeclarationDescriptor.getContainingDeclaration();
348 assert containingDeclarationDescriptor != null : "No containing declaration for primary constructor";
349 }
350 return containingDeclarationDescriptor;
351 }
352
353 private static boolean isAccessedInsideClosure(
354 @NotNull DeclarationDescriptor variableContainingDeclaration,
355 @NotNull BindingContext bindingContext,
356 @NotNull KtElement accessElement
357 ) {
358 PsiElement parent = accessElement.getParent();
359 while (parent != null) {
360 // We are inside some declaration
361 if (parent instanceof KtDeclarationWithBody || parent instanceof KtClassOrObject) {
362 DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, parent);
363 if (variableContainingDeclaration.equals(descriptor)) {
364 // Access is at the same declaration: not in closure
365 break;
366 }
367 else {
368 // Access is lower than parent: in closure
369 return true;
370 }
371 }
372 parent = parent.getParent();
373 }
374 return false;
375 }
376
377 private static boolean isAccessedBeforeAllClosureWriters(
378 @NotNull DeclarationDescriptor variableContainingDeclaration,
379 @NotNull Set<KtDeclaration> writers,
380 @NotNull BindingContext bindingContext,
381 @NotNull KtElement accessElement
382 ) {
383 // All writers should be before access element, with the exception:
384 // writer which is the same with declaration site does not count
385 for (KtDeclaration writer : writers) {
386 DeclarationDescriptor writerDescriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, writer);
387 // Access is after some writer
388 if (!variableContainingDeclaration.equals(writerDescriptor) && !PsiUtilsKt.before(accessElement, writer)) {
389 return false;
390 }
391 }
392 // Access is before all writers
393 return true;
394 }
395
396 private static Kind propertyKind(@NotNull PropertyDescriptor propertyDescriptor, @Nullable ModuleDescriptor usageModule) {
397 if (propertyDescriptor.isVar()) return MUTABLE_PROPERTY;
398 if (ModalityKt.isOverridable(propertyDescriptor)) return PROPERTY_WITH_GETTER;
399 if (!hasDefaultGetter(propertyDescriptor)) return PROPERTY_WITH_GETTER;
400 if (!invisibleFromOtherModules(propertyDescriptor)) {
401 ModuleDescriptor declarationModule = DescriptorUtils.getContainingModule(propertyDescriptor);
402 if (usageModule == null || !usageModule.equals(declarationModule)) {
403 return ALIEN_PUBLIC_PROPERTY;
404 }
405 }
406 return STABLE_VALUE;
407 }
408
409 private static Kind variableKind(
410 @NotNull VariableDescriptor variableDescriptor,
411 @Nullable ModuleDescriptor usageModule,
412 @NotNull BindingContext bindingContext,
413 @NotNull KtElement accessElement
414 ) {
415 if (variableDescriptor instanceof PropertyDescriptor) {
416 return propertyKind((PropertyDescriptor) variableDescriptor, usageModule);
417 }
418 if (!(variableDescriptor instanceof LocalVariableDescriptor) && !(variableDescriptor instanceof ParameterDescriptor)) return OTHER;
419 if (!variableDescriptor.isVar()) return STABLE_VALUE;
420 if (variableDescriptor instanceof SyntheticFieldDescriptor) return MUTABLE_PROPERTY;
421
422 // Local variable classification: PREDICTABLE or UNPREDICTABLE
423 PreliminaryDeclarationVisitor preliminaryVisitor =
424 PreliminaryDeclarationVisitor.Companion.getVisitorByVariable(variableDescriptor, bindingContext);
425 // A case when we just analyse an expression alone: counts as unpredictable
426 if (preliminaryVisitor == null) return UNPREDICTABLE_VARIABLE;
427
428 // Analyze who writes variable
429 // If there is no writer: predictable
430 Set<KtDeclaration> writers = preliminaryVisitor.writers(variableDescriptor);
431 if (writers.isEmpty()) return PREDICTABLE_VARIABLE;
432
433 // If access element is inside closure: unpredictable
434 DeclarationDescriptor variableContainingDeclaration = getVariableContainingDeclaration(variableDescriptor);
435 if (isAccessedInsideClosure(variableContainingDeclaration, bindingContext, accessElement)) return UNPREDICTABLE_VARIABLE;
436
437 // Otherwise, predictable iff considered position is BEFORE all writers except declarer itself
438 if (isAccessedBeforeAllClosureWriters(variableContainingDeclaration, writers, bindingContext, accessElement)) return PREDICTABLE_VARIABLE;
439 else return UNPREDICTABLE_VARIABLE;
440 }
441
442 /**
443 * Determines whether a variable with a given descriptor is stable or not at the given usage place.
444 * <p/>
445 * Stable means that the variable value cannot change. The simple (non-property) variable is considered stable if it's immutable (val).
446 * <p/>
447 * If the variable is a property, it's considered stable if it's immutable (val) AND it's final (not open) AND
448 * the default getter is in use (otherwise nobody can guarantee that a getter is consistent) AND
449 * (it's private OR internal OR used at the same module where it's defined).
450 * The last check corresponds to a risk of changing property definition in another module, e.g. from "val" to "var".
451 *
452 * @param variableDescriptor descriptor of a considered variable
453 * @param usageModule a module with a considered usage place, or null if it's not known (not recommended)
454 * @return true if variable is stable, false otherwise
455 */
456 public static boolean isStableValue(
457 @NotNull VariableDescriptor variableDescriptor,
458 @Nullable ModuleDescriptor usageModule
459 ) {
460 if (variableDescriptor.isVar()) return false;
461 if (variableDescriptor instanceof PropertyDescriptor) {
462 return propertyKind((PropertyDescriptor) variableDescriptor, usageModule) == STABLE_VALUE;
463 }
464 return true;
465 }
466
467 private static boolean invisibleFromOtherModules(@NotNull DeclarationDescriptorWithVisibility descriptor) {
468 if (Visibilities.INVISIBLE_FROM_OTHER_MODULES.contains(descriptor.getVisibility())) return true;
469
470 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
471 if (!(containingDeclaration instanceof DeclarationDescriptorWithVisibility)) {
472 return false;
473 }
474
475 return invisibleFromOtherModules((DeclarationDescriptorWithVisibility) containingDeclaration);
476 }
477
478 private static boolean hasDefaultGetter(PropertyDescriptor propertyDescriptor) {
479 PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
480 return getter == null || getter.isDefault();
481 }
482 }