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