001: package spoon.jdiet;
002:
003: import java.util.ArrayList;
004: import java.util.Arrays;
005: import java.util.Collection;
006: import java.util.Hashtable;
007: import java.util.Iterator;
008: import java.util.List;
009: import java.util.Map;
010: import java.util.Set;
011: import java.util.Vector;
012:
013: import spoon.jdiet.rt.Helper;
014: import spoon.processing.AbstractProcessor;
015: import spoon.processing.TraversalStrategy;
016: import spoon.reflect.code.CtExpression;
017: import spoon.reflect.code.CtInvocation;
018: import spoon.reflect.code.CtNewClass;
019: import spoon.reflect.declaration.CtElement;
020: import spoon.reflect.factory.CodeFactory;
021: import spoon.reflect.factory.ExecutableFactory;
022: import spoon.reflect.factory.TypeFactory;
023: import spoon.reflect.reference.CtExecutableReference;
024: import spoon.reflect.reference.CtTypeReference;
025:
026: /**
027: * This processor replaces Java API calls which are not in the J2ME API by some
028: * J2ME compliant equivalent calls.
029: *
030: * @author Lionel Seinturier <Lionel.Seinturier@lifl.fr>
031: */
032: public class InvocationProcessor extends
033: AbstractProcessor<CtInvocation> {
034:
035: public TraversalStrategy getTraversalStrategy() {
036: // Let arguments included in the construction be visited first
037: return TraversalStrategy.POST_ORDER;
038: }
039:
040: private List<Transformer<CtInvocation>> mits = new ArrayList<Transformer<CtInvocation>>();
041:
042: public InvocationProcessor() {
043:
044: Class objarraycl = new Object[0].getClass();
045:
046: /*
047: * Transforming into methods defined in the Helper class.
048: */
049: mits.add(new HelperClassCtInvTransformer(Arrays.class,
050: "asList", Vector.class, "asList", new Object[0]
051: .getClass()));
052: mits.add(new HelperClassCtInvTransformer(Collection.class,
053: "toArray", objarraycl, "toArray", Vector.class,
054: new Object[0].getClass()));
055: mits.add(new HelperClassCtInvTransformer(List.class, "add",
056: Boolean.class, "addList", Vector.class, Object.class));
057: mits
058: .add(new HelperClassCtInvTransformer(List.class,
059: "addAll", Boolean.class, "addAllList",
060: Vector.class, Vector.class));
061: mits.add(new HelperClassCtInvTransformer(Map.class, "values",
062: Vector.class, "values", Hashtable.class));
063: mits.add(new HelperClassCtInvTransformer(Map.class, "entrySet",
064: Vector.class, "entrySet", Hashtable.class));
065: mits.add(new HelperClassCtInvTransformer(Map.class, "keySet",
066: Vector.class, "keySet", Hashtable.class));
067: mits.add(new HelperClassCtInvTransformer(Set.class, "add",
068: Boolean.class, "addSet", Vector.class, Object.class));
069: mits
070: .add(new HelperClassCtInvTransformer(Set.class,
071: "addAll", Boolean.class, "addAllSet",
072: Vector.class, Vector.class));
073:
074: /*
075: * Transforming by replacing method names.
076: */
077: mits.add(new SimpleCtInvTransformer(Collection.class,
078: "iterator", "elements"));
079: mits.add(new SimpleCtInvTransformer(Collection.class, "remove",
080: "removeElement"));
081: mits.add(new SimpleCtInvTransformer(Iterator.class, "hasNext",
082: "hasMoreElements"));
083: mits.add(new SimpleCtInvTransformer(Iterator.class, "next",
084: "nextElement"));
085: mits.add(new SimpleCtInvTransformer(List.class, "get",
086: "elementAt"));
087: }
088:
089: public void process(CtInvocation inv) {
090: // Perform the replacement for all registered transformers
091: for (Transformer<CtInvocation> t : mits) {
092: if (t.match(inv)) {
093: t.transform(inv);
094: }
095: }
096: }
097: }
098:
099: interface Transformer<T extends CtElement> {
100: boolean match(T element);
101:
102: void transform(T element);
103: }
104:
105: /**
106: * Root class for implementing replacements on method invocations
107: * (CtInvocation). The match(CtInvocation) method returns true if the
108: * CtInvocation matches the searched method.
109: *
110: * @author Lionel Seinturier <Lionel.Seinturier@lifl.fr>
111: */
112: abstract class AbstractCtInvTransformer implements
113: Transformer<CtInvocation> {
114:
115: private Class srcType;
116: private String methName;
117:
118: protected Class replMethType;
119: protected String replMethName;
120: protected Class[] replMethParameterTypes;
121:
122: public AbstractCtInvTransformer(Class srcType, String methName,
123: Class replMethType, String replMethName,
124: Class... replMethParameterTypes) {
125:
126: this .srcType = srcType;
127: this .methName = methName;
128: this .replMethType = replMethType;
129: this .replMethName = replMethName;
130: this .replMethParameterTypes = replMethParameterTypes;
131: }
132:
133: public boolean match(CtInvocation inv) {
134:
135: TypeFactory tf = inv.getFactory().Type();
136: CtTypeReference srcTypeRef = tf.createReference(srcType);
137: CtTypeReference invokedType = getTargetType(inv);
138:
139: if (invokedType.getQualifiedName().length() == 0) {
140: getTargetType(inv);
141: }
142:
143: if (invokedType.isSubtypeOf(srcTypeRef)) {
144: CtExecutableReference cer = inv.getExecutable();
145: String invokedMethodName = cer.getSimpleName();
146: return invokedMethodName.equals(methName);
147: }
148:
149: return false;
150: }
151:
152: abstract public void transform(CtInvocation inv);
153:
154: protected CtTypeReference getTargetType(CtInvocation inv) {
155: CtExpression target = inv.getTarget();
156: if (target == null) {
157: // Static method invocation
158: CtTypeReference ctr = inv.getExecutable()
159: .getDeclaringType();
160: return ctr;
161: } else {
162: if (target instanceof CtNewClass) {
163: // Invocation on an instance of an anonymous class
164: // e.g. new Runnable(){ public void run(){} }
165: CtNewClass nc = (CtNewClass) target;
166: CtTypeReference ctr = NewClassProcessor.getType(nc);
167: return ctr;
168: } else {
169: // Instance method invocation
170: CtTypeReference ctr = target.getType();
171: return ctr;
172: }
173: }
174: }
175: }
176:
177: /**
178: * This class replaces a given method invocation (CtInvocation) by substituing
179: * method names.
180: *
181: * @author Lionel Seinturier <Lionel.Seinturier@lifl.fr>
182: */
183: class SimpleCtInvTransformer extends AbstractCtInvTransformer {
184:
185: public SimpleCtInvTransformer(Class targetType, String methName,
186: String replMethName) {
187:
188: super (targetType, methName, null, replMethName, (Class[]) null);
189: }
190:
191: public void transform(CtInvocation inv) {
192: CtExecutableReference cer = inv.getExecutable();
193: cer.setSimpleName(replMethName);
194: }
195: }
196:
197: /**
198: * This class replaces a given method invocation (CtInvocation) into a call to
199: * one of the static methods defined in the {@link Helper} class. The
200: * replacement takes the form of a method name substitution.
201: *
202: * @author Lionel Seinturier <Lionel.Seinturier@lifl.fr>
203: */
204: class HelperClassCtInvTransformer extends AbstractCtInvTransformer {
205:
206: public HelperClassCtInvTransformer(Class targetType,
207: String methName, Class replMethType, String replMethName,
208: Class... replMethParameterTypes) {
209:
210: super (targetType, methName, replMethType, replMethName,
211: replMethParameterTypes);
212: }
213:
214: public void transform(CtInvocation inv) {
215:
216: CodeFactory cf = inv.getFactory().Code();
217: ExecutableFactory ef = inv.getFactory().Executable();
218: TypeFactory tf = inv.getFactory().Type();
219:
220: // Construct the signature of the replacement method
221: CtTypeReference[] trs = new CtTypeReference[replMethParameterTypes.length];
222: for (int i = 0; i < replMethParameterTypes.length; i++) {
223: trs[i] = tf.createReference(replMethParameterTypes[i]);
224: }
225:
226: // Get the replacement method
227: CtExecutableReference replmeth = ef
228: .createReference(tf.createReference(Helper.class),
229: true, replMethName, trs);
230: replmeth.setType(tf.createReference(replMethType));
231:
232: // Construct the array of arguments for the replacement method
233: List<CtExpression<?>> l = inv.getArguments();
234: CtExpression target = inv.getTarget();
235: if (target != null) {
236: // Instance (i.e. non static) method invocation
237: // Add the target of the call as a first parameter
238: l.add(0, target);
239: }
240:
241: // Construct the method invocation
242: CtInvocation repl = cf.createInvocation(null, replmeth, l);
243: repl.setType(tf.createReference(replMethType));
244: repl.setTypeCasts(inv.getTypeCasts());
245:
246: // Perform the replacement
247: inv.replace(repl);
248: }
249: }
|