001: package tide.classsyntax;
002:
003: import tide.project.JDocRes;
004: import java.lang.reflect.*;
005: import snow.utils.StringUtils;
006: import java.util.*;
007: import tide.editor.MainEditorFrame;
008: import tide.bytecode.*;
009:
010: /** Looks for attribute parameter names.
011: * i.e. Object.wait method signature is wait(long,int)
012: * with names: public final void wait(long timeout, int nanos)
013: * the names are NOT available through the reflection mechamism (Class.forName(..).getMethod().toString()...)
014: * but the names may be present in the bytecode (if compiled with -g, usually not the case)
015: * If not found, looks in javadoc.
016: * If not, in the source (todo)...
017: */
018: public final class AttributesParamNamesManager {
019: private static AttributesParamNamesManager instance;
020:
021: private AttributesParamNamesManager() {
022: }
023:
024: /** For Method and Constructor.
025: */
026: public List<String> getParameterNames(Member m) {
027: List<String> paramNames = new ArrayList<String>();
028:
029: // 1) try disassembled class
030: //
031: DecompiledClass.TMember tme = DecompileManager.getInstance()
032: .getDecompiledMember(m, true, false); // returns null if no arg names, no bytecode needed
033: if (tme != null) {
034: if (!tme.hasDefaultNamedArguments) {
035: List<DecompiledClass.Param> params = tme
036: .getParameters();
037: for (DecompiledClass.Param pi : params) {
038: paramNames.add(pi.name);
039: }
040: return paramNames;
041: }
042: }
043:
044: // 2) try javadoc
045: //
046: final JDocRes jdr = MainEditorFrame.instance.getActualProject()
047: .getJavaDocManager().getJavaDocFor(m);
048: if (jdr != null && jdr != JDocRes.notFound) {
049: final String jds = jdr.part;
050: if (jds.indexOf("Cannot find javadoc") >= 0)
051: return null;
052:
053: //System.out.println("HTML:"+jds);
054: int posS = jds.indexOf("</B>(");
055: if (posS < 0) {
056: System.out.println("No </B>( in " + jds);
057: new Throwable().printStackTrace();
058: return null;
059: }
060: int posE = jds.indexOf(')', posS + 5);
061: if (posE < 0) {
062: System.out.println("No ) in " + jds);
063: new Throwable().printStackTrace();
064: return null;
065: }
066:
067: String args = jds.substring(posS + 5, posE);
068: // important, otherwise, we can't split using the ","
069: args = StringUtils.balancedRemoveAll(args, "<", ">");
070: args = StringUtils.balancedRemoveAll(args, "<A", "/A>");
071: //System.out.println("Args:"+args);
072: String[] ais = args.split(",");
073: //String[] ains = new String[ais.length];
074: try {
075: for (int i = 0; i < ais.length; i++) {
076: String pni = StringUtils.keepAfterLastExcl(ais[i],
077: " ");
078: if (pni == null) {
079: System.out.println("Cannot find name in "
080: + ais[i]);
081: //paramNames.add("p"+(i+1));
082: paramNames.add(ais[i].trim());
083: } else {
084: pni = pni.trim();
085: paramNames.add(pni);
086: }
087: }
088: } catch (Exception e) {
089: System.out.println("ais=" + Arrays.toString(ais));
090: e.printStackTrace();
091: }
092: return paramNames;
093: }
094:
095: // 3) todo: try in source
096: return null;
097: }
098:
099: /** With vararg and simple names and spaces. Uses p1,...,pn if no name present.
100: * @param mapper may be null if not knowed
101: */
102: public static String createArgumentListWithNames(final Member m,
103: final List<String> argNames,
104: final TypeParametersMapper mapper,
105: final boolean withFinalModifier) {
106: if (m == null)
107: throw new NullPointerException("null member passed, an="
108: + argNames);
109:
110: final boolean vararg; // = false;
111: final Type[] paramTypes; // = null;
112:
113: if (m instanceof Method) {
114: Method me = (Method) m;
115: paramTypes = me.getGenericParameterTypes();
116: vararg = me.isVarArgs();
117: } else if (m instanceof Constructor) {
118: Constructor co = (Constructor) m;
119: paramTypes = co.getGenericParameterTypes();
120: vararg = co.isVarArgs();
121: } else {
122: throw new RuntimeException(
123: "only method and constructors here, not "
124: + m.getClass().getName());
125: }
126:
127: StringBuilder sb = new StringBuilder();
128:
129: sb.append("( "); // nice spacing for better readability
130: for (int i = 0; i < paramTypes.length; i++) {
131: final String tn;
132:
133: if (mapper != null) {
134: tn = mapper.mapType(paramTypes[i]);
135: } else {
136: tn = ClassUtils
137: .toStringTypeForCompletion(paramTypes[i]);
138: }
139:
140: /* if(tn.startsWith("class "))
141: {
142: tn = tn.substring(6);
143: }
144: else if(tn.startsWith("interface "))
145: {
146: tn = tn.substring(10);
147: }
148: // java.util.List<java.io.File> => List<File>
149: tn = SyntaxUtils.makeAllJavaNamesSimpleInText(SyntaxUtils.createReadableJavaNamesForClassNameWithArrays(tn));
150: */
151:
152: if (withFinalModifier)
153: sb.append("final ");
154:
155: //System.out.println("TN="+tn+" for '"+paramTypes[i]+"'");
156: if (vararg && i == paramTypes.length - 1) // vararg exist only at last pos.
157: {
158: sb.append(tn.substring(0, tn.length() - 2) + "...");
159: } else {
160: sb.append(tn);
161: }
162: sb.append(" ");
163: if (argNames != null && i < argNames.size()) {
164: sb.append(argNames.get(i));
165: } else {
166: // default name (ok, ok, it's defensive programming...)
167: sb.append("p" + (i + 1));
168: }
169: if (i < paramTypes.length - 1) {
170: sb.append(", ");
171: }
172: }
173: sb.append(" )");
174: return sb.toString();
175: }
176:
177: /** Just calls DecompileManager removeDecompForSources method to reset cached decomps.
178: * must be called when the souce has changed.
179: */
180: public void removeClassDecompForSources() {
181: DecompileManager.getInstance().removeDecompForSources();
182: }
183:
184: public static AttributesParamNamesManager getInstance() {
185: if (instance == null)
186: instance = new AttributesParamNamesManager();
187: return instance;
188: }
189: }
|