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    
017    package org.jetbrains.jet.lang.resolve.calls.autocasts;
018    
019    import com.google.common.collect.Lists;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.jet.lang.resolve.BindingContext;
022    import org.jetbrains.jet.lang.resolve.BindingTrace;
023    import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
024    import org.jetbrains.jet.lang.types.JetType;
025    
026    import java.util.Collections;
027    import java.util.List;
028    
029    import static org.jetbrains.jet.lang.diagnostics.Errors.AUTOCAST_IMPOSSIBLE;
030    import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
031    import static org.jetbrains.jet.lang.resolve.BindingContext.EXPRESSION_TYPE;
032    
033    public 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    }