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