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 // SCRIPT: autocasts data flow
064 JetType type = receiverValue.getType();
065 boolean nullable = type.isNullable() || TypeUtils.hasNullableSuperType(type);
066 return new DataFlowValue(receiverValue, type, nullable, Nullability.NOT_NULL);
067 }
068 else if (receiverValue instanceof ClassReceiver || receiverValue instanceof ExtensionReceiver) {
069 return createDataFlowValue((ThisReceiver) receiverValue);
070 }
071 else if (receiverValue instanceof ExpressionReceiver) {
072 return createDataFlowValue(((ExpressionReceiver) receiverValue).getExpression(), receiverValue.getType(), bindingContext);
073 }
074 else if (receiverValue == ReceiverValue.NO_RECEIVER) {
075 throw new IllegalArgumentException("No DataFlowValue exists for ReceiverValue.NO_RECEIVER");
076 }
077 else {
078 throw new UnsupportedOperationException("Unsupported receiver value: " + receiverValue.getClass().getName());
079 }
080 }
081
082 @NotNull
083 private static Nullability getImmanentNullability(@NotNull JetType type) {
084 return type.isNullable() || TypeUtils.hasNullableSuperType(type) ? Nullability.UNKNOWN : Nullability.NOT_NULL;
085 }
086
087 private static class IdentifierInfo {
088 public final Object id;
089 public final boolean isStable;
090 public final boolean isPackage;
091
092 private IdentifierInfo(Object id, boolean isStable, boolean isPackage) {
093 this.id = id;
094 this.isStable = isStable;
095 this.isPackage = isPackage;
096 }
097 }
098
099 private static final IdentifierInfo NO_IDENTIFIER_INFO = new IdentifierInfo(null, false, false) {
100 @Override
101 public String toString() {
102 return "NO_IDENTIFIER_INFO";
103 }
104 };
105
106 @NotNull
107 private static IdentifierInfo createInfo(Object id, boolean isStable) {
108 return new IdentifierInfo(id, isStable, false);
109 }
110
111 @NotNull
112 private static IdentifierInfo createPackageInfo(Object id) {
113 return new IdentifierInfo(id, true, true);
114 }
115
116 @NotNull
117 private static IdentifierInfo combineInfo(@Nullable IdentifierInfo receiverInfo, @NotNull IdentifierInfo selectorInfo) {
118 if (selectorInfo.id == null) {
119 return NO_IDENTIFIER_INFO;
120 }
121 if (receiverInfo == null || receiverInfo == NO_IDENTIFIER_INFO || receiverInfo.isPackage) {
122 return selectorInfo;
123 }
124 return createInfo(Pair.create(receiverInfo.id, selectorInfo.id), receiverInfo.isStable && selectorInfo.isStable);
125 }
126
127 @NotNull
128 private static IdentifierInfo getIdForStableIdentifier(
129 @Nullable JetExpression expression,
130 @NotNull BindingContext bindingContext
131 ) {
132 if (expression != null) {
133 JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression);
134 if (expression != deparenthesized) {
135 return getIdForStableIdentifier(deparenthesized, bindingContext);
136 }
137 }
138 if (expression instanceof JetQualifiedExpression) {
139 JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) expression;
140 JetExpression receiverExpression = qualifiedExpression.getReceiverExpression();
141 JetExpression selectorExpression = qualifiedExpression.getSelectorExpression();
142 IdentifierInfo receiverId = getIdForStableIdentifier(receiverExpression, bindingContext);
143 IdentifierInfo selectorId = getIdForStableIdentifier(selectorExpression, bindingContext);
144
145 return combineInfo(receiverId, selectorId);
146 }
147 if (expression instanceof JetSimpleNameExpression) {
148 return getIdForSimpleNameExpression((JetSimpleNameExpression) expression, bindingContext);
149 }
150 else if (expression instanceof JetThisExpression) {
151 JetThisExpression thisExpression = (JetThisExpression) expression;
152 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, thisExpression.getInstanceReference());
153
154 return getIdForThisReceiver(declarationDescriptor);
155 }
156 else if (expression instanceof JetRootPackageExpression) {
157 return createPackageInfo(JetModuleUtil.getRootPackageType(expression));
158 }
159 return NO_IDENTIFIER_INFO;
160 }
161
162 @NotNull
163 private static IdentifierInfo getIdForSimpleNameExpression(
164 @NotNull JetSimpleNameExpression simpleNameExpression,
165 @NotNull BindingContext bindingContext
166 ) {
167 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, simpleNameExpression);
168 if (declarationDescriptor instanceof VariableDescriptor) {
169 ResolvedCall<?> resolvedCall = bindingContext.get(RESOLVED_CALL, simpleNameExpression);
170 // todo uncomment assert
171 // KT-4113
172 // for now it fails for resolving 'invoke' convention, return it after 'invoke' algorithm changes
173 // assert resolvedCall != null : "Cannot create right identifier info if the resolved call is not known yet for " + declarationDescriptor;
174
175 IdentifierInfo receiverInfo = resolvedCall != null ? getIdForImplicitReceiver(resolvedCall.getThisObject(), simpleNameExpression) : null;
176
177 VariableDescriptor variableDescriptor = (VariableDescriptor) declarationDescriptor;
178 return combineInfo(receiverInfo, createInfo(variableDescriptor, isStableVariable(variableDescriptor)));
179 }
180 if (declarationDescriptor instanceof PackageViewDescriptor) {
181 return createPackageInfo(declarationDescriptor);
182 }
183 return NO_IDENTIFIER_INFO;
184 }
185
186 @Nullable
187 private static IdentifierInfo getIdForImplicitReceiver(@NotNull ReceiverValue receiverValue, @Nullable JetExpression expression) {
188 if (receiverValue instanceof ThisReceiver) {
189 return getIdForThisReceiver(((ThisReceiver) receiverValue).getDeclarationDescriptor());
190 }
191 else {
192 assert !(receiverValue instanceof TransientReceiver)
193 : "Transient receiver is implicit for an explicit expression: " + expression + ". Receiver: " + receiverValue;
194 // For ExpressionReceiver there is an explicit "this" expression and it was analyzed earlier
195 return null;
196 }
197 }
198
199 @NotNull
200 private static IdentifierInfo getIdForThisReceiver(@Nullable DeclarationDescriptor descriptorOfThisReceiver) {
201 if (descriptorOfThisReceiver instanceof CallableDescriptor) {
202 ReceiverParameterDescriptor receiverParameter = ((CallableDescriptor) descriptorOfThisReceiver).getReceiverParameter();
203 assert receiverParameter != null : "'This' refers to the callable member without a receiver parameter: " + descriptorOfThisReceiver;
204 return createInfo(receiverParameter.getValue(), true);
205 }
206 if (descriptorOfThisReceiver instanceof ClassDescriptor) {
207 return createInfo(((ClassDescriptor) descriptorOfThisReceiver).getThisAsReceiverParameter().getValue(), true);
208 }
209 return NO_IDENTIFIER_INFO;
210 }
211
212 public static boolean isStableVariable(@NotNull VariableDescriptor variableDescriptor) {
213 if (variableDescriptor.isVar()) return false;
214 if (variableDescriptor instanceof PropertyDescriptor) {
215 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
216 if (!invisibleFromOtherModules(propertyDescriptor)) return false;
217 if (!isFinal(propertyDescriptor)) return false;
218 if (!hasDefaultGetter(propertyDescriptor)) return false;
219 }
220 return true;
221 }
222
223 private static boolean isFinal(PropertyDescriptor propertyDescriptor) {
224 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
225 if (containingDeclaration instanceof ClassDescriptor) {
226 ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
227 if (classDescriptor.getModality().isOverridable() && propertyDescriptor.getModality().isOverridable()) return false;
228 }
229 else {
230 if (propertyDescriptor.getModality().isOverridable()) {
231 throw new IllegalStateException("Property outside a class must not be overridable: " + propertyDescriptor.getName());
232 }
233 }
234 return true;
235 }
236
237 private static boolean invisibleFromOtherModules(@NotNull DeclarationDescriptorWithVisibility descriptor) {
238 if (Visibilities.INVISIBLE_FROM_OTHER_MODULES.contains(descriptor.getVisibility())) return true;
239
240 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
241 if (!(containingDeclaration instanceof DeclarationDescriptorWithVisibility)) {
242 return false;
243 }
244
245 return invisibleFromOtherModules((DeclarationDescriptorWithVisibility) containingDeclaration);
246 }
247
248 private static boolean hasDefaultGetter(PropertyDescriptor propertyDescriptor) {
249 PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
250 return getter == null || getter.isDefault();
251 }
252 }