001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 2006 Nomair A. Naeem
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the
016: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
017: * Boston, MA 02111-1307, USA.
018: */
019:
020: package soot.dava.toolkits.base.renamer;
021:
022: import java.util.ArrayList;
023: import java.util.HashMap;
024: import java.util.Iterator;
025: import java.util.List;
026:
027: import soot.ArrayType;
028: import soot.Local;
029: import soot.RefLikeType;
030: import soot.SootClass;
031: import soot.SootField;
032: import soot.Type;
033: import soot.dava.internal.AST.ASTMethodNode;
034: import soot.util.Chain;
035:
036: public class Renamer {
037: public final boolean DEBUG = false;
038: heuristicSet heuristics;
039:
040: List locals; // a list of locals in scope
041:
042: Chain fields; // a list of fields in scope
043:
044: ASTMethodNode methodNode;
045: List forLoopNames;
046:
047: HashMap<Local, Boolean> changedOrNot;//keeps track of which local was changed previously
048:
049: public Renamer(heuristicSet info, ASTMethodNode node) {
050: heuristics = info;
051: locals = null;
052: methodNode = node;
053:
054: changedOrNot = new HashMap<Local, Boolean>();
055: Iterator<Local> localIt = info.getLocalsIterator();
056: while (localIt.hasNext())
057: changedOrNot.put(localIt.next(), new Boolean(false));
058:
059: forLoopNames = new ArrayList();
060: forLoopNames.add("i");
061: forLoopNames.add("j");
062: forLoopNames.add("k");
063: forLoopNames.add("l");
064: }
065:
066: /*
067: * Add any naming heuristic as a separate method and invoke the method from
068: * this method.
069: *
070: * HOWEVER, NOTE that the order of naming really really matters
071: */
072: public void rename() {
073: debug("rename", "Renaming started");
074:
075: // String args
076: mainMethodArgument();
077:
078: //for(i=0;i<bla;i++)
079: forLoopIndexing();
080:
081: //exceptions are named using first letter of each capital char in the class name
082: exceptionNaming();
083:
084: //arrays get <type>Array
085: arraysGetTypeArray();
086:
087: //if a local is assigned a field that name can be used since fields are conserved
088: assignedFromAField();
089:
090: //check if a local is assigned the result of a new invocation
091: newClassName();
092:
093: //check if a local is assigned after casting
094: castedObject();
095:
096: //if nothing else give a reference the name of the class
097: objectsGetClassName();
098:
099: //atleast remove the ugly dollar signs
100: removeDollarSigns();
101: }
102:
103: /*
104: * if there is an array int[] x. then if no other heuristic matches give it the name intArray
105: */
106: private void arraysGetTypeArray() {
107: Iterator<Local> it = heuristics.getLocalsIterator();
108: while (it.hasNext()) {
109: Local tempLocal = it.next();
110: if (alreadyChanged(tempLocal)) {
111: continue;
112: }
113:
114: debug("arraysGetTypeArray", "checking " + tempLocal);
115:
116: Type type = tempLocal.getType();
117: if (type instanceof ArrayType) {
118: debug("arraysGetTypeArray", "Local:" + tempLocal
119: + " is an Array Type: " + type.toString());
120: String tempClassName = type.toString();
121: //remember that a toString of an array gives you the square brackets
122: if (tempClassName.indexOf('[') >= 0)
123: tempClassName = tempClassName.substring(0,
124: tempClassName.indexOf('['));
125:
126: //debug("arraysGetTypeArray","type of object is"+tempClassName);
127: if (tempClassName.indexOf('.') != -1) {
128: //contains a dot have to remove that
129: tempClassName = tempClassName
130: .substring(tempClassName.lastIndexOf('.') + 1);
131: }
132:
133: String newName = tempClassName.toLowerCase();
134: newName = newName + "Array";
135: int count = 0;
136: newName += count;
137: count++;
138:
139: while (!isUniqueName(newName)) {
140: newName = newName
141: .substring(0, newName.length() - 1)
142: + count;
143: count++;
144: }
145: setName(tempLocal, newName);
146:
147: }
148: }
149:
150: }
151:
152: /*
153: * The method assigns any local whose name hasnt been changed yet to
154: * the name of the class type it belongs to
155: */
156: private void objectsGetClassName() {
157: Iterator<Local> it = heuristics.getLocalsIterator();
158: while (it.hasNext()) {
159: Local tempLocal = it.next();
160: if (alreadyChanged(tempLocal)) {
161: continue;
162: }
163:
164: debug("objectsGetClassName", "checking " + tempLocal);
165:
166: Type type = tempLocal.getType();
167: if (type instanceof ArrayType) {
168: //should have been handled by arraysGetTypeArray heuristic
169: continue;
170: }
171:
172: if (type instanceof RefLikeType) {
173: debug("objectsGetClassName", "Local:" + tempLocal
174: + " Type: " + type.toString());
175: //debug("objectsGetClassName","getting array type"+type.getArrayType());
176: String tempClassName = type.toString();
177: //debug("objectsGetClassName","type of object is"+tempClassName);
178: if (tempClassName.indexOf('.') != -1) {
179: //contains a dot have to remove that
180: tempClassName = tempClassName
181: .substring(tempClassName.lastIndexOf('.') + 1);
182: }
183:
184: String newName = tempClassName.toLowerCase();
185: int count = 0;
186: newName += count;
187: count++;
188:
189: while (!isUniqueName(newName)) {
190: newName = newName
191: .substring(0, newName.length() - 1)
192: + count;
193: count++;
194: }
195: setName(tempLocal, newName);
196:
197: }
198: }
199:
200: }
201:
202: /*
203: * If a local is assigned the resullt of a cast expression temp = (List) object;
204: * then u can use list as the name...however only if its always casted to the same object
205: */
206: private void castedObject() {
207: debug("castedObject", "");
208:
209: Iterator<Local> it = heuristics.getLocalsIterator();
210: while (it.hasNext()) {
211: Local tempLocal = it.next();
212: if (!alreadyChanged(tempLocal)) {
213: debug("castedObject", "checking " + tempLocal);
214: List<String> classes = heuristics
215: .getCastStrings(tempLocal);
216:
217: Iterator<String> itClass = classes.iterator();
218: String classNameToUse = null;
219: while (itClass.hasNext()) {
220: String tempClassName = itClass.next();
221: if (tempClassName.indexOf('.') != -1) {
222: //contains a dot have to remove that
223: tempClassName = tempClassName
224: .substring(tempClassName
225: .lastIndexOf('.') + 1);
226: }
227: if (classNameToUse == null)
228: classNameToUse = tempClassName;
229: else if (!classNameToUse.equals(tempClassName)) {
230: //different new assignment
231: //cant use these classNames
232: classNameToUse = null;
233: break;
234: }
235: }//going through class names stored
236: if (classNameToUse != null) {
237: debug("castedObject",
238: "found a classNametoUse through cast expr");
239: /*
240: * We should use this classNAme to assign to the local name
241: * We are guaranteed that all cast expressions use this type
242: */
243: String newName = classNameToUse.toLowerCase();
244: int count = 0;
245: newName += count;
246: count++;
247:
248: while (!isUniqueName(newName)) {
249: newName = newName.substring(0,
250: newName.length() - 1)
251: + count;
252: count++;
253: }
254: setName(tempLocal, newName);
255: }
256: }//not already changed
257: }//going through locals
258: }
259:
260: /*
261: * See if any local was initialized using the new operator
262: * That name might give us a hint to a name to use for the local
263: */
264: private void newClassName() {
265:
266: debug("newClassName", "");
267: //check if CLASSNAME is set
268: //that would mean there was new className invocation
269: Iterator<Local> it = heuristics.getLocalsIterator();
270: while (it.hasNext()) {
271: Local tempLocal = it.next();
272: if (!alreadyChanged(tempLocal)) {
273: debug("newClassName", "checking " + tempLocal);
274: List<String> classes = heuristics
275: .getObjectClassName(tempLocal);
276: Iterator<String> itClass = classes.iterator();
277: String classNameToUse = null;
278: while (itClass.hasNext()) {
279: String tempClassName = itClass.next();
280: if (tempClassName.indexOf('.') != -1) {
281: //contains a dot have to remove that
282: tempClassName = tempClassName
283: .substring(tempClassName
284: .lastIndexOf('.') + 1);
285: }
286: if (classNameToUse == null)
287: classNameToUse = tempClassName;
288: else if (!classNameToUse.equals(tempClassName)) {
289: //different new assignment
290: //cant use these classNames
291: classNameToUse = null;
292: break;
293: }
294: }//going through class names stored
295: if (classNameToUse != null) {
296: debug("newClassName", "found a classNametoUse");
297: /*
298: * We should use this classNAme to assign to the local name
299: * We are guaranteed that all new invocations use this class name
300: */
301: String newName = classNameToUse.toLowerCase();
302: int count = 0;
303: newName += count;
304: count++;
305:
306: while (!isUniqueName(newName)) {
307: newName = newName.substring(0,
308: newName.length() - 1)
309: + count;
310: count++;
311: }
312: setName(tempLocal, newName);
313: }
314: }//not already changed
315: }//going through locals
316:
317: }
318:
319: /*
320: * If a local is assigned from a field (static or non staitc) we can use that name
321: * to assign a some what better name for the local
322: *
323: * If multiple fields are assigned then it might be a better idea to not do
324: * anything since that will only confuse the user
325: *
326: */
327: private void assignedFromAField() {
328: Iterator<Local> it = heuristics.getLocalsIterator();
329: while (it.hasNext()) {
330: Local tempLocal = it.next();
331: if (!alreadyChanged(tempLocal)) {
332: debug("assignedFromField", "checking " + tempLocal);
333: List<String> fieldNames = heuristics
334: .getFieldName(tempLocal);
335: if (fieldNames.size() > 1) {
336: //more than one fields were assigned to this var
337: continue;
338: } else if (fieldNames.size() == 1) {
339: //only one field was used
340: String fieldName = fieldNames.get(0);
341:
342: //okkay to use the name of the field if its not in scope
343: //eg it was some other classes field
344: int count = 0;
345: while (!isUniqueName(fieldName)) {
346: if (count == 0)
347: fieldName = fieldName + count;
348: else
349: fieldName = fieldName.substring(0,
350: fieldName.length() - 1)
351: + count;
352: count++;
353: }
354:
355: setName(tempLocal, fieldName);
356: }//only one field assigned to this local
357: }//not changed
358: }//going through locals
359: }
360:
361: /*
362: * If we cant come up with any better name atleast we should remove the $ signs
363: */
364: private void removeDollarSigns() {
365: Iterator<Local> it = heuristics.getLocalsIterator();
366: while (it.hasNext()) {
367: Local tempLocal = it.next();
368: String currentName = tempLocal.getName();
369: int dollarIndex = currentName.indexOf('$');
370: if (dollarIndex == 0) {
371: //meaning there is a $ sign in the first location
372: String newName = currentName.substring(1, currentName
373: .length());
374:
375: if (isUniqueName(newName)) {
376: setName(tempLocal, newName);
377: // System.out.println("Changed "+currentName+" to "+newName);
378: //tempLocal.setName(newName);
379: }
380: }
381: }
382: }
383:
384: /*
385: *
386: */
387: private void exceptionNaming() {
388: Iterator<Local> it = heuristics.getLocalsIterator();
389: while (it.hasNext()) {
390: Local tempLocal = it.next();
391: Type localType = tempLocal.getType();
392: String typeString = localType.toString();
393: if (typeString.indexOf("Exception") >= 0) {
394: //the string xception occurs in this type
395: debug("exceptionNaming", "Type is an exception"
396: + tempLocal);
397:
398: //make a new name of all caps characters in typeString
399: String newName = "";
400: for (int i = 0; i < typeString.length(); i++) {
401: char character = typeString.charAt(i);
402: if (Character.isUpperCase(character)) {
403: newName += Character.toLowerCase(character);
404: }
405: }
406: int count = 0;
407: if (!isUniqueName(newName)) {
408: count++;
409: while (!isUniqueName(newName + count)) {
410: count++;
411: }
412: }
413: if (count != 0)
414: newName = newName + count;
415:
416: setName(tempLocal, newName);
417: }
418: }
419: }
420:
421: /*
422: * Probably one of the most common programming idioms
423: * for loop indexes are often i j k l
424: */
425: private void forLoopIndexing() {
426: Iterator<Local> it = heuristics.getLocalsIterator();
427: while (it.hasNext()) {
428: Local tempLocal = it.next();
429: debug("foeLoopIndexing", "Checking local"
430: + tempLocal.getName());
431: if (heuristics.getHeuristic(tempLocal,
432: infoGatheringAnalysis.FORLOOPUPDATE)) {
433: // this local variable is the main argument
434: // will like to set it to args if no one has an objection
435: int count = -1;
436:
437: String newName;
438:
439: do {
440: count++;
441: if (count >= forLoopNames.size()) {
442: newName = null;
443: break;
444: }
445: newName = (String) forLoopNames.get(count);
446: } while (!isUniqueName(newName));
447:
448: if (newName != null) {
449: setName(tempLocal, newName);
450: }
451: }
452: }
453: }
454:
455: /*
456: * A simple heuristic which sets the mainMethodArgument's name to args
457: */
458: private void mainMethodArgument() {
459: Iterator<Local> it = heuristics.getLocalsIterator();
460: while (it.hasNext()) {
461: Local tempLocal = it.next();
462: if (heuristics.getHeuristic(tempLocal,
463: infoGatheringAnalysis.MAINARG)) {
464:
465: // this local variable is the main argument
466: // will like to set it to args if no one has an objection
467: String newName = "args";
468: int count = 0;
469: while (!isUniqueName(newName)) {
470: if (count == 0)
471: newName = newName + count;
472: else
473: newName = newName.substring(0,
474: newName.length() - 1)
475: + count;
476:
477: count++;
478: }
479: setName(tempLocal, newName);
480: //there cant be a same local with this heuristic set so just return
481: return;
482: }
483: }
484:
485: }
486:
487: /*
488: * In order to make sure that some previous heuristic which is usually a STRONGER
489: * heuristic has not already changed the name we use this method which checks for
490: * past name changes and only changes the name if the name hasnt been changed previously
491: */
492: private void setName(Local var, String newName) {
493:
494: Object truthValue = changedOrNot.get(var);
495:
496: //if it wasnt in there add it
497: if (truthValue == null)
498: changedOrNot.put(var, new Boolean(false));
499: else {
500: if (((Boolean) truthValue).booleanValue()) {
501: //already changed just return
502: debug("setName", "Var: " + var
503: + " had already been renamed");
504: return;
505: }
506: }
507: //will only get here if the var had not been changed
508:
509: debug("setName", "Changed " + var.getName() + " to " + newName);
510: var.setName(newName);
511: changedOrNot.put(var, new Boolean(true));
512: }
513:
514: /*
515: * Check if a local has already been changed
516: * @param local to check
517: * @return true if already changed otherwise false
518: */
519: private boolean alreadyChanged(Local var) {
520: Object truthValue = changedOrNot.get(var);
521:
522: //if it wasnt in there add it
523: if (truthValue == null) {
524: changedOrNot.put(var, new Boolean(false));
525: return false;
526: } else {
527: if (((Boolean) truthValue).booleanValue()) {
528: //already changed just return
529: debug("alreadyChanged", "Var: " + var
530: + " had already been renamed");
531: return true;
532: } else
533: return false;
534: }
535: }
536:
537: /*
538: * Should return true if the name is unique
539: */
540: private boolean isUniqueName(String name) {
541: Iterator it = getScopedLocals();
542: // check that none of the locals uses this name
543: while (it.hasNext()) {
544: Local tempLocal = (Local) it.next();
545: if (tempLocal.getName().equals(name)) {
546: debug(
547: "isUniqueName",
548: "New Name "
549: + name
550: + " is not unique (matches some local)..changing");
551: return false;
552: } else
553: debug("isUniqueName", "New Name " + name
554: + " is different from local "
555: + tempLocal.getName());
556: }
557:
558: it = getScopedFields();
559: // check that none of the fields uses this name
560: while (it.hasNext()) {
561: SootField tempField = (SootField) it.next();
562: if (tempField.getName().equals(name)) {
563: debug("isUniqueName", "New Name " + name
564: + " is not unique (matches field)..changing");
565: return false;
566: } else
567: debug("isUniqurName", "New Name " + name
568: + " is different from field "
569: + tempField.getName());
570: }
571: return true;
572: }
573:
574: /*
575: * Method is responsible to find all names with which there could be a
576: * potential clash The variables are: all the fields of this class and all
577: * the locals defined in this method
578: */
579: private Iterator getScopedFields() {
580: // get the fields for this class and store them
581: SootClass sootClass = methodNode.getDavaBody().getMethod()
582: .getDeclaringClass();
583: fields = sootClass.getFields();
584:
585: return fields.iterator();
586: }
587:
588: /*
589: * Method is responsible to find all variable names with which there could
590: * be a potential clash The variables are: all the fields of this class and
591: * all the locals defined in this method
592: */
593: private Iterator getScopedLocals() {
594: Iterator<Local> it = heuristics.getLocalsIterator();
595:
596: locals = new ArrayList();
597: while (it.hasNext())
598: locals.add(it.next());
599:
600: return locals.iterator();
601:
602: }
603:
604: public void debug(String methodName, String debug) {
605:
606: if (DEBUG)
607: System.out.println(methodName + " DEBUG: " + debug);
608: }
609:
610: }
|