001: /*
002: * Author: Chris Seguin
003: *
004: * This software has been developed under the copyleft
005: * rules of the GNU General Public License. Please
006: * consult the GNU General Public License for more
007: * details about use and distribution of this software.
008: */
009: package org.acm.seguin.refactor.method;
010:
011: import java.util.Iterator;
012: import java.util.StringTokenizer;
013: import net.sourceforge.jrefactory.ast.ASTBlock;
014: import net.sourceforge.jrefactory.ast.ASTClassBodyDeclaration;
015: import net.sourceforge.jrefactory.ast.ASTClassDeclaration;
016: import net.sourceforge.jrefactory.ast.ASTFormalParameter;
017: import net.sourceforge.jrefactory.ast.ASTFormalParameters;
018: import net.sourceforge.jrefactory.ast.ASTConstructorDeclaration;
019: import net.sourceforge.jrefactory.ast.ASTExplicitConstructorInvocation;
020: import net.sourceforge.jrefactory.ast.ASTArguments;
021: import net.sourceforge.jrefactory.ast.ASTArgumentList;
022: import net.sourceforge.jrefactory.ast.ASTName;
023: import net.sourceforge.jrefactory.ast.ASTNameList;
024: import net.sourceforge.jrefactory.ast.ASTPrimitiveType;
025: import net.sourceforge.jrefactory.ast.ASTResultType;
026: import net.sourceforge.jrefactory.ast.ASTType;
027: import net.sourceforge.jrefactory.ast.ASTTypeDeclaration;
028: import net.sourceforge.jrefactory.ast.ASTVariableDeclaratorId;
029: import net.sourceforge.jrefactory.ast.SimpleNode;
030: import net.sourceforge.jrefactory.build.BuildExpression;
031: import net.sourceforge.jrefactory.ast.ModifierHolder;
032: import org.acm.seguin.refactor.TransformAST;
033: import org.acm.seguin.summary.MethodSummary;
034: import org.acm.seguin.summary.ParameterSummary;
035: import org.acm.seguin.summary.TypeDeclSummary;
036:
037: import net.sourceforge.jrefactory.ast.ASTReferenceType;
038: import net.sourceforge.jrefactory.ast.ASTClassOrInterfaceType;
039: import net.sourceforge.jrefactory.parser.JavaParserTreeConstants;
040:
041: /**
042: * A series of transformations taht adds a new constructor to a class.
043: * The constructor invokes the super classes's constructor. This
044: * object shares a lot in common with the AddNewMethod class, and
045: * combining these two objects can be considered for future refactorings.
046: *
047: *@author Chris Seguin
048: */
049: public class AddConstructor extends TransformAST {
050: /**
051: * The method we are updating
052: */
053: protected MethodSummary methodSummary;
054: private String typeName;
055:
056: /**
057: * Constructor for the AddConstructor object
058: *
059: *@param init the method summary to add
060: */
061: public AddConstructor(MethodSummary init, String name) {
062: methodSummary = init;
063: typeName = name;
064: }
065:
066: /**
067: * Update the syntax tree
068: *
069: *@param root the root of the syntax tree
070: */
071: public void update(SimpleNode root) {
072: // Find the type declaration
073: int last = root.jjtGetNumChildren();
074: for (int ndx = 0; ndx < last; ndx++) {
075: if (root.jjtGetChild(ndx) instanceof ASTTypeDeclaration) {
076: drillIntoType((SimpleNode) root.jjtGetChild(ndx));
077: return;
078: }
079: }
080: }
081:
082: /**
083: * Determines if the method is abstract
084: *
085: *@return true if the method is abstract
086: */
087: protected boolean isAbstract() {
088: return methodSummary.isAbstract();
089: }
090:
091: /**
092: * Adds the return to the method declaration
093: *
094: *@param methodDecl The feature to be added to the Return attribute
095: *@param index The feature to be added to the Return attribute
096: */
097: protected void addReturn(SimpleNode methodDecl, int index) {
098: ASTResultType result = new ASTResultType(
099: JavaParserTreeConstants.JJTRESULTTYPE);
100: TypeDeclSummary returnType = methodSummary.getReturnType();
101: if ((returnType != null)
102: && !returnType.getType().equals("void")) {
103: ASTType type = buildType(returnType);
104: result.jjtAddChild(type, 0);
105: }
106: methodDecl.jjtAddChild(result, index);
107: }
108:
109: /**
110: * Creates the parameters
111: *
112: *@return Description of the Returned Value
113: */
114: protected ASTFormalParameters createParameters() {
115: ASTFormalParameters params = new ASTFormalParameters(
116: JavaParserTreeConstants.JJTFORMALPARAMETERS);
117: Iterator iter = methodSummary.getParameters();
118: if (iter != null) {
119: int paramCount = 0;
120: while (iter.hasNext()) {
121: ParameterSummary paramSummary = (ParameterSummary) iter
122: .next();
123: ASTFormalParameter nextParam = new ASTFormalParameter(
124: JavaParserTreeConstants.JJTFORMALPARAMETER);
125: ASTType type = buildType(paramSummary.getTypeDecl());
126: nextParam.jjtAddChild(type, 0);
127: ASTVariableDeclaratorId paramDeclID = new ASTVariableDeclaratorId(
128: JavaParserTreeConstants.JJTVARIABLEDECLARATORID);
129: paramDeclID.setName(paramSummary.getName());
130: nextParam.jjtAddChild(paramDeclID, 1);
131: params.jjtAddChild(nextParam, paramCount);
132: paramCount++;
133: }
134: }
135: return params;
136: }
137:
138: /**
139: * Creates the exceptions
140: *
141: *@param iter Description of Parameter
142: *@return Description of the Returned Value
143: */
144: protected ASTNameList createExceptions(Iterator iter) {
145: ASTNameList list = new ASTNameList(
146: JavaParserTreeConstants.JJTNAMELIST);
147: int ndx = 0;
148: while (iter.hasNext()) {
149: TypeDeclSummary next = (TypeDeclSummary) iter.next();
150: list.jjtAddChild(buildName(next), ndx);
151: ndx++;
152: }
153: return list;
154: }
155:
156: /**
157: * Adds the exceptions to the node
158: *
159: *@param methodDecl The feature to be added to the Exceptions attribute
160: *@param index The feature to be added to the Exceptions attribute
161: *@return Description of the Returned Value
162: */
163: protected int addExceptions(SimpleNode methodDecl, int index) {
164: Iterator iter = methodSummary.getExceptions();
165: if (iter != null) {
166: ASTNameList list = createExceptions(iter);
167: methodDecl.jjtAddChild(list, index);
168: index++;
169: }
170: return index;
171: }
172:
173: /**
174: * Adds the body of the method
175: *
176: *@param methodDecl The feature to be added to the Body attribute
177: *@param index The feature to be added to the Body attribute
178: */
179: protected void addBody(SimpleNode methodDecl, int index) {
180: ASTExplicitConstructorInvocation eci = new ASTExplicitConstructorInvocation(
181: JavaParserTreeConstants.JJTEXPLICITCONSTRUCTORINVOCATION);
182: eci.setName("super");
183:
184: ASTArguments args = new ASTArguments(
185: JavaParserTreeConstants.JJTARGUMENTS);
186: eci.jjtAddChild(args, 0);
187:
188: ASTArgumentList argList = new ASTArgumentList(
189: JavaParserTreeConstants.JJTARGUMENTLIST);
190: args.jjtAddChild(argList, 0);
191:
192: Iterator iter = methodSummary.getParameters();
193: int item = 0;
194: if (iter != null) {
195: BuildExpression builder = new BuildExpression();
196: while (iter.hasNext()) {
197: ParameterSummary param = (ParameterSummary) iter.next();
198: argList.jjtAddChild(builder.buildName(param.getName()),
199: item);
200: item++;
201: }
202: }
203:
204: methodDecl.jjtAddChild(eci, index);
205: }
206:
207: /**
208: * Drills down into the class definition to add the method
209: *
210: *@param node the type syntax tree node that is being modified
211: */
212: private void drillIntoType(SimpleNode node) {
213: ASTClassDeclaration classDecl = (ASTClassDeclaration) node
214: .jjtGetFirstChild();
215: if (isAbstract()) {
216: classDecl.setAbstract(true);
217: }
218: SimpleNode unmodified = (SimpleNode) classDecl
219: .jjtGetFirstChild();
220: SimpleNode classBody = (SimpleNode) unmodified
221: .jjtGetChild(unmodified.jjtGetNumChildren() - 1);
222: ASTClassBodyDeclaration decl = new ASTClassBodyDeclaration(
223: JavaParserTreeConstants.JJTCLASSBODYDECLARATION);
224: decl.jjtAddChild(build(), 0);
225: classBody.jjtAddChild(decl, classBody.jjtGetNumChildren());
226: }
227:
228: /**
229: * Builds the method to be adding
230: *
231: *@return a syntax tree branch containing the new method
232: */
233: private ASTConstructorDeclaration build() {
234: ASTConstructorDeclaration methodDecl = new ASTConstructorDeclaration(
235: 0);
236:
237: // Set the modifiers
238: copyModifiers(methodSummary, methodDecl);
239:
240: // Set the declaration
241: methodDecl.setName(typeName);
242: ASTFormalParameters params = createParameters();
243: methodDecl.jjtAddChild(params, 0);
244:
245: int index = 1;
246:
247: index = addExceptions(methodDecl, index);
248:
249: addBody(methodDecl, index);
250:
251: return methodDecl;
252: }
253:
254: /**
255: * Builds the type from the type declaration summary
256: *
257: *@param summary the summary
258: *@return the AST type node
259: */
260: private ASTType buildType(TypeDeclSummary summary) {
261: ASTType type = new ASTType(JavaParserTreeConstants.JJTTYPE);
262: if (summary.getArrayCount() == 0 && summary.isPrimitive()) {
263: type.jjtAddChild(buildPrimitive(summary), 0);
264: } else {
265: type.jjtAddChild(buildReferenceType(summary), 0);
266: }
267: return type;
268: }
269:
270: /**
271: * Builds the name of the type from the type decl summary
272: *
273: *@param summary the summary
274: *@return the name node
275: */
276: private ASTName buildName(TypeDeclSummary summary) {
277: ASTName name = new ASTName();
278: name.fromString(summary.getLongName());
279: return name;
280: }
281:
282: /**
283: * Builds the name of the type from the type decl summary
284: *
285: *@param summary the summary
286: *@return the name node
287: */
288: private ASTClassOrInterfaceType buildClassName(
289: TypeDeclSummary summary) {
290: ASTClassOrInterfaceType name = new ASTClassOrInterfaceType(
291: JavaParserTreeConstants.JJTCLASSORINTERFACETYPE);
292: name.fromString(summary.getLongName());
293: return name;
294: }
295:
296: /**
297: * Builds the name of the type from the type decl summary
298: *
299: *@param summary the summary
300: *@return the name node
301: */
302: private ASTPrimitiveType buildPrimitive(TypeDeclSummary summary) {
303: ASTPrimitiveType primitive = new ASTPrimitiveType(
304: JavaParserTreeConstants.JJTPRIMITIVETYPE);
305: primitive.setName(summary.getLongName());
306: return primitive;
307: }
308:
309: /**
310: * Builds the name of the type from the type decl summary
311: *
312: *@param summary the summary
313: *@return the name node
314: */
315: private ASTReferenceType buildReferenceType(TypeDeclSummary summary) {
316: ASTReferenceType reference = new ASTReferenceType(
317: JavaParserTreeConstants.JJTREFERENCETYPE);
318: if (summary.isPrimitive()) {
319: reference.jjtAddChild(buildPrimitive(summary), 0);
320: } else {
321: reference.jjtAddChild(buildClassName(summary), 0);
322: }
323: reference.setArrayCount(summary.getArrayCount());
324: return reference;
325: }
326: }
|