KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > soot > javaToJimple > InitialResolver


1 /* Soot - a J*va Optimization Framework
2  * Copyright (C) 2004 Jennifer Lhotak
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */

19
20 package soot.javaToJimple;
21 import soot.*;
22 import java.util.*;
23
24 public class InitialResolver {
25
26     private polyglot.ast.Node astNode; // source node
27
private polyglot.frontend.Compiler compiler;
28     private polyglot.util.Position currentClassDeclPos;
29     private BiMap anonClassMap; // maps New to SootClass (name)
30
private HashMap anonTypeMap; //maps polyglot types to soot types
31
private BiMap localClassMap; // maps LocalClassDecl to SootClass (name)
32
private HashMap localTypeMap; // maps polyglot types to soot types
33
private int privateAccessCounter = 0; // global for whole program because
34
// the methods created are static
35
private HashMap finalLocalInfo; // new or lcd mapped to list of final locals avail in current meth and the whether its static
36
private HashMap newToOuterMap;
37   
38     private HashMap sootNameToAST = null;
39     private ArrayList hasOuterRefInInit; // list of sootclass types that need an outer class this param in for init
40

41     private HashMap classToSourceMap;
42     private HashMap specialAnonMap;
43     private HashMap privateFieldGetAccessMap;
44     private HashMap privateFieldSetAccessMap;
45     private HashMap privateMethodGetAccessMap;
46     private ArrayList interfacesList;
47     private ArrayList cCallList;
48     
49     private HashMap anonConstructorMap;
50
51     public void addToAnonConstructorMap(polyglot.ast.New anonNew, polyglot.types.ConstructorInstance ci){
52         if (anonConstructorMap == null){
53             anonConstructorMap = new HashMap();
54         }
55         anonConstructorMap.put(anonNew, ci);
56     }
57    
58     public polyglot.types.ConstructorInstance getConstructorForAnon(polyglot.ast.New anonNew){
59         if (anonConstructorMap == null) return null;
60         return (polyglot.types.ConstructorInstance)anonConstructorMap.get(anonNew);
61     }
62
63     private FastHierarchy hierarchy;
64
65     private AbstractJBBFactory jbbFactory = new JimpleBodyBuilderFactory();
66
67     public void setJBBFactory(AbstractJBBFactory jbbFactory){
68         this.jbbFactory = jbbFactory;
69     }
70     
71     public AbstractJBBFactory getJBBFactory(){
72         return jbbFactory;
73     }
74     
75     /**
76      * returns true if there is an AST avail for given soot class
77      */

78     public boolean hasASTForSootName(String JavaDoc name){
79        if (sootNameToAST == null) return false;
80        if (sootNameToAST.containsKey(name)) return true;
81        return false;
82     }
83     
84     /**
85      * sets AST for given soot class if possible
86      */

87     public void setASTForSootName(String JavaDoc name){
88         if (!hasASTForSootName(name)) {
89             throw new RuntimeException JavaDoc("Can only set AST for name if it exists. You should probably not be calling this method unless you know what you're doing!");
90         }
91         setAst((polyglot.ast.Node)sootNameToAST.get(name));
92     }
93    
94     public InitialResolver(soot.Singletons.Global g){}
95     public static InitialResolver v() {
96         return soot.G.v().soot_javaToJimple_InitialResolver();
97     }
98     
99
100     
101     /**
102      * Invokes polyglot and gets the AST for the source given in fullPath
103      */

104     public void formAst(String JavaDoc fullPath, List locations){
105     
106         JavaToJimple jtj = new JavaToJimple();
107         polyglot.frontend.ExtensionInfo extInfo = jtj.initExtInfo(fullPath, locations);
108         // only have one compiler - for memory issues
109
//if (compiler == null) {
110
compiler = new polyglot.frontend.Compiler(extInfo);
111         //}
112
// build ast
113
astNode = jtj.compile(compiler, fullPath, extInfo);
114  
115         resolveAST();
116
117
118     }
119
120     /**
121      * if you have a special AST set it here then call resolveFormJavaFile
122      * on the soot class
123      */

124     public void setAst(polyglot.ast.Node ast) {
125         astNode = ast;
126     }
127     
128     /*
129      * March 2nd, 2006 Nomair
130      * Is it okkay get the ast and send it to the ASTMetrics package????
131      */

132     public polyglot.ast.Node getAst(){
133         return astNode;
134     }
135
136     private void makeASTMap() {
137         ClassDeclFinder finder = new ClassDeclFinder();
138         astNode.visit(finder);
139         Iterator it = finder.declsFound().iterator();
140         while (it.hasNext()){
141             polyglot.ast.ClassDecl decl = (polyglot.ast.ClassDecl)it.next();
142             polyglot.types.ClassType type = (polyglot.types.ClassType)decl.type();
143             if (type.flags().isInterface()){
144                 if (interfacesList == null){
145                     interfacesList = new ArrayList();
146                 }
147                 interfacesList.add(Util.getSootType(type).toString());
148             }
149             addNameToAST(Util.getSootType(type).toString());
150         }
151     }
152     
153     /**
154      * add name to AST to map - used mostly for inner and non public
155      * top-level classes
156      */

157     protected void addNameToAST(String JavaDoc name){
158         if (sootNameToAST == null){
159             sootNameToAST = new HashMap();
160         }
161         sootNameToAST.put(name, astNode);
162     }
163    
164     public void resolveAST(){
165         buildInnerClassInfo();
166         if (astNode instanceof polyglot.ast.SourceFile) {
167             createClassToSourceMap((polyglot.ast.SourceFile)astNode);
168         }
169     }
170     
171     // resolves all types and deals with .class literals and asserts
172
public List resolveFromJavaFile(soot.SootClass sc) {
173         List references = new ArrayList();
174         ClassResolver cr = new ClassResolver(sc, references);
175         
176         // create class to source map first
177
// create source file
178
if (astNode instanceof polyglot.ast.SourceFile) {
179             cr.createSource((polyglot.ast.SourceFile)astNode);
180         }
181         
182         cr.addSourceFileTag(sc);
183         
184         makeASTMap();
185         
186         return references;
187     }
188     
189
190     private void createClassToSourceMap(polyglot.ast.SourceFile src){
191        
192         String JavaDoc srcName = src.source().path();
193         String JavaDoc srcFileName = null;
194         if (src.package_() != null){
195             String JavaDoc slashedPkg = soot.util.StringTools.replaceAll(src.package_().package_().fullName(), ".", System.getProperty("file.separator"));
196             srcFileName = srcName.substring(srcName.lastIndexOf(slashedPkg));
197         }
198         else {
199             srcFileName = srcName.substring(srcName.lastIndexOf(System.getProperty("file.separator"))+1);
200         }
201
202         ArrayList list = new ArrayList();
203         Iterator it = src.decls().iterator();
204         while (it.hasNext()){
205             polyglot.ast.ClassDecl nextDecl = (polyglot.ast.ClassDecl)it.next();
206             addToClassToSourceMap(Util.getSootType(nextDecl.type()).toString(), srcFileName);
207         }
208
209     }
210
211     private void createLocalAndAnonClassNames(ArrayList anonBodyList, ArrayList localClassDeclList){
212         Iterator anonBodyIt = anonBodyList.iterator();
213         while (anonBodyIt.hasNext()){
214             createAnonClassName((polyglot.ast.New)anonBodyIt.next());
215         }
216         Iterator localClassDeclIt = localClassDeclList.iterator();
217         while (localClassDeclIt.hasNext()){
218             createLocalClassName((polyglot.ast.LocalClassDecl)localClassDeclIt.next());
219         }
220     }
221
222     protected int getNextAnonNum(){
223         if (anonTypeMap == null) return 1;
224         else return anonTypeMap.size()+1;
225     }
226     
227     private void createAnonClassName(polyglot.ast.New nextNew){
228         // maybe this anon has already been resolved
229
if (anonClassMap == null){
230             anonClassMap = new BiMap();
231         }
232         if (anonTypeMap == null){
233             anonTypeMap = new HashMap();
234         }
235         if (!anonClassMap.containsKey(nextNew)){
236             int nextAvailNum = 1;
237             polyglot.types.ClassType outerToMatch = nextNew.anonType().outer();
238             while (outerToMatch.isNested()){
239                 outerToMatch = outerToMatch.outer();
240             }
241
242             if (!anonTypeMap.isEmpty()){
243                 Iterator matchIt = anonTypeMap.keySet().iterator();
244                 while (matchIt.hasNext()){
245                     polyglot.types.ClassType pType = (polyglot.types.ClassType)((polyglot.util.IdentityKey)matchIt.next()).object();
246                     polyglot.types.ClassType outerMatch = pType.outer();
247                     while (outerMatch.isNested()){
248                         outerMatch = outerMatch.outer();
249                     }
250                     if (outerMatch.equals(outerToMatch)){
251                         int numFound = getAnonClassNum((String JavaDoc)anonTypeMap.get(new polyglot.util.IdentityKey(pType)));
252                         if (numFound >= nextAvailNum){
253                             nextAvailNum = numFound+1;
254                         }
255                     }
256                 }
257             }
258             
259             String JavaDoc realName = outerToMatch.fullName()+"$"+nextAvailNum;
260             anonClassMap.put(nextNew, realName);
261             anonTypeMap.put(new polyglot.util.IdentityKey(nextNew.anonType()), realName);
262             addNameToAST(realName);
263             
264         }
265     }
266     
267     private void createLocalClassName(polyglot.ast.LocalClassDecl lcd){
268         // maybe this localdecl has already been resolved
269
if (localClassMap == null){
270             localClassMap = new BiMap();
271         }
272         if (localTypeMap == null){
273             localTypeMap = new HashMap();
274         }
275         
276         if (!localClassMap.containsKey(lcd)){
277             int nextAvailNum = 1;
278             polyglot.types.ClassType outerToMatch = lcd.decl().type().outer();
279             while (outerToMatch.isNested()){
280                 outerToMatch = outerToMatch.outer();
281             }
282
283             if (!localTypeMap.isEmpty()){
284                 Iterator matchIt = localTypeMap.keySet().iterator();
285                 while (matchIt.hasNext()){
286                     polyglot.types.ClassType pType = (polyglot.types.ClassType)((polyglot.util.IdentityKey)matchIt.next()).object();
287                     polyglot.types.ClassType outerMatch = pType.outer();
288                     while (outerMatch.isNested()){
289                         outerMatch = outerMatch.outer();
290                     }
291                     if (outerMatch.equals(outerToMatch)){
292                         int numFound = getLocalClassNum((String JavaDoc)localTypeMap.get(new polyglot.util.IdentityKey(pType)), lcd.decl().name());
293                         if (numFound >= nextAvailNum){
294                             nextAvailNum = numFound+1;
295                         }
296                     }
297                 }
298             }
299
300             String JavaDoc realName = outerToMatch.fullName()+"$"+nextAvailNum+lcd.decl().name();
301             localClassMap.put(lcd, realName);
302             localTypeMap.put(new polyglot.util.IdentityKey(lcd.decl().type()), realName);
303             addNameToAST(realName);
304         }
305     }
306
307     private static final int NO_MATCH = 0;
308     
309     private int getLocalClassNum(String JavaDoc realName, String JavaDoc simpleName){
310         // a local inner class is named outer$NsimpleName where outer
311
// is the very outer most class
312
int dIndex = realName.indexOf("$");
313         int nIndex = realName.indexOf(simpleName, dIndex);
314         if (nIndex == -1) return NO_MATCH;
315         if (dIndex == -1) {
316             throw new RuntimeException JavaDoc("Matching an incorrectly named local inner class: "+realName);
317         }
318         String JavaDoc numString = realName.substring(dIndex+1, nIndex);
319         for (int i = 0; i < numString.length(); i++){
320             if (!Character.isDigit(numString.charAt(i))) return NO_MATCH;
321         }
322         return (new Integer JavaDoc(numString)).intValue();
323     }
324     
325     private int getAnonClassNum(String JavaDoc realName){
326         // a anon inner class is named outer$N where outer
327
// is the very outer most class
328
int dIndex = realName.indexOf("$");
329         if (dIndex == -1) {
330             throw new RuntimeException JavaDoc("Matching an incorrectly named anon inner class: "+realName);
331         }
332         return (new Integer JavaDoc(realName.substring(dIndex+1))).intValue();
333     }
334     
335
336     /**
337      * ClassToSourceMap is for classes whos names don't match the source file
338      * name - ex: multiple top level classes in a single file
339      */

340     private void addToClassToSourceMap(String JavaDoc className, String JavaDoc sourceName) {
341             
342         if (classToSourceMap == null){
343             classToSourceMap = new HashMap();
344         }
345         classToSourceMap.put(className, sourceName);
346     }
347     
348
349     public boolean hasClassInnerTag(soot.SootClass sc, String JavaDoc innerName){
350         Iterator it = sc.getTags().iterator();
351         while (it.hasNext()){
352             soot.tagkit.Tag t = (soot.tagkit.Tag)it.next();
353             if (t instanceof soot.tagkit.InnerClassTag) {
354                 soot.tagkit.InnerClassTag tag = (soot.tagkit.InnerClassTag)t;
355                 if (tag.getInnerClass().equals(innerName)) return true;
356             }
357         }
358         return false;
359     }
360    
361     private void buildInnerClassInfo(){
362         InnerClassInfoFinder icif = new InnerClassInfoFinder();
363         astNode.visit(icif);
364         createLocalAndAnonClassNames(icif.anonBodyList(), icif.localClassDeclList());
365         buildFinalLocalMap(icif.memberList());
366     }
367     
368     private void buildFinalLocalMap(ArrayList memberList){
369         Iterator it = memberList.iterator();
370         while (it.hasNext()){
371             handleFinalLocals((polyglot.ast.ClassMember)it.next());
372         }
373     }
374     
375     private void handleFinalLocals(polyglot.ast.ClassMember member){
376         MethodFinalsChecker mfc = new MethodFinalsChecker();
377         member.visit(mfc);
378         //System.out.println("member: "+member);
379
//System.out.println("mcf final locals avail: "+mfc.finalLocals());
380
//System.out.println("mcf locals used: "+mfc.typeToLocalsUsed());
381
//System.out.println("mfc inners: "+mfc.inners());
382
if (cCallList == null){
383             cCallList = new ArrayList();
384         }
385         cCallList.addAll(mfc.ccallList());
386         //System.out.println("cCallList: "+cCallList);
387
AnonLocalClassInfo alci = new AnonLocalClassInfo();
388         if (member instanceof polyglot.ast.ProcedureDecl){
389             polyglot.ast.ProcedureDecl procedure = (polyglot.ast.ProcedureDecl)member;
390             // not sure if this will break deep nesting
391
alci.finalLocalsAvail(mfc.finalLocals());
392             if (procedure.flags().isStatic()){
393                 alci.inStaticMethod(true);
394             }
395         }
396         else if (member instanceof polyglot.ast.FieldDecl){
397             alci.finalLocalsAvail(new ArrayList());
398             if (((polyglot.ast.FieldDecl)member).flags().isStatic()){
399                 alci.inStaticMethod(true);
400             }
401         }
402         else if (member instanceof polyglot.ast.Initializer){
403             // for now don't make final locals avail in init blocks
404
// need to test this
405
alci.finalLocalsAvail(mfc.finalLocals());
406             if (((polyglot.ast.Initializer)member).flags().isStatic()){
407                 alci.inStaticMethod(true);
408             }
409         }
410         if (finalLocalInfo == null){
411             finalLocalInfo = new HashMap();
412         }
413         Iterator it = mfc.inners().iterator();
414         while (it.hasNext()){
415             
416             polyglot.types.ClassType cType = (polyglot.types.ClassType)((polyglot.util.IdentityKey)it.next()).object();
417             // do the comparison about locals avail and locals used here
418
HashMap typeToLocalUsed = mfc.typeToLocalsUsed();
419             ArrayList localsUsed = new ArrayList();
420             if (typeToLocalUsed.containsKey(new polyglot.util.IdentityKey(cType))){
421                 ArrayList localsNeeded = (ArrayList)typeToLocalUsed.get(new polyglot.util.IdentityKey(cType));
422                 Iterator usesIt = localsNeeded.iterator();
423                 while (usesIt.hasNext()){
424                     polyglot.types.LocalInstance li = (polyglot.types.LocalInstance)((polyglot.util.IdentityKey)usesIt.next()).object();
425                     if (alci.finalLocalsAvail().contains(new polyglot.util.IdentityKey(li))){
426                         localsUsed.add(new polyglot.util.IdentityKey(li));
427                     }
428                 }
429             }
430                 
431             
432             AnonLocalClassInfo info = new AnonLocalClassInfo();
433             info.inStaticMethod(alci.inStaticMethod());
434             info.finalLocalsAvail(localsUsed);
435             if (!finalLocalInfo.containsKey(new polyglot.util.IdentityKey(cType))){
436                 finalLocalInfo.put(new polyglot.util.IdentityKey(cType), info);
437             }
438         }
439     }
440     
441     public boolean isAnonInCCall(polyglot.types.ClassType anonType){
442         //System.out.println("checking type: "+anonType);
443
Iterator it = cCallList.iterator();
444         while (it.hasNext()){
445             polyglot.ast.ConstructorCall cCall = (polyglot.ast.ConstructorCall)it.next();
446             //System.out.println("cCall params: "+cCall.arguments());
447
Iterator argsIt = cCall.arguments().iterator();
448             while (argsIt.hasNext()){
449                 Object JavaDoc next = argsIt.next();
450                 if (next instanceof polyglot.ast.New && ((polyglot.ast.New)next).anonType() != null){
451                     //System.out.println("comparing: "+((polyglot.ast.New)next).anonType());
452
if (((polyglot.ast.New)next).anonType().equals(anonType)) return true;
453                 }
454             }
455         }
456         return false;
457     }
458     
459     public BiMap getAnonClassMap(){
460         return anonClassMap;
461     }
462
463     public BiMap getLocalClassMap(){
464         return localClassMap;
465     }
466     
467     public HashMap getAnonTypeMap(){
468         return anonTypeMap;
469     }
470
471     public HashMap getLocalTypeMap(){
472         return localTypeMap;
473     }
474   
475     public HashMap finalLocalInfo(){
476         return finalLocalInfo;
477     }
478
479     public int getNextPrivateAccessCounter(){
480         int res = privateAccessCounter;
481         privateAccessCounter++;
482         return res;
483     }
484
485     public ArrayList getHasOuterRefInInit(){
486         return hasOuterRefInInit;
487     }
488
489     public void setHasOuterRefInInit(ArrayList list){
490         hasOuterRefInInit = list;
491     }
492
493     public HashMap specialAnonMap(){
494         return specialAnonMap;
495     }
496
497     public void setSpecialAnonMap(HashMap map){
498         specialAnonMap = map;
499     }
500
501     public void hierarchy(soot.FastHierarchy fh){
502         hierarchy = fh;
503     }
504     
505     public soot.FastHierarchy hierarchy(){
506         return hierarchy;
507     }
508
509     private HashMap innerClassInfoMap;
510    
511     public HashMap getInnerClassInfoMap(){
512         return innerClassInfoMap;
513     }
514  
515     public void setInnerClassInfoMap(HashMap map){
516         innerClassInfoMap = map;
517     }
518  
519     protected HashMap classToSourceMap(){
520         return classToSourceMap;
521     }
522
523     public void addToPrivateFieldGetAccessMap(polyglot.ast.Field field, soot.SootMethod meth){
524         if (privateFieldGetAccessMap == null){
525             privateFieldGetAccessMap = new HashMap();
526         }
527         privateFieldGetAccessMap.put(new polyglot.util.IdentityKey(field.fieldInstance()), meth);
528     }
529     
530     public HashMap getPrivateFieldGetAccessMap(){
531         return privateFieldGetAccessMap;
532     }
533     
534     public void addToPrivateFieldSetAccessMap(polyglot.ast.Field field, soot.SootMethod meth){
535         if (privateFieldSetAccessMap == null){
536             privateFieldSetAccessMap = new HashMap();
537         }
538         privateFieldSetAccessMap.put(new polyglot.util.IdentityKey(field.fieldInstance()), meth);
539     }
540     
541     public HashMap getPrivateFieldSetAccessMap(){
542         return privateFieldSetAccessMap;
543     }
544     
545     public void addToPrivateMethodGetAccessMap(polyglot.ast.Call call, soot.SootMethod meth){
546         if (privateMethodGetAccessMap == null){
547             privateMethodGetAccessMap = new HashMap();
548         }
549         privateMethodGetAccessMap.put(new polyglot.util.IdentityKey(call.methodInstance()), meth);
550     }
551     
552     public HashMap getPrivateMethodGetAccessMap(){
553         return privateMethodGetAccessMap;
554     }
555
556     public ArrayList getInterfacesList() {
557         return interfacesList;
558     }
559 }
560
561
Popular Tags