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.parser.ChildrenVisitor;
014: import net.sourceforge.jrefactory.ast.Node;
015: import net.sourceforge.jrefactory.ast.ASTArguments;
016: import net.sourceforge.jrefactory.ast.ASTArgumentList;
017: import net.sourceforge.jrefactory.ast.ASTConstructorDeclaration;
018: import net.sourceforge.jrefactory.ast.ASTMethodDeclarator;
019: import net.sourceforge.jrefactory.ast.ASTFormalParameter;
020: import net.sourceforge.jrefactory.ast.ASTFormalParameters;
021: import net.sourceforge.jrefactory.ast.ASTMethodDeclaration;
022: import net.sourceforge.jrefactory.ast.ASTName;
023: import net.sourceforge.jrefactory.ast.ASTPackageDeclaration;
024: import net.sourceforge.jrefactory.ast.ASTPrimaryExpression;
025: import net.sourceforge.jrefactory.ast.ASTPrimaryPrefix;
026: import net.sourceforge.jrefactory.ast.ASTPrimarySuffix;
027: import net.sourceforge.jrefactory.ast.ASTUnmodifiedClassDeclaration;
028: import net.sourceforge.jrefactory.ast.ASTUnmodifiedInterfaceDeclaration;
029: import net.sourceforge.jrefactory.ast.ASTVariableDeclarator;
030: import net.sourceforge.jrefactory.ast.ASTVariableDeclaratorId;
031: import java.util.Iterator;
032: import org.acm.seguin.awt.Question;
033: import org.acm.seguin.summary.TraversalVisitor;
034: import org.acm.seguin.summary.Summary;
035: import org.acm.seguin.summary.MethodSummary;
036: import org.acm.seguin.summary.PackageSummary;
037: import org.acm.seguin.summary.FileSummary;
038: import org.acm.seguin.summary.TypeSummary;
039: import org.acm.seguin.summary.TypeDeclSummary;
040: import org.acm.seguin.summary.VariableSummary;
041: import org.acm.seguin.refactor.ComplexTransform;
042: import org.acm.seguin.summary.query.Ancestor;
043: import org.acm.seguin.summary.query.GetTypeSummary;
044: import org.acm.seguin.summary.query.ImportsType;
045: import org.acm.seguin.summary.query.LookupVariable;
046:
047: /**
048: * Removes the method from all subclasses of a particular class.
049: *
050: *@author Chris Seguin
051: */
052: public class RenameMethodVisitor extends ChildrenVisitor {
053: /**
054: * Visit a package declaration
055: *
056: *@param node the class body node
057: *@param data the data for the visitor
058: *@return the field if it is found
059: */
060: public Object visit(ASTPackageDeclaration node, Object data) {
061: RenameMethodData rfd = (RenameMethodData) data;
062:
063: ASTName name = (ASTName) node.jjtGetFirstChild();
064: PackageSummary packageSummary = PackageSummary
065: .getPackageSummary(name.getName());
066: rfd.setCurrentSummary(packageSummary);
067:
068: return super .visit(node, data);
069: }
070:
071: /**
072: * Visit a class declaration
073: *
074: *@param node the class body node
075: *@param data the data for the visitor
076: *@return the field if it is found
077: */
078: public Object visit(ASTUnmodifiedClassDeclaration node, Object data) {
079: RenameMethodData rfd = (RenameMethodData) data;
080: Summary current = rfd.getCurrentSummary();
081:
082: if (current == null) {
083: rfd.setCurrentSummary(GetTypeSummary.query("", node
084: .getName()));
085: } else if (current instanceof PackageSummary) {
086: rfd.setCurrentSummary(GetTypeSummary.query(
087: (PackageSummary) current, node.getName()));
088: } else if (current instanceof TypeSummary) {
089: rfd.setCurrentSummary(GetTypeSummary.query(
090: (TypeSummary) current, node.getName()));
091: } else if (current instanceof MethodSummary) {
092: rfd.setCurrentSummary(GetTypeSummary.query(
093: (MethodSummary) current, node.getName()));
094: }
095:
096: Object result = super .visit(node, data);
097:
098: rfd.setCurrentSummary(current);
099: return result;
100: }
101:
102: /**
103: * Visit a class declaration
104: *
105: *@param node the class body node
106: *@param data the data for the visitor
107: *@return the field if it is found
108: */
109: public Object visit(ASTUnmodifiedInterfaceDeclaration node,
110: Object data) {
111: RenameMethodData rfd = (RenameMethodData) data;
112: Summary current = rfd.getCurrentSummary();
113:
114: if (current == null) {
115: rfd.setCurrentSummary(GetTypeSummary.query("", node
116: .getName()));
117: } else if (current instanceof PackageSummary) {
118: rfd.setCurrentSummary(GetTypeSummary.query(
119: (PackageSummary) current, node.getName()));
120: } else if (current instanceof TypeSummary) {
121: rfd.setCurrentSummary(GetTypeSummary.query(
122: (TypeSummary) current, node.getName()));
123: } else if (current instanceof MethodSummary) {
124: rfd.setCurrentSummary(GetTypeSummary.query(
125: (MethodSummary) current, node.getName()));
126: }
127:
128: Object result = super .visit(node, data);
129:
130: rfd.setCurrentSummary(current);
131: return result;
132: }
133:
134: /**
135: * Visit a field declaration
136: *
137: *@param node the class body node
138: *@param data the data for the visitor
139: *@return the field if it is found
140: */
141: public Object visit(ASTMethodDeclaration node, Object data) {
142: RenameMethodData rfd = (RenameMethodData) data;
143:
144: if (rfd.getCurrentSummary() == rfd.getTypeSummary()) {
145: int childNo = node.skipAnnotations();
146: for (int ndx = childNo + 1; ndx < node.jjtGetNumChildren(); ndx++) {
147: Node child = node.jjtGetChild(ndx);
148: if (child instanceof ASTMethodDeclarator) {
149: ASTMethodDeclarator method = (ASTMethodDeclarator) child;
150: if (method.getName().equals(rfd.getOldName())) {
151: // FIXME check parameters
152: ASTFormalParameters params = (ASTFormalParameters) method
153: .jjtGetFirstChild();
154: int oldCount = rfd.getOldMethod()
155: .getParameterCount();
156: int paramCount = params.jjtGetNumChildren();
157: System.out
158: .println("visit(ASTMethodDeclaration): oldCount="
159: + oldCount
160: + ", paramCount="
161: + paramCount);
162: if (oldCount == paramCount) {
163: method.setName(rfd.getNewName());
164: }
165: }
166: }
167: }
168: }
169:
170: return super .visit(node, data);
171: }
172:
173: /**
174: * Visit a primary expression
175: *
176: *@param node the class body node
177: *@param data the data for the visitor
178: *@return the field if it is found
179: */
180: public Object visit(ASTPrimaryExpression node, Object data) {
181: RenameMethodData rfd = (RenameMethodData) data;
182: ASTPrimaryPrefix prefix = (ASTPrimaryPrefix) node
183: .jjtGetFirstChild();
184: if ("this".equals(prefix.getName())) {
185: processThisExpression(rfd, node, prefix);
186: } else if ((prefix.jjtGetNumChildren() >= 1)
187: && (prefix.jjtGetFirstChild() instanceof ASTName)) {
188: processNameExpression(rfd, node, prefix);
189: }
190:
191: return super .visit(node, data);
192: }
193:
194: /**
195: * Description of the Method
196: *
197: *@param name Description of Parameter
198: *@param oldName Description of Parameter
199: *@param current Description of Parameter
200: *@param hasSuffixArguments Description of Parameter
201: *@param changingType Description of Parameter
202: *@return Description of the Returned Value
203: */
204: private int shouldChangePart(ASTName name, String oldName,
205: Summary current, boolean hasSuffixArguments,
206: TypeSummary changingType) {
207: int last = name.getNameSize() - 1;
208: if (hasSuffixArguments) {
209: last--;
210: }
211:
212: int forwardTo = -1;
213: for (int ndx = last; ndx >= 0; ndx--) {
214: if (name.getNamePart(ndx).equals(oldName)) {
215: forwardTo = ndx;
216: }
217: }
218:
219: if (forwardTo == -1) {
220: return -1;
221: }
222:
223: VariableSummary varSummary = LookupVariable.query(
224: (MethodSummary) current, name.getNamePart(0));
225: if (varSummary == null) {
226: return -1;
227: }
228: TypeSummary currentType = GetTypeSummary.query(varSummary
229: .getTypeDecl());
230:
231: for (int ndx = 1; ndx < forwardTo; ndx++) {
232: varSummary = LookupVariable.queryFieldSummary(currentType,
233: name.getNamePart(ndx));
234: if (varSummary == null) {
235: return -1;
236: }
237: currentType = GetTypeSummary
238: .query(varSummary.getTypeDecl());
239: }
240:
241: if (currentType == changingType) {
242: return forwardTo;
243: }
244:
245: return -1;
246: }
247:
248: /**
249: * Description of the Method
250: *
251: *@param rfd Description of Parameter
252: *@param node Description of Parameter
253: *@param prefix Description of Parameter
254: */
255: private void processThisExpression(RenameMethodData rfd,
256: ASTPrimaryExpression node, ASTPrimaryPrefix prefix) {
257: if (rfd.isAllowedToChangeThis()
258: && (node.jjtGetNumChildren() >= 2)) {
259: ASTPrimarySuffix suffix = (ASTPrimarySuffix) node
260: .jjtGetChild(1);
261: if (rfd.getOldName().equals(suffix.getName())) {
262: boolean change = true;
263:
264: if (node.jjtGetNumChildren() >= 3) {
265: ASTPrimarySuffix next = (ASTPrimarySuffix) node
266: .jjtGetChild(2);
267: if ((next.jjtGetFirstChild() != null)
268: && (next.jjtGetFirstChild() instanceof ASTArguments)) {
269: change = false;
270: }
271: }
272:
273: if (change) {
274: suffix.setName(rfd.getNewName());
275: }
276: }
277: }
278: }
279:
280: /**
281: * Description of the Method
282: *
283: *@param rfd Description of Parameter
284: *@param node Description of Parameter
285: *@param prefix Description of Parameter
286: */
287: private void processNameExpression(RenameMethodData rfd,
288: ASTPrimaryExpression node, ASTPrimaryPrefix prefix) {
289: ASTName name = (ASTName) prefix.jjtGetFirstChild();
290: System.out.println("processNameExpression() " + name);
291:
292: //MethodSummary oldMethod = rfd.getOldMethod();
293: if (!rfd.isThisRequired()) {
294: ASTArguments arguments = null;
295:
296: if (node.jjtGetNumChildren() >= 2) {
297: ASTPrimarySuffix next = (ASTPrimarySuffix) node
298: .jjtGetChild(1);
299: if ((next.jjtGetFirstChild() != null)
300: && (next.jjtGetFirstChild() instanceof ASTArguments)) {
301: arguments = (ASTArguments) next.jjtGetFirstChild();
302: }
303: }
304:
305: System.out.println("arguments=" + arguments);
306: if (arguments != null) {
307: System.out.println("name.getNameSize()="
308: + name.getNameSize()
309: + ", rfd.isAllowedToChangeFirst()="
310: + rfd.isAllowedToChangeFirst());
311: if ((name.getNameSize() == 1)
312: && rfd.isAllowedToChangeFirst()
313: && (name.getNamePart(0)
314: .equals(rfd.getOldName()))) {
315: if (checkParameters(rfd, arguments)) {
316: name.setNamePart(0, rfd.getNewName());
317: if (rfd.isMustInsertThis()) {
318: name.insertNamePart(0, "this");
319: }
320: System.out
321: .println("[1] old MethodSummary.name="
322: + rfd.getOldMethod().getName()
323: + ", name.getName()="
324: + name.getName());
325: //rfd.getOldMethod().setName(name.getName());
326: //System.out.println("[1] new MethodSummary.name="+rfd.getOldMethod().getName());
327: }
328: } else if (name.getNamePart(name.getNameSize() - 1)
329: .equals(rfd.getOldName())) {
330: if (checkParameters(rfd, arguments)) {
331: int last = name.getNameSize() - 1;
332: if (name.getNamePart(last).equals(
333: rfd.getOldName())) {
334: name.setNamePart(last, rfd.getNewName());
335: }
336: System.out
337: .println("[2] old MethodSummary.name="
338: + rfd.getOldMethod().getName()
339: + ", name.getName()="
340: + name.getName());
341: //rfd.getOldMethod().setName(name.getName());
342: //System.out.println("[2] new MethodSummary.name="+rfd.getOldMethod().getName());
343: }
344: }
345: }
346: }
347:
348: if (rfd.getOldMethod().isStatic()) {
349: String nameString = name.getName();
350: System.out.println("oldMethod is static nameString="
351: + nameString + ", rfd.getFullName()="
352: + rfd.getFullName() + ", rfd.getImportedName()="
353: + rfd.getImportedName());
354: if (nameString.startsWith(rfd.getFullName())) {
355: replaceNamePart(name, rfd.getFullName(), rfd
356: .getNewName());
357: System.out.println("[3] old MethodSummary.name="
358: + rfd.getOldMethod().getName());
359: //rfd.getOldMethod().setName(rfd.getFullName());
360: //System.out.println("[3] new MethodSummary.name="+rfd.getOldMethod().getName());
361: } else if (nameString.startsWith(rfd.getImportedName())
362: && ImportsType.query(rfd.getCurrentSummary(), rfd
363: .getTypeSummary())) {
364: replaceNamePart(name, rfd.getImportedName(), rfd
365: .getNewName());
366: System.out.println("[4] old MethodSummary.name="
367: + rfd.getOldMethod().getName());
368: //rfd.getOldMethod().setName(rfd.getImportedName());
369: //System.out.println("[4] new MethodSummary.name="+rfd.getOldMethod().getName());
370: }
371: }
372: }
373:
374: private boolean checkParameters(RenameMethodData rfd,
375: ASTArguments arguments) {
376: int oldCount = rfd.getOldMethod().getParameterCount();
377: if (arguments.jjtGetNumChildren() == 0) {
378: return oldCount == 0;
379: }
380: ASTArgumentList argList = (ASTArgumentList) arguments
381: .jjtGetFirstChild();
382: int argCount = argList.jjtGetNumChildren();
383: System.out.println("checkParameters(): oldCount=" + oldCount
384: + ", argCount=" + argCount);
385: if (oldCount != argCount) {
386: return false;
387: }
388: // FIXME check the parameter types
389: return true;
390: }
391:
392: /**
393: * Description of the Method
394: *
395: *@param name Description of Parameter
396: *@param form Description of Parameter
397: *@param newName Description of Parameter
398: */
399: private void replaceNamePart(ASTName name, String form,
400: String newName) {
401: StringTokenizer tok = new StringTokenizer(form, ".");
402: int count = -1;
403: String finalPart = null;
404: while (tok.hasMoreTokens()) {
405: finalPart = tok.nextToken();
406: count++;
407: }
408:
409: if (name.getNamePart(count).equals(finalPart)) {
410: name.setNamePart(count, newName);
411: }
412: }
413: }
|