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