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