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