001package daikon.chicory; 002 003import daikon.Chicory; 004import daikon.plumelib.reflection.Signatures; 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 (which includes the point string at the end) 141 * 142 * @param member reflection object for the method/constructor 143 * @param point usually "ENTER" or "EXIT" 144 */ 145 private static String methodName(Member member, String point) { 146 String fullname; 147 Class<?>[] args; 148 Class<?> declaring_class = member.getDeclaringClass(); 149 if (member instanceof Method) { 150 Method method = (Method) member; 151 fullname = declaring_class.getName() + "." + method.getName(); 152 args = method.getParameterTypes(); 153 } else { 154 Constructor<?> constructor = (Constructor<?>) member; 155 fullname = declaring_class.getName() + "." + declaring_class.getSimpleName(); 156 args = constructor.getParameterTypes(); 157 } 158 String arg_str = ""; 159 for (Class<?> arg : args) { 160 if (arg_str.length() > 0) { 161 arg_str += ", "; 162 } 163 if (arg.isArray()) { 164 arg_str += Signatures.fieldDescriptorToBinaryName(arg.getName()); 165 } else { 166 arg_str += arg.getName(); 167 } 168 } 169 String ppt_name = String.format("%s(%s):::%s", fullname, arg_str, point); 170 return ppt_name; 171 } 172 173 /** Determines if the given method should be instrumented. */ 174 protected boolean shouldInstrumentMethod(Member method) { 175 if (method == null) { // <clinit> 176 return Chicory.instrument_clinit; 177 } 178 int modifiers = method.getModifiers(); 179 if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { 180 return false; 181 } 182 return true; 183 } 184 185 /** 186 * Returns the class name of the specified class as a binary name (i.e., as the class would have 187 * been declared in Java source code, except with '$' instead of '.' separating outer and inner 188 * classes). 189 */ 190 public static @BinaryName String stdClassName(Class<?> type) { 191 return Runtime.classGetNameToBinaryName(type.getName()); 192 } 193 194 /** Escapes blanks and backslashes in names written to the decl/dtrace files. */ 195 public String escape(String str) { 196 197 // If there is nothing to escape, return the original string 198 if ((str.indexOf('\\') == -1) && (str.indexOf(' ') == -1)) { 199 return str; 200 } 201 202 str = str.replace("\\", "\\\\"); 203 str = str.replace(" ", "\\_"); 204 return str; 205 } 206}