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.cfg.pseudocode;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.kotlin.cfg.ControlFlowProcessor;
022    import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction;
023    import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessTarget;
024    import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessValueInstruction;
025    import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.ReadValueInstruction;
026    import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.WriteValueInstruction;
027    import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.VariableDeclarationInstruction;
028    import org.jetbrains.kotlin.descriptors.VariableDescriptor;
029    import org.jetbrains.kotlin.diagnostics.Diagnostic;
030    import org.jetbrains.kotlin.psi.KtDeclaration;
031    import org.jetbrains.kotlin.psi.KtElement;
032    import org.jetbrains.kotlin.psi.KtExpression;
033    import org.jetbrains.kotlin.resolve.BindingContext;
034    import org.jetbrains.kotlin.resolve.BindingContextUtils;
035    import org.jetbrains.kotlin.resolve.BindingTrace;
036    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
037    import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.ResolvedCallUtilKt;
038    import org.jetbrains.kotlin.types.KotlinType;
039    import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice;
040    import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
041    
042    import java.util.Collection;
043    
044    public class PseudocodeUtil {
045        @NotNull
046        public static Pseudocode generatePseudocode(@NotNull KtDeclaration declaration, @NotNull final BindingContext bindingContext) {
047            BindingTrace mockTrace = new BindingTrace() {
048                @NotNull
049                @Override
050                public BindingContext getBindingContext() {
051                    return bindingContext;
052                }
053    
054                @Override
055                public <K, V> void record(WritableSlice<K, V> slice, K key, V value) {
056                }
057    
058                @Override
059                public <K> void record(WritableSlice<K, Boolean> slice, K key) {
060                }
061    
062                @Override
063                public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
064                    return bindingContext.get(slice, key);
065                }
066    
067                @NotNull
068                @Override
069                public <K, V> Collection<K> getKeys(WritableSlice<K, V> slice) {
070                    return bindingContext.getKeys(slice);
071                }
072    
073                @Nullable
074                @Override
075                public KotlinType getType(@NotNull KtExpression expression) {
076                    return bindingContext.getType(expression);
077                }
078    
079                @Override
080                public void recordType(@NotNull KtExpression expression, @Nullable KotlinType type) {
081                }
082    
083                @Override
084                public void report(@NotNull Diagnostic diagnostic) {
085                }
086            };
087            return new ControlFlowProcessor(mockTrace).generatePseudocode(declaration);
088        }
089    
090        @Nullable
091        public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull Instruction instruction, boolean onlyReference, @NotNull BindingContext bindingContext) {
092            KtElement element = null;
093            if (instruction instanceof ReadValueInstruction) {
094                element = ((ReadValueInstruction) instruction).getElement();
095            }
096            else if (instruction instanceof WriteValueInstruction) {
097                element = ((WriteValueInstruction) instruction).getLValue();
098            }
099            else if (instruction instanceof VariableDeclarationInstruction) {
100                element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
101            }
102            return BindingContextUtils.extractVariableDescriptorIfAny(bindingContext, element, onlyReference);
103        }
104    
105        // When deal with constructed object (not this) treat it like it's fully initialized
106        // Otherwise (this or access with empty receiver) access instruction should be handled as usual
107        public static boolean isThisOrNoDispatchReceiver(
108                @NotNull AccessValueInstruction instruction,
109                @NotNull BindingContext bindingContext
110        ) {
111            if (instruction.getReceiverValues().isEmpty()) {
112                return true;
113            }
114            AccessTarget accessTarget = instruction.getTarget();
115            if (accessTarget instanceof AccessTarget.BlackBox) return false;
116            assert accessTarget instanceof AccessTarget.Call :
117                    "AccessTarget.Declaration has no receivers and it's not BlackBox, so it should be Call";
118    
119            ResolvedCall<?> accessResolvedCall = ((AccessTarget.Call) accessTarget).getResolvedCall();
120            return ResolvedCallUtilKt.hasThisOrNoDispatchReceiver(accessResolvedCall, bindingContext);
121        }
122    }