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.reflect.factory;
019:
020: import java.util.ArrayList;
021: import java.util.List;
022: import java.util.Set;
023: import java.util.TreeSet;
024:
025: import spoon.reflect.Factory;
026: import spoon.reflect.code.BinaryOperatorKind;
027: import spoon.reflect.code.CtAssignment;
028: import spoon.reflect.code.CtBinaryOperator;
029: import spoon.reflect.code.CtBlock;
030: import spoon.reflect.code.CtCodeSnippetExpression;
031: import spoon.reflect.code.CtCodeSnippetStatement;
032: import spoon.reflect.code.CtExpression;
033: import spoon.reflect.code.CtFieldAccess;
034: import spoon.reflect.code.CtInvocation;
035: import spoon.reflect.code.CtLiteral;
036: import spoon.reflect.code.CtLocalVariable;
037: import spoon.reflect.code.CtNewArray;
038: import spoon.reflect.code.CtStatement;
039: import spoon.reflect.code.CtStatementList;
040: import spoon.reflect.code.CtVariableAccess;
041: import spoon.reflect.declaration.CtNamedElement;
042: import spoon.reflect.declaration.CtVariable;
043: import spoon.reflect.declaration.ModifierKind;
044: import spoon.reflect.reference.CtExecutableReference;
045: import spoon.reflect.reference.CtFieldReference;
046: import spoon.reflect.reference.CtLocalVariableReference;
047: import spoon.reflect.reference.CtReference;
048: import spoon.reflect.reference.CtTypeReference;
049: import spoon.reflect.reference.CtVariableReference;
050:
051: /**
052: * This sub-factory contains utility methods to create code elements. To avoid
053: * over-using reflection, consider using {@link spoon.template.Template}.
054: */
055: public class CodeFactory extends SubFactory {
056:
057: private static final long serialVersionUID = 1L;
058:
059: /**
060: * Creates a {@link spoon.reflect.code.CtCodeElement} sub-factory.
061: */
062: public CodeFactory(Factory factory) {
063: super (factory);
064: }
065:
066: /**
067: * Creates a binary operator.
068: *
069: * @param <T>
070: * the type of the expression
071: * @param left
072: * the left operand
073: * @param right
074: * the right operand
075: * @param kind
076: * the operator kind
077: * @return a binary operator expression
078: */
079: public <T> CtBinaryOperator<T> createBinaryOperator(
080: CtExpression<?> left, CtExpression<?> right,
081: BinaryOperatorKind kind) {
082: CtBinaryOperator<T> op = factory.Core().createBinaryOperator();
083: op.setLeftHandOperand(left);
084: op.setRightHandOperand(right);
085: setParent(op, left, right);
086: op.setKind(kind);
087: return op;
088: }
089:
090: /**
091: * Creates a class access expression of the form <code>C.class</code>.
092: *
093: * @param <T>
094: * the actual type of the accessed class if available
095: * @param type
096: * a type reference to the accessed class
097: * @return the class access expression.
098: */
099: @SuppressWarnings("unchecked")
100: public <T> CtFieldAccess<Class<T>> createClassAccess(
101: CtTypeReference<T> type) {
102: CtFieldAccess<Class<T>> ca = factory.Core().createFieldAccess();
103: CtTypeReference classType = factory.Type().createReference(
104: Class.class);
105:
106: ca.setType(classType);
107: CtFieldReference field = factory.Core().createFieldReference();
108: field.setDeclaringType(type);
109: field.setType(classType);
110: field.setSimpleName("class");
111: ca.setVariable(field);
112: return ca;
113: }
114:
115: /**
116: * Creates an invocation (can be a statement or an expression).
117: *
118: * @param <T>
119: * the return type of the invoked method
120: * @param target
121: * the target expression
122: * @param executable
123: * the invoked executable
124: * @param arguments
125: * the argument list
126: * @return the new invocation
127: */
128: public <T> CtInvocation<T> createInvocation(CtExpression<?> target,
129: CtExecutableReference<T> executable,
130: CtExpression<?>... arguments) {
131: List<CtExpression<?>> ext = new ArrayList<CtExpression<?>>();
132: for (CtExpression<?> arg : arguments) {
133: ext.add(arg);
134: }
135: return createInvocation(target, executable, ext);
136: }
137:
138: /**
139: * Creates an invocation (can be a statement or an expression).
140: *
141: * @param <T>
142: * the return type of the invoked method
143: * @param target
144: * the target expression
145: * @param executable
146: * the invoked executable
147: * @param arguments
148: * the argument list
149: * @return the new invocation
150: */
151: public <T> CtInvocation<T> createInvocation(CtExpression<?> target,
152: CtExecutableReference<T> executable,
153: List<CtExpression<?>> arguments) {
154: CtInvocation<T> invocation = factory.Core().createInvocation();
155: invocation.setTarget(target);
156: invocation.setExecutable(executable);
157: invocation.setArguments(arguments);
158: return invocation;
159: }
160:
161: /**
162: * Creates a literal with a given value.
163: *
164: * @param <T>
165: * the type of the literal
166: * @param value
167: * the value of the litteral
168: * @return a new literal
169: */
170: public <T> CtLiteral<T> createLiteral(T value) {
171: CtLiteral<T> l = factory.Core().createLiteral();
172: l.setValue(value);
173: return l;
174: }
175:
176: /**
177: * Creates a one-dimension array that must only contain literals.
178: */
179: @SuppressWarnings("unchecked")
180: public <T> CtNewArray<T[]> createLiteralArray(T[] value) {
181: if (!value.getClass().isArray())
182: throw new RuntimeException("value is not an array");
183: if (value.getClass().getComponentType().isArray())
184: throw new RuntimeException(
185: "can only create one-dimension arrays");
186: CtNewArray<T[]> array = factory.Core().createNewArray();
187: array.setType(factory.Type()
188: .createArrayReference(
189: factory.Type().createReference(
190: (Class<T>) value.getClass()
191: .getComponentType())));
192: for (T e : value) {
193: CtLiteral<T> l = factory.Core().createLiteral();
194: l.setValue(e);
195: l.setParent(array);
196: array.getElements().add(l);
197: }
198: return array;
199: }
200:
201: /**
202: * Creates a local variable declaration.
203: *
204: * @param <T>
205: * the local variable type
206: * @param type
207: * the reference to the type
208: * @param name
209: * the name of the variable
210: * @param defaultExpression
211: * the assigned default expression
212: * @return a new local variable declaration
213: */
214: public <T> CtLocalVariable<T> createLocalVariable(
215: CtTypeReference<T> type, String name,
216: CtExpression<T> defaultExpression) {
217: CtLocalVariable<T> var = factory.Core().createLocalVariable();
218: var.setSimpleName(name);
219: var.setType(type);
220: var.setDefaultExpression(defaultExpression);
221: return var;
222: }
223:
224: /**
225: * Creates a local variable reference that points to an existing local
226: * variable (strong referencing).
227: */
228: public <T> CtLocalVariableReference<T> createLocalVariableReference(
229: CtLocalVariable<T> localVariable) {
230: CtLocalVariableReference<T> ref = factory.Core()
231: .createLocalVariableReference();
232: ref.setType(localVariable.getType());
233: ref.setSimpleName(localVariable.getSimpleName());
234: ref.setDeclaration(localVariable);
235: return ref;
236: }
237:
238: /**
239: * Creates a local variable reference with its name an type (weak
240: * referencing).
241: */
242: public <T> CtLocalVariableReference<T> createLocalVariableReference(
243: CtTypeReference<T> type, String name) {
244: CtLocalVariableReference<T> ref = factory.Core()
245: .createLocalVariableReference();
246: ref.setType(type);
247: ref.setSimpleName(name);
248: return ref;
249: }
250:
251: /**
252: * Creates a new statement list from an existing block.
253: */
254: @SuppressWarnings("unchecked")
255: public CtStatementList createStatementList(CtBlock<?> block) {
256: CtStatementList l = factory.Core().createStatementList();
257: for (CtStatement s : block.getStatements()) {
258: l.getStatements().add(factory.Core().clone(s));
259: }
260: return l;
261: }
262:
263: /**
264: * Creates an access to a <code>this</code> variable (of the form
265: * <code>type.this</code>).
266: *
267: * @param <T>
268: * the actual type of <code>this</code>
269: * @param type
270: * the reference to the type that holds the <code>this</code>
271: * variable
272: * @return a <code>type.this</code> expression
273: */
274: public <T> CtFieldAccess<T> createThisAccess(CtTypeReference<T> type) {
275: CtFieldAccess<T> fa = factory.Core().createFieldAccess();
276: fa.setType(type);
277: CtFieldReference<T> field = factory.Core()
278: .createFieldReference();
279: field.setDeclaringType(type);
280: field.setType(type);
281: field.setSimpleName("this");
282: fa.setVariable(field);
283: return fa;
284: }
285:
286: /**
287: * Creates a variable access.
288: */
289: public <T> CtVariableAccess<T> createVariableAccess(
290: CtVariableReference<T> variable, boolean isStatic) {
291: CtVariableAccess<T> va;
292: if (variable instanceof CtFieldReference) {
293: va = factory.Core().createFieldAccess();
294: // creates a this target for non-static fields to avoid name
295: // conflicts...
296: if (!isStatic) {
297: ((CtFieldAccess<T>) va)
298: .setTarget(createThisAccess(((CtFieldReference<T>) variable)
299: .getDeclaringType()));
300: }
301: } else {
302: va = factory.Core().createVariableAccess();
303: }
304: va.setVariable(variable);
305: va.setType(variable.getType());
306: return va;
307: }
308:
309: /**
310: * Creates a list of variable accesses.
311: *
312: * @param variables
313: * the variables to be accessed
314: */
315: public List<CtExpression<?>> createVariableAccesses(
316: List<? extends CtVariable<?>> variables) {
317: List<CtExpression<?>> result = new ArrayList<CtExpression<?>>();
318: for (CtVariable<?> v : variables) {
319: result.add(createVariableAccess(v.getReference(), v
320: .getModifiers().contains(ModifierKind.STATIC)));
321: }
322: return result;
323: }
324:
325: /**
326: * Creates a variable assignment (can be an expression or a statement).
327: *
328: * @param <T>
329: * the type of the assigned variable
330: * @param variable
331: * a reference to the assigned variable
332: * @param isStatic
333: * tells if the assigned variable is static or not
334: * @param expression
335: * the assigned expression
336: * @return a variable assignment
337: */
338: public <A, T extends A> CtAssignment<A, T> createVariableAssignment(
339: CtVariableReference<A> variable, boolean isStatic,
340: CtExpression<T> expression) {
341: CtAssignment<A, T> va = factory.Core().createAssignment();
342: va.setAssignment(expression);
343: expression.setParent(va);
344: CtVariableAccess<A> vaccess = createVariableAccess(variable,
345: isStatic);
346: va.setAssigned(vaccess);
347: vaccess.setParent(va);
348: return va;
349: }
350:
351: /**
352: * Creates a list of statements that contains the assignments of a set of
353: * variables.
354: *
355: * @param variables
356: * the variables to be assigned
357: * @param expressions
358: * the assigned expressions
359: * @return a list of variable assignments
360: */
361: @SuppressWarnings("unchecked")
362: public CtStatementList createVariableAssignments(
363: List<? extends CtVariable> variables,
364: List<? extends CtExpression> expressions) {
365: CtStatementList<?> result = factory.Core()
366: .createStatementList();
367: for (int i = 0; i < variables.size(); i++) {
368: result.getStatements().add(
369: createVariableAssignment(variables.get(i)
370: .getReference(), variables.get(i)
371: .getModifiers().contains(
372: ModifierKind.STATIC), expressions
373: .get(i)));
374: }
375: return result;
376: }
377:
378: /**
379: * Gets a list of references from a list of elements.
380: *
381: * @param <R>
382: * the expected reference type
383: * @param <E>
384: * the element type
385: * @param elements
386: * the element list
387: * @return the corresponding list of references
388: */
389: @SuppressWarnings("unchecked")
390: public <R extends CtReference, E extends CtNamedElement> List<R> getReferences(
391: List<E> elements) {
392: List<R> refs = new ArrayList<R>();
393: for (E e : elements) {
394: refs.add((R) e.getReference());
395: }
396: return refs;
397: }
398:
399: /**
400: * Creates a modifier set.
401: *
402: * @param modifiers
403: * to put in set
404: * @return Set of given modifiers
405: */
406: public Set<ModifierKind> modifiers(ModifierKind... modifiers) {
407: Set<ModifierKind> ret = new TreeSet<ModifierKind>();
408: for (ModifierKind m : modifiers)
409: ret.add(m);
410: return ret;
411: }
412:
413: /**
414: * Creates a Code Snippet expression.
415: *
416: * @param <T> The type of the expression represented by the CodeSnippet
417: * @param expression The string that contains the expression.
418: * @return a new CtCodeSnippetExpression.
419: */
420: public <T> CtCodeSnippetExpression<T> createCodeSnippetExpression(
421: String expression) {
422: CtCodeSnippetExpression<T> e = factory.Core()
423: .createCodeSnippetExpression();
424: e.setValue(expression);
425: return e;
426: }
427:
428: /**
429: * Creates a Code Snippet statement.
430: *
431: * @param statement The String containing the statement.
432: * @return a new CtCodeSnippetStatement
433: */
434: public CtCodeSnippetStatement createCodeSnippetStatement(
435: String statement) {
436: CtCodeSnippetStatement e = factory.Core()
437: .createCodeSnippetStatement();
438: e.setValue(statement);
439: return e;
440: }
441:
442: }
|