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