001    /*
002     * Copyright 2010-2013 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.jet.lang.resolve.calls.autocasts;
018    
019    import com.intellij.openapi.util.Pair;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.JetNodeTypes;
023    import org.jetbrains.jet.lang.descriptors.*;
024    import org.jetbrains.jet.lang.psi.*;
025    import org.jetbrains.jet.lang.resolve.BindingContext;
026    import org.jetbrains.jet.lang.resolve.JetModuleUtil;
027    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
028    import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
029    import org.jetbrains.jet.lang.types.JetType;
030    import org.jetbrains.jet.lang.types.TypeUtils;
031    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
032    
033    import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
034    import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
035    
036    public class DataFlowValueFactory {
037        private DataFlowValueFactory() {}
038    
039        @NotNull
040        public static DataFlowValue createDataFlowValue(
041                @NotNull JetExpression expression,
042                @NotNull JetType type,
043                @NotNull BindingContext bindingContext
044        ) {
045            if (expression instanceof JetConstantExpression) {
046                JetConstantExpression constantExpression = (JetConstantExpression) expression;
047                if (constantExpression.getNode().getElementType() == JetNodeTypes.NULL) return DataFlowValue.NULL;
048            }
049            if (TypeUtils.equalTypes(type, KotlinBuiltIns.getInstance().getNullableNothingType())) return DataFlowValue.NULL; // 'null' is the only inhabitant of 'Nothing?'
050            IdentifierInfo result = getIdForStableIdentifier(expression, bindingContext);
051            return new DataFlowValue(result.id == null ? expression : result.id, type, result.isStable, getImmanentNullability(type));
052        }
053    
054        @NotNull
055        public static DataFlowValue createDataFlowValue(@NotNull ThisReceiver receiver) {
056            JetType type = receiver.getType();
057            return new DataFlowValue(receiver, type, true, getImmanentNullability(type));
058        }
059    
060        @NotNull
061        public static DataFlowValue createDataFlowValue(@NotNull ReceiverValue receiverValue, @NotNull BindingContext bindingContext) {
062            if (receiverValue instanceof TransientReceiver || receiverValue instanceof ScriptReceiver) {
063                JetType type = receiverValue.getType();
064                boolean nullable = type.isNullable() || TypeUtils.hasNullableSuperType(type);
065                return new DataFlowValue(receiverValue, type, nullable, Nullability.NOT_NULL);
066            }
067            else if (receiverValue instanceof ClassReceiver || receiverValue instanceof ExtensionReceiver) {
068                return createDataFlowValue((ThisReceiver) receiverValue);
069            }
070            else if (receiverValue instanceof ExpressionReceiver) {
071                return createDataFlowValue(((ExpressionReceiver) receiverValue).getExpression(), receiverValue.getType(), bindingContext);
072            }
073            else if (receiverValue instanceof AutoCastReceiver) {
074                return createDataFlowValue(((AutoCastReceiver) receiverValue).getOriginal(), bindingContext);
075            }
076            else if (receiverValue == ReceiverValue.NO_RECEIVER) {
077                throw new IllegalArgumentException("No DataFlowValue exists for ReceiverValue.NO_RECEIVER");
078            }
079            else {
080                throw new UnsupportedOperationException("Unsupported receiver value: " + receiverValue.getClass().getName());
081            }
082        }
083    
084        @NotNull
085        private static Nullability getImmanentNullability(@NotNull JetType type) {
086            return type.isNullable() || TypeUtils.hasNullableSuperType(type) ? Nullability.UNKNOWN : Nullability.NOT_NULL;
087        }
088    
089        private static class IdentifierInfo {
090            public final Object id;
091            public final boolean isStable;
092            public final boolean isNamespace;
093    
094            private IdentifierInfo(Object id, boolean isStable, boolean isNamespace) {
095                this.id = id;
096                this.isStable = isStable;
097                this.isNamespace = isNamespace;
098            }
099        }
100    
101        private static final IdentifierInfo NO_IDENTIFIER_INFO = new IdentifierInfo(null, false, false) {
102            @Override
103            public String toString() {
104                return "NO_IDENTIFIER_INFO";
105            }
106        };
107    
108        @NotNull
109        private static IdentifierInfo createInfo(Object id, boolean isStable) {
110            return new IdentifierInfo(id, isStable, false);
111        }
112    
113        @NotNull
114        private static IdentifierInfo createNamespaceInfo(Object id) {
115            return new IdentifierInfo(id, true, true);
116        }
117    
118        @NotNull
119        private static IdentifierInfo combineInfo(@Nullable IdentifierInfo receiverInfo, @NotNull IdentifierInfo selectorInfo) {
120            if (selectorInfo.id == null) {
121                return NO_IDENTIFIER_INFO;
122            }
123            if (receiverInfo == null || receiverInfo == NO_IDENTIFIER_INFO || receiverInfo.isNamespace) {
124                return selectorInfo;
125            }
126            return createInfo(Pair.create(receiverInfo.id, selectorInfo.id), receiverInfo.isStable && selectorInfo.isStable);
127        }
128    
129        @NotNull
130        private static IdentifierInfo getIdForStableIdentifier(
131                @Nullable JetExpression expression,
132                @NotNull BindingContext bindingContext
133        ) {
134            if (expression != null) {
135                JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression);
136                if (expression != deparenthesized) {
137                    return getIdForStableIdentifier(deparenthesized, bindingContext);
138                }
139            }
140            if (expression instanceof JetQualifiedExpression) {
141                JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) expression;
142                JetExpression receiverExpression = qualifiedExpression.getReceiverExpression();
143                JetExpression selectorExpression = qualifiedExpression.getSelectorExpression();
144                IdentifierInfo receiverId = getIdForStableIdentifier(receiverExpression, bindingContext);
145                IdentifierInfo selectorId = getIdForStableIdentifier(selectorExpression, bindingContext);
146    
147                return combineInfo(receiverId, selectorId);
148            }
149            if (expression instanceof JetSimpleNameExpression) {
150                return getIdForSimpleNameExpression((JetSimpleNameExpression) expression, bindingContext);
151            }
152            else if (expression instanceof JetThisExpression) {
153                JetThisExpression thisExpression = (JetThisExpression) expression;
154                DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, thisExpression.getInstanceReference());
155    
156                return getIdForThisReceiver(declarationDescriptor);
157            }
158            else if (expression instanceof JetRootNamespaceExpression) {
159                return createNamespaceInfo(JetModuleUtil.getRootNamespaceType(expression));
160            }
161            return NO_IDENTIFIER_INFO;
162        }
163    
164        @NotNull
165        private static IdentifierInfo getIdForSimpleNameExpression(
166                @NotNull JetSimpleNameExpression simpleNameExpression,
167                @NotNull BindingContext bindingContext
168        ) {
169            DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, simpleNameExpression);
170            if (declarationDescriptor instanceof VariableDescriptor) {
171                ResolvedCall<?> resolvedCall = bindingContext.get(RESOLVED_CALL, simpleNameExpression);
172                // todo uncomment assert
173                // KT-4113
174                // for now it fails for resolving 'invoke' convention, return it after 'invoke' algorithm changes
175                // assert resolvedCall != null : "Cannot create right identifier info if the resolved call is not known yet for " + declarationDescriptor;
176    
177                IdentifierInfo receiverInfo = resolvedCall != null ? getIdForImplicitReceiver(resolvedCall.getThisObject(), simpleNameExpression) : null;
178    
179                VariableDescriptor variableDescriptor = (VariableDescriptor) declarationDescriptor;
180                return combineInfo(receiverInfo, createInfo(variableDescriptor, isStableVariable(variableDescriptor)));
181            }
182            if (declarationDescriptor instanceof NamespaceDescriptor) {
183                return createNamespaceInfo(declarationDescriptor);
184            }
185            return NO_IDENTIFIER_INFO;
186        }
187    
188        @Nullable
189        private static IdentifierInfo getIdForImplicitReceiver(@NotNull ReceiverValue receiverValue, @Nullable JetExpression expression) {
190            if (receiverValue instanceof ThisReceiver) {
191                return getIdForThisReceiver(((ThisReceiver) receiverValue).getDeclarationDescriptor());
192            }
193            else if (receiverValue instanceof AutoCastReceiver) {
194                return getIdForImplicitReceiver(((AutoCastReceiver) receiverValue).getOriginal(), expression);
195            }
196            else {
197                assert !(receiverValue instanceof TransientReceiver)
198                        : "Transient receiver is implicit for an explicit expression: " + expression + ". Receiver: " + receiverValue;
199                // For ExpressionReceiver there is an explicit "this" expression and it was analyzed earlier
200                return null;
201            }
202        }
203    
204        @NotNull
205        private static IdentifierInfo getIdForThisReceiver(@Nullable DeclarationDescriptor descriptorOfThisReceiver) {
206            if (descriptorOfThisReceiver instanceof CallableDescriptor) {
207                ReceiverParameterDescriptor receiverParameter = ((CallableDescriptor) descriptorOfThisReceiver).getReceiverParameter();
208                assert receiverParameter != null : "'This' refers to the callable member without a receiver parameter: " + descriptorOfThisReceiver;
209                return createInfo(receiverParameter.getValue(), true);
210            }
211            if (descriptorOfThisReceiver instanceof ClassDescriptor) {
212                return createInfo(((ClassDescriptor) descriptorOfThisReceiver).getThisAsReceiverParameter().getValue(), true);
213            }
214            return NO_IDENTIFIER_INFO;
215        }
216    
217        public static boolean isStableVariable(@NotNull VariableDescriptor variableDescriptor) {
218            if (variableDescriptor.isVar()) return false;
219            if (variableDescriptor instanceof PropertyDescriptor) {
220                PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
221                if (!invisibleFromOtherModules(propertyDescriptor)) return false;
222                if (!isFinal(propertyDescriptor)) return false;
223                if (!hasDefaultGetter(propertyDescriptor)) return false;
224            }
225            return true;
226        }
227    
228        private static boolean isFinal(PropertyDescriptor propertyDescriptor) {
229            DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
230            if (containingDeclaration instanceof ClassDescriptor) {
231                ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
232                if (classDescriptor.getModality().isOverridable() && propertyDescriptor.getModality().isOverridable()) return false;
233            }
234            else {
235                if (propertyDescriptor.getModality().isOverridable()) {
236                    throw new IllegalStateException("Property outside a class must not be overridable: " + propertyDescriptor.getName());
237                }
238            }
239            return true;
240        }
241    
242        private static boolean invisibleFromOtherModules(@NotNull DeclarationDescriptorWithVisibility descriptor) {
243            if (Visibilities.INVISIBLE_FROM_OTHER_MODULES.contains(descriptor.getVisibility())) return true;
244    
245            DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
246            if (!(containingDeclaration instanceof DeclarationDescriptorWithVisibility)) {
247                return false;
248            }
249    
250            return invisibleFromOtherModules((DeclarationDescriptorWithVisibility) containingDeclaration);
251        }
252    
253        private static boolean hasDefaultGetter(PropertyDescriptor propertyDescriptor) {
254            PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
255            return getter == null || getter.isDefault();
256        }
257    }