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