0001: /* Soot - a J*va Optimization Framework
0002: * Copyright (C) 2004 Jennifer Lhotak
0003: *
0004: * This library is free software; you can redistribute it and/or
0005: * modify it under the terms of the GNU Lesser General Public
0006: * License as published by the Free Software Foundation; either
0007: * version 2.1 of the License, or (at your option) any later version.
0008: *
0009: * This library is distributed in the hope that it will be useful,
0010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0012: * Lesser General Public License for more details.
0013: *
0014: * You should have received a copy of the GNU Lesser General Public
0015: * License along with this library; if not, write to the
0016: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
0017: * Boston, MA 02111-1307, USA.
0018: */
0019:
0020: package soot.javaToJimple;
0021:
0022: import soot.*;
0023: import soot.options.Options;
0024:
0025: import java.util.*;
0026:
0027: import polyglot.ast.Block;
0028: import polyglot.ast.FieldDecl;
0029: import polyglot.ast.Node;
0030: import polyglot.types.Type;
0031: import polyglot.util.IdentityKey;
0032:
0033: public class ClassResolver {
0034:
0035: private ArrayList<FieldDecl> staticFieldInits;
0036: private ArrayList<FieldDecl> fieldInits;
0037: private ArrayList<Block> initializerBlocks;
0038: private ArrayList<Block> staticInitializerBlocks;
0039:
0040: /**
0041: * adds source file tag to each sootclass
0042: */
0043: protected void addSourceFileTag(soot.SootClass sc) {
0044: soot.tagkit.SourceFileTag tag = null;
0045: if (sc.hasTag("SourceFileTag")) {
0046: tag = (soot.tagkit.SourceFileTag) sc
0047: .getTag("SourceFileTag");
0048: } else {
0049: tag = new soot.tagkit.SourceFileTag();
0050: sc.addTag(tag);
0051: }
0052:
0053: String name = Util.getSourceFileOfClass(sc);
0054:
0055: if (InitialResolver.v().classToSourceMap() != null) {
0056: if (InitialResolver.v().classToSourceMap()
0057: .containsKey(name)) {
0058: name = InitialResolver.v().classToSourceMap().get(name);
0059: }
0060: }
0061:
0062: // the pkg is not included in the tag for some unknown reason
0063: // I think in this case windows uses the same slash - may cause
0064: // windows problems though
0065: int slashIndex = name.lastIndexOf("/");
0066: if (slashIndex != -1) {
0067: name = name.substring(slashIndex + 1);
0068: }
0069: tag.setSourceFile(name);
0070: //sc.addTag(new soot.tagkit.SourceFileTag(name));
0071: }
0072:
0073: /**
0074: * Class Declaration Creation
0075: */
0076: private void createClassDecl(polyglot.ast.ClassDecl cDecl) {
0077:
0078: //add outer class tag if neccessary (if class is not top-level)
0079: if (!cDecl.type().isTopLevel()) {
0080: SootClass outerClass = ((soot.RefType) Util
0081: .getSootType(cDecl.type().outer())).getSootClass();
0082:
0083: if (InitialResolver.v().getInnerClassInfoMap() == null) {
0084: InitialResolver.v().setInnerClassInfoMap(
0085: new HashMap<SootClass, InnerClassInfo>());
0086: }
0087: InitialResolver.v().getInnerClassInfoMap().put(
0088: sootClass,
0089: new InnerClassInfo(outerClass, cDecl.name(),
0090: InnerClassInfo.NESTED));
0091: sootClass.setOuterClass(outerClass);
0092: }
0093:
0094: // modifiers
0095: polyglot.types.Flags flags = cDecl.flags();
0096: addModifiers(flags, cDecl);
0097:
0098: // super class
0099: if (cDecl.super Class() == null) {
0100: soot.SootClass super Class = soot.Scene.v().getSootClass(
0101: "java.lang.Object");
0102: sootClass.setSuperclass(super Class);
0103: } else {
0104:
0105: sootClass.setSuperclass(((soot.RefType) Util
0106: .getSootType(cDecl.super Class().type()))
0107: .getSootClass());
0108: if (((polyglot.types.ClassType) cDecl.super Class().type())
0109: .isNested()) {
0110: polyglot.types.ClassType super Type = (polyglot.types.ClassType) cDecl
0111: .super Class().type();
0112: // add inner clas tag
0113:
0114: Util.addInnerClassTag(sootClass, sootClass.getName(),
0115: ((soot.RefType) Util.getSootType(super Type
0116: .outer())).toString(),
0117: super Type.name(), Util.getModifier(super Type
0118: .flags()));
0119: }
0120:
0121: }
0122:
0123: // implements
0124: Iterator interfacesIt = cDecl.interfaces().iterator();
0125: while (interfacesIt.hasNext()) {
0126: polyglot.ast.TypeNode next = (polyglot.ast.TypeNode) interfacesIt
0127: .next();
0128: sootClass.addInterface(((soot.RefType) Util
0129: .getSootType(next.type())).getSootClass());
0130: }
0131:
0132: findReferences(cDecl);
0133: createClassBody(cDecl.body());
0134:
0135: // handle initialization of fields
0136: // static fields init in clinit
0137: // other fields init in init
0138: handleFieldInits();
0139:
0140: if ((staticFieldInits != null)
0141: || (staticInitializerBlocks != null)) {
0142: soot.SootMethod clinitMethod;
0143: if (!sootClass.declaresMethod("<clinit>", new ArrayList(),
0144: soot.VoidType.v())) {
0145: clinitMethod = new soot.SootMethod("<clinit>",
0146: new ArrayList(), soot.VoidType.v(),
0147: soot.Modifier.STATIC,
0148: new ArrayList<SootClass>());
0149:
0150: sootClass.addMethod(clinitMethod);
0151: PolyglotMethodSource mSource = new PolyglotMethodSource();
0152: mSource.setJBB(InitialResolver.v().getJBBFactory()
0153: .createJimpleBodyBuilder());
0154: clinitMethod.setSource(mSource);
0155: } else {
0156: clinitMethod = sootClass.getMethod("<clinit>",
0157: new ArrayList(), soot.VoidType.v());
0158:
0159: }
0160: ((PolyglotMethodSource) clinitMethod.getSource())
0161: .setStaticFieldInits(staticFieldInits);
0162: ((PolyglotMethodSource) clinitMethod.getSource())
0163: .setStaticInitializerBlocks(staticInitializerBlocks);
0164:
0165: }
0166:
0167: // add final locals to local inner classes inits
0168: if (cDecl.type().isLocal()) {
0169: AnonLocalClassInfo info = InitialResolver.v()
0170: .finalLocalInfo()
0171: .get(new polyglot.util.IdentityKey(cDecl.type()));
0172: ArrayList<SootField> finalsList = addFinalLocals(cDecl
0173: .body(), info.finalLocalsAvail(), cDecl.type(),
0174: info);
0175: Iterator it = sootClass.getMethods().iterator();
0176: while (it.hasNext()) {
0177: soot.SootMethod meth = (soot.SootMethod) it.next();
0178: if (meth.getName().equals("<init>")) {
0179: ((PolyglotMethodSource) meth.getSource())
0180: .setFinalsList(finalsList);
0181: }
0182: }
0183: if (!info.inStaticMethod()) {
0184: polyglot.types.ClassType outerType = cDecl.type()
0185: .outer();
0186: addOuterClassThisRefToInit(outerType);
0187: addOuterClassThisRefField(outerType);
0188: }
0189: }
0190:
0191: // add outer class ref to constructors of inner classes
0192: // and out class field ref (only for non-static inner classes
0193: else if (cDecl.type().isNested() && !cDecl.flags().isStatic()) {
0194: polyglot.types.ClassType outerType = cDecl.type().outer();
0195: addOuterClassThisRefToInit(outerType);
0196: addOuterClassThisRefField(outerType);
0197: }
0198:
0199: Util.addLnPosTags(sootClass, cDecl.position());
0200: }
0201:
0202: private void findReferences(polyglot.ast.Node node) {
0203: TypeListBuilder typeListBuilder = new TypeListBuilder();
0204:
0205: node.visit(typeListBuilder);
0206:
0207: for (Type type : typeListBuilder.getList()) {
0208:
0209: if (type.isPrimitive())
0210: continue;
0211: if (!type.isClass())
0212: continue;
0213: polyglot.types.ClassType classType = (polyglot.types.ClassType) type;
0214: soot.Type sootClassType = Util.getSootType(classType);
0215: references.add(sootClassType);
0216: }
0217: }
0218:
0219: /**
0220: * Class Body Creation
0221: */
0222: private void createClassBody(polyglot.ast.ClassBody classBody) {
0223:
0224: // reinit static lists
0225: staticFieldInits = null;
0226: fieldInits = null;
0227: initializerBlocks = null;
0228: staticInitializerBlocks = null;
0229:
0230: // handle members
0231: Iterator it = classBody.members().iterator();
0232: while (it.hasNext()) {
0233: Object next = it.next();
0234:
0235: if (next instanceof polyglot.ast.MethodDecl) {
0236: createMethodDecl((polyglot.ast.MethodDecl) next);
0237: } else if (next instanceof polyglot.ast.FieldDecl) {
0238: createFieldDecl((polyglot.ast.FieldDecl) next);
0239: } else if (next instanceof polyglot.ast.ConstructorDecl) {
0240: createConstructorDecl((polyglot.ast.ConstructorDecl) next);
0241: } else if (next instanceof polyglot.ast.ClassDecl) {
0242: // this handles inner class tags for immediately enclosed
0243: // normal nested classes
0244: Util
0245: .addInnerClassTag(
0246: sootClass,
0247: Util.getSootType(
0248: ((polyglot.ast.ClassDecl) next)
0249: .type()).toString(),
0250: sootClass.getName(),
0251: ((polyglot.ast.ClassDecl) next).name()
0252: .toString(),
0253: Util
0254: .getModifier(((polyglot.ast.ClassDecl) next)
0255: .flags()));
0256: } else if (next instanceof polyglot.ast.Initializer) {
0257: createInitializer((polyglot.ast.Initializer) next);
0258: } else if (Options.v().verbose()) {
0259: G.v().out
0260: .println("Class Body Member not implemented for type "
0261: + next.getClass().getName());
0262: }
0263: }
0264: handleInnerClassTags(classBody);
0265: handleClassLiteral(classBody);
0266: handleAssert(classBody);
0267: }
0268:
0269: private void addOuterClassThisRefField(polyglot.types.Type outerType) {
0270: soot.Type outerSootType = Util.getSootType(outerType);
0271: soot.SootField field = new soot.SootField("this$0",
0272: outerSootType, soot.Modifier.PRIVATE
0273: | soot.Modifier.FINAL);
0274: sootClass.addField(field);
0275: field.addTag(new soot.tagkit.SyntheticTag());
0276: }
0277:
0278: private void addOuterClassThisRefToInit(
0279: polyglot.types.Type outerType) {
0280: soot.Type outerSootType = Util.getSootType(outerType);
0281: Iterator it = sootClass.getMethods().iterator();
0282: while (it.hasNext()) {
0283: soot.SootMethod meth = (soot.SootMethod) it.next();
0284: if (meth.getName().equals("<init>")) {
0285: List newParams = new ArrayList();
0286: newParams.add(outerSootType);
0287: newParams.addAll(meth.getParameterTypes());
0288: meth.setParameterTypes(newParams);
0289: meth.addTag(new soot.tagkit.EnclosingTag());
0290: if (InitialResolver.v().getHasOuterRefInInit() == null) {
0291: InitialResolver.v().setHasOuterRefInInit(
0292: new ArrayList());
0293: }
0294: InitialResolver.v().getHasOuterRefInInit().add(
0295: meth.getDeclaringClass().getType());
0296: }
0297: }
0298: }
0299:
0300: private void addFinals(polyglot.types.LocalInstance li,
0301: ArrayList<SootField> finalFields) {
0302: // add as param for init
0303: Iterator it = sootClass.getMethods().iterator();
0304: while (it.hasNext()) {
0305: soot.SootMethod meth = (soot.SootMethod) it.next();
0306: if (meth.getName().equals("<init>")) {
0307: List newParams = new ArrayList();
0308: newParams.addAll(meth.getParameterTypes());
0309: newParams.add(Util.getSootType(li.type()));
0310: meth.setParameterTypes(newParams);
0311: }
0312: }
0313:
0314: // add field
0315: soot.SootField sf = new soot.SootField("val$" + li.name(), Util
0316: .getSootType(li.type()), soot.Modifier.FINAL
0317: | soot.Modifier.PRIVATE);
0318: sootClass.addField(sf);
0319: finalFields.add(sf);
0320: sf.addTag(new soot.tagkit.SyntheticTag());
0321: }
0322:
0323: private ArrayList<SootField> addFinalLocals(
0324: polyglot.ast.ClassBody cBody,
0325: ArrayList<IdentityKey> finalLocalsAvail,
0326: polyglot.types.ClassType nodeKeyType,
0327: AnonLocalClassInfo info) {
0328: ArrayList<SootField> finalFields = new ArrayList<SootField>();
0329:
0330: LocalUsesChecker luc = new LocalUsesChecker();
0331: cBody.visit(luc);
0332: /*Iterator localsNeededIt = luc.getLocals().iterator();*/
0333: ArrayList<IdentityKey> localsUsed = new ArrayList<IdentityKey>();
0334: /*while (localsNeededIt.hasNext()){
0335: polyglot.types.LocalInstance li = (polyglot.types.LocalInstance)((polyglot.util.IdentityKey)localsNeededIt.next()).object();
0336: //if (luc.getLocalDecls().contains(new polyglot.util.IdentityKey(li))){
0337: //}
0338: //else {
0339: //}
0340: if (finalLocalsAvail.contains(new polyglot.util.IdentityKey(li)) && !luc.getLocalDecls().contains(new polyglot.util.IdentityKey(li))){
0341:
0342: addFinals(li,finalFields);
0343:
0344: localsUsed.add(new polyglot.util.IdentityKey(li));
0345: }
0346: }*/
0347: Iterator<IdentityKey> fieldsNeededIt = finalLocalsAvail
0348: .iterator();
0349: while (fieldsNeededIt.hasNext()) {
0350:
0351: polyglot.types.LocalInstance li = (polyglot.types.LocalInstance) fieldsNeededIt
0352: .next().object();
0353: if (!luc.getLocalDecls().contains(
0354: new polyglot.util.IdentityKey(li))) {
0355: localsUsed.add(new polyglot.util.IdentityKey(li));
0356: addFinals(li, finalFields);
0357: }
0358: }
0359:
0360: // this part is broken it adds all final locals available for the new
0361: // not just the ones used (which is a problem)
0362: Iterator<Node> newsIt = luc.getNews().iterator();
0363: while (newsIt.hasNext()) {
0364: polyglot.ast.New tempNew = (polyglot.ast.New) newsIt.next();
0365: polyglot.types.ClassType tempNewType = (polyglot.types.ClassType) tempNew
0366: .objectType().type();
0367: if (InitialResolver.v().finalLocalInfo().containsKey(
0368: new polyglot.util.IdentityKey(tempNewType))) {
0369: AnonLocalClassInfo lInfo = InitialResolver.v()
0370: .finalLocalInfo().get(
0371: new polyglot.util.IdentityKey(
0372: tempNewType));
0373: Iterator<IdentityKey> it = lInfo.finalLocalsAvail()
0374: .iterator();
0375: while (it.hasNext()) {
0376: polyglot.types.LocalInstance li2 = (polyglot.types.LocalInstance) it
0377: .next().object();
0378: if (!sootClass.declaresField("val$" + li2.name(),
0379: Util.getSootType(li2.type()))) {
0380: if (!luc.getLocalDecls().contains(
0381: new polyglot.util.IdentityKey(li2))) {
0382: addFinals(li2, finalFields);
0383: localsUsed
0384: .add(new polyglot.util.IdentityKey(
0385: li2));
0386: }
0387: }
0388: }
0389: }
0390: }
0391: // also need to add them if any super class all the way up needs one
0392: // because the super() will be made in init and it will require
0393: // possibly eventually to send in the finals
0394:
0395: polyglot.types.ClassType super Type = (polyglot.types.ClassType) nodeKeyType
0396: .super Type();
0397: while (!Util.getSootType(super Type).equals(
0398: soot.Scene.v().getSootClass("java.lang.Object")
0399: .getType())) {
0400: if (InitialResolver.v().finalLocalInfo().containsKey(
0401: new polyglot.util.IdentityKey(super Type))) {
0402: AnonLocalClassInfo lInfo = InitialResolver.v()
0403: .finalLocalInfo()
0404: .get(new polyglot.util.IdentityKey(super Type));
0405: Iterator<IdentityKey> it = lInfo.finalLocalsAvail()
0406: .iterator();
0407: while (it.hasNext()) {
0408: polyglot.types.LocalInstance li2 = (polyglot.types.LocalInstance) it
0409: .next().object();
0410: if (!sootClass.declaresField("val$" + li2.name(),
0411: Util.getSootType(li2.type()))) {
0412: if (!luc.getLocalDecls().contains(
0413: new polyglot.util.IdentityKey(li2))) {
0414: addFinals(li2, finalFields);
0415: localsUsed
0416: .add(new polyglot.util.IdentityKey(
0417: li2));
0418: }
0419: }
0420: }
0421: }
0422: super Type = (polyglot.types.ClassType) super Type
0423: .super Type();
0424: }
0425: info.finalLocalsUsed(localsUsed);
0426: InitialResolver.v().finalLocalInfo().put(
0427: new polyglot.util.IdentityKey(nodeKeyType), info);
0428: return finalFields;
0429: }
0430:
0431: /**
0432: * creates the Jimple for an anon class - in the AST there is no class
0433: * decl for anon classes - the revelant fields and methods are
0434: * created
0435: */
0436: private void createAnonClassDecl(polyglot.ast.New aNew) {
0437:
0438: SootClass outerClass = ((soot.RefType) Util.getSootType(aNew
0439: .anonType().outer())).getSootClass();
0440: if (InitialResolver.v().getInnerClassInfoMap() == null) {
0441: InitialResolver.v().setInnerClassInfoMap(
0442: new HashMap<SootClass, InnerClassInfo>());
0443: }
0444: InitialResolver.v().getInnerClassInfoMap()
0445: .put(
0446: sootClass,
0447: new InnerClassInfo(outerClass, "0",
0448: InnerClassInfo.ANON));
0449: sootClass.setOuterClass(outerClass);
0450:
0451: soot.SootClass typeClass = ((soot.RefType) Util
0452: .getSootType(aNew.objectType().type())).getSootClass();
0453:
0454: // set superclass
0455: if (((polyglot.types.ClassType) aNew.objectType().type())
0456: .flags().isInterface()) {
0457: sootClass.addInterface(typeClass);
0458: sootClass.setSuperclass(soot.Scene.v().getSootClass(
0459: "java.lang.Object"));
0460: } else {
0461: sootClass.setSuperclass(typeClass);
0462: if (((polyglot.types.ClassType) aNew.objectType().type())
0463: .isNested()) {
0464: polyglot.types.ClassType super Type = (polyglot.types.ClassType) aNew
0465: .objectType().type();
0466: // add inner clas tag
0467: Util.addInnerClassTag(sootClass, typeClass.getName(),
0468: ((soot.RefType) Util.getSootType(super Type
0469: .outer())).toString(),
0470: super Type.name(), Util.getModifier(super Type
0471: .flags()));
0472:
0473: }
0474: }
0475:
0476: // needs to be done for local also
0477: ArrayList params = new ArrayList();
0478:
0479: soot.SootMethod method;
0480: // if interface there are no extra params
0481: if (((polyglot.types.ClassType) aNew.objectType().type())
0482: .flags().isInterface()) {
0483: method = new soot.SootMethod("<init>", params,
0484: soot.VoidType.v());
0485: } else {
0486: if (!aNew.arguments().isEmpty()) {
0487:
0488: polyglot.types.ConstructorInstance ci = InitialResolver
0489: .v().getConstructorForAnon(aNew);
0490: Iterator aIt = ci.formalTypes().iterator();
0491: while (aIt.hasNext()) {
0492: polyglot.types.Type pType = (polyglot.types.Type) aIt
0493: .next();
0494: params.add(Util.getSootType(pType));
0495: }
0496: }
0497: /*Iterator aIt = aNew.arguments().iterator();
0498: while (aIt.hasNext()){
0499: polyglot.types.Type pType = ((polyglot.ast.Expr)aIt.next()).type();
0500: params.add(Util.getSootType(pType));
0501: }*/
0502: method = new soot.SootMethod("<init>", params,
0503: soot.VoidType.v());
0504: }
0505:
0506: AnonClassInitMethodSource src = new AnonClassInitMethodSource();
0507: method.setSource(src);
0508: sootClass.addMethod(method);
0509:
0510: AnonLocalClassInfo info = InitialResolver.v().finalLocalInfo()
0511: .get(new polyglot.util.IdentityKey(aNew.anonType()));
0512:
0513: if (aNew.qualifier() != null) {// && (!(aNew.qualifier() instanceof polyglot.ast.Special && ((polyglot.ast.Special)aNew.qualifier()).kind() == polyglot.ast.Special.THIS)) ){
0514: //if (aNew.qualifier() != null ) {
0515: // add qualifier ref - do this first to get right order
0516: addQualifierRefToInit(aNew.qualifier().type());
0517: src.hasQualifier(true);
0518: }
0519: if (info != null && !info.inStaticMethod()) {
0520: if (!InitialResolver.v().isAnonInCCall(aNew.anonType())) {
0521: addOuterClassThisRefToInit(aNew.anonType().outer());
0522: addOuterClassThisRefField(aNew.anonType().outer());
0523: src.this OuterType(Util.getSootType(aNew.anonType()
0524: .outer()));
0525: src.hasOuterRef(true);
0526: }
0527: }
0528: src.polyglotType((polyglot.types.ClassType) aNew.anonType()
0529: .super Type());
0530: src.anonType(aNew.anonType());
0531: src.inStaticMethod(info.inStaticMethod());
0532: if (info != null) {
0533: src.setFinalsList(addFinalLocals(aNew.body(), info
0534: .finalLocalsAvail(), aNew.anonType(), info));
0535: }
0536: src.outerClassType(Util.getSootType(aNew.anonType().outer()));
0537: if (((polyglot.types.ClassType) aNew.objectType().type())
0538: .isNested()) {
0539: src.super OuterType(Util
0540: .getSootType(((polyglot.types.ClassType) aNew
0541: .objectType().type()).outer()));
0542: src.isSubType(Util.isSubType(aNew.anonType().outer(),
0543: ((polyglot.types.ClassType) aNew.objectType()
0544: .type()).outer()));
0545: }
0546:
0547: Util.addLnPosTags(sootClass, aNew.position().line(), aNew
0548: .body().position().endLine(), aNew.position().column(),
0549: aNew.body().position().endColumn());
0550: }
0551:
0552: public int getModifiers(polyglot.types.Flags flags) {
0553: return Util.getModifier(flags);
0554: }
0555:
0556: /**
0557: * adds modifiers
0558: */
0559: private void addModifiers(polyglot.types.Flags flags,
0560: polyglot.ast.ClassDecl cDecl) {
0561: int modifiers = 0;
0562: if (cDecl.type().isNested()) {
0563: if (flags.isPublic() || flags.isProtected()
0564: || flags.isPrivate()) {
0565: modifiers = soot.Modifier.PUBLIC;
0566: }
0567: if (flags.isInterface()) {
0568: modifiers = modifiers | soot.Modifier.INTERFACE;
0569: }
0570: if (flags.isAbstract()) {
0571: modifiers = modifiers | soot.Modifier.ABSTRACT;
0572: }
0573: // if inner classes are declared in an interface they need to be
0574: // given public access but I have no idea why
0575: // if inner classes are declared in an interface the are
0576: // implicitly static and public (jls9.5)
0577: if (cDecl.type().outer().flags().isInterface()) {
0578: modifiers = modifiers | soot.Modifier.PUBLIC;
0579: }
0580: } else {
0581: modifiers = getModifiers(flags);
0582: }
0583: sootClass.setModifiers(modifiers);
0584: }
0585:
0586: private soot.SootClass getSpecialInterfaceAnonClass(
0587: soot.SootClass addToClass) {
0588: // check to see if there is already a special anon class for this
0589: // interface
0590: if ((InitialResolver.v().specialAnonMap() != null)
0591: && (InitialResolver.v().specialAnonMap()
0592: .containsKey(addToClass))) {
0593: return InitialResolver.v().specialAnonMap().get(addToClass);
0594: } else {
0595: String specialClassName = addToClass.getName() + "$"
0596: + InitialResolver.v().getNextAnonNum();
0597: // add class to scene and other maps and lists as needed
0598: soot.SootClass specialClass = new soot.SootClass(
0599: specialClassName);
0600: soot.Scene.v().addClass(specialClass);
0601: specialClass.setApplicationClass();
0602: specialClass.addTag(new soot.tagkit.SyntheticTag());
0603: specialClass.setSuperclass(soot.Scene.v().getSootClass(
0604: "java.lang.Object"));
0605: Util.addInnerClassTag(addToClass, specialClass.getName(),
0606: addToClass.getName(), null, soot.Modifier.STATIC);
0607: Util.addInnerClassTag(specialClass, specialClass.getName(),
0608: addToClass.getName(), null, soot.Modifier.STATIC);
0609: InitialResolver.v().addNameToAST(specialClassName);
0610: references.add(specialClassName);
0611: if (InitialResolver.v().specialAnonMap() == null) {
0612: InitialResolver.v().setSpecialAnonMap(
0613: new HashMap<SootClass, SootClass>());
0614: }
0615: InitialResolver.v().specialAnonMap().put(addToClass,
0616: specialClass);
0617: return specialClass;
0618: }
0619: }
0620:
0621: /**
0622: * Handling for assert stmts - extra fields and methods are needed
0623: * in the Jimple
0624: */
0625: private void handleAssert(polyglot.ast.ClassBody cBody) {
0626:
0627: // find any asserts in class body but not in inner class bodies
0628: AssertStmtChecker asc = new AssertStmtChecker();
0629: cBody.visit(asc);
0630: if (!asc.isHasAssert())
0631: return;
0632:
0633: // two extra fields
0634:
0635: // $assertionsDisabled field is added to the actual class where the
0636: // assert is found (even if its an inner class - interfaces cannot
0637: // have asserts stmts directly contained within them)
0638: String fieldName = "$assertionsDisabled";
0639: soot.Type fieldType = soot.BooleanType.v();
0640: if (!sootClass.declaresField(fieldName, fieldType)) {
0641: soot.SootField assertionsDisabledField = new soot.SootField(
0642: fieldName, fieldType, soot.Modifier.STATIC
0643: | soot.Modifier.FINAL);
0644: sootClass.addField(assertionsDisabledField);
0645: assertionsDisabledField
0646: .addTag(new soot.tagkit.SyntheticTag());
0647: }
0648:
0649: // class$ field is added to the outer most class if sootClass
0650: // containing the assert is inner - if the outer most class is
0651: // an interface - add instead to special interface anon class
0652: soot.SootClass addToClass = sootClass;
0653: while ((InitialResolver.v().getInnerClassInfoMap() != null)
0654: && (InitialResolver.v().getInnerClassInfoMap()
0655: .containsKey(addToClass))) {
0656: addToClass = InitialResolver.v().getInnerClassInfoMap()
0657: .get(addToClass).getOuterClass();
0658: }
0659:
0660: // this field is named after the outer class even if the outer
0661: // class is an interface and will be actually added to the
0662: // special interface anon class
0663: fieldName = "class$"
0664: + soot.util.StringTools.replaceAll(
0665: addToClass.getName(), ".", "$");
0666: if ((InitialResolver.v().getInterfacesList() != null)
0667: && (InitialResolver.v().getInterfacesList()
0668: .contains(addToClass.getName()))) {
0669: addToClass = getSpecialInterfaceAnonClass(addToClass);
0670: }
0671:
0672: fieldType = soot.RefType.v("java.lang.Class");
0673:
0674: if (!addToClass.declaresField(fieldName, fieldType)) {
0675: soot.SootField classField = new soot.SootField(fieldName,
0676: fieldType, soot.Modifier.STATIC);
0677: addToClass.addField(classField);
0678: classField.addTag(new soot.tagkit.SyntheticTag());
0679: }
0680:
0681: // two extra methods
0682:
0683: // class$ method is added to the outer most class if sootClass
0684: // containing the assert is inner - if the outer most class is
0685: // an interface - add instead to special interface anon class
0686: String methodName = "class$";
0687: soot.Type methodRetType = soot.RefType.v("java.lang.Class");
0688: ArrayList paramTypes = new ArrayList();
0689: paramTypes.add(soot.RefType.v("java.lang.String"));
0690:
0691: // make meth
0692: soot.SootMethod sootMethod = new soot.SootMethod(methodName,
0693: paramTypes, methodRetType, soot.Modifier.STATIC);
0694: AssertClassMethodSource assertMSrc = new AssertClassMethodSource();
0695: sootMethod.setSource(assertMSrc);
0696:
0697: if (!addToClass.declaresMethod(methodName, paramTypes,
0698: methodRetType)) {
0699: addToClass.addMethod(sootMethod);
0700: sootMethod.addTag(new soot.tagkit.SyntheticTag());
0701: }
0702:
0703: // clinit method is added to actual class where assert is found
0704: // if the class already has a clinit method its method source is
0705: // informed of an assert
0706: methodName = "<clinit>";
0707: methodRetType = soot.VoidType.v();
0708: paramTypes = new ArrayList();
0709:
0710: // make meth
0711: sootMethod = new soot.SootMethod(methodName, paramTypes,
0712: methodRetType, soot.Modifier.STATIC);
0713: PolyglotMethodSource mSrc = new PolyglotMethodSource();
0714: mSrc.setJBB(InitialResolver.v().getJBBFactory()
0715: .createJimpleBodyBuilder());
0716: mSrc.hasAssert(true);
0717: sootMethod.setSource(mSrc);
0718:
0719: if (!sootClass.declaresMethod(methodName, paramTypes,
0720: methodRetType)) {
0721: sootClass.addMethod(sootMethod);
0722: } else {
0723: ((soot.javaToJimple.PolyglotMethodSource) sootClass
0724: .getMethod(methodName, paramTypes, methodRetType)
0725: .getSource()).hasAssert(true);
0726: }
0727: }
0728:
0729: /**
0730: * Constructor Declaration Creation
0731: */
0732: private void createConstructorDecl(
0733: polyglot.ast.ConstructorDecl constructor) {
0734: String name = "<init>";
0735:
0736: ArrayList parameters = createParameters(constructor);
0737:
0738: ArrayList<SootClass> exceptions = createExceptions(constructor);
0739:
0740: soot.SootMethod sootMethod = createSootConstructor(name,
0741: constructor.flags(), parameters, exceptions);
0742:
0743: finishProcedure(constructor, sootMethod);
0744: }
0745:
0746: /**
0747: * Method Declaration Creation
0748: */
0749: private void createMethodDecl(polyglot.ast.MethodDecl method) {
0750:
0751: String name = createName(method);
0752:
0753: // parameters
0754: ArrayList parameters = createParameters(method);
0755:
0756: // exceptions
0757: ArrayList<SootClass> exceptions = createExceptions(method);
0758:
0759: soot.SootMethod sootMethod = createSootMethod(name, method
0760: .flags(), method.returnType().type(), parameters,
0761: exceptions);
0762:
0763: finishProcedure(method, sootMethod);
0764: }
0765:
0766: /**
0767: * looks after pos tags for methods and constructors
0768: */
0769: private void finishProcedure(polyglot.ast.ProcedureDecl procedure,
0770: soot.SootMethod sootMethod) {
0771:
0772: addProcedureToClass(sootMethod);
0773:
0774: if (procedure.position() != null) {
0775: Util.addLnPosTags(sootMethod, procedure.position());
0776: }
0777:
0778: PolyglotMethodSource mSrc = new PolyglotMethodSource(procedure
0779: .body(), procedure.formals());
0780: mSrc.setJBB(InitialResolver.v().getJBBFactory()
0781: .createJimpleBodyBuilder());
0782:
0783: sootMethod.setSource(mSrc);
0784:
0785: }
0786:
0787: private void handleFieldInits() {
0788: if ((fieldInits != null) || (initializerBlocks != null)) {
0789: Iterator methodsIt = sootClass.getMethods().iterator();
0790: while (methodsIt.hasNext()) {
0791: soot.SootMethod next = (soot.SootMethod) methodsIt
0792: .next();
0793: if (next.getName().equals("<init>")) {
0794:
0795: soot.javaToJimple.PolyglotMethodSource src = (soot.javaToJimple.PolyglotMethodSource) next
0796: .getSource();
0797: src.setInitializerBlocks(initializerBlocks);
0798: src.setFieldInits(fieldInits);
0799:
0800: }
0801: }
0802: }
0803:
0804: }
0805:
0806: private void handleClassLiteral(polyglot.ast.ClassBody cBody) {
0807:
0808: // check for class lits whose type is not primitive
0809: ClassLiteralChecker classLitChecker = new ClassLiteralChecker();
0810: cBody.visit(classLitChecker);
0811: ArrayList<Node> classLitList = classLitChecker.getList();
0812:
0813: if (!classLitList.isEmpty()) {
0814:
0815: soot.SootClass addToClass = sootClass;
0816: if (addToClass.isInterface()) {
0817: addToClass = getSpecialInterfaceAnonClass(addToClass);
0818: }
0819:
0820: // add class$ meth
0821: String methodName = "class$";
0822: soot.Type methodRetType = soot.RefType.v("java.lang.Class");
0823: ArrayList paramTypes = new ArrayList();
0824: paramTypes.add(soot.RefType.v("java.lang.String"));
0825: soot.SootMethod sootMethod = new soot.SootMethod(
0826: methodName, paramTypes, methodRetType,
0827: soot.Modifier.STATIC);
0828: ClassLiteralMethodSource mSrc = new ClassLiteralMethodSource();
0829: sootMethod.setSource(mSrc);
0830:
0831: if (!addToClass.declaresMethod(methodName, paramTypes,
0832: methodRetType)) {
0833: addToClass.addMethod(sootMethod);
0834: sootMethod.addTag(new soot.tagkit.SyntheticTag());
0835: }
0836:
0837: // add fields for all non prim class lits
0838: Iterator<Node> classLitIt = classLitList.iterator();
0839: while (classLitIt.hasNext()) {
0840: polyglot.ast.ClassLit classLit = (polyglot.ast.ClassLit) classLitIt
0841: .next();
0842:
0843: // field
0844: String fieldName = Util
0845: .getFieldNameForClassLit(classLit.typeNode()
0846: .type());
0847: soot.Type fieldType = soot.RefType.v("java.lang.Class");
0848:
0849: soot.SootField sootField = new soot.SootField(
0850: fieldName, fieldType, soot.Modifier.STATIC);
0851: if (!addToClass.declaresField(fieldName, fieldType)) {
0852: addToClass.addField(sootField);
0853: sootField.addTag(new soot.tagkit.SyntheticTag());
0854: }
0855: }
0856: }
0857: }
0858:
0859: /**
0860: * Source Creation
0861: */
0862: protected void createSource(polyglot.ast.SourceFile source) {
0863:
0864: // add absolute path to sourceFileTag
0865: if (sootClass.hasTag("SourceFileTag")) {
0866: soot.tagkit.SourceFileTag t = (soot.tagkit.SourceFileTag) sootClass
0867: .getTag("SourceFileTag");
0868: /*System.out.println("source: "+source);
0869: System.out.println("source.source(): "+source.source());
0870: System.out.println("source path: "+source.source().path());
0871: System.out.println("source name: "+source.source().name());*/
0872: t.setAbsolutePath(source.source().path());
0873: } else {
0874: soot.tagkit.SourceFileTag t = new soot.tagkit.SourceFileTag();
0875: /*System.out.println("source: "+source);
0876: System.out.println("source.source(): "+source.source());
0877: System.out.println("source path: "+source.source().path());
0878: System.out.println("source name: "+source.source().name());*/
0879: t.setAbsolutePath(source.source().path());
0880: sootClass.addTag(t);
0881: }
0882:
0883: String simpleName = sootClass.getName();
0884:
0885: Iterator declsIt = source.decls().iterator();
0886: boolean found = false;
0887:
0888: // first look in top-level decls
0889: while (declsIt.hasNext()) {
0890: Object next = declsIt.next();
0891: if (next instanceof polyglot.ast.ClassDecl) {
0892: polyglot.types.ClassType nextType = ((polyglot.ast.ClassDecl) next)
0893: .type();
0894: if (Util.getSootType(nextType).equals(
0895: sootClass.getType())) {
0896: createClassDecl((polyglot.ast.ClassDecl) next);
0897: found = true;
0898: }
0899: }
0900: }
0901:
0902: // if the class wasn't a top level then its nested, local or anon
0903: if (!found) {
0904: NestedClassListBuilder nestedClassBuilder = new NestedClassListBuilder();
0905: source.visit(nestedClassBuilder);
0906:
0907: Iterator<Node> nestedDeclsIt = nestedClassBuilder
0908: .getClassDeclsList().iterator();
0909: while (nestedDeclsIt.hasNext() && !found) {
0910:
0911: polyglot.ast.ClassDecl nextDecl = (polyglot.ast.ClassDecl) nestedDeclsIt
0912: .next();
0913: polyglot.types.ClassType type = nextDecl.type();
0914: if (type.isLocal() && !type.isAnonymous()) {
0915:
0916: if (InitialResolver.v().getLocalClassMap()
0917: .containsVal(simpleName)) {
0918: createClassDecl(((polyglot.ast.LocalClassDecl) InitialResolver
0919: .v().getLocalClassMap().getKey(
0920: simpleName)).decl());
0921: found = true;
0922: }
0923: } else {
0924:
0925: if (Util.getSootType(type).equals(
0926: sootClass.getType())) {
0927: createClassDecl(nextDecl);
0928: found = true;
0929: }
0930: }
0931: }
0932:
0933: if (!found) {
0934: // assume its anon class (only option left)
0935: //
0936: if ((InitialResolver.v().getAnonClassMap() != null)
0937: && InitialResolver.v().getAnonClassMap()
0938: .containsVal(simpleName)) {
0939:
0940: polyglot.ast.New aNew = (polyglot.ast.New) InitialResolver
0941: .v().getAnonClassMap().getKey(simpleName);
0942: createAnonClassDecl(aNew);
0943: findReferences(aNew.body());
0944: createClassBody(aNew.body());
0945: handleFieldInits();
0946:
0947: } else {
0948: // could be an anon class that was created out of thin air
0949: // for handling class lits (and asserts) in interfaces
0950: // this is now done on creation of this special class
0951: //sootClass.setSuperclass(soot.Scene.v().getSootClass("java.lang.Object"));
0952: }
0953: }
0954: }
0955:
0956: }
0957:
0958: private void handleInnerClassTags(polyglot.ast.ClassBody classBody) {
0959: // if this class is an inner class add self
0960: if ((InitialResolver.v().getInnerClassInfoMap() != null)
0961: && (InitialResolver.v().getInnerClassInfoMap()
0962: .containsKey(sootClass))) {
0963: //hasTag("OuterClassTag")){
0964:
0965: InnerClassInfo tag = InitialResolver.v()
0966: .getInnerClassInfoMap().get(sootClass);
0967: Util.addInnerClassTag(sootClass, sootClass.getName(), tag
0968: .getInnerType() == InnerClassInfo.ANON ? null : tag
0969: .getOuterClass().getName(),
0970: tag.getInnerType() == InnerClassInfo.ANON ? null
0971: : tag.getSimpleName(),
0972: soot.Modifier.isInterface(tag.getOuterClass()
0973: .getModifiers()) ? soot.Modifier.STATIC
0974: | soot.Modifier.PUBLIC : sootClass
0975: .getModifiers());
0976: // if this class is an inner class and enclosing class is also
0977: // an inner class add enclsing class
0978: SootClass outerClass = tag.getOuterClass();
0979: while (InitialResolver.v().getInnerClassInfoMap()
0980: .containsKey(outerClass)) {
0981: InnerClassInfo tag2 = InitialResolver.v()
0982: .getInnerClassInfoMap().get(outerClass);
0983: Util
0984: .addInnerClassTag(
0985: sootClass,
0986: outerClass.getName(),
0987: tag2.getInnerType() == InnerClassInfo.ANON ? null
0988: : tag2.getOuterClass()
0989: .getName(),
0990: tag2.getInnerType() == InnerClassInfo.ANON ? null
0991: : tag2.getSimpleName(),
0992: tag2.getInnerType() == InnerClassInfo.ANON
0993: && soot.Modifier
0994: .isInterface(tag2
0995: .getOuterClass()
0996: .getModifiers()) ? soot.Modifier.STATIC
0997: | soot.Modifier.PUBLIC
0998: : outerClass.getModifiers());
0999: outerClass = tag2.getOuterClass();
1000: }
1001: }
1002:
1003: }
1004:
1005: private void addQualifierRefToInit(polyglot.types.Type type) {
1006: soot.Type sootType = Util.getSootType(type);
1007: Iterator it = sootClass.getMethods().iterator();
1008: while (it.hasNext()) {
1009: soot.SootMethod meth = (soot.SootMethod) it.next();
1010: if (meth.getName().equals("<init>")) {
1011: List newParams = new ArrayList();
1012: newParams.add(sootType);
1013: newParams.addAll(meth.getParameterTypes());
1014: meth.setParameterTypes(newParams);
1015: meth.addTag(new soot.tagkit.QualifyingTag());
1016: }
1017: }
1018: }
1019:
1020: private void addProcedureToClass(soot.SootMethod method) {
1021: sootClass.addMethod(method);
1022: }
1023:
1024: private void addConstValTag(polyglot.ast.FieldDecl field,
1025: soot.SootField sootField) {
1026: //G.v().out.println("adding constantval tag to field: "+field);
1027: if (field.fieldInstance().constantValue() instanceof Integer) {
1028: sootField.addTag(new soot.tagkit.IntegerConstantValueTag(
1029: ((Integer) field.fieldInstance().constantValue())
1030: .intValue()));
1031: } else if (field.fieldInstance().constantValue() instanceof Character) {
1032: sootField.addTag(new soot.tagkit.IntegerConstantValueTag(
1033: ((Character) field.fieldInstance().constantValue())
1034: .charValue()));
1035: } else if (field.fieldInstance().constantValue() instanceof Short) {
1036: sootField.addTag(new soot.tagkit.IntegerConstantValueTag(
1037: ((Short) field.fieldInstance().constantValue())
1038: .shortValue()));
1039: } else if (field.fieldInstance().constantValue() instanceof Byte) {
1040: sootField.addTag(new soot.tagkit.IntegerConstantValueTag(
1041: ((Byte) field.fieldInstance().constantValue())
1042: .byteValue()));
1043: } else if (field.fieldInstance().constantValue() instanceof Boolean) {
1044: boolean b = ((Boolean) field.fieldInstance()
1045: .constantValue()).booleanValue();
1046: sootField.addTag(new soot.tagkit.IntegerConstantValueTag(
1047: b ? 1 : 0));
1048: } else if (field.fieldInstance().constantValue() instanceof Long) {
1049: sootField.addTag(new soot.tagkit.LongConstantValueTag(
1050: ((Long) field.fieldInstance().constantValue())
1051: .longValue()));
1052: } else if (field.fieldInstance().constantValue() instanceof Double) {
1053: //System.out.println("const val: "+field.fieldInstance().constantValue());
1054: sootField.addTag(new soot.tagkit.DoubleConstantValueTag(
1055: (long) ((Double) field.fieldInstance()
1056: .constantValue()).doubleValue()));
1057: //System.out.println(((Double)field.fieldInstance().constantValue()).doubleValue());
1058: soot.tagkit.DoubleConstantValueTag tag = (soot.tagkit.DoubleConstantValueTag) sootField
1059: .getTag("DoubleConstantValueTag");
1060: //System.out.println("tag: "+tag);
1061: } else if (field.fieldInstance().constantValue() instanceof Float) {
1062: sootField.addTag(new soot.tagkit.FloatConstantValueTag(
1063: ((Float) field.fieldInstance().constantValue())
1064: .floatValue()));
1065: } else if (field.fieldInstance().constantValue() instanceof String) {
1066: sootField.addTag(new soot.tagkit.StringConstantValueTag(
1067: (String) field.fieldInstance().constantValue()));
1068: } else {
1069: throw new RuntimeException(
1070: "Expecting static final field to have a constant value! For field: "
1071: + field
1072: + " of type: "
1073: + field.fieldInstance().constantValue()
1074: .getClass());
1075: }
1076: }
1077:
1078: /**
1079: * Field Declaration Creation
1080: */
1081: private void createFieldDecl(polyglot.ast.FieldDecl field) {
1082:
1083: //System.out.println("field decl: "+field);
1084: int modifiers = Util.getModifier(field.fieldInstance().flags());
1085: String name = field.fieldInstance().name();
1086: soot.Type sootType = Util.getSootType(field.fieldInstance()
1087: .type());
1088: soot.SootField sootField = new soot.SootField(name, sootType,
1089: modifiers);
1090: sootClass.addField(sootField);
1091:
1092: if (field.fieldInstance().flags().isStatic()) {
1093: if (field.init() != null) {
1094: if (field.flags().isFinal()
1095: && (field.type().type().isPrimitive() || (field
1096: .type().type().toString()
1097: .equals("java.lang.String")))
1098: && field.fieldInstance().isConstant()) {
1099: //System.out.println("adding constantValtag: to field: "+sootField);
1100: addConstValTag(field, sootField);
1101: } else {
1102: if (staticFieldInits == null) {
1103: staticFieldInits = new ArrayList<FieldDecl>();
1104: }
1105: staticFieldInits.add(field);
1106: }
1107: }
1108: } else {
1109: if (field.init() != null) {
1110: if (fieldInits == null) {
1111: fieldInits = new ArrayList<FieldDecl>();
1112: }
1113: fieldInits.add(field);
1114: }
1115: }
1116:
1117: Util.addLnPosTags(sootField, field.position());
1118: }
1119:
1120: ClassResolver(SootClass sootClass, List references) {
1121: this .sootClass = sootClass;
1122: this .references = references;
1123: }
1124:
1125: private final SootClass sootClass;
1126: private final List references;
1127:
1128: /**
1129: * Procedure Declaration Helper Methods
1130: * creates procedure name
1131: */
1132: private String createName(polyglot.ast.ProcedureDecl procedure) {
1133: return procedure.name();
1134: }
1135:
1136: /**
1137: * creates soot params from polyglot formals
1138: */
1139: private ArrayList createParameters(
1140: polyglot.ast.ProcedureDecl procedure) {
1141: ArrayList parameters = new ArrayList();
1142: Iterator formalsIt = procedure.formals().iterator();
1143: while (formalsIt.hasNext()) {
1144: polyglot.ast.Formal next = (polyglot.ast.Formal) formalsIt
1145: .next();
1146: parameters.add(Util.getSootType(next.type().type()));
1147: }
1148: return parameters;
1149: }
1150:
1151: /**
1152: * creates soot exceptions from polyglot throws
1153: */
1154: private ArrayList<SootClass> createExceptions(
1155: polyglot.ast.ProcedureDecl procedure) {
1156: ArrayList<SootClass> exceptions = new ArrayList<SootClass>();
1157: Iterator throwsIt = procedure.throwTypes().iterator();
1158: while (throwsIt.hasNext()) {
1159: polyglot.types.Type throwType = ((polyglot.ast.TypeNode) throwsIt
1160: .next()).type();
1161: exceptions.add(((soot.RefType) Util.getSootType(throwType))
1162: .getSootClass());
1163: }
1164: return exceptions;
1165: }
1166:
1167: private soot.SootMethod createSootMethod(String name,
1168: polyglot.types.Flags flags, polyglot.types.Type returnType,
1169: ArrayList parameters, ArrayList<SootClass> exceptions) {
1170:
1171: int modifier = Util.getModifier(flags);
1172: soot.Type sootReturnType = Util.getSootType(returnType);
1173:
1174: soot.SootMethod method = new soot.SootMethod(name, parameters,
1175: sootReturnType, modifier, exceptions);
1176: return method;
1177: }
1178:
1179: /**
1180: * Initializer Creation
1181: */
1182: private void createInitializer(polyglot.ast.Initializer initializer) {
1183: if (initializer.flags().isStatic()) {
1184: if (staticInitializerBlocks == null) {
1185: staticInitializerBlocks = new ArrayList<Block>();
1186: }
1187: staticInitializerBlocks.add(initializer.body());
1188: } else {
1189: if (initializerBlocks == null) {
1190: initializerBlocks = new ArrayList<Block>();
1191: }
1192: initializerBlocks.add(initializer.body());
1193: }
1194: }
1195:
1196: private soot.SootMethod createSootConstructor(String name,
1197: polyglot.types.Flags flags, ArrayList parameters,
1198: ArrayList<SootClass> exceptions) {
1199:
1200: int modifier = Util.getModifier(flags);
1201:
1202: soot.SootMethod method = new soot.SootMethod(name, parameters,
1203: soot.VoidType.v(), modifier, exceptions);
1204:
1205: return method;
1206: }
1207:
1208: }
|