001: package org.acm.seguin.refactor.method;
002:
003: import java.util.Iterator;
004: import org.acm.seguin.summary.*;
005: import org.acm.seguin.summary.query.FieldQuery;
006: import net.sourceforge.jrefactory.ast.*;
007: import net.sourceforge.jrefactory.parser.ChildrenVisitor;
008: import net.sourceforge.jrefactory.parser.JavaParserTreeConstants;
009:
010: /**
011: * Visitor that prepares a method for being incorporated into another class.
012: *
013: *@author Chris Seguin
014: */
015: public class MoveMethodVisitor extends ChildrenVisitor {
016: private MethodSummary methodSummary;
017: private TypeSummary typeSummary;
018: private Summary destination;
019:
020: /**
021: * Constructor for the MoveMethodVisitor object
022: *
023: *@param initType Description of Parameter
024: *@param initMethod Description of Parameter
025: *@param initDest Description of Parameter
026: */
027: public MoveMethodVisitor(TypeSummary initType,
028: MethodSummary initMethod, Summary initDest) {
029: typeSummary = initType;
030: methodSummary = initMethod;
031: destination = initDest;
032: }
033:
034: /**
035: * Don't go into any class definitions
036: *
037: *@param node Description of Parameter
038: *@param data Description of Parameter
039: *@return Description of the Returned Value
040: */
041: public Object visit(ASTUnmodifiedClassDeclaration node, Object data) {
042: return data;
043: }
044:
045: /**
046: * Don't go into any interface definitions
047: *
048: *@param node Description of Parameter
049: *@param data Description of Parameter
050: *@return Description of the Returned Value
051: */
052: public Object visit(ASTUnmodifiedInterfaceDeclaration node,
053: Object data) {
054: return data;
055: }
056:
057: /**
058: * To visit a node
059: *
060: *@param node The node we are visiting
061: *@param data The rename type data
062: *@return The rename type data
063: */
064: public Object visit(ASTFormalParameters node, Object data) {
065: if (destination instanceof ParameterSummary) {
066: String name = destination.getName();
067:
068: int last = node.jjtGetNumChildren();
069: for (int ndx = 0; ndx < last; ndx++) {
070: ASTFormalParameter param = (ASTFormalParameter) node
071: .jjtGetChild(ndx);
072: int childNo = param.skipAnnotations();
073: ASTVariableDeclaratorId decl = (ASTVariableDeclaratorId) param
074: .jjtGetChild(childNo + 1);
075: if (decl.getName().equals(name)) {
076: node.jjtDeleteChild(ndx);
077: ndx--;
078: last--;
079: }
080: }
081:
082: if (ObjectReference.isReferenced(methodSummary)) {
083: ASTFormalParameter newParam = new ASTFormalParameter(
084: JavaParserTreeConstants.JJTFORMALPARAMETER);
085: ASTType type = new ASTType(
086: JavaParserTreeConstants.JJTTYPE);
087: newParam.jjtAddChild(type, 0);
088: ASTClassOrInterfaceType nameNode = new ASTClassOrInterfaceType(
089: 0);
090: //nameNode.fromString(typeDecl.getLongName());
091:
092: //ASTName nameNode = new ASTName();
093: String typeName = typeSummary.getName();
094: nameNode.addNamePart(typeName);
095: type.jjtAddChild(nameNode, 0);
096: ASTVariableDeclaratorId id = new ASTVariableDeclaratorId(
097: JavaParserTreeConstants.JJTVARIABLEDECLARATORID);
098: id.setName(typeName.substring(0, 1).toLowerCase()
099: + typeName.substring(1));
100: newParam.jjtAddChild(id, 1);
101:
102: last = node.jjtGetNumChildren();
103: node.jjtAddChild(newParam, last);
104: }
105: }
106:
107: return data;
108: }
109:
110: /**
111: * Description of the Method
112: *
113: *@param node Description of Parameter
114: *@param data Description of Parameter
115: *@return Description of the Returned Value
116: */
117: public Object visit(ASTExpression node, Object data) {
118: if (node.jjtGetNumChildren() > 1) {
119: Object result = super .visit(node, Boolean.TRUE);
120: if (result != null) {
121: ASTArguments args = (ASTArguments) result;
122: ASTArgumentList list = new ASTArgumentList(
123: JavaParserTreeConstants.JJTARGUMENTLIST);
124: args.jjtAddChild(list, 0);
125: list.jjtAddChild(node.jjtGetChild(2), 0);
126: node.jjtDeleteChild(2);
127: node.jjtDeleteChild(1);
128: }
129:
130: return null;
131: } else {
132: return super .visit(node, Boolean.FALSE);
133: }
134: }
135:
136: /**
137: * Visit method for primary expressions
138: *
139: *@param node the node we are visiting
140: *@param data Description of Parameter
141: *@return Description of the Returned Value
142: */
143: public Object visit(ASTPrimaryExpression node, Object data) {
144: Object result = null;
145: if (destination instanceof ParameterSummary) {
146: String parameterName = destination.getName();
147:
148: ASTPrimaryPrefix prefix = (ASTPrimaryPrefix) node
149: .jjtGetFirstChild();
150: if ("this".equals(prefix.getName())) {
151: ASTName nameNode = new ASTName();
152: nameNode.addNamePart(getReplacementVariableName());
153: prefix.jjtAddChild(nameNode, 0);
154: } else if (isMethod(node, prefix)) {
155: updatePrimaryPrefix(prefix, parameterName);
156: } else if (isVariable(node, prefix)) {
157: ASTName nameNode = (ASTName) prefix.jjtGetFirstChild();
158: if (!isLocalVariable(nameNode.getNamePart(0))) {
159: Boolean value = (Boolean) data;
160: result = updatePrivateField(node, prefix, nameNode,
161: parameterName, value.booleanValue());
162: }
163: }
164: }
165:
166: super .visit(node, data);
167:
168: return result;
169: }
170:
171: /**
172: * Determine if we have a method
173: *
174: *@param node Description of Parameter
175: *@param prefix Description of Parameter
176: *@return The Method value
177: */
178: private boolean isMethod(ASTPrimaryExpression node,
179: ASTPrimaryPrefix prefix) {
180: return (node.jjtGetNumChildren() > 1)
181: && (node.jjtGetChild(1).jjtGetFirstChild() instanceof ASTArguments)
182: && (prefix.jjtGetFirstChild() instanceof ASTName);
183: }
184:
185: /**
186: * Determine if we have a field access
187: *
188: *@param node Description of Parameter
189: *@param prefix Description of Parameter
190: *@return The Variable value
191: */
192: private boolean isVariable(ASTPrimaryExpression node,
193: ASTPrimaryPrefix prefix) {
194: return (node.jjtGetNumChildren() == 1)
195: && (prefix.jjtGetFirstChild() instanceof ASTName);
196: }
197:
198: /**
199: * Checks if the value is a local variable
200: *
201: *@param name the name of the variable
202: *@return true if the name is a local variable
203: */
204: private boolean isLocalVariable(String name) {
205: Iterator iter = methodSummary.getDependencies();
206: if (iter != null) {
207: while (iter.hasNext()) {
208: Summary next = (Summary) iter.next();
209: if (next instanceof LocalVariableSummary) {
210: LocalVariableSummary lvs = (LocalVariableSummary) next;
211: if (lvs.getName().equals(name)) {
212: return true;
213: }
214: }
215: }
216: }
217: return false;
218: }
219:
220: /**
221: * Gets the name of the getter for the field
222: *
223: *@param summary the field summary
224: *@return the getter
225: */
226: private String getFieldGetter(FieldSummary summary) {
227: String typeName = summary.getType();
228: String prefix = "get";
229: if (typeName.equalsIgnoreCase("boolean")) {
230: prefix = "is";
231: }
232:
233: String name = summary.getName();
234:
235: return prefix + name.substring(0, 1).toUpperCase()
236: + name.substring(1);
237: }
238:
239: /**
240: * Gets the name of the setter for the field
241: *
242: *@param summary the field summary
243: *@return the setter
244: */
245: private String getFieldSetter(FieldSummary summary) {
246: String prefix = "set";
247: String name = summary.getName();
248: return prefix + name.substring(0, 1).toUpperCase()
249: + name.substring(1);
250: }
251:
252: /**
253: * Update the primary prefix
254: *
255: *@param prefix Description of Parameter
256: *@param parameterName Description of Parameter
257: */
258: private void updatePrimaryPrefix(ASTPrimaryPrefix prefix,
259: String parameterName) {
260: ASTName nameNode = (ASTName) prefix.jjtGetFirstChild();
261:
262: if (nameNode.getNameSize() == 1) {
263: updateLocalReferences(prefix, nameNode);
264: } else if ((nameNode.getNameSize() == 2)
265: && (nameNode.getNamePart(0).equals(parameterName))) {
266: updateParameterReferences(prefix, nameNode);
267: }
268: }
269:
270: /**
271: * Updates the local references
272: *
273: *@param prefix Description of Parameter
274: *@param nameNode Description of Parameter
275: */
276: private void updateLocalReferences(ASTPrimaryPrefix prefix,
277: ASTName nameNode) {
278: ASTName newName = new ASTName();
279: newName.addNamePart(getReplacementVariableName());
280: newName.addNamePart(nameNode.getNamePart(0));
281: prefix.jjtAddChild(newName, 0);
282: }
283:
284: /**
285: * Gets the variable name that is replacing "this" in the method
286: *
287: *@return the name of the variable
288: */
289: private String getReplacementVariableName() {
290: String typeName = typeSummary.getName();
291: return typeName.substring(0, 1).toLowerCase()
292: + typeName.substring(1);
293: }
294:
295: /**
296: * Updates references to the parameter
297: *
298: *@param prefix Description of Parameter
299: *@param nameNode Description of Parameter
300: */
301: private void updateParameterReferences(ASTPrimaryPrefix prefix,
302: ASTName nameNode) {
303: ASTName newName = new ASTName();
304: newName.addNamePart(nameNode.getNamePart(1));
305: prefix.jjtAddChild(newName, 0);
306: }
307:
308: /**
309: * Updates a private field
310: *
311: *@param primary Description of Parameter
312: *@param prefix Description of Parameter
313: *@param nameNode Description of Parameter
314: *@param parameterName Description of Parameter
315: *@param isSetter Description of Parameter
316: *@return Description of the Returned Value
317: */
318: private Object updatePrivateField(ASTPrimaryExpression primary,
319: ASTPrimaryPrefix prefix, ASTName nameNode,
320: String parameterName, boolean isSetter) {
321: if (nameNode.getNameSize() == 1) {
322: String name = nameNode.getNamePart(0);
323: FieldSummary field = FieldQuery.find(typeSummary, name);
324: if (field.isPrivate()) {
325: ASTName newName = new ASTName();
326: newName.addNamePart(getReplacementVariableName());
327: newName.addNamePart(isSetter ? getFieldSetter(field)
328: : getFieldGetter(field));
329: prefix.jjtAddChild(newName, 0);
330:
331: ASTPrimarySuffix suffix = new ASTPrimarySuffix(
332: JavaParserTreeConstants.JJTPRIMARYSUFFIX);
333: ASTArguments args = new ASTArguments(
334: JavaParserTreeConstants.JJTARGUMENTS);
335: suffix.jjtAddChild(args, 0);
336: primary.jjtInsertChild(suffix, 1);
337:
338: return args;
339: }
340: }
341:
342: updatePrimaryPrefix(prefix, parameterName);
343:
344: return null;
345: }
346: }
|