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