001 /*
002 * Copyright 2010-2015 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.kotlin.resolve.calls.smartcasts;
018
019 import com.intellij.openapi.util.Pair;
020 import com.intellij.psi.tree.IElementType;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.kotlin.JetNodeTypes;
024 import org.jetbrains.kotlin.descriptors.*;
025 import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
026 import org.jetbrains.kotlin.lexer.JetTokens;
027 import org.jetbrains.kotlin.psi.*;
028 import org.jetbrains.kotlin.resolve.BindingContext;
029 import org.jetbrains.kotlin.resolve.BindingContextUtils;
030 import org.jetbrains.kotlin.resolve.DescriptorUtils;
031 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
032 import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
033 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
034 import org.jetbrains.kotlin.resolve.scopes.receivers.*;
035 import org.jetbrains.kotlin.types.JetType;
036 import org.jetbrains.kotlin.types.TypeUtils;
037
038 import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableNothing;
039 import static org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET;
040
041 /**
042 * This class is intended to create data flow values for different kind of expressions.
043 * Then data flow values serve as keys to obtain data flow information for these expressions.
044 */
045 public class DataFlowValueFactory {
046 private DataFlowValueFactory() {
047 }
048
049 @NotNull
050 public static DataFlowValue createDataFlowValue(
051 @NotNull JetExpression expression,
052 @NotNull JetType type,
053 @NotNull ResolutionContext resolutionContext
054 ) {
055 return createDataFlowValue(expression, type, resolutionContext.trace.getBindingContext(),
056 resolutionContext.scope.getContainingDeclaration());
057 }
058
059 @NotNull
060 public static DataFlowValue createDataFlowValue(
061 @NotNull JetExpression expression,
062 @NotNull JetType type,
063 @NotNull BindingContext bindingContext,
064 @NotNull DeclarationDescriptor containingDeclarationOrModule
065 ) {
066 if (expression instanceof JetConstantExpression) {
067 JetConstantExpression constantExpression = (JetConstantExpression) expression;
068 if (constantExpression.getNode().getElementType() == JetNodeTypes.NULL) return DataFlowValue.NULL;
069 }
070 if (type.isError()) return DataFlowValue.ERROR;
071 if (isNullableNothing(type)) {
072 return DataFlowValue.NULL; // 'null' is the only inhabitant of 'Nothing?'
073 }
074 IdentifierInfo result = getIdForStableIdentifier(expression, bindingContext, containingDeclarationOrModule);
075 return new DataFlowValue(result == NO_IDENTIFIER_INFO ? expression : result.id,
076 type,
077 result.isStable,
078 result.isLocal,
079 getImmanentNullability(type));
080 }
081
082 @NotNull
083 public static DataFlowValue createDataFlowValue(@NotNull ThisReceiver receiver) {
084 JetType type = receiver.getType();
085 return new DataFlowValue(receiver, type, true, false, getImmanentNullability(type));
086 }
087
088 @NotNull
089 public static DataFlowValue createDataFlowValue(
090 @NotNull ReceiverValue receiverValue,
091 @NotNull ResolutionContext resolutionContext
092 ) {
093 return createDataFlowValue(receiverValue, resolutionContext.trace.getBindingContext(),
094 resolutionContext.scope.getContainingDeclaration());
095 }
096
097 @NotNull
098 public static DataFlowValue createDataFlowValue(
099 @NotNull ReceiverValue receiverValue,
100 @NotNull BindingContext bindingContext,
101 @NotNull DeclarationDescriptor containingDeclarationOrModule
102 ) {
103 if (receiverValue instanceof TransientReceiver || receiverValue instanceof ScriptReceiver) {
104 // SCRIPT: smartcasts data flow
105 JetType type = receiverValue.getType();
106 boolean nullable = type.isMarkedNullable() || TypeUtils.hasNullableSuperType(type);
107 return new DataFlowValue(receiverValue, type, nullable, false, Nullability.NOT_NULL);
108 }
109 else if (receiverValue instanceof ClassReceiver || receiverValue instanceof ExtensionReceiver) {
110 return createDataFlowValue((ThisReceiver) receiverValue);
111 }
112 else if (receiverValue instanceof ExpressionReceiver) {
113 return createDataFlowValue(((ExpressionReceiver) receiverValue).getExpression(),
114 receiverValue.getType(),
115 bindingContext,
116 containingDeclarationOrModule);
117 }
118 else if (receiverValue == ReceiverValue.NO_RECEIVER) {
119 throw new IllegalArgumentException("No DataFlowValue exists for ReceiverValue.NO_RECEIVER");
120 }
121 else {
122 throw new UnsupportedOperationException("Unsupported receiver value: " + receiverValue.getClass().getName());
123 }
124 }
125
126 @NotNull
127 public static DataFlowValue createDataFlowValue(
128 @NotNull VariableDescriptor variableDescriptor,
129 @NotNull BindingContext bindingContext,
130 @Nullable ModuleDescriptor usageContainingModule
131 ) {
132 JetType type = variableDescriptor.getType();
133 return new DataFlowValue(variableDescriptor, type,
134 isStableVariable(variableDescriptor, usageContainingModule),
135 isUncapturedLocalVariable(variableDescriptor, bindingContext),
136 getImmanentNullability(type));
137 }
138
139 @NotNull
140 private static Nullability getImmanentNullability(@NotNull JetType type) {
141 return TypeUtils.isNullableType(type) ? Nullability.UNKNOWN : Nullability.NOT_NULL;
142 }
143
144 private static class IdentifierInfo {
145 public final Object id;
146 public final boolean isStable;
147 public final boolean isLocal;
148 public final boolean isPackage;
149
150 private IdentifierInfo(Object id, boolean isStable, boolean isLocal, boolean isPackage) {
151 assert !isStable || !isLocal : "Identifier info for object " + id + " cannot be stable and local at one time";
152 this.id = id;
153 this.isStable = isStable;
154 this.isLocal = isLocal;
155 this.isPackage = isPackage;
156 }
157 }
158
159 private static final IdentifierInfo NO_IDENTIFIER_INFO = new IdentifierInfo(null, false, false, false) {
160 @Override
161 public String toString() {
162 return "NO_IDENTIFIER_INFO";
163 }
164 };
165
166 @NotNull
167 private static IdentifierInfo createInfo(Object id, boolean isStable, boolean isLocal) {
168 return new IdentifierInfo(id, isStable, isLocal, false);
169 }
170
171 @NotNull
172 private static IdentifierInfo createStableInfo(Object id) {
173 return createInfo(id, true, false);
174 }
175
176 @NotNull
177 private static IdentifierInfo createPackageInfo(Object id) {
178 return new IdentifierInfo(id, true, false, true);
179 }
180
181 @NotNull
182 private static IdentifierInfo combineInfo(@Nullable IdentifierInfo receiverInfo, @NotNull IdentifierInfo selectorInfo) {
183 if (selectorInfo.id == null) {
184 return NO_IDENTIFIER_INFO;
185 }
186 if (receiverInfo == null || receiverInfo == NO_IDENTIFIER_INFO || receiverInfo.isPackage) {
187 return selectorInfo;
188 }
189 return createInfo(Pair.create(receiverInfo.id, selectorInfo.id),
190 receiverInfo.isStable && selectorInfo.isStable,
191 // x.y can never be a local variable
192 false);
193 }
194
195 @NotNull
196 private static IdentifierInfo createPostfixInfo(@NotNull JetPostfixExpression expression, @NotNull IdentifierInfo argumentInfo) {
197 if (argumentInfo == NO_IDENTIFIER_INFO) {
198 return NO_IDENTIFIER_INFO;
199 }
200 return createInfo(Pair.create(expression, argumentInfo.id), argumentInfo.isStable, argumentInfo.isLocal);
201 }
202
203 @NotNull
204 private static IdentifierInfo getIdForStableIdentifier(
205 @Nullable JetExpression expression,
206 @NotNull BindingContext bindingContext,
207 @NotNull DeclarationDescriptor containingDeclarationOrModule
208 ) {
209 if (expression != null) {
210 JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression);
211 if (expression != deparenthesized) {
212 return getIdForStableIdentifier(deparenthesized, bindingContext, containingDeclarationOrModule);
213 }
214 }
215 if (expression instanceof JetQualifiedExpression) {
216 JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) expression;
217 JetExpression receiverExpression = qualifiedExpression.getReceiverExpression();
218 JetExpression selectorExpression = qualifiedExpression.getSelectorExpression();
219 IdentifierInfo receiverId = getIdForStableIdentifier(receiverExpression, bindingContext, containingDeclarationOrModule);
220 IdentifierInfo selectorId = getIdForStableIdentifier(selectorExpression, bindingContext, containingDeclarationOrModule);
221
222 return combineInfo(receiverId, selectorId);
223 }
224 if (expression instanceof JetSimpleNameExpression) {
225 return getIdForSimpleNameExpression((JetSimpleNameExpression) expression, bindingContext, containingDeclarationOrModule);
226 }
227 else if (expression instanceof JetThisExpression) {
228 JetThisExpression thisExpression = (JetThisExpression) expression;
229 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, thisExpression.getInstanceReference());
230
231 return getIdForThisReceiver(declarationDescriptor);
232 }
233 else if (expression instanceof JetPostfixExpression) {
234 JetPostfixExpression postfixExpression = (JetPostfixExpression) expression;
235 IElementType operationType = postfixExpression.getOperationReference().getReferencedNameElementType();
236 if (operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS) {
237 return createPostfixInfo(postfixExpression,
238 getIdForStableIdentifier(postfixExpression.getBaseExpression(), bindingContext, containingDeclarationOrModule));
239 }
240 }
241 else if (expression instanceof JetRootPackageExpression) {
242 //todo return createPackageInfo());
243 }
244 return NO_IDENTIFIER_INFO;
245 }
246
247 @NotNull
248 private static IdentifierInfo getIdForSimpleNameExpression(
249 @NotNull JetSimpleNameExpression simpleNameExpression,
250 @NotNull BindingContext bindingContext,
251 @NotNull DeclarationDescriptor containingDeclarationOrModule
252 ) {
253 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, simpleNameExpression);
254 if (declarationDescriptor instanceof VariableDescriptor) {
255 ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(simpleNameExpression, bindingContext);
256
257 // todo uncomment assert
258 // KT-4113
259 // for now it fails for resolving 'invoke' convention, return it after 'invoke' algorithm changes
260 // assert resolvedCall != null : "Cannot create right identifier info if the resolved call is not known yet for
261 ModuleDescriptor usageModuleDescriptor = DescriptorUtils.getContainingModuleOrNull(containingDeclarationOrModule);
262 IdentifierInfo receiverInfo =
263 resolvedCall != null ? getIdForImplicitReceiver(resolvedCall.getDispatchReceiver(), simpleNameExpression) : null;
264
265 VariableDescriptor variableDescriptor = (VariableDescriptor) declarationDescriptor;
266 return combineInfo(receiverInfo, createInfo(variableDescriptor,
267 isStableVariable(variableDescriptor, usageModuleDescriptor),
268 isUncapturedLocalVariable(variableDescriptor, bindingContext)));
269 }
270 if (declarationDescriptor instanceof PackageViewDescriptor) {
271 return createPackageInfo(declarationDescriptor);
272 }
273 return NO_IDENTIFIER_INFO;
274 }
275
276 @Nullable
277 private static IdentifierInfo getIdForImplicitReceiver(@NotNull ReceiverValue receiverValue, @Nullable JetExpression expression) {
278 if (receiverValue instanceof ThisReceiver) {
279 return getIdForThisReceiver(((ThisReceiver) receiverValue).getDeclarationDescriptor());
280 }
281 else {
282 assert !(receiverValue instanceof TransientReceiver)
283 : "Transient receiver is implicit for an explicit expression: " + expression + ". Receiver: " + receiverValue;
284 // For ExpressionReceiver there is an explicit "this" expression and it was analyzed earlier
285 return null;
286 }
287 }
288
289 @NotNull
290 private static IdentifierInfo getIdForThisReceiver(@Nullable DeclarationDescriptor descriptorOfThisReceiver) {
291 if (descriptorOfThisReceiver instanceof CallableDescriptor) {
292 ReceiverParameterDescriptor receiverParameter = ((CallableDescriptor) descriptorOfThisReceiver).getExtensionReceiverParameter();
293 assert receiverParameter != null : "'This' refers to the callable member without a receiver parameter: " +
294 descriptorOfThisReceiver;
295 return createStableInfo(receiverParameter.getValue());
296 }
297 if (descriptorOfThisReceiver instanceof ClassDescriptor) {
298 return createStableInfo(((ClassDescriptor) descriptorOfThisReceiver).getThisAsReceiverParameter().getValue());
299 }
300 return NO_IDENTIFIER_INFO;
301 }
302
303 public static boolean isUncapturedLocalVariable(@NotNull VariableDescriptor variableDescriptor, @NotNull BindingContext bindingContext) {
304 return variableDescriptor.isVar()
305 && variableDescriptor instanceof LocalVariableDescriptor
306 && !BindingContextUtils.isVarCapturedInClosure(bindingContext, variableDescriptor);
307 }
308
309 /**
310 * Determines whether a variable with a given descriptor is stable or not at the given usage place.
311 * <p/>
312 * Stable means that the variable value cannot change. The simple (non-property) variable is considered stable if it's immutable (val).
313 * <p/>
314 * If the variable is a property, it's considered stable if it's immutable (val) AND it's final (not open) AND
315 * the default getter is in use (otherwise nobody can guarantee that a getter is consistent) AND
316 * (it's private OR internal OR used at the same module where it's defined).
317 * The last check corresponds to a risk of changing property definition in another module, e.g. from "val" to "var".
318 *
319 * @param variableDescriptor descriptor of a considered variable
320 * @param usageModule a module with a considered usage place, or null if it's not known (not recommended)
321 * @return true if variable is stable, false otherwise
322 */
323 public static boolean isStableVariable(
324 @NotNull VariableDescriptor variableDescriptor,
325 @Nullable ModuleDescriptor usageModule
326 ) {
327 if (variableDescriptor.isVar()) return false;
328 if (variableDescriptor instanceof PropertyDescriptor) {
329 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
330 if (!isFinal(propertyDescriptor)) return false;
331 if (!hasDefaultGetter(propertyDescriptor)) return false;
332 if (!invisibleFromOtherModules(propertyDescriptor)) {
333 ModuleDescriptor declarationModule = DescriptorUtils.getContainingModule(propertyDescriptor);
334 if (usageModule == null || !usageModule.equals(declarationModule)) {
335 return false;
336 }
337 }
338 }
339 return true;
340 }
341
342 private static boolean isFinal(PropertyDescriptor propertyDescriptor) {
343 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
344 if (containingDeclaration instanceof ClassDescriptor) {
345 ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
346 if (classDescriptor.getModality().isOverridable() && propertyDescriptor.getModality().isOverridable()) return false;
347 }
348 else {
349 if (propertyDescriptor.getModality().isOverridable()) {
350 throw new IllegalStateException("Property outside a class must not be overridable: " + propertyDescriptor.getName());
351 }
352 }
353 return true;
354 }
355
356 private static boolean invisibleFromOtherModules(@NotNull DeclarationDescriptorWithVisibility descriptor) {
357 if (Visibilities.INVISIBLE_FROM_OTHER_MODULES.contains(descriptor.getVisibility())) return true;
358
359 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
360 if (!(containingDeclaration instanceof DeclarationDescriptorWithVisibility)) {
361 return false;
362 }
363
364 return invisibleFromOtherModules((DeclarationDescriptorWithVisibility) containingDeclaration);
365 }
366
367 private static boolean hasDefaultGetter(PropertyDescriptor propertyDescriptor) {
368 PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
369 return getter == null || getter.isDefault();
370 }
371 }