001: /*
002: * Spoon - http://spoon.gforge.inria.fr/
003: * Copyright (C) 2006 INRIA Futurs <renaud.pawlak@inria.fr>
004: *
005: * This software is governed by the CeCILL-C License under French law and
006: * abiding by the rules of distribution of free software. You can use, modify
007: * and/or redistribute the software under the terms of the CeCILL-C license as
008: * circulated by CEA, CNRS and INRIA at http://www.cecill.info.
009: *
010: * This program is distributed in the hope that it will be useful, but WITHOUT
011: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
012: * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
013: *
014: * The fact that you are presently reading this means that you have had
015: * knowledge of the CeCILL-C license and that you accept its terms.
016: */
017:
018: package spoon.template;
019:
020: import java.util.List;
021:
022: import spoon.reflect.code.CtBlock;
023: import spoon.reflect.code.CtExpression;
024: import spoon.reflect.declaration.CtAnonymousExecutable;
025: import spoon.reflect.declaration.CtClass;
026: import spoon.reflect.declaration.CtConstructor;
027: import spoon.reflect.declaration.CtElement;
028: import spoon.reflect.declaration.CtExecutable;
029: import spoon.reflect.declaration.CtField;
030: import spoon.reflect.declaration.CtInterface;
031: import spoon.reflect.declaration.CtMethod;
032: import spoon.reflect.declaration.CtSimpleType;
033: import spoon.reflect.declaration.CtType;
034: import spoon.reflect.reference.CtPackageReference;
035: import spoon.reflect.reference.CtTypeReference;
036: import spoon.reflect.visitor.Query;
037: import spoon.reflect.visitor.filter.ReferenceTypeFilter;
038: import spoon.support.template.Parameters;
039: import spoon.support.template.SubstitutionVisitor;
040:
041: /**
042: * This class defines the substitution API for templates (see {@link Template}).
043: */
044: public abstract class Substitution {
045:
046: private Substitution() {
047: }
048:
049: /**
050: * Inserts all the methods, fields, constructors, initialization blocks (if
051: * target is a class), inner types, and super interfaces (except
052: * {@link Template}) from a given template by substituting all the template
053: * parameters by their values. Members annotated with
054: * {@link spoon.template.Local} or {@link Parameter} are not inserted.
055: *
056: * @param targetType
057: * the target type
058: * @param template
059: * the source template
060: */
061: @SuppressWarnings("unchecked")
062: public static void insertAll(CtType<?> targetType, Template template) {
063:
064: CtClass<? extends Template> sourceClass = targetType
065: .getFactory().Template().get(template.getClass());
066: // insert all the interfaces
067: for (CtTypeReference<?> t : sourceClass.getSuperInterfaces()) {
068: if (!t.equals(targetType.getFactory().Type()
069: .createReference(Template.class))) {
070: CtTypeReference<?> t1 = t;
071: // substitute ref if needed
072: if (Parameters.getNames(sourceClass).contains(
073: t.getSimpleName())) {
074: Object o = Parameters.getValue(template, t
075: .getSimpleName(), null);
076: if (o instanceof CtTypeReference) {
077: t1 = (CtTypeReference) o;
078: } else if (o instanceof Class) {
079: t1 = targetType.getFactory().Type()
080: .createReference((Class) o);
081: } else if (o instanceof String) {
082: t1 = targetType.getFactory().Type()
083: .createReference((String) o);
084: }
085: }
086: if (!t1.equals(targetType.getReference())) {
087: Class c = null;
088: try {
089: c = t1.getActualClass();
090: } catch (Exception e) {
091: // swallow it
092: }
093: if (c != null && c.isInterface()) {
094: targetType.getSuperInterfaces().add(t1);
095: }
096: if (c == null) {
097: targetType.getSuperInterfaces().add(t1);
098: }
099: }
100: }
101: }
102: // insert all the methods
103: for (CtMethod<?> m : sourceClass.getMethods()) {
104: if (m.getAnnotation(Local.class) != null)
105: continue;
106: if (m.getAnnotation(Parameter.class) != null)
107: continue;
108: insertMethod(targetType, template, m);
109: }
110: // insert all the constructors
111: if (targetType instanceof CtClass) {
112: for (CtConstructor c : sourceClass.getConstructors()) {
113: if (c.isImplicit())
114: continue;
115: if (c.getAnnotation(Local.class) != null)
116: continue;
117: insertConstructor((CtClass<?>) targetType, template, c);
118: }
119: }
120: // insert all the initialization blocks (only for classes)
121: if (targetType instanceof CtClass) {
122: for (CtAnonymousExecutable e : sourceClass
123: .getAnonymousExecutables()) {
124: ((CtClass<?>) targetType).getAnonymousExecutables()
125: .add(substitute(targetType, template, e));
126: }
127: }
128: // insert all the fields
129: for (CtField<?> f : sourceClass.getFields()) {
130: if (f.getAnnotation(Local.class) != null)
131: continue;
132: if (Parameters.isParameterSource(f.getReference()))
133: continue;
134:
135: insertField(targetType, template, f);
136: }
137: // insert all the inner types
138: for (CtSimpleType<?> t : sourceClass.getNestedTypes()) {
139: if (t.getAnnotation(Local.class) != null)
140: continue;
141: CtSimpleType<?> result = substitute(sourceClass, template,
142: t);
143: targetType.getNestedTypes().add(result);
144: result.setParent(targetType);
145: }
146:
147: }
148:
149: /**
150: * Inserts all the super interfaces (except {@link Template}) from a given
151: * template by substituting all the template parameters by their values.
152: *
153: * @param targetType
154: * the target type
155: * @param template
156: * the source template
157: */
158: @SuppressWarnings("unchecked")
159: public static void insertAllSuperInterfaces(CtType<?> targetType,
160: Template template) {
161:
162: CtClass<? extends Template> sourceClass = targetType
163: .getFactory().Template().get(template.getClass());
164: // insert all the interfaces
165: for (CtTypeReference<?> t : sourceClass.getSuperInterfaces()) {
166: if (!t.equals(targetType.getFactory().Type()
167: .createReference(Template.class))) {
168: CtTypeReference<?> t1 = t;
169: // substitute ref if needed
170: if (Parameters.getNames(sourceClass).contains(
171: t.getSimpleName())) {
172: Object o = Parameters.getValue(template, t
173: .getSimpleName(), null);
174: if (o instanceof CtTypeReference) {
175: t1 = (CtTypeReference) o;
176: } else if (o instanceof Class) {
177: t1 = targetType.getFactory().Type()
178: .createReference((Class) o);
179: } else if (o instanceof String) {
180: t1 = targetType.getFactory().Type()
181: .createReference((String) o);
182: }
183: }
184: if (!t1.equals(targetType.getReference())) {
185: Class c = t1.getActualClass();
186: if (c != null && c.isInterface()) {
187: targetType.getSuperInterfaces().add(t1);
188: }
189: if (c == null) {
190: targetType.getSuperInterfaces().add(t1);
191: }
192: }
193: }
194: }
195: }
196:
197: /**
198: * Inserts all the methods from a given template by substituting all the
199: * template parameters by their values. Members annotated with
200: * {@link spoon.template.Local} or {@link Parameter} are not inserted.
201: *
202: * @param targetType
203: * the target type
204: * @param template
205: * the source template
206: */
207: @SuppressWarnings("unchecked")
208: public static void insertAllMethods(CtType<?> targetType,
209: Template template) {
210:
211: CtClass<?> sourceClass = targetType.getFactory().Template()
212: .get(template.getClass());
213: // insert all the methods
214: for (CtMethod<?> m : sourceClass.getMethods()) {
215: if (m.getAnnotation(Local.class) != null)
216: continue;
217: if (m.getAnnotation(Parameter.class) != null)
218: continue;
219: insertMethod(targetType, template, m);
220: }
221: }
222:
223: /**
224: * Inserts all the fields from a given template by substituting all the
225: * template parameters by their values. Members annotated with
226: * {@link spoon.template.Local} or {@link Parameter} are not inserted.
227: *
228: * @param targetType
229: * the target type
230: * @param template
231: * the source template
232: */
233: @SuppressWarnings("unchecked")
234: public static void insertAllFields(CtType<?> targetType,
235: Template template) {
236:
237: CtClass<?> sourceClass = targetType.getFactory().Template()
238: .get(template.getClass());
239: // insert all the fields
240: for (CtField<?> f : sourceClass.getFields()) {
241: if (f.getAnnotation(Local.class) != null)
242: continue;
243: if (Parameters.isParameterSource(f.getReference()))
244: continue;
245:
246: insertField(targetType, template, f);
247: }
248: }
249:
250: /**
251: * Inserts all constructors and initialization blocks from a given template
252: * by substituting all the template parameters by their values. Members
253: * annotated with {@link spoon.template.Local} or {@link Parameter} are not
254: * inserted.
255: *
256: * @param targetType
257: * the target type
258: * @param template
259: * the source template
260: */
261: @SuppressWarnings("unchecked")
262: public static void insertAllConstructors(CtType<?> targetType,
263: Template template) {
264:
265: CtClass<?> sourceClass = targetType.getFactory().Template()
266: .get(template.getClass());
267: // insert all the constructors
268: if (targetType instanceof CtClass) {
269: for (CtConstructor c : sourceClass.getConstructors()) {
270: if (c.isImplicit())
271: continue;
272: if (c.getAnnotation(Local.class) != null)
273: continue;
274: insertConstructor((CtClass<?>) targetType, template, c);
275: }
276: }
277: // insert all the initialization blocks (only for classes)
278: if (targetType instanceof CtClass) {
279: for (CtAnonymousExecutable e : sourceClass
280: .getAnonymousExecutables()) {
281: ((CtClass<?>) targetType).getAnonymousExecutables()
282: .add(substitute(targetType, template, e));
283: }
284: }
285: }
286:
287: /**
288: * Generates a constructor from a template method by substituting all the
289: * template parameters by their values.
290: *
291: * @param targetClass
292: * the target class where to insert the generated constructor
293: * @param template
294: * the template instance that holds the source template method
295: * and that defines the parameter values
296: * @param sourceMethod
297: * the source template method
298: * @return the generated method
299: */
300: public static <T> CtConstructor<T> insertConstructor(
301: CtClass<T> targetClass, Template template,
302: CtMethod<?> sourceMethod) {
303:
304: if (targetClass instanceof CtInterface)
305: return null;
306: CtConstructor<T> newConstructor = targetClass.getFactory()
307: .Constructor().create(targetClass, sourceMethod);
308: newConstructor = substitute(targetClass, template,
309: newConstructor);
310: targetClass.getConstructors().add(newConstructor);
311: newConstructor.setParent(targetClass);
312: return newConstructor;
313: }
314:
315: /**
316: * Generates a method from a template method by substituting all the
317: * template parameters by their values.
318: *
319: * @param targetType
320: * the target type where to insert the generated method
321: * @param template
322: * the template instance that holds the source template method
323: * and that defines the parameter values
324: * @param sourceMethod
325: * the source template method
326: * @return the generated method
327: */
328: public static <T> CtMethod<T> insertMethod(CtType<?> targetType,
329: Template template, CtMethod<T> sourceMethod) {
330:
331: CtMethod<T> newMethod = substitute(targetType, template,
332: sourceMethod);
333: if (targetType instanceof CtInterface)
334: newMethod.setBody(null);
335: targetType.getMethods().add(newMethod);
336: newMethod.setParent(targetType);
337: return newMethod;
338: }
339:
340: /**
341: * Generates a constructor from a template constructor by substituting all
342: * the template parameters by their values.
343: *
344: * @param targetClass
345: * the target class where to insert the generated constructor
346: * @param template
347: * the template instance that holds the source template
348: * constructor and that defines the parameter values
349: * @param sourceConstructor
350: * the source template constructor
351: * @return the generated constructor
352: */
353: @SuppressWarnings("unchecked")
354: public static <T> CtConstructor<T> insertConstructor(
355: CtClass<T> targetClass, Template template,
356: CtConstructor<?> sourceConstructor) {
357:
358: CtConstructor<T> newConstrutor = substitute(targetClass,
359: template, (CtConstructor<T>) sourceConstructor);
360: newConstrutor.setParent(targetClass);
361: // remove the implicit constructor if clashing
362: if (newConstrutor.getParameters().isEmpty()) {
363: CtConstructor<?> c = targetClass.getConstructor();
364: if (c != null && c.isImplicit())
365: targetClass.getConstructors().remove(c);
366: }
367: targetClass.getConstructors().add(newConstrutor);
368: return newConstrutor;
369: }
370:
371: /**
372: * Gets a body from a template executable with all the template parameters
373: * substituted.
374: *
375: * @param targetClass
376: * the target class
377: * @param template
378: * the template that holds the executable
379: * @param executableName
380: * the source executable template
381: * @param parameterTypes
382: * the parameter types of the source executable
383: * @return the body expression of the source executable template with all
384: * the template parameters substituted
385: */
386:
387: public static CtBlock<?> substituteMethodBody(
388: CtClass<?> targetClass, Template template,
389: String executableName, CtTypeReference<?>... parameterTypes) {
390: CtClass<?> sourceClass = targetClass.getFactory().Template()
391: .get(template.getClass());
392: CtExecutable<?> sourceExecutable = executableName
393: .equals(template.getClass().getSimpleName()) ? sourceClass
394: .getConstructor(parameterTypes)
395: : sourceClass.getMethod(executableName, parameterTypes);
396: return substitute(targetClass, template, sourceExecutable
397: .getBody());
398: }
399:
400: /**
401: * Gets a default expression from a template field with all the template
402: * parameters substituted.
403: *
404: * @param targetType
405: * the target type
406: * @param template
407: * the template that holds the field
408: * @param fieldName
409: * the template source field
410: * @return the expression of the template source field with all the template
411: * parameters substituted
412: */
413:
414: public static CtExpression<?> substituteFieldDefaultExpression(
415: CtSimpleType<?> targetType, Template template,
416: String fieldName) {
417: CtClass<?> sourceClass = targetType.getFactory().Template()
418: .get(template.getClass());
419: CtField<?> sourceField = sourceClass.getField(fieldName);
420: return substitute(targetType, template, sourceField
421: .getDefaultExpression());
422: }
423:
424: /**
425: * Substitutes all the template parameters in a random piece of code.
426: *
427: * @param targetType
428: * the target type
429: * @param template
430: * the template instance
431: * @param code
432: * the code
433: * @return the code where all the template parameters has be substituted by
434: * their values
435: */
436: public static <E extends CtElement> E substitute(
437: CtSimpleType<?> targetType, Template template, E code) {
438: if (code == null)
439: return null;
440: if (targetType == null)
441: throw new RuntimeException("target is null in substitution");
442: E result = targetType.getFactory().Core().clone(code);
443: new SubstitutionVisitor(targetType.getFactory(), targetType,
444: template).scan(result);
445: return result;
446: }
447:
448: /**
449: * Substitutes all the template parameters in the first template element
450: * annotated with an instance of the given annotation type.
451: *
452: * @param targetType
453: * the target type
454: * @param template
455: * the template instance
456: * @param annotationType
457: * the annotation type
458: * @return the element where all the template parameters has be substituted
459: * by their values
460: */
461: // public static <E extends CtElement> E substitute(
462: // CtSimpleType<?> targetType, Template template,
463: // Class<? extends Annotation> annotationType) {
464: // CtClass<? extends Template> c = targetType.getFactory().Class
465: // .get(template.getClass());
466: // E element = (E) c.getAnnotatedChildren(annotationType).get(0);
467: // if (element == null)
468: // return null;
469: // if (targetType == null)
470: // throw new RuntimeException("target is null in substitution");
471: // E result = CtCloner.clone(element);
472: // new SubstitutionVisitor(targetType.getFactory(), targetType, template)
473: // .scan(result);
474: // return result;
475: // }
476: /**
477: * Substitutes all the template parameters in a given template type and
478: * returns the resulting type.
479: *
480: * @param template
481: * the template instance (holds the parameter values)
482: * @param templateType
483: * the template type
484: * @return a copy of the template type where all the parameters has been
485: * substituted
486: */
487: public static <T extends CtSimpleType<?>> T substitute(
488: Template template, T templateType) {
489: T result = templateType.getFactory().Core().clone(templateType);
490: result.setPositions(null);
491: result.setParent(templateType.getParent());
492: new SubstitutionVisitor(templateType.getFactory(), result,
493: template).scan(result);
494: return result;
495: }
496:
497: /**
498: * Generates a field (and its initialization expression) from a template
499: * field by substituting all the template parameters by their values.
500: *
501: * @param <T>
502: * the type of the field
503: * @param targetType
504: * the target type where the field is inserted
505: * @param template
506: * the template that defines the source template field
507: * @param sourceField
508: * the source template field
509: * @return the inserted field
510: */
511: public static <T> CtField<T> insertField(CtType<?> targetType,
512: Template template, CtField<T> sourceField) {
513: CtField<T> field = substitute(targetType, template, sourceField);
514: targetType.getFields().add(field);
515: field.setParent(targetType);
516: return field;
517: }
518:
519: /**
520: * A helper method that recursively redirects all the type references from a
521: * source type to a target type in the given element.
522: */
523: public static void redirectTypeReferences(CtElement element,
524: CtTypeReference<?> source, CtTypeReference<?> target) {
525:
526: List<CtTypeReference<?>> refs = Query.getReferences(element,
527: new ReferenceTypeFilter<CtTypeReference<?>>(
528: CtTypeReference.class));
529:
530: String srcName = source.getQualifiedName();
531: String targetName = target.getSimpleName();
532: CtPackageReference targetPackage = target.getPackage();
533:
534: for (CtTypeReference<?> ref : refs) {
535: if (ref.getQualifiedName().equals(srcName)) {
536: ref.setSimpleName(targetName);
537: ref.setPackage(targetPackage);
538: }
539: }
540: }
541: }
|