001: package spoon.jdiet;
002:
003: import java.util.ArrayList;
004: import java.util.Collection;
005: import java.util.List;
006: import java.util.Map;
007: import java.util.Set;
008: import java.util.Vector;
009:
010: import spoon.jdiet.rt.Helper;
011: import spoon.processing.AbstractProcessor;
012: import spoon.processing.TraversalStrategy;
013: import spoon.reflect.code.CtExpression;
014: import spoon.reflect.code.CtInvocation;
015: import spoon.reflect.code.CtNewClass;
016: import spoon.reflect.declaration.CtClass;
017: import spoon.reflect.factory.CodeFactory;
018: import spoon.reflect.factory.ExecutableFactory;
019: import spoon.reflect.factory.TypeFactory;
020: import spoon.reflect.reference.CtExecutableReference;
021: import spoon.reflect.reference.CtTypeReference;
022:
023: /**
024: * This processor replaces class instantiation with a J2ME compliant equivalent
025: * instantiation.
026: *
027: * @author Lionel Seinturier <Lionel.Seinturier@lifl.fr>
028: */
029: public class NewClassProcessor extends AbstractProcessor<CtNewClass> {
030:
031: public TraversalStrategy getTraversalStrategy() {
032: // Let arguments included in the construction be visited first
033: return TraversalStrategy.POST_ORDER;
034: }
035:
036: public void process(CtNewClass nc) {
037:
038: TypeFactory tf = getFactory().Type();
039: ExecutableFactory ef = getFactory().Executable();
040: CodeFactory cf = getFactory().Code();
041:
042: CtTypeReference ctr = getType(nc);
043:
044: if (!ctr.isPrimitif()) {
045:
046: // Transform new ArrayList(Collection) (or a sub-type) into Helper.newList
047: // Do not use List as Vector implements List
048: if (ctr.isSubtypeOf(tf.createReference(ArrayList.class))) {
049: List<CtExpression<?>> args = nc.getArguments();
050: if (args.size() == 1) {
051: CtExpression<?> arg = args.get(0);
052: if (arg.getType().isSubtypeOf(
053: tf.createReference(Collection.class))) {
054: CtExecutableReference replmeth = ef
055: .createReference(
056: tf
057: .createReference(Helper.class),
058: true,
059: "newList",
060: tf
061: .createReference(Vector.class));
062: CtInvocation repl = cf.createInvocation(null,
063: replmeth, args);
064: nc.replace(repl);
065: return;
066: }
067: }
068: }
069:
070: // Transform new Set(Collection) (or a sub-type) into Helper.newSet
071: if (ctr.isSubtypeOf(tf.createReference(Set.class))) {
072: List<CtExpression<?>> args = nc.getArguments();
073: if (args.size() == 1) {
074: CtExpression<?> arg = args.get(0);
075:
076: if (arg.getType().isSubtypeOf(
077: tf.createReference(Collection.class))) {
078: CtExecutableReference replmeth = ef
079: .createReference(
080: tf
081: .createReference(Helper.class),
082: true,
083: "newSet",
084: tf
085: .createReference(Vector.class));
086: CtInvocation repl = cf.createInvocation(null,
087: replmeth, args);
088: nc.replace(repl);
089: return;
090: }
091: }
092: }
093:
094: /*
095: * No else clause the previous branches may not match all
096: * conditions. In such a case, we may need to enter the next branch
097: * (especially for new Collection(...) where ... is different from
098: * Collection.
099: */
100:
101: // Transform new Collection (or a sub-type) into new Vector
102: if (ctr.isSubtypeOf(tf.createReference(Collection.class))) {
103: ctr.setSimpleName("Vector");
104: }
105:
106: // Transform new Map (or a sub-type) into new Hashtable
107: else if (ctr.isSubtypeOf(tf.createReference(Map.class))) {
108: ctr.setSimpleName("Hashtable");
109: }
110:
111: // Transform new Throwable(Throwable t) into new Throwable(t.getMessage())
112: else if (ctr.isSubtypeOf(tf
113: .createReference(Throwable.class))) {
114: List<CtExpression<?>> args = nc.getArguments();
115: if (args.size() == 1) {
116: CtExpression<?> arg = args.get(0);
117: if (arg.getType().isSubtypeOf(
118: tf.createReference(Throwable.class))) {
119: CtExecutableReference getmessage = ef
120: .createReference(
121: tf
122: .createReference(Throwable.class),
123: "getMessage");
124: CtInvocation repl = cf.createInvocation(arg,
125: getmessage);
126: arg.replace(repl);
127: }
128: }
129: }
130: }
131: }
132:
133: /**
134: * Return the type of a CtNewClass element.
135: * Deals with anonymous class instanciation
136: * e.g. new Thread(){ public void run(){} }
137: * or new Runnable(){ public void run(){} }
138: *
139: * We don't use the CtTypeReference of the anonymous class which is
140: * under-defined with spoon (e.g. simpleName == "") but the CtTypeReference
141: * of the superclass (Thread in the example) or of the superinterface.
142: */
143: static CtTypeReference getType(CtNewClass nc) {
144:
145: CtClass c = nc.getAnonymousClass();
146: if (c == null) {
147: // Not a anonymous class
148: return nc.getType();
149: }
150:
151: CtTypeReference ctr = c.getSuperclass();
152: if (ctr != null) {
153: return ctr;
154: }
155:
156: // No superclass, return the superinterface (only one superinterface)
157: Set<CtTypeReference> sups = c.getSuperinterfaces();
158: ctr = sups.iterator().next();
159: return ctr;
160: }
161:
162: }
|