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    }