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 == NO_IDENTIFIER_INFO ? 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 }