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