001/*
002 * Copyright 2010-2013 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
017package org.jetbrains.jet.lang.resolve.calls.autocasts;
018
019import com.google.common.collect.Lists;
020import org.jetbrains.annotations.NotNull;
021import org.jetbrains.jet.lang.resolve.BindingContext;
022import org.jetbrains.jet.lang.resolve.BindingTrace;
023import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
024import org.jetbrains.jet.lang.types.JetType;
025
026import java.util.Collections;
027import java.util.List;
028
029import static org.jetbrains.jet.lang.diagnostics.Errors.AUTOCAST_IMPOSSIBLE;
030import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
031import static org.jetbrains.jet.lang.resolve.BindingContext.EXPRESSION_TYPE;
032
033public class AutoCastUtils {
034
035    private AutoCastUtils() {}
036
037    /**
038     * @return variants @param receiverToCast may be cast to according to @param dataFlowInfo, @param receiverToCast itself is NOT included
039     */
040    public static List<ReceiverValue> getAutoCastVariants(
041            @NotNull final BindingContext bindingContext,
042            @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverValue receiverToCast
043    ) {
044        return receiverToCast.accept(new ReceiverValueVisitor<List<ReceiverValue>, Object>() {
045            @Override
046            public List<ReceiverValue> visitNoReceiver(ReceiverValue noReceiver, Object data) {
047                return Collections.emptyList();
048            }
049
050            @Override
051            public List<ReceiverValue> visitTransientReceiver(TransientReceiver receiver, Object data) {
052                return Collections.emptyList();
053            }
054
055            @Override
056            public List<ReceiverValue> visitExtensionReceiver(ExtensionReceiver receiver, Object data) {
057                return castThis(dataFlowInfo, receiver);
058            }
059
060            @Override
061            public List<ReceiverValue> visitClassReceiver(ClassReceiver receiver, Object data) {
062                return castThis(dataFlowInfo, receiver);
063            }
064
065            @Override
066            public List<ReceiverValue> visitScriptReceiver(ScriptReceiver receiver, Object data) {
067                return Collections.emptyList();
068            }
069
070            @Override
071            public List<ReceiverValue> visitExpressionReceiver(ExpressionReceiver receiver, Object data) {
072                DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(receiver.getExpression(), receiver.getType(),
073                                                                                                bindingContext);
074                List<ReceiverValue> result = Lists.newArrayList();
075                for (JetType possibleType : dataFlowInfo.getPossibleTypes(dataFlowValue)) {
076                    result.add(new AutoCastReceiver(receiver, possibleType, dataFlowValue.isStableIdentifier()));
077                }
078                return result;
079            }
080        }, null);
081    }
082
083    private static List<ReceiverValue> castThis(@NotNull DataFlowInfo dataFlowInfo, @NotNull ThisReceiver receiver) {
084        assert receiver.exists();
085        List<ReceiverValue> result = Lists.newArrayList();
086        for (JetType possibleType : dataFlowInfo.getPossibleTypes(DataFlowValueFactory.INSTANCE.createDataFlowValue(receiver))) {
087            result.add(new AutoCastReceiver(receiver, possibleType, true));
088        }
089        return result;
090    }
091
092    public static void recordAutoCastIfNecessary(ReceiverValue receiver, @NotNull BindingTrace trace) {
093        if (receiver instanceof AutoCastReceiver) {
094            AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver;
095            ReceiverValue original = autoCastReceiver.getOriginal();
096            if (original instanceof ExpressionReceiver) {
097                ExpressionReceiver expressionReceiver = (ExpressionReceiver) original;
098                if (autoCastReceiver.canCast()) {
099                    trace.record(AUTOCAST, expressionReceiver.getExpression(), autoCastReceiver.getType());
100                    trace.record(EXPRESSION_TYPE, expressionReceiver.getExpression(), autoCastReceiver.getType());
101                }
102                else {
103                    trace.report(AUTOCAST_IMPOSSIBLE.on(expressionReceiver.getExpression(), autoCastReceiver.getType(), expressionReceiver.getExpression().getText()));
104                }
105            }
106            else {
107                assert autoCastReceiver.canCast() : "A non-expression receiver must always be autocastabe: " + original;
108            }
109        }
110    }
111}