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