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.types.expressions;
018
019 import com.google.common.collect.Sets;
020 import com.intellij.openapi.util.Ref;
021 import com.intellij.psi.tree.IElementType;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
025 import org.jetbrains.kotlin.descriptors.*;
026 import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt;
027 import org.jetbrains.kotlin.incremental.KotlinLookupLocation;
028 import org.jetbrains.kotlin.lexer.KtTokens;
029 import org.jetbrains.kotlin.psi.*;
030 import org.jetbrains.kotlin.resolve.BindingContext;
031 import org.jetbrains.kotlin.resolve.BindingTrace;
032 import org.jetbrains.kotlin.resolve.DescriptorUtils;
033 import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker;
034 import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
035 import org.jetbrains.kotlin.resolve.calls.smartcasts.*;
036 import org.jetbrains.kotlin.resolve.constants.*;
037 import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
038 import org.jetbrains.kotlin.types.KotlinType;
039 import org.jetbrains.kotlin.types.TypeConstructor;
040 import org.jetbrains.kotlin.types.TypeUtils;
041 import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
042 import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
043 import org.jetbrains.kotlin.util.OperatorNameConventions;
044
045 import java.util.Collection;
046
047 import static org.jetbrains.kotlin.diagnostics.Errors.*;
048 import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
049 import static org.jetbrains.kotlin.types.TypeUtils.*;
050
051 public class DataFlowAnalyzer {
052
053 private final Iterable<AdditionalTypeChecker> additionalTypeCheckers;
054 private final ConstantExpressionEvaluator constantExpressionEvaluator;
055 private final KotlinBuiltIns builtIns;
056 private final SmartCastManager smartCastManager;
057 private final ExpressionTypingFacade facade;
058
059 public DataFlowAnalyzer(
060 @NotNull Iterable<AdditionalTypeChecker> additionalTypeCheckers,
061 @NotNull ConstantExpressionEvaluator constantExpressionEvaluator,
062 @NotNull KotlinBuiltIns builtIns,
063 @NotNull SmartCastManager smartCastManager,
064 @NotNull ExpressionTypingFacade facade
065 ) {
066 this.additionalTypeCheckers = additionalTypeCheckers;
067 this.constantExpressionEvaluator = constantExpressionEvaluator;
068 this.builtIns = builtIns;
069 this.smartCastManager = smartCastManager;
070 this.facade = facade;
071 }
072
073 // NB: use this method only for functions from 'Any'
074 @Nullable
075 private static FunctionDescriptor getOverriddenDescriptorFromClass(@NotNull FunctionDescriptor descriptor) {
076 if (descriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) return descriptor;
077 Collection<? extends FunctionDescriptor> overriddenDescriptors = descriptor.getOverriddenDescriptors();
078 if (overriddenDescriptors.isEmpty()) return descriptor;
079 for (FunctionDescriptor overridden : overriddenDescriptors) {
080 DeclarationDescriptor containingDeclaration = overridden.getContainingDeclaration();
081 if (DescriptorUtils.isClass(containingDeclaration) || DescriptorUtils.isObject(containingDeclaration)) {
082 // Exactly one class should exist in the list
083 return getOverriddenDescriptorFromClass(overridden);
084 }
085 }
086 return null;
087 }
088
089 private static boolean typeHasOverriddenEquals(@NotNull KotlinType type, @NotNull KtElement lookupElement) {
090 Collection<SimpleFunctionDescriptor> members = type.getMemberScope().getContributedFunctions(
091 OperatorNameConventions.EQUALS, new KotlinLookupLocation(lookupElement));
092 for (FunctionDescriptor member : members) {
093 KotlinType returnType = member.getReturnType();
094 if (returnType == null || !KotlinBuiltIns.isBoolean(returnType)) continue;
095 if (member.getValueParameters().size() != 1) continue;
096 KotlinType parameterType = member.getValueParameters().iterator().next().getType();
097 if (!KotlinBuiltIns.isNullableAny(parameterType)) continue;
098 FunctionDescriptor fromSuperClass = getOverriddenDescriptorFromClass(member);
099 if (fromSuperClass == null) return false;
100 ClassifierDescriptor superClassDescriptor = (ClassifierDescriptor) fromSuperClass.getContainingDeclaration();
101 // We should have override fun in class other than Any (to prove unknown behaviour)
102 return !KotlinBuiltIns.isAnyOrNullableAny(superClassDescriptor.getDefaultType());
103 }
104 return false;
105 }
106
107 // Returns true if we can prove that 'type' has equals method from 'Any' base type
108 public static boolean typeHasEqualsFromAny(@NotNull KotlinType type, @NotNull KtElement lookupElement) {
109 TypeConstructor constructor = type.getConstructor();
110 // Subtypes can override equals for non-final types
111 if (!constructor.isFinal()) return false;
112 // check whether 'equals' is overriden
113 return !typeHasOverriddenEquals(type, lookupElement);
114 }
115
116 @NotNull
117 public DataFlowInfo extractDataFlowInfoFromCondition(
118 @Nullable final KtExpression condition,
119 final boolean conditionValue,
120 final ExpressionTypingContext context
121 ) {
122 if (condition == null) return context.dataFlowInfo;
123 final Ref<DataFlowInfo> result = new Ref<DataFlowInfo>(null);
124 condition.accept(new KtVisitorVoid() {
125 @Override
126 public void visitIsExpression(@NotNull KtIsExpression expression) {
127 if (conditionValue && !expression.isNegated() || !conditionValue && expression.isNegated()) {
128 result.set(context.trace.get(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression));
129 }
130 }
131
132 @Override
133 public void visitBinaryExpression(@NotNull KtBinaryExpression expression) {
134 IElementType operationToken = expression.getOperationToken();
135 if (OperatorConventions.BOOLEAN_OPERATIONS.containsKey(operationToken)) {
136 DataFlowInfo dataFlowInfo = extractDataFlowInfoFromCondition(expression.getLeft(), conditionValue, context);
137 KtExpression expressionRight = expression.getRight();
138 if (expressionRight != null) {
139 boolean and = operationToken == KtTokens.ANDAND;
140 DataFlowInfo rightInfo = extractDataFlowInfoFromCondition(
141 expressionRight, conditionValue,
142 and == conditionValue ? context.replaceDataFlowInfo(dataFlowInfo) : context
143 );
144 if (and == conditionValue) { // this means: and && conditionValue || !and && !conditionValue
145 dataFlowInfo = dataFlowInfo.and(rightInfo);
146 }
147 else {
148 dataFlowInfo = dataFlowInfo.or(rightInfo);
149 }
150 }
151 result.set(dataFlowInfo);
152 }
153 else {
154 DataFlowInfo expressionFlowInfo = facade.getTypeInfo(expression, context).getDataFlowInfo();
155 KtExpression left = expression.getLeft();
156 if (left == null) return;
157 KtExpression right = expression.getRight();
158 if (right == null) return;
159
160 KotlinType lhsType = context.trace.getBindingContext().getType(left);
161 if (lhsType == null) return;
162 KotlinType rhsType = context.trace.getBindingContext().getType(right);
163 if (rhsType == null) return;
164
165 DataFlowValue leftValue = DataFlowValueFactory.createDataFlowValue(left, lhsType, context);
166 DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rhsType, context);
167
168 Boolean equals = null;
169 if (operationToken == KtTokens.EQEQ || operationToken == KtTokens.EQEQEQ) {
170 equals = true;
171 }
172 else if (operationToken == KtTokens.EXCLEQ || operationToken == KtTokens.EXCLEQEQEQ) {
173 equals = false;
174 }
175 if (equals != null) {
176 if (equals == conditionValue) { // this means: equals && conditionValue || !equals && !conditionValue
177 boolean byIdentity = operationToken == KtTokens.EQEQEQ || operationToken == KtTokens.EXCLEQEQEQ ||
178 typeHasEqualsFromAny(lhsType, condition);
179 result.set(context.dataFlowInfo.equate(leftValue, rightValue, byIdentity).and(expressionFlowInfo));
180 }
181 else {
182 result.set(context.dataFlowInfo.disequate(leftValue, rightValue).and(expressionFlowInfo));
183 }
184 }
185 else {
186 result.set(expressionFlowInfo);
187 }
188 }
189 }
190
191 @Override
192 public void visitUnaryExpression(@NotNull KtUnaryExpression expression) {
193 IElementType operationTokenType = expression.getOperationReference().getReferencedNameElementType();
194 if (operationTokenType == KtTokens.EXCL) {
195 KtExpression baseExpression = expression.getBaseExpression();
196 if (baseExpression != null) {
197 result.set(extractDataFlowInfoFromCondition(baseExpression, !conditionValue, context));
198 }
199 }
200 else {
201 visitExpression(expression);
202 }
203 }
204
205 @Override
206 public void visitExpression(@NotNull KtExpression expression) {
207 // In fact, everything is taken from trace here
208 result.set(facade.getTypeInfo(expression, context).getDataFlowInfo());
209 }
210
211 @Override
212 public void visitParenthesizedExpression(@NotNull KtParenthesizedExpression expression) {
213 KtExpression body = expression.getExpression();
214 if (body != null) {
215 body.accept(this);
216 }
217 }
218 });
219 if (result.get() == null) {
220 return context.dataFlowInfo;
221 }
222 return context.dataFlowInfo.and(result.get());
223 }
224
225 @Nullable
226 public KotlinType checkType(@Nullable KotlinType expressionType, @NotNull KtExpression expression, @NotNull ResolutionContext context) {
227 return checkType(expressionType, expression, context, null);
228 }
229
230 @NotNull
231 public KotlinTypeInfo checkType(@NotNull KotlinTypeInfo typeInfo, @NotNull KtExpression expression, @NotNull ResolutionContext context) {
232 return typeInfo.replaceType(checkType(typeInfo.getType(), expression, context));
233 }
234
235 @NotNull
236 private KotlinType checkTypeInternal(
237 @NotNull KotlinType expressionType,
238 @NotNull KtExpression expression,
239 @NotNull ResolutionContext c,
240 @NotNull Ref<Boolean> hasError
241 ) {
242 if (noExpectedType(c.expectedType) || !c.expectedType.getConstructor().isDenotable() ||
243 KotlinTypeChecker.DEFAULT.isSubtypeOf(expressionType, c.expectedType)) {
244 return expressionType;
245 }
246
247 if (expression instanceof KtConstantExpression) {
248 ConstantValue<?> constantValue = constantExpressionEvaluator.evaluateToConstantValue(expression, c.trace, c.expectedType);
249 boolean error = new CompileTimeConstantChecker(c, builtIns, true)
250 .checkConstantExpressionType(constantValue, (KtConstantExpression) expression, c.expectedType);
251 hasError.set(error);
252 return expressionType;
253 }
254
255 if (expression instanceof KtWhenExpression) {
256 // No need in additional check because type mismatch is already reported for entries
257 return expressionType;
258 }
259
260 SmartCastResult castResult = checkPossibleCast(expressionType, expression, c);
261 if (castResult != null) return castResult.getResultType();
262
263 if (!DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection(c, expression, c.expectedType, expressionType)) {
264 c.trace.report(TYPE_MISMATCH.on(expression, c.expectedType, expressionType));
265 }
266 hasError.set(true);
267 return expressionType;
268 }
269
270 @Nullable
271 public KotlinType checkType(
272 @Nullable KotlinType expressionType,
273 @NotNull KtExpression expressionToCheck,
274 @NotNull ResolutionContext c,
275 @Nullable Ref<Boolean> hasError
276 ) {
277 if (hasError == null) {
278 hasError = Ref.create(false);
279 }
280 else {
281 hasError.set(false);
282 }
283
284 KtExpression expression = KtPsiUtil.safeDeparenthesize(expressionToCheck);
285 recordExpectedType(c.trace, expression, c.expectedType);
286
287 if (expressionType == null) return null;
288
289 KotlinType result = checkTypeInternal(expressionType, expression, c, hasError);
290 if (Boolean.FALSE.equals(hasError.get())) {
291 for (AdditionalTypeChecker checker : additionalTypeCheckers) {
292 checker.checkType(expression, expressionType, result, c);
293 }
294 }
295
296 return result;
297 }
298
299 @Nullable
300 public static SmartCastResult checkPossibleCast(
301 @NotNull KotlinType expressionType,
302 @NotNull KtExpression expression,
303 @NotNull ResolutionContext c
304 ) {
305 DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, expressionType, c);
306
307 return SmartCastManager.Companion.checkAndRecordPossibleCast(dataFlowValue, c.expectedType, expression, c, null, false);
308 }
309
310 public void recordExpectedType(@NotNull BindingTrace trace, @NotNull KtExpression expression, @NotNull KotlinType expectedType) {
311 if (expectedType != NO_EXPECTED_TYPE) {
312 KotlinType normalizeExpectedType = expectedType == UNIT_EXPECTED_TYPE ? builtIns.getUnitType() : expectedType;
313 trace.record(BindingContext.EXPECTED_EXPRESSION_TYPE, expression, normalizeExpectedType);
314 }
315 }
316
317 @Nullable
318 public KotlinType checkStatementType(@NotNull KtExpression expression, @NotNull ResolutionContext context) {
319 if (!noExpectedType(context.expectedType) && !KotlinBuiltIns.isUnit(context.expectedType) && !context.expectedType.isError()) {
320 context.trace.report(EXPECTED_TYPE_MISMATCH.on(expression, context.expectedType));
321 return null;
322 }
323 return builtIns.getUnitType();
324 }
325
326 @NotNull
327 public static KotlinTypeInfo illegalStatementType(@NotNull KtExpression expression, @NotNull ExpressionTypingContext context, @NotNull ExpressionTypingInternals facade) {
328 facade.checkStatementType(
329 expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT));
330 context.trace.report(EXPRESSION_EXPECTED.on(expression, expression));
331 return TypeInfoFactoryKt.noTypeInfo(context);
332 }
333
334 @NotNull
335 public static Collection<KotlinType> getAllPossibleTypes(
336 @NotNull KtExpression expression,
337 @NotNull DataFlowInfo dataFlowInfo,
338 @NotNull KotlinType type,
339 @NotNull ResolutionContext c
340 ) {
341 DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, c);
342 Collection<KotlinType> possibleTypes = Sets.newHashSet(type);
343 possibleTypes.addAll(dataFlowInfo.getPredictableTypes(dataFlowValue));
344 return possibleTypes;
345 }
346
347 @NotNull
348 public KotlinTypeInfo createCheckedTypeInfo(
349 @Nullable KotlinType type,
350 @NotNull ResolutionContext<?> context,
351 @NotNull KtExpression expression
352 ) {
353 return checkType(TypeInfoFactoryKt.createTypeInfo(type, context), expression, context);
354 }
355
356 @NotNull
357 public KotlinTypeInfo createCompileTimeConstantTypeInfo(
358 @NotNull CompileTimeConstant<?> value,
359 @NotNull KtExpression expression,
360 @NotNull ExpressionTypingContext context
361 ) {
362 KotlinType expressionType;
363 if (value instanceof IntegerValueTypeConstant) {
364 IntegerValueTypeConstant integerValueTypeConstant = (IntegerValueTypeConstant) value;
365 if (context.contextDependency == INDEPENDENT) {
366 expressionType = integerValueTypeConstant.getType(context.expectedType);
367 constantExpressionEvaluator.updateNumberType(expressionType, expression, context.statementFilter, context.trace);
368 }
369 else {
370 expressionType = integerValueTypeConstant.getUnknownIntegerType();
371 }
372 }
373 else {
374 expressionType = ((TypedCompileTimeConstant<?>) value).getType();
375 }
376
377 return createCheckedTypeInfo(expressionType, context, expression);
378 }
379 }