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