001package daikon.chicory; 002 003import daikon.Chicory; 004import daikon.SignaturesUtil; 005import java.lang.reflect.Constructor; 006import java.lang.reflect.Field; 007import java.lang.reflect.Member; 008import java.lang.reflect.Method; 009import java.lang.reflect.Modifier; 010import java.util.StringJoiner; 011import org.checkerframework.checker.signature.qual.BinaryName; 012 013/** DaikonWriter is the parent class of DeclWriter and DTraceWriter. */ 014public abstract class DaikonWriter { 015 /** Controls whether modifiers and the return type are included in the decl output. */ 016 protected static final boolean no_modifiers_ppt = true; 017 018 /** Platform-dependent line separator. Should be "\n" on Unix. */ 019 public static final String lineSep = System.lineSeparator(); 020 021 protected DaikonWriter() {} 022 023 /** 024 * Determines if this field warrants an [ = val ] entry in decls file. 025 * 026 * @param field requires field != null 027 * @return true iff field warrants an [ = val ] entry in the decls files 028 */ 029 protected static boolean isStaticConstField(Field field) { 030 Class<?> type = field.getType(); 031 int mod = field.getModifiers(); 032 033 if (DaikonVariableInfo.dkconfig_constant_infer) { 034 return Modifier.isFinal(mod) && Modifier.isStatic(mod); 035 } else { 036 return Modifier.isFinal(mod) && Modifier.isStatic(mod) && type.isPrimitive(); 037 } 038 } 039 040 /** 041 * Given a method, returns the method entry program point name for Daikon. 042 * 043 * @param method non-null method 044 * @return the decorated method entry name for Daikon 045 */ 046 public static String methodEntryName(Member method) { 047 return methodName(method, daikon.FileIO.enter_suffix); 048 } 049 050 /** 051 * Given a method, returns the method entry program point name for Daikon. Used when reflection 052 * information is not available. 053 * 054 * @param fullClassName packageName.className 055 * @param types string representation of the declared types of the parameters 056 * @param name the method with modifiers and parameters, such as "public static void 057 * DataStructures.StackArTester.doNew(int size)" 058 * @param short_name just the method's name ("{@code <init>}" for constructors) 059 * @return the decorated method entry name for Daikon 060 */ 061 public static String methodEntryName( 062 String fullClassName, String[] types, String name, String short_name) { 063 return methodName(fullClassName, types, name, short_name, daikon.FileIO.enter_suffix); 064 } 065 066 /** 067 * Given a method, returns the method exit program point name for Daikon. 068 * 069 * @param method non-null method 070 * @param lineNum the line number of a return statement in the method 071 * @return the decorated method exit name for Daikon 072 */ 073 public static String methodExitName(Member method, int lineNum) { 074 return methodName(method, daikon.FileIO.exit_suffix + lineNum); 075 } 076 077 /** 078 * Given a method, returns the method exit program point name for Daikon. Used when reflection 079 * information is not available. 080 * 081 * @param fullClassName packageName.className 082 * @param types string representation of the declared types of the parameters 083 * @param name the method name with modifiers and parameters 084 * @param short_name just the method's name ("{@code <init>}" for constructors) 085 * @param lineNum the line number of a return statement in the method 086 * @return the decorated method exit name for Daikon 087 */ 088 public static String methodExitName( 089 String fullClassName, String[] types, String name, String short_name, int lineNum) { 090 return methodName(fullClassName, types, name, short_name, daikon.FileIO.exit_suffix + lineNum); 091 } 092 093 /** 094 * Constructs the program point name (which includes the point string at the end) 095 * 096 * @param fullClassName packageName.className 097 * @param types string representation of the declared types of the parameters. For example: 098 * {"int", "java.lang.Object", "float"}. 099 * @param name the method with modifiers and parameters, such as "public static void 100 * DataStructures.StackArTester.doNew(int size)" 101 * @param short_name just the method's name ("{@code <init>}" for constructors) 102 * @param point program point type/suffix such as "EXIT" or "ENTER" 103 * @return same thing as {@link #methodName(Member, String)} 104 */ 105 private static String methodName( 106 String fullClassName, String[] types, String name, String short_name, String point) { 107 108 // System.out.printf("fullclass: %s !!! name: %s !!! short_name: %s %n", 109 // fullClassName, name, short_name); 110 111 boolean isConstructor = name.equals("<init>") || name.equals(""); 112 113 if (isConstructor) { 114 // replace <init>'s with the actual class name 115 // so "public void <init>" becomes "public void StackAr" for example 116 short_name = fullClassName.substring(fullClassName.lastIndexOf('.') + 1); 117 name = name.replace("<init>", short_name); 118 } 119 120 // build up the string to go inside the parens 121 StringJoiner paramTypes = new StringJoiner(",", "(", ")"); 122 for (int i = 0; i < types.length; i++) { 123 paramTypes.add(types[i]); 124 } 125 String pptname = fullClassName + "." + short_name + paramTypes + ":::" + point; 126 127 if (Chicory.debug_ppt_names) { 128 System.out.printf("methodName1 final ppt name = '%s'%n", pptname); 129 } 130 131 // Throwable t = new Throwable("debug"); 132 // t.fillInStackTrace(); 133 // t.printStackTrace(); 134 // System.out.printf("ppt name = %s%n", pptname); 135 136 return pptname; 137 } 138 139 /** 140 * Constructs the program point name. It includes {@code point} at the end, after ":::". 141 * 142 * @param member reflection object for the method/constructor 143 * @param point usually "ENTER" or "EXIT" 144 * @return the program point name 145 */ 146 private static String methodName(Member member, String point) { 147 String fullname; 148 Class<?>[] args; 149 Class<?> declaring_class = member.getDeclaringClass(); 150 if (member instanceof Method) { 151 Method method = (Method) member; 152 fullname = declaring_class.getName() + "." + method.getName(); 153 args = method.getParameterTypes(); 154 } else { 155 Constructor<?> constructor = (Constructor<?>) member; 156 fullname = declaring_class.getName() + "." + declaring_class.getSimpleName(); 157 args = constructor.getParameterTypes(); 158 } 159 String arg_str = ""; 160 for (Class<?> arg : args) { 161 if (arg_str.length() > 0) { 162 arg_str += ", "; 163 } 164 if (arg.isArray()) { 165 arg_str += SignaturesUtil.classGetNameToBinaryName(arg.getName()); 166 } else { 167 arg_str += arg.getName(); 168 } 169 } 170 String ppt_name = String.format("%s(%s):::%s", fullname, arg_str, point); 171 return ppt_name; 172 } 173 174 /** Determines if the given method should be instrumented. */ 175 protected boolean shouldInstrumentMethod(Member method) { 176 if (method == null) { // <clinit> 177 return Chicory.instrument_clinit; 178 } 179 int modifiers = method.getModifiers(); 180 if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { 181 return false; 182 } 183 return true; 184 } 185 186 /** 187 * Returns the class name of the specified class as a binary name (i.e., as the class would have 188 * been declared in Java source code, except with '$' instead of '.' separating outer and inner 189 * classes). 190 */ 191 public static @BinaryName String stdClassName(Class<?> type) { 192 return Runtime.classGetNameToBinaryName(type.getName()); 193 } 194 195 /** Escapes blanks and backslashes in names written to the decl/dtrace files. */ 196 public String escape(String str) { 197 198 // If there is nothing to escape, return the original string 199 if ((str.indexOf('\\') == -1) && (str.indexOf(' ') == -1)) { 200 return str; 201 } 202 203 str = str.replace("\\", "\\\\"); 204 str = str.replace(" ", "\\_"); 205 return str; 206 } 207}