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