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 org.acm.seguin.refactor.ComplexTransform;
013: import org.acm.seguin.refactor.RefactoringException;
014: import org.acm.seguin.summary.FieldAccessSummary;
015: import org.acm.seguin.summary.FieldSummary;
016: import org.acm.seguin.summary.FileSummary;
017: import org.acm.seguin.summary.MessageSendSummary;
018: import org.acm.seguin.summary.MethodSummary;
019: import org.acm.seguin.summary.Summary;
020: import org.acm.seguin.summary.TypeSummary;
021: import org.acm.seguin.summary.query.FieldQuery;
022: import org.acm.seguin.summary.query.MethodQuery;
023: import org.acm.seguin.summary.PackageSummary;
024:
025: /**
026: * Moves a method from one class to another. Generally used to move a method into a local variable or a parameter.
027: *
028: * @author CMike Atkinson
029: * @since 2.9.11
030: */
031: public class RenameMethodRefactoring extends MethodRefactoring {
032: private String newName;
033: private MethodSummary oldMethod;
034:
035: /**
036: * Constructor for the MoveMethodRefactoring object
037: *
038: * @since empty
039: */
040: public RenameMethodRefactoring() {
041: super ();
042: }
043:
044: /**
045: * Sets the Method attribute of the MoveMethodRefactoring object
046: *
047: * @param value The new Method value
048: * @since empty
049: */
050: public void setMethod(MethodSummary value) {
051: oldMethod = value;
052: Summary current = oldMethod;
053: while (!(current instanceof TypeSummary)) {
054: current = current.getParent();
055: }
056: typeSummary = (TypeSummary) current;
057: }
058:
059: /**
060: * Sets the Destination attribute of the MoveMethodRefactoring object
061: *
062: * @param newName The new newMethodName value
063: * @since empty
064: */
065: public void setNewMethodName(String newName) {
066: this .newName = newName;
067: }
068:
069: /**
070: * Gets the description of the refactoring
071: *
072: * @return the description
073: * @since empty
074: */
075: public String getDescription() {
076: return "Renaming " + oldMethod.toString() + " to " + newName;
077: }
078:
079: /**
080: * Gets the ID attribute of the MoveMethodRefactoring object
081: *
082: * @return The ID value
083: * @since empty
084: */
085: public int getID() {
086: return RENAME_METHOD;
087: }
088:
089: /**
090: * Describes the preconditions that must be true for this refactoring to be applied
091: *
092: * @exception RefactoringException thrown if one or more of the preconditions is not satisfied. The text of the
093: * exception provides a hint of what went wrong.
094: * @since empty
095: */
096: protected void preconditions() throws RefactoringException {
097: System.out.println();
098: System.out.println();
099: System.out.println("preconditions() method=" + method + "");
100: getMethodSummary();
101: Iterator iter = oldMethod.getDependencies();
102: while ((iter != null) && (iter.hasNext())) {
103: Summary next = (Summary) iter.next();
104: // Check to see if we have any private fields without the appropriate getters/setters
105: if (next instanceof FieldAccessSummary) {
106: FieldAccessSummary fas = (FieldAccessSummary) next;
107: checkFieldAccess(fas);
108: } else if (next instanceof MessageSendSummary) {
109: MessageSendSummary mss = (MessageSendSummary) next;
110: checkMessageSend(mss);
111: }
112: }
113: }
114:
115: private void getMethodSummary() throws RefactoringException {
116: if (oldMethod == null) {
117: Iterator iter = typeSummary.getMethods();
118: if (iter == null) {
119: throw new RefactoringException(
120: typeSummary.getName()
121: + " has no methods associated with it, so it cannot be renamed");
122: }
123:
124: boolean found = false;
125: while (iter.hasNext()) {
126: MethodSummary next = (MethodSummary) iter.next();
127: System.out.println(" " + next);
128: if (next.getName().equals(method) && checkParams(next)) {
129: found = true;
130: oldMethod = next;
131: }
132: if (next.getName().equals(newName) && checkParams(next)) {
133: throw new RefactoringException("A method named "
134: + newName + " already exists in class "
135: + typeSummary.getName());
136: }
137: }
138:
139: if (!found) {
140: throw new RefactoringException("No method named "
141: + method + " is contained in "
142: + typeSummary.getName());
143: }
144:
145: }
146: }
147:
148: protected boolean checkParams(MethodSummary summary) {
149: System.out.println("summary=" + summary);
150: System.out.println("params.length=" + params.length);
151: System.out.println("summary.getParameterCount()="
152: + summary.getParameterCount());
153: return summary.getParameterCount() == params.length;
154: }
155:
156: /**
157: * Performs the transform on the rest of the classes
158: *
159: * @since empty
160: */
161: protected void transform() {
162: if (oldMethod.getName().equals(newName)) {
163: return;
164: }
165:
166: FileSummary fileSummary = (FileSummary) getFileSummary(typeSummary);
167: RenameMethodTransform rft = new RenameMethodTransform(
168: oldMethod, newName);
169: ComplexTransform transform = getComplexTransform();
170: transform.add(rft);
171: transform.apply(fileSummary.getFile(), fileSummary.getFile());
172:
173: if (oldMethod.isPrivate()) {
174: // We are done
175: System.out.println("handle private");
176: } else if (oldMethod.isPackage()) {
177: System.out.println("handle package");
178: RenameSystemTraversal rsv = new RenameSystemTraversal();
179: rsv.visit(getPackage(), new RenameMethodData(oldMethod,
180: newName, transform));
181: } else {
182: System.out.println("handle public or protected");
183: RenameSystemTraversal rsv = new RenameSystemTraversal();
184: rsv.visit(new RenameMethodData(oldMethod, newName,
185: transform));
186: }
187: }
188:
189: /**
190: * Gets the Package attribute of the RenameFieldRefactoring object
191: *
192: *@return The Package value
193: */
194: private PackageSummary getPackage() {
195: Summary current = oldMethod;
196: while (!(current instanceof PackageSummary)) {
197: current = current.getParent();
198: }
199:
200: return (PackageSummary) current;
201: }
202:
203: /**
204: * Description of the Method
205: *
206: *@param methodDecl Description of Parameter
207: *@return Description of the Returned Value
208: */
209: /*
210: protected ASTMethodDeclaration updateMethod(SimpleNode methodDecl) {
211: ASTMethodDeclaration decl = (ASTMethodDeclaration) methodDecl.jjtGetFirstChild();
212: for (int i=0; i<decl.jjtGetNumChildren(); i++) {
213: if (decl.jjtGetChild(i) instanceof ASTMethodDeclarator) {
214: ((ASTMethodDeclarator)decl.jjtGetChild(i)).setName(newName);
215: break;
216: }
217: }
218: return decl;
219: }
220: */
221:
222: /**
223: * Removes the method from the source
224: *
225: * @param source the source type
226: * @param transform the transform
227: * @return Description of the Returned Value
228: * @since empty
229: */
230: /*
231: protected SimpleNode removeMethod(TypeSummary source, ComplexTransform transform) {
232: RemoveMethodTransform rft = new RemoveMethodTransform(oldMethod);
233: transform.add(rft);
234:
235: InvokeMovedMethodTransform immt = new InvokeMovedMethodTransform(oldMethod, typeSummary);
236: transform.add(immt);
237:
238: FileSummary fileSummary = (FileSummary)source.getParent();
239: transform.apply(fileSummary.getFile(), fileSummary.getFile());
240:
241: return rft.getMethodDeclaration();
242: }
243: */
244:
245: /**
246: * Adds the method to the destination class
247: *
248: *@param transform The feature to be added to the MethodToDest attribute
249: *@param rft The feature to be added to the MethodToDest attribute
250: *@param methodDecl The feature to be added to the MethodToDest attribute
251: *@param dest The feature to be added to the MethodToDest attribute
252: */
253: /*
254: protected void addMethodToDest(ComplexTransform transform,
255: RemoveMethodTransform rft,
256: SimpleNode methodDecl,
257: TypeSummary dest) {
258: transform.clear();
259: transform.add(rft);
260: AddMethodTransform aft = new AddMethodTransform(methodDecl);
261: transform.add(aft);
262:
263: AddMethodTypeVisitor visitor = new AddMethodTypeVisitor();
264: oldMethod.accept(visitor, transform);
265:
266: // Add appropriate import statements - to be determined later
267: FileSummary parentFileSummary = (FileSummary) dest.getParent();
268: transform.apply(parentFileSummary.getFile(), parentFileSummary.getFile());
269: }
270: */
271:
272: /**
273: * Gets the name of the getter for the field
274: *
275: * @param summary the field summary
276: * @return the getter
277: * @since empty
278: */
279: private String getFieldGetter(FieldSummary summary) {
280: String typeName = summary.getType();
281: String prefix = "get";
282: if (typeName.equalsIgnoreCase("boolean")) {
283: prefix = "is";
284: }
285:
286: String name = summary.getName();
287:
288: return prefix + name.substring(0, 1).toUpperCase()
289: + name.substring(1);
290: }
291:
292: /**
293: * Gets the name of the setter for the field
294: *
295: * @param summary the field summary
296: * @return the setter
297: * @since empty
298: */
299: private String getFieldSetter(FieldSummary summary) {
300: String prefix = "set";
301: String name = summary.getName();
302: return prefix + name.substring(0, 1).toUpperCase()
303: + name.substring(1);
304: }
305:
306: /**
307: * Checks if we can properly transform the field access
308: *
309: * @param fas Description of Parameter
310: * @exception RefactoringException Description of Exception
311: * @since empty
312: */
313: private void checkFieldAccess(FieldAccessSummary fas)
314: throws RefactoringException {
315: if ((fas.getPackageName() == null)
316: && ((fas.getObjectName() == null) || fas
317: .getObjectName().equals("this"))) {
318: // Now we have to find the field
319: FieldSummary field = FieldQuery.find(typeSummary, fas
320: .getFieldName());
321: if (field != null) {
322: if (field.isPrivate()) {
323: checkForMethod(fas, field);
324: }
325: }
326: }
327: }
328:
329: /**
330: * For a private field, check that we have the correct setters or getters (as appropriate)
331: *
332: * @param fas Description of Parameter
333: * @param field Description of Parameter
334: * @exception RefactoringException Description of Exception
335: * @since empty
336: */
337: private void checkForMethod(FieldAccessSummary fas,
338: FieldSummary field) throws RefactoringException {
339: String methodName;
340: if (fas.isAssignment()) {
341: methodName = getFieldSetter(field);
342: } else {
343: methodName = getFieldGetter(field);
344: }
345: MethodSummary method = MethodQuery
346: .find(typeSummary, methodName);
347: if (method == null) {
348: throw new RefactoringException(
349: "Unable to find the appropriate method ("
350: + methodName
351: + ") for private field access in "
352: + typeSummary.getName());
353: }
354: }
355:
356: /**
357: * Updates the node fore move method
358: *
359: * @param node Description of Parameter
360: * @since empty
361: */
362: /*
363: private void update(SimpleNode node) {
364: MoveMethodVisitor mmv = new MoveMethodVisitor(typeSummary, oldMethod, typeSummary);
365: node.jjtAccept(mmv, null);
366: }
367: */
368:
369: /**
370: * Description of the Method
371: *
372: * @param mss Description of Parameter
373: * @exception RefactoringException Description of Exception
374: * @since empty
375: */
376: private void checkMessageSend(MessageSendSummary mss)
377: throws RefactoringException {
378: if ((mss.getPackageName() == null)
379: && ((mss.getObjectName() == null) || mss
380: .getObjectName().equals("this"))) {
381: MethodSummary method = MethodQuery.find(typeSummary, mss
382: .getMessageName());
383: if (method == null) {
384: throw new RefactoringException(
385: "Unable to find the method ("
386: + mss.getMessageName() + ") in "
387: + typeSummary.getName());
388: }
389: }
390: }
391:
392: }
|