001package daikon.chicory; 002 003import java.util.EnumSet; 004import java.util.Iterator; 005import java.util.List; 006import java.util.StringJoiner; 007 008/** 009 * The StringInfo class is a subtype of DaikonVariableInfo used for variable types that can be 010 * converted into strings (.toString()). 011 */ 012public class StringInfo extends DaikonVariableInfo { 013 public StringInfo( 014 String theName, String typeName, String repTypeName, String receiverName, boolean arr) { 015 super(theName, typeName, repTypeName, arr); 016 017 function_args = receiverName; 018 } 019 020 @Override 021 public Object getMyValFromParentVal(Object value) { 022 if ((value == null) || (value instanceof NonsensicalObject)) { 023 return NonsensicalObject.getInstance(); 024 } 025 return value; 026 } 027 028 /** Returns a String that contains a string representation of val, used for dtrace information. */ 029 @Override 030 public String getDTraceValueString(Object val) { 031 if (isArray) { 032 List<?> valAsList = (List<?>) val; 033 return getStringList(valAsList); 034 } else { 035 return getValueStringNonArr(val); 036 } 037 } 038 039 /** 040 * Returns a space-separated String of the elements in theValues. If theValues is null, returns 041 * "null." If theValues is nonsensical, returns "nonsensical". Also contains the modbit, on a 042 * separate line. 043 * 044 * @param theValues a list of values, each is a String or NonsensicalObject or NonsensicalList 045 * @return a space-separated String of the elements in theValues 046 */ 047 public static String getStringList(List<?> theValues) { 048 if (theValues == null) { 049 // buf.append("null"); 050 return "null" + DaikonWriter.lineSep + "1"; 051 } 052 053 // assert !NonsensicalList.isNonsensicalList (theValues); 054 if (NonsensicalList.isNonsensicalList(theValues) 055 // How can this happen, given the declared type of theValues? 056 // || theValues instanceof NonsensicalObject 057 ) { 058 // buf.append("nonsensical"); 059 return "nonsensical" + DaikonWriter.lineSep + "2"; 060 } 061 062 StringJoiner buf = new StringJoiner(" ", "[", "]"); 063 064 for (Iterator<?> iter = theValues.iterator(); iter.hasNext(); ) { 065 Object str = iter.next(); 066 067 if (str == null) { 068 buf.add("null"); 069 } else if (str instanceof String) { 070 buf.add("\"" + encodeString((String) str) + "\""); 071 } else if (str instanceof NonsensicalObject || str instanceof NonsensicalList) { 072 buf.add("nonsensical"); 073 } else { 074 throw new Error("Impossible"); 075 } 076 } 077 078 if (NonsensicalList.isNonsensicalList(theValues)) { 079 return buf.toString() + DaikonWriter.lineSep + "2"; 080 } else { 081 return buf.toString() + DaikonWriter.lineSep + "1"; 082 } 083 } 084 085 /** Similar to showStringList, but used for non-array objects. */ 086 public String getValueStringNonArr(Object val) { 087 String retString; 088 089 if (val == null) { 090 retString = "null"; 091 } else if (val instanceof NonsensicalObject) { 092 retString = "nonsensical"; 093 } else { 094 retString = getString((String) val); 095 } 096 retString += DaikonWriter.lineSep; 097 098 if (val instanceof NonsensicalObject) { 099 retString += "2"; 100 } else { 101 retString += "1"; 102 } 103 104 return retString; 105 } 106 107 // encodes a string: surrounds in quotes and removes line breaks 108 private String getString(String stringRef) { 109 return ("\"" + encodeString(stringRef) + "\""); 110 } 111 112 // removes endlines in string 113 private static String encodeString(String input) { 114 return Runtime.quote(input); 115 } 116 117 /** toString is a function. */ 118 @Override 119 public VarKind get_var_kind() { 120 return VarKind.FUNCTION; 121 } 122 123 /** Returns the name of this function. */ 124 @Override 125 public String get_relative_name() { 126 return "toString()"; 127 } 128 129 @Override 130 public EnumSet<VarFlags> get_var_flags() { 131 EnumSet<VarFlags> flags = super.get_var_flags(); 132 flags.add(VarFlags.SYNTHETIC); 133 flags.add(VarFlags.TO_STRING); 134 return flags; 135 } 136}