KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > soot > javaToJimple > ClassResolver


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 ClassResolver {
25
26     private ArrayList staticFieldInits;
27     private ArrayList fieldInits;
28     private ArrayList initializerBlocks;
29     private ArrayList staticInitializerBlocks;
30    
31     /**
32      * adds source file tag to each sootclass
33      */

34     protected void addSourceFileTag(soot.SootClass sc){
35         soot.tagkit.SourceFileTag tag = null;
36         if (sc.hasTag("SourceFileTag")) {
37             tag = (soot.tagkit.SourceFileTag)sc.getTag("SourceFileTag");
38         }
39         else {
40             tag = new soot.tagkit.SourceFileTag();
41             sc.addTag(tag);
42         }
43         
44         String JavaDoc name = Util.getSourceFileOfClass(sc);
45
46
47         if (InitialResolver.v().classToSourceMap() != null){
48             if (InitialResolver.v().classToSourceMap().containsKey(name)){
49                 name = (String JavaDoc)InitialResolver.v().classToSourceMap().get(name);
50             }
51         }
52
53         // the pkg is not included in the tag for some unknown reason
54
// I think in this case windows uses the same slash - may cause
55
// windows problems though
56
int slashIndex = name.lastIndexOf("/");
57         if (slashIndex != -1){
58             name = name.substring(slashIndex+1);
59         }
60         tag.setSourceFile(name);
61         //sc.addTag(new soot.tagkit.SourceFileTag(name));
62
}
63     
64     /**
65      * Class Declaration Creation
66      */

67     private void createClassDecl(polyglot.ast.ClassDecl cDecl){
68     
69         //add outer class tag if neccessary (if class is not top-level)
70
if (!cDecl.type().isTopLevel()){
71             SootClass outerClass = ((soot.RefType)Util.getSootType(cDecl.type().outer())).getSootClass();
72             
73             if (InitialResolver.v().getInnerClassInfoMap() == null){
74                 InitialResolver.v().setInnerClassInfoMap(new HashMap());
75             }
76             InitialResolver.v().getInnerClassInfoMap().put(sootClass, new InnerClassInfo(outerClass, cDecl.name(), InnerClassInfo.NESTED));
77             sootClass.setOuterClass(outerClass);
78         }
79     
80         // modifiers
81
polyglot.types.Flags flags = cDecl.flags();
82         addModifiers(flags, cDecl);
83         
84         // super class
85
if (cDecl.superClass() == null) {
86             soot.SootClass superClass = soot.Scene.v().getSootClass ("java.lang.Object");
87             sootClass.setSuperclass(superClass);
88         }
89         else {
90     
91             sootClass.setSuperclass(((soot.RefType)Util.getSootType(cDecl.superClass().type())).getSootClass());
92             if (((polyglot.types.ClassType)cDecl.superClass().type()).isNested()){
93                 polyglot.types.ClassType superType = (polyglot.types.ClassType)cDecl.superClass().type();
94                 // add inner clas tag
95

96                 Util.addInnerClassTag(sootClass, sootClass.getName(), ((soot.RefType)Util.getSootType(superType.outer())).toString(), superType.name(), Util.getModifier(superType.flags()));
97             }
98         
99         }
100     
101     
102         // implements
103
Iterator interfacesIt = cDecl.interfaces().iterator();
104         while (interfacesIt.hasNext()) {
105             polyglot.ast.TypeNode next = (polyglot.ast.TypeNode)interfacesIt.next();
106             sootClass.addInterface(((soot.RefType)Util.getSootType(next.type())).getSootClass());
107         }
108         
109         findReferences(cDecl);
110         createClassBody(cDecl.body());
111     
112         // handle initialization of fields
113
// static fields init in clinit
114
// other fields init in init
115
handleFieldInits();
116         
117         if ((staticFieldInits != null) || (staticInitializerBlocks != null)) {
118             soot.SootMethod clinitMethod;
119             if (!sootClass.declaresMethod("<clinit>", new ArrayList(), soot.VoidType.v())) {
120                 clinitMethod = new soot.SootMethod("<clinit>", new ArrayList(), soot.VoidType.v(), soot.Modifier.STATIC, new ArrayList());
121                 
122                 sootClass.addMethod(clinitMethod);
123                 PolyglotMethodSource mSource = new PolyglotMethodSource();
124                 mSource.setJBB(InitialResolver.v().getJBBFactory().createJimpleBodyBuilder());
125                 clinitMethod.setSource(mSource);
126             }
127             else {
128                 clinitMethod = sootClass.getMethod("<clinit>", new ArrayList(), soot.VoidType.v());
129             
130             }
131             ((PolyglotMethodSource)clinitMethod.getSource()).setStaticFieldInits(staticFieldInits);
132             ((PolyglotMethodSource)clinitMethod.getSource()).setStaticInitializerBlocks(staticInitializerBlocks);
133     
134         }
135     
136     
137         // add final locals to local inner classes inits
138
if (cDecl.type().isLocal()) {
139             AnonLocalClassInfo info = (AnonLocalClassInfo)InitialResolver.v().finalLocalInfo().get(new polyglot.util.IdentityKey(cDecl.type()));
140                 ArrayList finalsList = addFinalLocals(cDecl.body(), info.finalLocalsAvail(), cDecl.type(), info);
141                 Iterator it = sootClass.getMethods().iterator();
142                 while (it.hasNext()){
143                     soot.SootMethod meth = (soot.SootMethod)it.next();
144                     if (meth.getName().equals("<init>")){
145                         ((PolyglotMethodSource)meth.getSource()).setFinalsList(finalsList);
146                     }
147                 }
148             if (!info.inStaticMethod()){
149                 polyglot.types.ClassType outerType = cDecl.type().outer();
150                 addOuterClassThisRefToInit(outerType);
151                 addOuterClassThisRefField(outerType);
152             }
153         }
154         
155         // add outer class ref to constructors of inner classes
156
// and out class field ref (only for non-static inner classes
157
else if (cDecl.type().isNested() && !cDecl.flags().isStatic()) {
158             polyglot.types.ClassType outerType = cDecl.type().outer();
159             addOuterClassThisRefToInit(outerType);
160             addOuterClassThisRefField(outerType);
161         }
162         
163         Util.addLnPosTags(sootClass, cDecl.position());
164     }
165
166     
167     private void findReferences(polyglot.ast.Node node) {
168         TypeListBuilder typeListBuilder = new TypeListBuilder();
169         
170         node.visit(typeListBuilder);
171
172         for( Iterator typeIt = typeListBuilder.getList().iterator(); typeIt.hasNext(); ) {
173
174             final polyglot.types.Type type = (polyglot.types.Type) typeIt.next();
175             if (type.isPrimitive()) continue;
176             if (!type.isClass()) continue;
177             polyglot.types.ClassType classType = (polyglot.types.ClassType)type;
178             soot.Type sootClassType = Util.getSootType(classType);
179             references.add(sootClassType);
180         }
181     }
182
183     /**
184      * Class Body Creation
185      */

186     private void createClassBody(polyglot.ast.ClassBody classBody){
187         
188
189         // reinit static lists
190
staticFieldInits = null;
191         fieldInits = null;
192         initializerBlocks = null;
193         staticInitializerBlocks = null;
194     
195         
196         // handle members
197
Iterator it = classBody.members().iterator();
198         while (it.hasNext()){
199             Object JavaDoc next = it.next();
200             
201             if (next instanceof polyglot.ast.MethodDecl) {
202                 createMethodDecl((polyglot.ast.MethodDecl)next);
203             }
204             else if (next instanceof polyglot.ast.FieldDecl) {
205                 createFieldDecl((polyglot.ast.FieldDecl)next);
206             }
207             else if (next instanceof polyglot.ast.ConstructorDecl){
208                 createConstructorDecl((polyglot.ast.ConstructorDecl)next);
209             }
210             else if (next instanceof polyglot.ast.ClassDecl){
211                 // this handles inner class tags for immediately enclosed
212
// normal nested classes
213
Util.addInnerClassTag(sootClass, Util.getSootType(((polyglot.ast.ClassDecl)next).type()).toString(), sootClass.getName(), ((polyglot.ast.ClassDecl)next).name().toString(), Util.getModifier(((polyglot.ast.ClassDecl)next).flags()));
214             }
215             else if (next instanceof polyglot.ast.Initializer) {
216                 createInitializer((polyglot.ast.Initializer)next);
217             }
218             else {
219                 throw new RuntimeException JavaDoc("Class Body Member not implemented");
220             }
221         }
222         handleInnerClassTags(classBody);
223         handleClassLiteral(classBody);
224         handleAssert(classBody);
225     }
226
227     private void addOuterClassThisRefField(polyglot.types.Type outerType){
228         soot.Type outerSootType = Util.getSootType(outerType);
229         soot.SootField field = new soot.SootField("this$0", outerSootType, soot.Modifier.PRIVATE | soot.Modifier.FINAL);
230         sootClass.addField(field);
231         field.addTag(new soot.tagkit.SyntheticTag());
232     }
233
234     private void addOuterClassThisRefToInit(polyglot.types.Type outerType){
235         soot.Type outerSootType = Util.getSootType(outerType);
236         Iterator it = sootClass.getMethods().iterator();
237         while (it.hasNext()){
238             soot.SootMethod meth = (soot.SootMethod)it.next();
239             if (meth.getName().equals("<init>")){
240                 List newParams = new ArrayList();
241                 newParams.add(outerSootType);
242                 newParams.addAll(meth.getParameterTypes());
243                 meth.setParameterTypes(newParams);
244                 meth.addTag(new soot.tagkit.EnclosingTag());
245                 if (InitialResolver.v().getHasOuterRefInInit() == null){
246                     InitialResolver.v().setHasOuterRefInInit(new ArrayList());
247                 }
248                 InitialResolver.v().getHasOuterRefInInit().add(meth.getDeclaringClass().getType());
249             }
250         }
251     }
252     private void addFinals(polyglot.types.LocalInstance li, ArrayList finalFields){
253         // add as param for init
254
Iterator it = sootClass.getMethods().iterator();
255         while (it.hasNext()){
256             soot.SootMethod meth = (soot.SootMethod)it.next();
257             if (meth.getName().equals("<init>")){
258                 List newParams = new ArrayList();
259                 newParams.addAll(meth.getParameterTypes());
260                 newParams.add(Util.getSootType(li.type()));
261                 meth.setParameterTypes(newParams);
262             }
263         }
264                 
265         // add field
266
soot.SootField sf = new soot.SootField("val$"+li.name(), Util.getSootType(li.type()), soot.Modifier.FINAL | soot.Modifier.PRIVATE);
267         sootClass.addField(sf);
268         finalFields.add(sf);
269         sf.addTag(new soot.tagkit.SyntheticTag());
270     }
271     private ArrayList addFinalLocals(polyglot.ast.ClassBody cBody, ArrayList finalLocalsAvail, polyglot.types.ClassType nodeKeyType, AnonLocalClassInfo info){
272         ArrayList finalFields = new ArrayList();
273         
274         LocalUsesChecker luc = new LocalUsesChecker();
275         cBody.visit(luc);
276         /*Iterator localsNeededIt = luc.getLocals().iterator();*/
277         ArrayList localsUsed = new ArrayList();
278         /*while (localsNeededIt.hasNext()){
279             polyglot.types.LocalInstance li = (polyglot.types.LocalInstance)((polyglot.util.IdentityKey)localsNeededIt.next()).object();
280             //if (luc.getLocalDecls().contains(new polyglot.util.IdentityKey(li))){
281             //}
282             //else {
283             //}
284             if (finalLocalsAvail.contains(new polyglot.util.IdentityKey(li)) && !luc.getLocalDecls().contains(new polyglot.util.IdentityKey(li))){
285                
286                 addFinals(li,finalFields);
287                 
288                 localsUsed.add(new polyglot.util.IdentityKey(li));
289             }
290         }*/

291         Iterator fieldsNeededIt = finalLocalsAvail.iterator();
292         while (fieldsNeededIt.hasNext()){
293             
294             polyglot.types.LocalInstance li = (polyglot.types.LocalInstance)((polyglot.util.IdentityKey)fieldsNeededIt.next()).object();
295             if (!luc.getLocalDecls().contains(new polyglot.util.IdentityKey(li))){
296                 localsUsed.add(new polyglot.util.IdentityKey(li));
297                 addFinals(li, finalFields);
298             }
299         }
300         
301         // this part is broken it adds all final locals available for the new
302
// not just the ones used (which is a problem)
303
Iterator newsIt = luc.getNews().iterator();
304         while (newsIt.hasNext()){
305             polyglot.ast.New tempNew = (polyglot.ast.New)newsIt.next();
306             polyglot.types.ClassType tempNewType = (polyglot.types.ClassType)tempNew.objectType().type();
307             if (InitialResolver.v().finalLocalInfo().containsKey(new polyglot.util.IdentityKey(tempNewType))){
308                 AnonLocalClassInfo lInfo = (AnonLocalClassInfo)InitialResolver.v().finalLocalInfo().get(new polyglot.util.IdentityKey(tempNewType));
309                 Iterator it = lInfo.finalLocalsAvail().iterator();
310                 while (it.hasNext()){
311                     polyglot.types.LocalInstance li2 = (polyglot.types.LocalInstance)((polyglot.util.IdentityKey)it.next()).object();
312                     if (!sootClass.declaresField("val$"+li2.name(), Util.getSootType(li2.type()))){
313                         if (!luc.getLocalDecls().contains(new polyglot.util.IdentityKey(li2))){
314                             addFinals(li2, finalFields);
315                             localsUsed.add(new polyglot.util.IdentityKey(li2));
316                         }
317                     }
318                 }
319             }
320         }
321         // also need to add them if any super class all the way up needs one
322
// because the super() will be made in init and it will require
323
// possibly eventually to send in the finals
324

325         polyglot.types.ClassType superType = (polyglot.types.ClassType)nodeKeyType.superType();
326         while (!Util.getSootType(superType).equals(soot.Scene.v().getSootClass("java.lang.Object").getType())){
327             if (InitialResolver.v().finalLocalInfo().containsKey(new polyglot.util.IdentityKey(superType))){
328                 AnonLocalClassInfo lInfo = (AnonLocalClassInfo)InitialResolver.v().finalLocalInfo().get(new polyglot.util.IdentityKey(superType));
329                 Iterator it = lInfo.finalLocalsAvail().iterator();
330                 while (it.hasNext()){
331                     polyglot.types.LocalInstance li2 = (polyglot.types.LocalInstance)((polyglot.util.IdentityKey)it.next()).object();
332                     if (!sootClass.declaresField("val$"+li2.name(), Util.getSootType(li2.type()))){
333                         if (!luc.getLocalDecls().contains(new polyglot.util.IdentityKey(li2))){
334                             addFinals(li2, finalFields);
335                             localsUsed.add(new polyglot.util.IdentityKey(li2));
336                         }
337                     }
338                 }
339             }
340             superType = (polyglot.types.ClassType)superType.superType();
341         }
342         info.finalLocalsUsed(localsUsed);
343         InitialResolver.v().finalLocalInfo().put(new polyglot.util.IdentityKey(nodeKeyType), info);
344         return finalFields;
345     }
346     /**
347      * creates the Jimple for an anon class - in the AST there is no class
348      * decl for anon classes - the revelant fields and methods are
349      * created
350      */

351     private void createAnonClassDecl(polyglot.ast.New aNew) {
352         
353         SootClass outerClass = ((soot.RefType)Util.getSootType(aNew.anonType().outer())).getSootClass();
354         if (InitialResolver.v().getInnerClassInfoMap() == null){
355             InitialResolver.v().setInnerClassInfoMap(new HashMap());
356         }
357         InitialResolver.v().getInnerClassInfoMap().put(sootClass, new InnerClassInfo(outerClass, "0", InnerClassInfo.ANON));
358         sootClass.setOuterClass(outerClass);
359     
360         soot.SootClass typeClass = ((soot.RefType)Util.getSootType(aNew.objectType().type())).getSootClass();
361        
362         // set superclass
363
if (((polyglot.types.ClassType)aNew.objectType().type()).flags().isInterface()){
364             sootClass.addInterface(typeClass);
365             sootClass.setSuperclass(soot.Scene.v().getSootClass("java.lang.Object"));
366         }
367         else {
368             sootClass.setSuperclass(typeClass);
369             if (((polyglot.types.ClassType)aNew.objectType().type()).isNested()){
370                 polyglot.types.ClassType superType = (polyglot.types.ClassType)aNew.objectType().type();
371                 // add inner clas tag
372
Util.addInnerClassTag(sootClass, typeClass.getName(), ((soot.RefType)Util.getSootType(superType.outer())).toString(), superType.name(), Util.getModifier(superType.flags()));
373
374             }
375         }
376
377         // needs to be done for local also
378
ArrayList params = new ArrayList();
379             
380         soot.SootMethod method;
381         // if interface there are no extra params
382
if (((polyglot.types.ClassType)aNew.objectType().type()).flags().isInterface()){
383             method = new soot.SootMethod("<init>", params, soot.VoidType.v());
384         }
385         else {
386             if (!aNew.arguments().isEmpty()){
387                
388                 polyglot.types.ConstructorInstance ci = InitialResolver.v().getConstructorForAnon(aNew);
389                 Iterator aIt = ci.formalTypes().iterator();
390                 while (aIt.hasNext()){
391                     polyglot.types.Type pType = (polyglot.types.Type)aIt.next();
392                     params.add(Util.getSootType(pType));
393                 }
394             }
395             /*Iterator aIt = aNew.arguments().iterator();
396             while (aIt.hasNext()){
397                 polyglot.types.Type pType = ((polyglot.ast.Expr)aIt.next()).type();
398                 params.add(Util.getSootType(pType));
399             }*/

400             method = new soot.SootMethod("<init>", params, soot.VoidType.v());
401         }
402         
403         AnonClassInitMethodSource src = new AnonClassInitMethodSource();
404         method.setSource(src);
405         sootClass.addMethod(method);
406    
407         AnonLocalClassInfo info = (AnonLocalClassInfo)InitialResolver.v().finalLocalInfo().get(new polyglot.util.IdentityKey(aNew.anonType()));
408       
409         if (aNew.qualifier() != null){// && (!(aNew.qualifier() instanceof polyglot.ast.Special && ((polyglot.ast.Special)aNew.qualifier()).kind() == polyglot.ast.Special.THIS)) ){
410
//if (aNew.qualifier() != null ) {
411
// add qualifier ref - do this first to get right order
412
addQualifierRefToInit(aNew.qualifier().type());
413             src.hasQualifier(true);
414         }
415         if (info != null && !info.inStaticMethod()){
416             if (!InitialResolver.v().isAnonInCCall(aNew.anonType())){
417                 addOuterClassThisRefToInit(aNew.anonType().outer());
418                 addOuterClassThisRefField(aNew.anonType().outer());
419                 src.thisOuterType(Util.getSootType(aNew.anonType().outer()));
420                 src.hasOuterRef(true);
421             }
422         }
423         src.polyglotType((polyglot.types.ClassType)aNew.anonType().superType());
424         src.anonType((polyglot.types.ClassType)aNew.anonType());
425         src.inStaticMethod(info.inStaticMethod());
426         if (info != null){
427             src.setFinalsList(addFinalLocals(aNew.body(), info.finalLocalsAvail(), (polyglot.types.ClassType)aNew.anonType(), info));
428         }
429         src.outerClassType(Util.getSootType(aNew.anonType().outer()));
430         if (((polyglot.types.ClassType)aNew.objectType().type()).isNested()){
431             src.superOuterType(Util.getSootType(((polyglot.types.ClassType)aNew.objectType().type()).outer()));
432             src.isSubType(Util.isSubType(aNew.anonType().outer(), ((polyglot.types.ClassType)aNew.objectType().type()).outer()));
433         }
434         
435         Util.addLnPosTags(sootClass, aNew.position().line(), aNew.body().position().endLine(), aNew.position().column(), aNew.body().position().endColumn());
436     }
437
438     public int getModifiers(polyglot.types.Flags flags){
439         return Util.getModifier(flags);
440     }
441     
442     /**
443      * adds modifiers
444      */

445     private void addModifiers(polyglot.types.Flags flags, polyglot.ast.ClassDecl cDecl){
446         int modifiers = 0;
447         if (cDecl.type().isNested()){
448             if (flags.isPublic() || flags.isProtected() || flags.isPrivate()){
449                 modifiers = soot.Modifier.PUBLIC;
450             }
451             if (flags.isInterface()){
452                 modifiers = modifiers | soot.Modifier.INTERFACE;
453             }
454             if (flags.isAbstract()){
455                 modifiers = modifiers | soot.Modifier.ABSTRACT;
456             }
457             // if inner classes are declared in an interface they need to be
458
// given public access but I have no idea why
459
// if inner classes are declared in an interface the are
460
// implicitly static and public (jls9.5)
461
if (cDecl.type().outer().flags().isInterface()){
462                 modifiers = modifiers | soot.Modifier.PUBLIC;
463             }
464         }
465         else {
466             modifiers = getModifiers(flags);
467         }
468         sootClass.setModifiers(modifiers);
469     }
470
471     private soot.SootClass getSpecialInterfaceAnonClass(soot.SootClass addToClass){
472         // check to see if there is already a special anon class for this
473
// interface
474
if ((InitialResolver.v().specialAnonMap() != null) && (InitialResolver.v().specialAnonMap().containsKey(addToClass))){
475             return (soot.SootClass)InitialResolver.v().specialAnonMap().get(addToClass);
476         }
477         else {
478             String JavaDoc specialClassName = addToClass.getName()+"$"+InitialResolver.v().getNextAnonNum();
479             // add class to scene and other maps and lists as needed
480
soot.SootClass specialClass = new soot.SootClass(specialClassName);
481             soot.Scene.v().addClass(specialClass);
482             specialClass.setApplicationClass();
483             specialClass.addTag(new soot.tagkit.SyntheticTag());
484             specialClass.setSuperclass(soot.Scene.v().getSootClass("java.lang.Object"));
485             Util.addInnerClassTag(addToClass, specialClass.getName(), addToClass.getName(), null, soot.Modifier.STATIC);
486             Util.addInnerClassTag(specialClass, specialClass.getName(), addToClass.getName(), null, soot.Modifier.STATIC);
487             InitialResolver.v().addNameToAST(specialClassName);
488             references.add(specialClassName);
489             if (InitialResolver.v().specialAnonMap() == null){
490                 InitialResolver.v().setSpecialAnonMap(new HashMap());
491             }
492             InitialResolver.v().specialAnonMap().put(addToClass, specialClass);
493             return specialClass;
494         }
495     }
496         
497     /**
498      * Handling for assert stmts - extra fields and methods are needed
499      * in the Jimple
500      */

501     private void handleAssert(polyglot.ast.ClassBody cBody){
502         
503         // find any asserts in class body but not in inner class bodies
504
AssertStmtChecker asc = new AssertStmtChecker();
505         cBody.visit(asc);
506         if (!asc.isHasAssert()) return;
507         
508         // two extra fields
509

510         // $assertionsDisabled field is added to the actual class where the
511
// assert is found (even if its an inner class - interfaces cannot
512
// have asserts stmts directly contained within them)
513
String JavaDoc fieldName = "$assertionsDisabled";
514         soot.Type fieldType = soot.BooleanType.v();
515         if (!sootClass.declaresField(fieldName, fieldType)){
516             soot.SootField assertionsDisabledField = new soot.SootField(fieldName, fieldType, soot.Modifier.STATIC | soot.Modifier.FINAL);
517             sootClass.addField(assertionsDisabledField);
518             assertionsDisabledField.addTag(new soot.tagkit.SyntheticTag());
519         }
520
521         // class$ field is added to the outer most class if sootClass
522
// containing the assert is inner - if the outer most class is
523
// an interface - add instead to special interface anon class
524
soot.SootClass addToClass = sootClass;
525         while ((InitialResolver.v().getInnerClassInfoMap() != null) && (InitialResolver.v().getInnerClassInfoMap().containsKey(addToClass))){
526             addToClass = ((InnerClassInfo)InitialResolver.v().getInnerClassInfoMap().get(addToClass)).getOuterClass();
527         }
528         
529         // this field is named after the outer class even if the outer
530
// class is an interface and will be actually added to the
531
// special interface anon class
532
fieldName = "class$"+soot.util.StringTools.replaceAll(addToClass.getName(), ".", "$");
533         if ((InitialResolver.v().getInterfacesList() != null) && (InitialResolver.v().getInterfacesList().contains(addToClass.getName()))) {
534             addToClass = getSpecialInterfaceAnonClass(addToClass);
535         }
536         
537         fieldType = soot.RefType.v("java.lang.Class");
538         
539         if (!addToClass.declaresField(fieldName, fieldType)){
540             soot.SootField classField =new soot.SootField(fieldName, fieldType, soot.Modifier.STATIC);
541             addToClass.addField(classField);
542             classField.addTag(new soot.tagkit.SyntheticTag());
543         }
544         
545         // two extra methods
546

547         // class$ method is added to the outer most class if sootClass
548
// containing the assert is inner - if the outer most class is
549
// an interface - add instead to special interface anon class
550
String JavaDoc methodName = "class$";
551         soot.Type methodRetType = soot.RefType.v("java.lang.Class");
552         ArrayList paramTypes = new ArrayList();
553         paramTypes.add(soot.RefType.v("java.lang.String"));
554         
555         // make meth
556
soot.SootMethod sootMethod = new soot.SootMethod(methodName, paramTypes, methodRetType, soot.Modifier.STATIC);
557         AssertClassMethodSource assertMSrc = new AssertClassMethodSource();
558         sootMethod.setSource(assertMSrc);
559         
560         if (!addToClass.declaresMethod(methodName, paramTypes, methodRetType)){
561             addToClass.addMethod(sootMethod);
562             sootMethod.addTag(new soot.tagkit.SyntheticTag());
563         }
564
565         // clinit method is added to actual class where assert is found
566
// if the class already has a clinit method its method source is
567
// informed of an assert
568
methodName = "<clinit>";
569         methodRetType = soot.VoidType.v();
570         paramTypes = new ArrayList();
571         
572         // make meth
573
sootMethod = new soot.SootMethod(methodName, paramTypes, methodRetType, soot.Modifier.STATIC);
574         PolyglotMethodSource mSrc = new PolyglotMethodSource();
575         mSrc.setJBB(InitialResolver.v().getJBBFactory().createJimpleBodyBuilder());
576         mSrc.hasAssert(true);
577         sootMethod.setSource(mSrc);
578         
579         if (!sootClass.declaresMethod(methodName, paramTypes, methodRetType)){
580             sootClass.addMethod(sootMethod);
581         }
582         else {
583             ((soot.javaToJimple.PolyglotMethodSource)sootClass.getMethod(methodName, paramTypes, methodRetType).getSource()).hasAssert(true);
584         }
585     }
586     /**
587      * Constructor Declaration Creation
588      */

589     private void createConstructorDecl(polyglot.ast.ConstructorDecl constructor){
590         String JavaDoc name = "<init>";
591     
592         ArrayList parameters = createParameters(constructor);
593     
594         ArrayList exceptions = createExceptions(constructor);
595     
596         soot.SootMethod sootMethod = createSootConstructor(name, constructor.flags(), parameters, exceptions);
597     
598         finishProcedure(constructor, sootMethod);
599     }
600     /**
601      * Method Declaration Creation
602      */

603     private void createMethodDecl(polyglot.ast.MethodDecl method) {
604     
605         String JavaDoc name = createName(method);
606             
607         // parameters
608
ArrayList parameters = createParameters(method);
609                   
610         // exceptions
611
ArrayList exceptions = createExceptions(method);
612     
613         soot.SootMethod sootMethod = createSootMethod(name, method.flags(), method.returnType().type(), parameters, exceptions);
614     
615         finishProcedure(method, sootMethod);
616     }
617     /**
618      * looks after pos tags for methods and constructors
619      */

620     private void finishProcedure(polyglot.ast.ProcedureDecl procedure, soot.SootMethod sootMethod){
621         
622         addProcedureToClass(sootMethod);
623     
624         if (procedure.position() != null){
625                 if (procedure.body() != null) {
626                     if (procedure.body().position() != null) {
627                         Util.addLnPosTags(sootMethod, procedure.position().line(), procedure.body().position().endLine(), procedure.position().column(), procedure.body().position().endColumn());
628                     }
629                 }
630                 else {
631                     Util.addLnPosTags(sootMethod, procedure.position());
632                 }
633                 
634         }
635     
636     
637         PolyglotMethodSource mSrc = new PolyglotMethodSource(procedure.body(), procedure.formals());
638         mSrc.setJBB(InitialResolver.v().getJBBFactory().createJimpleBodyBuilder());
639         
640         sootMethod.setSource(mSrc);
641         
642     }
643
644     private void handleFieldInits(){
645         if ((fieldInits != null) || (initializerBlocks != null)) {
646             Iterator methodsIt = sootClass.getMethods().iterator();
647             while (methodsIt.hasNext()) {
648                 soot.SootMethod next = (soot.SootMethod)methodsIt.next();
649                 if (next.getName().equals("<init>")){
650                
651                         soot.javaToJimple.PolyglotMethodSource src = (soot.javaToJimple.PolyglotMethodSource)next.getSource();
652                         src.setInitializerBlocks(initializerBlocks);
653                         src.setFieldInits(fieldInits);
654           
655                 }
656             }
657         }
658         
659     }
660     private void handleClassLiteral(polyglot.ast.ClassBody cBody){
661     
662         // check for class lits whose type is not primitive
663
ClassLiteralChecker classLitChecker = new ClassLiteralChecker();
664         cBody.visit(classLitChecker);
665         ArrayList classLitList = classLitChecker.getList();
666         
667         if (!classLitList.isEmpty()){
668
669             soot.SootClass addToClass = sootClass;
670             if (addToClass.isInterface()) {
671                 addToClass = getSpecialInterfaceAnonClass(addToClass);
672             }
673             
674             // add class$ meth
675
String JavaDoc methodName = "class$";
676             soot.Type methodRetType = soot.RefType.v("java.lang.Class");
677             ArrayList paramTypes = new ArrayList();
678             paramTypes.add(soot.RefType.v("java.lang.String"));
679             soot.SootMethod sootMethod = new soot.SootMethod(methodName, paramTypes, methodRetType, soot.Modifier.STATIC);
680             ClassLiteralMethodSource mSrc = new ClassLiteralMethodSource();
681             sootMethod.setSource(mSrc);
682             
683             if (!addToClass.declaresMethod(methodName, paramTypes, methodRetType)){
684                 addToClass.addMethod(sootMethod);
685                 sootMethod.addTag(new soot.tagkit.SyntheticTag());
686             }
687             
688
689             // add fields for all non prim class lits
690
Iterator classLitIt = classLitList.iterator();
691             while (classLitIt.hasNext()) {
692                 polyglot.ast.ClassLit classLit = (polyglot.ast.ClassLit)classLitIt.next();
693         
694                 // field
695
String JavaDoc fieldName = Util.getFieldNameForClassLit(classLit.typeNode().type());
696                 soot.Type fieldType = soot.RefType.v("java.lang.Class");
697                 
698                 soot.SootField sootField = new soot.SootField(fieldName, fieldType, soot.Modifier.STATIC);
699                 if (!addToClass.declaresField(fieldName, fieldType)){
700                     addToClass.addField(sootField);
701                     sootField.addTag(new soot.tagkit.SyntheticTag());
702                 }
703             }
704         }
705     }
706     /**
707      * returns the name of the class without the package part
708      */

709     private String JavaDoc getSimpleClassName(){
710         String JavaDoc name = sootClass.getName();
711         if (sootClass.getPackageName() != null){
712             name = name.substring(name.lastIndexOf(".")+1, name.length());
713         }
714         return name;
715     }
716     /**
717      * Source Creation
718      */

719     protected void createSource(polyglot.ast.SourceFile source){
720     
721         // add absolute path to sourceFileTag
722
if (sootClass.hasTag("SourceFileTag")){
723             soot.tagkit.SourceFileTag t = (soot.tagkit.SourceFileTag)sootClass.getTag("SourceFileTag");
724             /*System.out.println("source: "+source);
725             System.out.println("source.source(): "+source.source());
726             System.out.println("source path: "+source.source().path());
727             System.out.println("source name: "+source.source().name());*/

728             t.setAbsolutePath(source.source().path());
729         }
730         else {
731             soot.tagkit.SourceFileTag t = new soot.tagkit.SourceFileTag();
732             /*System.out.println("source: "+source);
733             System.out.println("source.source(): "+source.source());
734             System.out.println("source path: "+source.source().path());
735             System.out.println("source name: "+source.source().name());*/

736             t.setAbsolutePath(source.source().path());
737             sootClass.addTag(t);
738         }
739         
740         String JavaDoc simpleName = sootClass.getName();
741         
742         Iterator declsIt = source.decls().iterator();
743         boolean found = false;
744     
745         // first look in top-level decls
746
while (declsIt.hasNext()){
747             Object JavaDoc next = declsIt.next();
748             if (next instanceof polyglot.ast.ClassDecl) {
749                 polyglot.types.ClassType nextType = ((polyglot.ast.ClassDecl)next).type();
750                 if (Util.getSootType(nextType).equals(sootClass.getType())){
751                     createClassDecl((polyglot.ast.ClassDecl)next);
752                     found = true;
753                 }
754             }
755         }
756     
757         // if the class wasn't a top level then its nested, local or anon
758
if (!found) {
759             NestedClassListBuilder nestedClassBuilder = new NestedClassListBuilder();
760             source.visit(nestedClassBuilder);
761             
762             Iterator nestedDeclsIt = nestedClassBuilder.getClassDeclsList().iterator();
763             while (nestedDeclsIt.hasNext() && !found){
764                 
765                 polyglot.ast.ClassDecl nextDecl = (polyglot.ast.ClassDecl)nestedDeclsIt.next();
766                 polyglot.types.ClassType type = (polyglot.types.ClassType)nextDecl.type();
767                 if (type.isLocal() && !type.isAnonymous()) {
768                    
769                     if (InitialResolver.v().getLocalClassMap().containsVal(simpleName)){
770                         createClassDecl(((polyglot.ast.LocalClassDecl)InitialResolver.v().getLocalClassMap().getKey(simpleName)).decl());
771                         found = true;
772                     }
773                 }
774                 else {
775                
776                     if (Util.getSootType(type).equals(sootClass.getType())){
777                         createClassDecl(nextDecl);
778                         found = true;
779                     }
780                 }
781             }
782     
783             if (!found) {
784                 // assume its anon class (only option left)
785
//
786
if ((InitialResolver.v().getAnonClassMap() != null) && InitialResolver.v().getAnonClassMap().containsVal(simpleName)){
787                     
788                     polyglot.ast.New aNew = (polyglot.ast.New)InitialResolver.v().getAnonClassMap().getKey(simpleName);
789                     createAnonClassDecl(aNew);
790                     findReferences(aNew.body());
791                     createClassBody(aNew.body());
792                     handleFieldInits();
793     
794                 }
795                 else {
796                     // could be an anon class that was created out of thin air
797
// for handling class lits (and asserts) in interfaces
798
// this is now done on creation of this special class
799
//sootClass.setSuperclass(soot.Scene.v().getSootClass("java.lang.Object"));
800
}
801             }
802         }
803     
804         
805     }
806
807     private void handleInnerClassTags(polyglot.ast.ClassBody classBody){
808         // if this class is an inner class add self
809
if ((InitialResolver.v().getInnerClassInfoMap() != null) && (InitialResolver.v().getInnerClassInfoMap().containsKey(sootClass))){
810             //hasTag("OuterClassTag")){
811

812             InnerClassInfo tag = (InnerClassInfo)InitialResolver.v().getInnerClassInfoMap().get(sootClass);
813             Util.addInnerClassTag(sootClass, sootClass.getName(), tag.getInnerType() == InnerClassInfo.ANON ? null : tag.getOuterClass().getName(), tag.getInnerType() == InnerClassInfo.ANON ? null : tag.getSimpleName(), soot.Modifier.isInterface(tag.getOuterClass().getModifiers()) ? soot.Modifier.STATIC | soot.Modifier.PUBLIC : sootClass.getModifiers());
814             // if this class is an inner class and enclosing class is also
815
// an inner class add enclsing class
816
SootClass outerClass = tag.getOuterClass();
817             while (InitialResolver.v().getInnerClassInfoMap().containsKey(outerClass)){
818                 InnerClassInfo tag2 = (InnerClassInfo)InitialResolver.v().getInnerClassInfoMap().get(outerClass);
819                 Util.addInnerClassTag(sootClass, outerClass.getName(), tag2.getInnerType() == InnerClassInfo.ANON ? null : tag2.getOuterClass().getName(), tag2.getInnerType() == InnerClassInfo.ANON ? null : tag2.getSimpleName(), tag2.getInnerType() == InnerClassInfo.ANON && soot.Modifier.isInterface(tag2.getOuterClass().getModifiers()) ? soot.Modifier.STATIC | soot.Modifier.PUBLIC : outerClass.getModifiers());
820                 outerClass = tag2.getOuterClass();
821             }
822         }
823     
824     }
825     private void addQualifierRefToInit(polyglot.types.Type type){
826         soot.Type sootType = Util.getSootType(type);
827         Iterator it = sootClass.getMethods().iterator();
828         while (it.hasNext()){
829             soot.SootMethod meth = (soot.SootMethod)it.next();
830             if (meth.getName().equals("<init>")){
831                 List newParams = new ArrayList();
832                 newParams.add(sootType);
833                 newParams.addAll(meth.getParameterTypes());
834                 meth.setParameterTypes(newParams);
835                 meth.addTag(new soot.tagkit.QualifyingTag());
836             }
837         }
838     }
839     private void addProcedureToClass(soot.SootMethod method) {
840         sootClass.addMethod(method);
841     }
842     
843     private void addConstValTag(polyglot.ast.FieldDecl field, soot.SootField sootField){
844         //G.v().out.println("adding constantval tag to field: "+field);
845
if (field.fieldInstance().constantValue() instanceof Integer JavaDoc){
846             sootField.addTag(new soot.tagkit.IntegerConstantValueTag(((Integer JavaDoc)field.fieldInstance().constantValue()).intValue()));
847         }
848         else if (field.fieldInstance().constantValue() instanceof Character JavaDoc){
849             sootField.addTag(new soot.tagkit.IntegerConstantValueTag(((Character JavaDoc)field.fieldInstance().constantValue()).charValue()));
850         }
851         else if (field.fieldInstance().constantValue() instanceof Short JavaDoc){
852             sootField.addTag(new soot.tagkit.IntegerConstantValueTag(((Short JavaDoc)field.fieldInstance().constantValue()).shortValue()));
853         }
854         else if (field.fieldInstance().constantValue() instanceof Byte JavaDoc){
855             sootField.addTag(new soot.tagkit.IntegerConstantValueTag(((Byte JavaDoc)field.fieldInstance().constantValue()).byteValue()));
856         }
857         else if (field.fieldInstance().constantValue() instanceof Boolean JavaDoc){
858             boolean b = ((Boolean JavaDoc)field.fieldInstance().constantValue()).booleanValue();
859             sootField.addTag(new soot.tagkit.IntegerConstantValueTag(b ? 1: 0));
860         }
861         else if (field.fieldInstance().constantValue() instanceof Long JavaDoc){
862             sootField.addTag(new soot.tagkit.LongConstantValueTag(((Long JavaDoc)field.fieldInstance().constantValue()).longValue()));
863         }
864         else if (field.fieldInstance().constantValue() instanceof Double JavaDoc){
865             //System.out.println("const val: "+field.fieldInstance().constantValue());
866
sootField.addTag(new soot.tagkit.DoubleConstantValueTag((long)((Double JavaDoc)field.fieldInstance().constantValue()).doubleValue()));
867             //System.out.println(((Double)field.fieldInstance().constantValue()).doubleValue());
868
soot.tagkit.DoubleConstantValueTag tag = (soot.tagkit.DoubleConstantValueTag)sootField.getTag("DoubleConstantValueTag");
869             //System.out.println("tag: "+tag);
870
}
871         else if (field.fieldInstance().constantValue() instanceof Float JavaDoc){
872             sootField.addTag(new soot.tagkit.FloatConstantValueTag(((Float JavaDoc)field.fieldInstance().constantValue()).floatValue()));
873         }
874         else if (field.fieldInstance().constantValue() instanceof String JavaDoc){
875             sootField.addTag(new soot.tagkit.StringConstantValueTag((String JavaDoc)field.fieldInstance().constantValue()));
876         }
877         else {
878             throw new RuntimeException JavaDoc("Expecting static final field to have a constant value! For field: "+field+" of type: "+field.fieldInstance().constantValue().getClass());
879         }
880     }
881     
882     /**
883      * Field Declaration Creation
884      */

885     private void createFieldDecl(polyglot.ast.FieldDecl field){
886    
887         //System.out.println("field decl: "+field);
888
int modifiers = Util.getModifier(field.fieldInstance().flags());
889         String JavaDoc name = field.fieldInstance().name();
890         soot.Type sootType = Util.getSootType(field.fieldInstance().type());
891         soot.SootField sootField = new soot.SootField(name, sootType, modifiers);
892         sootClass.addField(sootField);
893     
894         
895         if (field.fieldInstance().flags().isStatic()) {
896             if (field.init() != null) {
897                 if (field.flags().isFinal() && (field.type().type().isPrimitive() || (field.type().type().toString().equals("java.lang.String"))) && field.fieldInstance().isConstant()){
898                     //System.out.println("adding constantValtag: to field: "+sootField);
899
addConstValTag(field, sootField);
900                 }
901                 else {
902                     if (staticFieldInits == null) {
903                         staticFieldInits = new ArrayList();
904                     }
905                     staticFieldInits.add(field);
906                 }
907             }
908         }
909         else {
910             if (field.init() != null) {
911                 if (fieldInits == null) {
912                     fieldInits = new ArrayList();
913                 }
914                 fieldInits.add(field);
915             }
916         }
917     
918     
919         Util.addLnPosTags(sootField, field.position());
920     }
921     ClassResolver( SootClass sootClass, List references ) {
922         this.sootClass = sootClass;
923         this.references = references;
924     }
925     private final SootClass sootClass;
926     private final List references;
927
928     
929     /**
930      * Procedure Declaration Helper Methods
931      * creates procedure name
932      */

933     private String JavaDoc createName(polyglot.ast.ProcedureDecl procedure) {
934         return procedure.name();
935     }
936
937     /**
938      * creates soot params from polyglot formals
939      */

940     private ArrayList createParameters(polyglot.ast.ProcedureDecl procedure) {
941         ArrayList parameters = new ArrayList();
942         Iterator formalsIt = procedure.formals().iterator();
943         while (formalsIt.hasNext()){
944             polyglot.ast.Formal next = (polyglot.ast.Formal)formalsIt.next();
945             parameters.add(Util.getSootType(next.type().type()));
946         }
947         return parameters;
948     }
949     
950     /**
951      * creates soot exceptions from polyglot throws
952      */

953     private ArrayList createExceptions(polyglot.ast.ProcedureDecl procedure) {
954         ArrayList exceptions = new ArrayList();
955         Iterator throwsIt = procedure.throwTypes().iterator();
956         while (throwsIt.hasNext()){
957             polyglot.types.Type throwType = ((polyglot.ast.TypeNode)throwsIt.next()).type();
958             exceptions.add(((soot.RefType)Util.getSootType(throwType)).getSootClass());
959         }
960         return exceptions;
961     }
962     
963     
964     private soot.SootMethod createSootMethod(String JavaDoc name, polyglot.types.Flags flags , polyglot.types.Type returnType, ArrayList parameters, ArrayList exceptions){
965         
966         int modifier = Util.getModifier(flags);
967         soot.Type sootReturnType = Util.getSootType(returnType);
968
969         soot.SootMethod method = new soot.SootMethod(name, parameters, sootReturnType, modifier, exceptions);
970         return method;
971     }
972     
973     /**
974      * Initializer Creation
975      */

976     private void createInitializer(polyglot.ast.Initializer initializer) {
977         if (initializer.flags().isStatic()) {
978             if (staticInitializerBlocks == null) {
979                 staticInitializerBlocks = new ArrayList();
980             }
981             staticInitializerBlocks.add(initializer.body());
982         }
983         else {
984             if (initializerBlocks == null) {
985                 initializerBlocks = new ArrayList();
986             }
987             initializerBlocks.add(initializer.body());
988         }
989     }
990     
991     private soot.SootMethod createSootConstructor(String JavaDoc name, polyglot.types.Flags flags, ArrayList parameters, ArrayList exceptions) {
992         
993         int modifier = Util.getModifier(flags);
994
995         soot.SootMethod method = new soot.SootMethod(name, parameters, soot.VoidType.v(), modifier, exceptions);
996
997         return method;
998     }
999     
1000}
1001
1002
Popular Tags