001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 2003 Jerome Miecznikowski
003: * Copyright (C) 2004-2005 Nomair A. Naeem
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the
017: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
018: * Boston, MA 02111-1307, USA.
019: */
020:
021: package soot.dava;
022:
023: import java.io.PrintWriter;
024: import java.util.ArrayList;
025: import java.util.Iterator;
026: import java.util.List;
027: import soot.Body;
028: import soot.BooleanType;
029: import soot.ByteType;
030: import soot.CharType;
031: import soot.DoubleType;
032: import soot.FloatType;
033: import soot.G;
034: import soot.IntType;
035: import soot.LongType;
036: import soot.Modifier;
037: import soot.RefType;
038: import soot.Scene;
039: import soot.ShortType;
040: import soot.Singletons;
041: import soot.SootClass;
042: import soot.SootField;
043: import soot.SootMethod;
044: import soot.Type;
045: import soot.UnitPrinter;
046: import soot.dava.internal.AST.ASTNode;
047: import soot.dava.toolkits.base.renamer.RemoveFullyQualifiedName;
048: import soot.options.Options;
049: import soot.tagkit.DoubleConstantValueTag;
050: import soot.tagkit.FloatConstantValueTag;
051: import soot.tagkit.IntegerConstantValueTag;
052: import soot.tagkit.LongConstantValueTag;
053: import soot.tagkit.StringConstantValueTag;
054: import soot.tagkit.Tag;
055: import soot.util.Chain;
056: import soot.util.IterableSet;
057:
058: public class DavaPrinter {
059: public DavaPrinter(Singletons.Global g) {
060: }
061:
062: public static DavaPrinter v() {
063: return G.v().soot_dava_DavaPrinter();
064: }
065:
066: private void printStatementsInBody(Body body,
067: java.io.PrintWriter out) {
068:
069: if (Options.v().verbose())
070: System.out
071: .println("Printing " + body.getMethod().getName());
072:
073: Chain units = ((DavaBody) body).getUnits();
074:
075: if (units.size() != 1) {
076: throw new RuntimeException(
077: "DavaBody AST doesn't have single root.");
078: }
079:
080: UnitPrinter up = new DavaUnitPrinter((DavaBody) body);
081: ((ASTNode) units.getFirst()).toString(up);
082: out.print(up.toString());
083: }
084:
085: public void printTo(SootClass cl, PrintWriter out) {
086:
087: //IterableSet packagesUsed = new IterableSet();
088: IterableSet importList = new IterableSet();
089: {
090: String curPackage = cl.getJavaPackageName();
091:
092: if (!curPackage.equals("")) {
093: out.println("package " + curPackage + ";");
094: out.println();
095: }
096:
097: if (cl.hasSuperclass()) {
098: SootClass super Class = cl.getSuperclass();
099: importList.add(super Class.toString());
100: //packagesUsed.add(superClass.getJavaPackageName());
101: }
102:
103: Iterator interfaceIt = cl.getInterfaces().iterator();
104: while (interfaceIt.hasNext()) {
105: String interfacePackage = ((SootClass) interfaceIt
106: .next()).toString();
107:
108: if (!importList.contains(interfacePackage))
109: importList.add(interfacePackage);
110:
111: //if (!packagesUsed.contains(interfacePackage))
112: // packagesUsed.add(interfacePackage);
113: }
114:
115: Iterator methodIt = cl.methodIterator();
116: while (methodIt.hasNext()) {
117: SootMethod dm = (SootMethod) methodIt.next();
118:
119: if (dm.hasActiveBody()) {
120: //packagesUsed = packagesUsed.union(((DavaBody) dm.getActiveBody()).get_PackagesUsed());
121: importList = importList.union(((DavaBody) dm
122: .getActiveBody()).getImportList());
123: }
124:
125: Iterator<SootClass> eit = dm.getExceptions().iterator();
126: while (eit.hasNext()) {
127: String thrownPackage = eit.next().toString();
128: if (!importList.contains(thrownPackage))
129: importList.add(thrownPackage);
130:
131: //if (!packagesUsed.contains(thrownPackage))
132: // packagesUsed.add(thrownPackage);
133: }
134:
135: Iterator pit = dm.getParameterTypes().iterator();
136: while (pit.hasNext()) {
137: Type t = (Type) pit.next();
138:
139: if (t instanceof RefType) {
140: String paramPackage = ((RefType) t)
141: .getSootClass().toString();
142:
143: if (!importList.contains(paramPackage))
144: importList.add(paramPackage);
145:
146: //if (packagesUsed.contains(paramPackage) == false)
147: // packagesUsed.add(paramPackage);
148: }
149: }
150:
151: Type t = dm.getReturnType();
152: if (t instanceof RefType) {
153: String returnPackage = ((RefType) t).getSootClass()
154: .toString();
155:
156: if (!importList.contains(returnPackage))
157: importList.add(returnPackage);
158:
159: //if (packagesUsed.contains(returnPackage) == false)
160: // packagesUsed.add(returnPackage);
161: }
162: }
163:
164: Iterator fieldIt = cl.getFields().iterator();
165: while (fieldIt.hasNext()) {
166: SootField f = (SootField) fieldIt.next();
167:
168: if (f.isPhantom())
169: continue;
170:
171: Type t = f.getType();
172:
173: if (t instanceof RefType) {
174: String fieldPackage = ((RefType) t).getSootClass()
175: .toString();
176:
177: if (!importList.contains(fieldPackage))
178: importList.add(fieldPackage);
179: }
180: }
181:
182: Iterator pit = importList.iterator();
183: List toImport = new ArrayList();
184: while (pit.hasNext()) {
185: /*
186: * dont import any file which has currentPackage.className
187: * dont import any file which starts with java.lang
188: */
189: String temp = (String) pit.next();
190: //System.out.println("temp is "+temp);
191: if (temp.indexOf("java.lang") > -1) {
192: //problem is that we need to import sub packages java.lang.ref
193: //for instance if the type is java.lang.ref.WeakReference
194: String tempClassName = RemoveFullyQualifiedName
195: .getClassName(temp);
196: if (temp.equals("java.lang." + tempClassName)) {
197: //System.out.println("temp was not printed as it belongs to java.lang");
198: continue;
199: }
200: }
201:
202: if (curPackage.length() > 0
203: && temp.indexOf(curPackage) > -1) {
204: //System.out.println("here "+temp);
205: continue;
206: }
207:
208: if (cl.toString().equals(temp))
209: continue;
210:
211: //System.out.println("printing"+);
212: toImport.add(temp);
213:
214: }
215:
216: /*
217: * Check that we are not importing two classes with the same last name
218: * If yes then remove explicit import and import the whole package
219: * else output explicit import statement
220: */
221: Iterator it = toImport.iterator();
222: while (it.hasNext()) {
223: String temp = (String) it.next();
224: if (RemoveFullyQualifiedName.containsMultiple(toImport
225: .iterator(), temp, null)) {
226: //there are atleast two imports with this className
227: //import package add *
228: if (temp.lastIndexOf('.') > -1) {
229: temp = temp.substring(0, temp.lastIndexOf('.'));
230: out.println("import " + temp + ".*;");
231: } else
232: throw new DecompilationException(
233: "Cant find the DOT . for fullyqualified name");
234: } else {
235: if (temp.lastIndexOf('.') == -1) {
236: //dot not found this is a class belonging to this package so dont add
237: } else
238: out.println("import " + temp + ";");
239: }
240: }
241: boolean addNewLine = false;
242: addNewLine = true;
243:
244: // out.println("import " + temp + ";");
245:
246: if (addNewLine)
247: out.println();
248:
249: /*if (!packagesUsed.isEmpty())
250: out.println();
251:
252: packagesUsed.add("java.lang");
253: packagesUsed.add(curPackage);
254: */
255: Dava.v().set_CurrentPackageContext(importList);
256: //Dava.v().set_CurrentPackageContext(packagesUsed);
257: Dava.v().set_CurrentPackage(curPackage);
258: }
259:
260: // Print class name + modifiers
261: {
262: String classPrefix = "";
263:
264: classPrefix = classPrefix + " "
265: + Modifier.toString(cl.getModifiers());
266: classPrefix = classPrefix.trim();
267:
268: if (!cl.isInterface()) {
269: classPrefix = classPrefix + " class";
270: classPrefix = classPrefix.trim();
271: }
272:
273: out.print(classPrefix + " " + cl.getShortJavaStyleName());
274: }
275:
276: // Print extension
277: if (cl.hasSuperclass()
278: && !(cl.getSuperclass().getName()
279: .equals("java.lang.Object"))) {
280:
281: String super ClassName = cl.getSuperclass().getName();
282:
283: //Nomair Naeem 8th Feb 2006
284: //also check if the super class name is not a fully qualified
285: //name. in which case if the package is imported no need for
286: //the long name
287:
288: super ClassName = RemoveFullyQualifiedName.getReducedName(
289: importList, super ClassName, cl.getType());
290: out.print(" extends " + super ClassName + "");
291: }
292:
293: // Print interfaces
294: {
295: Iterator interfaceIt = cl.getInterfaces().iterator();
296:
297: if (interfaceIt.hasNext()) {
298: if (cl.isInterface())
299: out.print(" extends ");
300: else
301: out.print(" implements ");
302:
303: out.print(""
304: + ((SootClass) interfaceIt.next()).getName()
305: + "");
306:
307: while (interfaceIt.hasNext())
308: out.print(", "
309: + ((SootClass) interfaceIt.next())
310: .getName() + "");
311: }
312: }
313:
314: out.println();
315: out.println("{");
316:
317: // Print fields
318: {
319: Iterator fieldIt = cl.getFields().iterator();
320: if (fieldIt.hasNext()) {
321: while (fieldIt.hasNext()) {
322: SootField f = (SootField) fieldIt.next();
323:
324: if (f.isPhantom())
325: continue;
326:
327: String declaration = null;
328:
329: Type fieldType = f.getType();
330:
331: String qualifiers = Modifier.toString(f
332: .getModifiers())
333: + " ";
334:
335: qualifiers += RemoveFullyQualifiedName
336: .getReducedName(importList, fieldType
337: .toString(), fieldType);
338:
339: qualifiers = qualifiers.trim();
340:
341: if (qualifiers.equals(""))
342: declaration = Scene.v().quotedNameOf(
343: f.getName());
344: else
345: declaration = qualifiers + " "
346: + Scene.v().quotedNameOf(f.getName())
347: + "";
348:
349: if (f.isFinal() && f.isStatic()) {
350:
351: if (fieldType instanceof DoubleType
352: && f.hasTag("DoubleConstantValueTag")) {
353:
354: double val = ((DoubleConstantValueTag) f
355: .getTag("DoubleConstantValueTag"))
356: .getDoubleValue();
357: out.println(" " + declaration + " = "
358: + val + ";");
359:
360: } else if (fieldType instanceof FloatType
361: && f.hasTag("FloatConstantValueTag")) {
362:
363: float val = ((FloatConstantValueTag) f
364: .getTag("FloatConstantValueTag"))
365: .getFloatValue();
366: out.println(" " + declaration + " = "
367: + val + "f;");
368:
369: } else if (fieldType instanceof LongType
370: && f.hasTag("LongConstantValueTag")) {
371:
372: long val = ((LongConstantValueTag) f
373: .getTag("LongConstantValueTag"))
374: .getLongValue();
375: out.println(" " + declaration + " = "
376: + val + "l;");
377:
378: } else if (fieldType instanceof CharType
379: && f.hasTag("IntegerConstantValueTag")) {
380:
381: int val = ((IntegerConstantValueTag) f
382: .getTag("IntegerConstantValueTag"))
383: .getIntValue();
384: out.println(" " + declaration + " = '"
385: + ((char) val) + "';");
386:
387: } else if (fieldType instanceof BooleanType
388: && f.hasTag("IntegerConstantValueTag")) {
389:
390: int val = ((IntegerConstantValueTag) f
391: .getTag("IntegerConstantValueTag"))
392: .getIntValue();
393:
394: if (val == 0)
395: out.println(" " + declaration
396: + " = false;");
397: else
398: out.println(" " + declaration
399: + " = true;");
400:
401: } else if ((fieldType instanceof IntType
402: || fieldType instanceof ByteType || fieldType instanceof ShortType)
403: && f.hasTag("IntegerConstantValueTag")) {
404:
405: int val = ((IntegerConstantValueTag) f
406: .getTag("IntegerConstantValueTag"))
407: .getIntValue();
408: out.println(" " + declaration + " = "
409: + val + ";");
410:
411: } else if (f.hasTag("StringConstantValueTag")) {
412:
413: String val = ((StringConstantValueTag) f
414: .getTag("StringConstantValueTag"))
415: .getStringValue();
416: out.println(" " + declaration + " = \""
417: + val + "\";");
418:
419: } else {
420: // System.out.println("Couldnt find type of
421: // field"+f.getDeclaration());
422: out.println(" " + declaration + ";");
423: }
424: } // field is static final
425: else {
426: out.println(" " + declaration + ";");
427: }
428: }
429: }
430: }
431:
432: // Print methods
433: {
434: Iterator methodIt = cl.methodIterator();
435:
436: if (methodIt.hasNext()) {
437: if (cl.getMethodCount() != 0)
438: out.println();
439:
440: while (methodIt.hasNext()) {
441: SootMethod method = (SootMethod) methodIt.next();
442:
443: if (method.isPhantom())
444: continue;
445:
446: if (!Modifier.isAbstract(method.getModifiers())
447: && !Modifier
448: .isNative(method.getModifiers())) {
449: if (!method.hasActiveBody())
450: throw new RuntimeException("method "
451: + method.getName()
452: + " has no active body!");
453: else
454: printTo(method.getActiveBody(), out);
455:
456: if (methodIt.hasNext())
457: out.println();
458: } else {
459: //if method is abstract then print the declaration
460: out.print(" ");
461: out.print(method.getDavaDeclaration());
462: out.println(";");
463:
464: if (methodIt.hasNext())
465: out.println();
466: }
467: }
468: }
469: }
470:
471: /*
472: * January 23rd, 2006
473: * In trying to handle the suepr class problem we need to introduce an inner class
474: * Instead of creating a data structure for it we are right now just going to print it in the form
475: * of a string
476: *
477: * It would be interesting to later have an internal inner class structure so that we could
478: * decompile inner classes into inner classes
479: */
480:
481: if (G.v().SootClassNeedsDavaSuperHandlerClass.contains(cl)) {
482: out.println("\n private static class DavaSuperHandler{");
483: out
484: .println(" java.util.Vector myVector = new java.util.Vector();");
485:
486: out.println("\n public Object get(int pos){");
487: out.println(" return myVector.elementAt(pos);");
488: out.println(" }");
489:
490: out.println("\n public void store(Object obj){");
491: out.println(" myVector.add(obj);");
492: out.println(" }");
493: out.println(" }");
494: }
495:
496: out.println("}");
497: }
498:
499: /**
500: * Prints out the method corresponding to b Body, (declaration and body),
501: * in the textual format corresponding to the IR used to encode b body.
502: *
503: * @param out a PrintWriter instance to print to.
504: */
505: private void printTo(Body b, PrintWriter out) {
506: b.validate();
507:
508: String decl = b.getMethod().getDavaDeclaration();
509:
510: {
511: out.println(" " + decl);
512: for (Iterator tIt = b.getMethod().getTags().iterator(); tIt
513: .hasNext();) {
514: final Tag t = (Tag) tIt.next();
515: if (Options.v().print_tags_in_output()) {
516: out.println(t);
517: }
518: }
519: out.println(" {");
520:
521: /*
522: The locals are now printed out from within the toString method of ASTMethodNode
523: Nomair A Naeem 10-MARCH-2005
524: */
525: //printLocalsInBody(b, out);
526: }
527:
528: printStatementsInBody(b, out);
529:
530: out.println(" }");
531:
532: }
533:
534: }
|