001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 2003 Jerome Miecznikowski
003: * Copyright (C) 2004-2005 Nomair A. Naeem
004:
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the
018: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
019: * Boston, MA 02111-1307, USA.
020: */
021:
022: /**
023: * Maintained by Nomair A. Naeem
024: */package soot.dava.internal.AST;
025:
026: import soot.*;
027:
028: import java.util.*;
029:
030: import soot.dava.*;
031: import soot.util.*;
032: import soot.jimple.*;
033: import soot.dava.internal.javaRep.*;
034: import soot.dava.internal.asg.*;
035: import soot.dava.toolkits.base.AST.*;
036: import soot.dava.toolkits.base.AST.analysis.*;
037: import soot.dava.toolkits.base.renamer.RemoveFullyQualifiedName;
038:
039: /*
040: * ALWAYS REMEMBER THAT THE FIRST NODE IN THE BODY OF A METHODNODE HAS TO BE A STATEMENT
041: * SEQUENCE NODE WITH DECLARATIONS!!!!
042: */
043: public class ASTMethodNode extends ASTNode {
044: private List<Object> body;
045:
046: private DavaBody davaBody;
047:
048: private ASTStatementSequenceNode declarations;
049:
050: /*
051: * Variables that are used in shortcu statements are kept in the
052: * declarations since other analyses need quick access to all the declared
053: * locals in the method
054: *
055: * Any local in the dontPrintLocals list is not printed in the top declarations
056: */
057: private List<Local> dontPrintLocals = new ArrayList<Local>();
058:
059: /*
060: typeToLocals stores the type of the local and a list of all locals with that type
061: */
062: private Map<Type, List> typeToLocals;//Nomair A. Naeem 24th January why is this a field? why not a localVar of storeLocals???
063:
064: public ASTStatementSequenceNode getDeclarations() {
065: return declarations;
066: }
067:
068: public void setDeclarations(ASTStatementSequenceNode decl) {
069: declarations = decl;
070: }
071:
072: public void setDavaBody(DavaBody bod) {
073: this .davaBody = bod;
074: }
075:
076: public DavaBody getDavaBody() {
077: return davaBody;
078: }
079:
080: public void storeLocals(Body OrigBody) {
081: if ((OrigBody instanceof DavaBody) == false)
082: throw new RuntimeException(
083: "Only DavaBodies should invoke this method");
084:
085: davaBody = (DavaBody) OrigBody;
086: typeToLocals = new DeterministicHashMap(OrigBody
087: .getLocalCount() * 2 + 1, 0.7f);
088:
089: HashSet params = new HashSet();
090: params.addAll(davaBody.get_ParamMap().values());
091: params.addAll(davaBody.get_CaughtRefs());
092: HashSet<Object> this Locals = davaBody.get_ThisLocals();
093:
094: //populating the typeToLocals Map
095: Iterator localIt = OrigBody.getLocals().iterator();
096: while (localIt.hasNext()) {
097: Local local = (Local) localIt.next();
098:
099: if (params.contains(local) || this Locals.contains(local))
100: continue;
101:
102: List<Local> localList;
103:
104: String typeName;
105: Type t = local.getType();
106:
107: typeName = t.toString();
108:
109: if (typeToLocals.containsKey(t))
110: localList = typeToLocals.get(t);
111: else {
112: localList = new ArrayList<Local>();
113: typeToLocals.put(t, localList);
114: }
115:
116: localList.add(local);
117: }
118:
119: //create a StatementSequenceNode with all the declarations
120:
121: List<Object> statementSequence = new ArrayList<Object>();
122:
123: Iterator<Type> typeIt = typeToLocals.keySet().iterator();
124:
125: while (typeIt.hasNext()) {
126: Type typeObject = typeIt.next();
127: String type = typeObject.toString();
128:
129: List localList = typeToLocals.get(typeObject);
130: Object[] locals = localList.toArray();
131:
132: DVariableDeclarationStmt varStmt = null;
133: varStmt = new DVariableDeclarationStmt(typeObject, davaBody);
134:
135: for (Object element : locals) {
136: varStmt.addLocal((Local) element);
137: }
138: AugmentedStmt as = new AugmentedStmt(varStmt);
139: statementSequence.add(as);
140: }
141:
142: declarations = new ASTStatementSequenceNode(statementSequence);
143:
144: body.add(0, declarations);
145: subBodies = new ArrayList<Object>();
146: subBodies.add(body);
147: }
148:
149: public ASTMethodNode(List<Object> body) {
150: super ();
151: this .body = body;
152: subBodies.add(body);
153: }
154:
155: /*
156: Nomair A. Naeem 23rd November 2005
157: Need to efficiently get all locals being declared in the declarations node
158: Dont really care what type they are.. Interesting thing is that they are all different names :)
159: */
160: public List getDeclaredLocals() {
161: List toReturn = new ArrayList();
162:
163: Iterator<Object> it = declarations.getStatements().iterator();
164:
165: while (it.hasNext()) {//going through each stmt
166: Stmt s = ((AugmentedStmt) it.next()).get_Stmt();
167:
168: if (!(s instanceof DVariableDeclarationStmt))
169: continue;//shouldnt happen since this node only contains declarations
170:
171: DVariableDeclarationStmt varStmt = (DVariableDeclarationStmt) s;
172:
173: //get the locals of this particular type
174: List declarations = varStmt.getDeclarations();
175: Iterator decIt = declarations.iterator();
176: while (decIt.hasNext()) {
177: //going through each local declared
178:
179: toReturn.add(decIt.next());
180: }//going through all locals of this type
181: }//going through all stmts
182: return toReturn;
183: }
184:
185: /*
186: * Given a local first searches the declarations for the local
187: * Once it is found the local is removed from its declaring stmt
188: * If the declaring stmt does not declare any more locals the stmt itself is removed
189: * IT WOULD BE NICE TO ALSO CHECK IF THIS WAS THE LAST STMT IN THE NODE IN WHICH CASE THE NODE SHOULD BE REMOVED
190: * just afraid of its after effects on other analyses!!!!
191: */
192: public void removeDeclaredLocal(Local local) {
193: Stmt s = null;
194: Iterator<Object> it = declarations.getStatements().iterator();
195: while (it.hasNext()) {//going through each stmt
196: s = ((AugmentedStmt) it.next()).get_Stmt();
197:
198: if (!(s instanceof DVariableDeclarationStmt))
199: continue;//shouldnt happen since this node only contains declarations
200:
201: DVariableDeclarationStmt varStmt = (DVariableDeclarationStmt) s;
202:
203: //get the locals declared in this stmt
204: List declarations = varStmt.getDeclarations();
205: Iterator decIt = declarations.iterator();
206:
207: boolean foundIt = false;//becomes true if the local was found in this stmt
208: while (decIt.hasNext()) {
209: //going through each local declared
210: Local temp = (Local) decIt.next();
211: if (temp.getName().compareTo(local.getName()) == 0) {
212: //found it
213: foundIt = true;
214: break;
215: }
216: }
217:
218: if (foundIt) {
219: varStmt.removeLocal(local);
220: break; //breaks going through other stmts as we already did what we needed to do
221: }
222: }
223: //the removal of a local might have made some declaration empty
224: //remove such a declaraion
225:
226: List<Object> newSequence = new ArrayList<Object>();
227: it = declarations.getStatements().iterator();
228: while (it.hasNext()) {
229: AugmentedStmt as = (AugmentedStmt) it.next();
230: s = as.get_Stmt();
231:
232: if (!(s instanceof DVariableDeclarationStmt))
233: continue;
234:
235: DVariableDeclarationStmt varStmt = (DVariableDeclarationStmt) s;
236:
237: if (varStmt.getDeclarations().size() != 0)
238: newSequence.add(as);
239:
240: }
241: declarations.setStatements(newSequence);
242: }
243:
244: /*
245: Nomair A Naeem 21-FEB-2005
246: Used by UselessLabeledBlockRemove to update a body
247: */
248: public void replaceBody(List<Object> body) {
249: this .body = body;
250: subBodies = new ArrayList<Object>();
251: subBodies.add(body);
252: }
253:
254: public Object clone() {
255: ASTMethodNode toReturn = new ASTMethodNode(body);
256: toReturn
257: .setDeclarations((ASTStatementSequenceNode) declarations
258: .clone());
259: toReturn.setDontPrintLocals(dontPrintLocals);
260: return toReturn;
261: }
262:
263: public void setDontPrintLocals(List<Local> list) {
264: dontPrintLocals = list;
265: }
266:
267: public void addToDontPrintLocalsList(Local toAdd) {
268: dontPrintLocals.add(toAdd);
269: }
270:
271: public void perform_Analysis(ASTAnalysis a) {
272: perform_AnalysisOnSubBodies(a);
273: }
274:
275: public void toString(UnitPrinter up) {
276: if (!(up instanceof DavaUnitPrinter))
277: throw new RuntimeException(
278: "Only DavaUnitPrinter should be used to print DavaBody");
279:
280: DavaUnitPrinter dup = (DavaUnitPrinter) up;
281: /*
282: Print out constructor first
283: */
284: if (davaBody != null) {
285: InstanceInvokeExpr constructorExpr = davaBody
286: .get_ConstructorExpr();
287:
288: if (constructorExpr != null) {
289: boolean printCloseBrace = true;
290: if (davaBody.getMethod().getDeclaringClass().getName()
291: .equals(
292: constructorExpr.getMethodRef()
293: .declaringClass().toString()))
294: dup.printString(" this(");
295: else {
296: //only invoke super if its not the default call since the default is
297: //called automatically
298: if (constructorExpr.getArgCount() > 0)
299: dup.printString(" super(");
300: else
301: printCloseBrace = false;
302:
303: }
304: Iterator ait = constructorExpr.getArgs().iterator();
305: while (ait.hasNext()) {
306: /*
307: * January 12th, 2006
308: * found a problem here. If a super has a method
309: * call as one of the args then the toString prints the
310: * jimple representation and does not convert it into java
311: * syntax
312: */
313: Object arg = ait.next();
314: if (arg instanceof Value) {
315: //dup.printString(((Value)arg).toString());
316: //already in super no indentation required
317: dup.noIndent();
318: ((Value) arg).toString(dup);
319: } else {
320: /**
321: * Staying with the old style
322: */
323: dup.printString(arg.toString());
324: }
325:
326: if (ait.hasNext())
327: dup.printString(", ");
328: }
329:
330: if (printCloseBrace)
331: dup.printString(");\n");
332: }
333:
334: // print out the remaining body
335: up.newline();
336: }//if //davaBody != null
337:
338: //notice that for an ASTMethod Node the first element of the body list is the
339: //declared variables print it here so that we can control what gets printed
340: printDeclarationsFollowedByBody(up, body);
341: }
342:
343: /*
344: * This method has been written to bring into the printing of the method body the printing of the
345: * declared locals
346: *
347: * This is required because the dontPrintLocals list contains a list of locals which are declared from within
348: * the body and hence we dont want to print them here at the top of the method. However at the same time we dont
349: * want to remove the local entry in the declarations node since this is used by analyses throughout as a quick and
350: * easy way to find out which locals are used by this method...... bad code design but hey what can i say :(
351: */
352: public void printDeclarationsFollowedByBody(UnitPrinter up,
353: List<Object> body) {
354: //System.out.println("printing body from within MEthodNode\n\n"+body.toString());
355:
356: List<Object> stmts = declarations.getStatements();
357: Iterator<Object> it = stmts.iterator();
358: while (it.hasNext()) {
359: AugmentedStmt as = (AugmentedStmt) it.next();
360: //System.out.println("Stmt is:"+as.get_Stmt());
361: Unit u = as.get_Stmt();
362:
363: //stupid sanity check cos i am paranoid
364: if (u instanceof DVariableDeclarationStmt) {
365: DVariableDeclarationStmt declStmt = (DVariableDeclarationStmt) u;
366: List localDeclarations = declStmt.getDeclarations();
367: /*
368: * Check that of the localDeclarations List atleast one is not present in the dontPrintLocals list
369: */
370: boolean shouldContinue = false;
371: Iterator declsIt = localDeclarations.iterator();
372: while (declsIt.hasNext()) {
373: if (!dontPrintLocals.contains(declsIt.next())) {
374: shouldContinue = true;
375: break;
376: }
377: }
378: if (!shouldContinue) {
379: //shouldnt print this declaration stmt
380: continue;
381: }
382: if (localDeclarations.size() == 0)
383: continue;
384:
385: if (!(up instanceof DavaUnitPrinter))
386: throw new RuntimeException(
387: "DavaBody should always be printed using the DavaUnitPrinter");
388:
389: DavaUnitPrinter dup = (DavaUnitPrinter) up;
390: dup.startUnit(u);
391: String type = declStmt.getType().toString();
392:
393: if (type.equals("null_type"))
394: dup.printString("Object");
395: else {
396: IterableSet importSet = davaBody.getImportList();
397: if (!importSet.contains(type))
398: davaBody.addToImportList(type);
399:
400: type = RemoveFullyQualifiedName.getReducedName(
401: davaBody.getImportList(), type, declStmt
402: .getType());
403:
404: dup.printString(type);
405: }
406: dup.printString(" ");
407:
408: int number = 0;
409: Iterator decIt = localDeclarations.iterator();
410: while (decIt.hasNext()) {
411: Local tempDec = (Local) decIt.next();
412: if (dontPrintLocals.contains(tempDec))
413: continue;
414:
415: if (number != 0)
416: dup.printString(", ");
417: number++;
418: dup.printString(tempDec.getName());
419: }
420:
421: up.literal(";");
422: up.endUnit(u);
423: up.newline();
424: } //if DVariableDeclarationStmt
425: else {
426: up.startUnit(u);
427: u.toString(up);
428: up.literal(";");
429: up.endUnit(u);
430: up.newline();
431: }
432: }
433:
434: boolean printed = false;
435: if (body.size() > 0) {
436: ASTNode firstNode = (ASTNode) body.get(0);
437: if (firstNode instanceof ASTStatementSequenceNode) {
438: List<Object> tempstmts = ((ASTStatementSequenceNode) firstNode)
439: .getStatements();
440: if (tempstmts.size() != 0) {
441: AugmentedStmt tempas = (AugmentedStmt) tempstmts
442: .get(0);
443: Stmt temps = tempas.get_Stmt();
444: if (temps instanceof DVariableDeclarationStmt) {
445: printed = true;
446: body_toString(up, body.subList(1, body.size()));
447: }
448: }
449: }
450: }
451: if (!printed) {
452: //System.out.println("Here for method"+this.getDavaBody().getMethod().toString());
453: body_toString(up, body);
454: }
455: }
456:
457: public String toString() {
458: StringBuffer b = new StringBuffer();
459: /*
460: Print out constructor first
461: */
462: if (davaBody != null) {
463: InstanceInvokeExpr constructorExpr = davaBody
464: .get_ConstructorExpr();
465: if (constructorExpr != null) {
466:
467: if (davaBody.getMethod().getDeclaringClass().getName()
468: .equals(
469: constructorExpr.getMethodRef()
470: .declaringClass().toString()))
471: b.append(" this(");
472: else
473: b.append(" super(");
474:
475: Iterator ait = constructorExpr.getArgs().iterator();
476: while (ait.hasNext()) {
477: b.append(ait.toString());
478:
479: if (ait.hasNext())
480: b.append(", ");
481: }
482:
483: b.append(");\n\n");
484: }
485: }
486:
487: // print out the remaining body
488: b.append(body_toString(body));
489: return b.toString();
490: }
491:
492: /*
493: Nomair A. Naeem, 7-FEB-05
494: Part of Visitor Design Implementation for AST
495: See: soot.dava.toolkits.base.AST.analysis For details
496: */
497: public void apply(Analysis a) {
498: a.caseASTMethodNode(this);
499: }
500: }
|