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 }