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 java.util.List;
034
035 import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
036 import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
037
038 public class DataFlowValueFactory {
039 public static final DataFlowValueFactory INSTANCE = new DataFlowValueFactory();
040
041 private DataFlowValueFactory() {}
042
043 @NotNull
044 public DataFlowValue createDataFlowValue(@NotNull JetExpression expression, @NotNull JetType type, @NotNull BindingContext bindingContext) {
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 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 DataFlowValue createDataFlowValue(@NotNull VariableDescriptor variableDescriptor) {
062 JetType type = variableDescriptor.getType();
063 return new DataFlowValue(variableDescriptor, type, isStableVariable(variableDescriptor), getImmanentNullability(type));
064 }
065
066 @NotNull
067 public DataFlowValue createDataFlowValue(@NotNull ReceiverValue receiverValue, @NotNull BindingContext bindingContext) {
068 return receiverValue.accept(new ReceiverValueVisitor<DataFlowValue, BindingContext>() {
069 @Override
070 public DataFlowValue visitNoReceiver(ReceiverValue noReceiver, BindingContext data) {
071 throw new IllegalArgumentException("No DataFlowValue exists for ReceiverValue.NO_RECEIVER");
072 }
073
074 @Override
075 public DataFlowValue visitExtensionReceiver(ExtensionReceiver receiver, BindingContext data) {
076 return createDataFlowValue(receiver);
077 }
078
079 @Override
080 public DataFlowValue visitExpressionReceiver(ExpressionReceiver receiver, BindingContext bindingContext) {
081 return createDataFlowValue(receiver.getExpression(), receiver.getType(), bindingContext);
082 }
083
084 @Override
085 public DataFlowValue visitClassReceiver(ClassReceiver receiver, BindingContext data) {
086 return createDataFlowValue(receiver);
087 }
088
089 @Override
090 public DataFlowValue visitTransientReceiver(TransientReceiver receiver, BindingContext data) {
091 return createTransientDataFlowValue(receiver);
092 }
093
094 @Override
095 public DataFlowValue visitScriptReceiver(ScriptReceiver receiver, BindingContext data) {
096 return createTransientDataFlowValue(receiver);
097 }
098
099 @NotNull
100 private DataFlowValue createTransientDataFlowValue(ReceiverValue receiver) {
101 JetType type = receiver.getType();
102 boolean nullable = type.isNullable() || TypeUtils.hasNullableSuperType(type);
103 return new DataFlowValue(receiver, type, nullable, Nullability.NOT_NULL);
104 }
105 }, bindingContext);
106 }
107
108 private Nullability getImmanentNullability(JetType type) {
109 return type.isNullable() || TypeUtils.hasNullableSuperType(type) ? Nullability.UNKNOWN : Nullability.NOT_NULL;
110 }
111
112 private static class IdentifierInfo {
113 public final Object id;
114 public final boolean isStable;
115 public final boolean isNamespace;
116
117 private IdentifierInfo(Object id, boolean isStable, boolean isNamespace) {
118 this.id = id;
119 this.isStable = isStable;
120 this.isNamespace = isNamespace;
121 }
122 }
123
124 private static final IdentifierInfo NO_IDENTIFIER_INFO = new IdentifierInfo(null, false, false) {
125 @Override
126 public String toString() {
127 return "NO_IDENTIFIER_INFO";
128 }
129 };
130
131 @NotNull
132 private static IdentifierInfo createInfo(Object id, boolean isStable) {
133 return new IdentifierInfo(id, isStable, false);
134 }
135
136 @NotNull
137 private static IdentifierInfo createNamespaceInfo(Object id) {
138 return new IdentifierInfo(id, true, true);
139 }
140
141 @NotNull
142 private static IdentifierInfo combineInfo(@Nullable IdentifierInfo receiverInfo, @NotNull IdentifierInfo selectorInfo) {
143 if (selectorInfo.id == null) {
144 return NO_IDENTIFIER_INFO;
145 }
146 if (receiverInfo == null || receiverInfo == NO_IDENTIFIER_INFO || receiverInfo.isNamespace) {
147 return selectorInfo;
148 }
149 return createInfo(Pair.create(receiverInfo.id, selectorInfo.id), receiverInfo.isStable && selectorInfo.isStable);
150 }
151
152 @NotNull
153 private static IdentifierInfo getIdForStableIdentifier(
154 @Nullable JetExpression expression,
155 @NotNull BindingContext bindingContext
156 ) {
157 if (expression instanceof JetParenthesizedExpression) {
158 JetParenthesizedExpression parenthesizedExpression = (JetParenthesizedExpression) expression;
159 JetExpression innerExpression = parenthesizedExpression.getExpression();
160
161 return getIdForStableIdentifier(innerExpression, bindingContext);
162 }
163 else if (expression instanceof JetQualifiedExpression) {
164 JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) expression;
165 JetExpression receiverExpression = qualifiedExpression.getReceiverExpression();
166 JetExpression selectorExpression = qualifiedExpression.getSelectorExpression();
167 IdentifierInfo receiverId = getIdForStableIdentifier(receiverExpression, bindingContext);
168 IdentifierInfo selectorId = getIdForStableIdentifier(selectorExpression, bindingContext);
169
170 return combineInfo(receiverId, selectorId);
171 }
172 if (expression instanceof JetSimpleNameExpression) {
173 return getIdForSimpleNameExpression((JetSimpleNameExpression) expression, bindingContext);
174 }
175 else if (expression instanceof JetThisExpression) {
176 JetThisExpression thisExpression = (JetThisExpression) expression;
177 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, thisExpression.getInstanceReference());
178
179 return getIdForThisReceiver(declarationDescriptor);
180 }
181 else if (expression instanceof JetRootNamespaceExpression) {
182 return createNamespaceInfo(JetModuleUtil.getRootNamespaceType(expression));
183 }
184 return NO_IDENTIFIER_INFO;
185 }
186
187 @NotNull
188 private static IdentifierInfo getIdForSimpleNameExpression(
189 @NotNull JetSimpleNameExpression simpleNameExpression,
190 @NotNull BindingContext bindingContext
191 ) {
192 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, simpleNameExpression);
193 if (declarationDescriptor instanceof VariableDescriptor) {
194 ResolvedCall<?> resolvedCall = bindingContext.get(RESOLVED_CALL, simpleNameExpression);
195 // todo uncomment assert
196 // for now it fails for resolving 'invoke' convention, return it after 'invoke' algorithm changes
197 // assert resolvedCall != null : "Cannot create right identifier info if the resolved call is not known yet for " + declarationDescriptor;
198
199 IdentifierInfo receiverInfo = resolvedCall != null ? getIdForImplicitReceiver(resolvedCall.getThisObject(), simpleNameExpression) : null;
200
201 VariableDescriptor variableDescriptor = (VariableDescriptor) declarationDescriptor;
202 return combineInfo(receiverInfo, createInfo(variableDescriptor, isStableVariable(variableDescriptor)));
203 }
204 if (declarationDescriptor instanceof NamespaceDescriptor) {
205 return createNamespaceInfo(declarationDescriptor);
206 }
207 return NO_IDENTIFIER_INFO;
208 }
209
210 @Nullable
211 private static IdentifierInfo getIdForImplicitReceiver(@NotNull ReceiverValue receiverValue, @Nullable final JetExpression expression) {
212 return receiverValue.accept(new ReceiverValueVisitor<IdentifierInfo, Void>() {
213
214 @Override
215 public IdentifierInfo visitNoReceiver(ReceiverValue noReceiver, Void data) {
216 return null;
217 }
218
219 @Override
220 public IdentifierInfo visitTransientReceiver(TransientReceiver receiver, Void data) {
221 assert false: "Transient receiver is implicit for an explicit expression: " + expression + ". Receiver: " + receiver;
222 return null;
223 }
224
225 @Override
226 public IdentifierInfo visitExtensionReceiver(ExtensionReceiver receiver, Void data) {
227 return getIdForThisReceiver(receiver);
228 }
229
230 @Override
231 public IdentifierInfo visitExpressionReceiver(ExpressionReceiver receiver, Void data) {
232 // there is an explicit "this" expression and it was analyzed earlier
233 return null;
234 }
235
236 @Override
237 public IdentifierInfo visitClassReceiver(ClassReceiver receiver, Void data) {
238 return getIdForThisReceiver(receiver);
239 }
240
241 @Override
242 public IdentifierInfo visitScriptReceiver(ScriptReceiver receiver, Void data) {
243 return getIdForThisReceiver(receiver);
244 }
245 }, null);
246 }
247
248 @NotNull
249 private static IdentifierInfo getIdForThisReceiver(@NotNull ThisReceiver thisReceiver) {
250 return getIdForThisReceiver(thisReceiver.getDeclarationDescriptor());
251 }
252
253 @NotNull
254 private static IdentifierInfo getIdForThisReceiver(@Nullable DeclarationDescriptor descriptorOfThisReceiver) {
255 if (descriptorOfThisReceiver instanceof CallableDescriptor) {
256 ReceiverParameterDescriptor receiverParameter = ((CallableDescriptor) descriptorOfThisReceiver).getReceiverParameter();
257 assert receiverParameter != null : "'This' refers to the callable member without a receiver parameter: " + descriptorOfThisReceiver;
258 return createInfo(receiverParameter.getValue(), true);
259 }
260 if (descriptorOfThisReceiver instanceof ClassDescriptor) {
261 return createInfo(((ClassDescriptor) descriptorOfThisReceiver).getThisAsReceiverParameter().getValue(), true);
262 }
263 return NO_IDENTIFIER_INFO;
264 }
265
266 public static boolean isStableVariable(@NotNull VariableDescriptor variableDescriptor) {
267 if (variableDescriptor.isVar()) return false;
268 if (variableDescriptor instanceof PropertyDescriptor) {
269 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
270 if (!invisibleFromOtherModules(propertyDescriptor)) return false;
271 if (!isFinal(propertyDescriptor)) return false;
272 if (!hasDefaultGetter(propertyDescriptor)) return false;
273 }
274 return true;
275 }
276
277 private static boolean isFinal(PropertyDescriptor propertyDescriptor) {
278 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
279 if (containingDeclaration instanceof ClassDescriptor) {
280 ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
281 if (classDescriptor.getModality().isOverridable() && propertyDescriptor.getModality().isOverridable()) return false;
282 }
283 else {
284 if (propertyDescriptor.getModality().isOverridable()) {
285 throw new IllegalStateException("Property outside a class must not be overridable: " + propertyDescriptor.getName());
286 }
287 }
288 return true;
289 }
290
291 private static boolean invisibleFromOtherModules(@NotNull DeclarationDescriptorWithVisibility descriptor) {
292 if (Visibilities.INVISIBLE_FROM_OTHER_MODULES.contains(descriptor.getVisibility())) return true;
293
294 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
295 if (!(containingDeclaration instanceof DeclarationDescriptorWithVisibility)) {
296 return false;
297 }
298
299 return invisibleFromOtherModules((DeclarationDescriptorWithVisibility) containingDeclaration);
300 }
301
302 private static boolean hasDefaultGetter(PropertyDescriptor propertyDescriptor) {
303 PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
304 return getter == null || getter.isDefault();
305 }
306 }