001: /**
002: *
003: */package core;
004:
005: import java.util.Iterator;
006: import java.util.List;
007:
008: import org.eclipse.jdt.core.dom.ASTVisitor;
009: import org.eclipse.jdt.core.dom.Assignment;
010: import org.eclipse.jdt.core.dom.CompilationUnit;
011: import org.eclipse.jdt.core.dom.Expression;
012: import org.eclipse.jdt.core.dom.ExpressionStatement;
013: import org.eclipse.jdt.core.dom.FieldAccess;
014: import org.eclipse.jdt.core.dom.FieldDeclaration;
015: import org.eclipse.jdt.core.dom.MethodDeclaration;
016: import org.eclipse.jdt.core.dom.ReturnStatement;
017: import org.eclipse.jdt.core.dom.SimpleName;
018: import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
019: import org.eclipse.jdt.core.dom.Statement;
020: import org.eclipse.jdt.core.dom.Type;
021: import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
022:
023: /**
024: * This class is responsible for remove a field
025: * declaration and is used by the environment entry
026: * refactoring.
027: *
028: * @author sh
029: */
030: public class RemoveFieldDeclaration extends AbstractAST {
031:
032: // the Info Object containing all necessary refactor info
033: private RefactorInfo info = null;
034:
035: /**
036: * This method removes a field declaration and the concerning
037: * getter and setter methods for an EnvEntry in the compilation
038: * unit.
039: *
040: * @param info the info object containing needed info for field creation
041: */
042: public void removeFieldDeclarations(RefactorInfo info) {
043: CompilationUnit u = parse(info.getUnit());
044: this .info = info;
045: new FieldRemover().process(u);
046:
047: // write changes
048: ManipulateHelper.saveDirectlyModifiedUnit(u);
049: }
050:
051: private class FieldRemover extends ASTVisitor {
052:
053: /**
054: * Looks for field declarations.
055: * For an occurence we check if the type and the name of
056: * the member variable fits the environment entry. If so
057: * the field declaration will be removed.
058: *
059: * @param node the node to visit
060: */
061: @Override
062: public boolean visit(FieldDeclaration node) {
063: // iterate over all variable declarations
064: List<VariableDeclarationFragment> fragments = node
065: .fragments();
066: for (Iterator<VariableDeclarationFragment> iterator = fragments
067: .iterator(); iterator.hasNext();) {
068: VariableDeclarationFragment name = (VariableDeclarationFragment) iterator
069: .next();
070: String varName = name.getName().toString();
071:
072: // if the right variable type and name was found
073: // remove the field
074: Type type = node.getType();
075: if (varName.equals(info.getNewVarName())
076: && type.toString().equals(info.getNewName())) {
077: node.delete();
078: }
079: }
080: return super .visit(node);
081: }
082:
083: /**
084: * Looks for method declarations.
085: * For an occurence we check if the methods return
086: * value and the set assignment fit the member
087: * variable. If so the method will be deleted.
088: */
089: @Override
090: public boolean visit(MethodDeclaration node) {
091: // we assume a setter and a getter method have
092: // just one statement in the method body
093: if (node.getBody().statements().size() != 1)
094: return super .visit(node);
095: Statement retStatement = (Statement) node.getBody()
096: .statements().get(0);
097:
098: // handle the setter method
099: MethodDeclaration methodToDelete = findSetterMethod(node,
100: retStatement);
101: if (methodToDelete != null) {
102: methodToDelete.delete();
103: }
104:
105: // handle the getter method
106: methodToDelete = findGetterMethod(node, retStatement);
107: if (methodToDelete != null) {
108: methodToDelete.delete();
109: }
110: return super .visit(node);
111: }
112:
113: /**
114: * Handle the Setter Method removing.
115: * This algorithm investigates the method body and searches for
116: * the return statement. Then it checks if the method parameter
117: * is used by the set assignment. If so the field to delete
118: * has been found, we know that we have right method to delete.
119: *
120: * @param node the method declaration to check
121: * @param statement the statement used for the check
122: * @return node the method declaration to delete
123: */
124: private MethodDeclaration findSetterMethod(
125: MethodDeclaration node, Statement statement) {
126: if (statement instanceof ExpressionStatement == false)
127: return null;
128:
129: Expression expr = ((ExpressionStatement) statement)
130: .getExpression();
131:
132: // step over if it is not an assignment
133: if (expr instanceof Assignment == false)
134: return null;
135: Assignment assign = (Assignment) expr;
136:
137: // investigate the assignment
138: Expression lhs = assign.getLeftHandSide();
139:
140: // step over if the left hand site of the expression is not a field access
141: if (lhs instanceof FieldAccess == false)
142: return null;
143:
144: // investigate the field access, continue if
145: // the field to refactor isn't used
146: FieldAccess lhsf = (FieldAccess) lhs;
147: if (!lhsf.getName().toString().equals(info.getNewVarName()))
148: return null;
149:
150: // get the the right hand site of the expression to know which
151: // variable declaration we have to adapt in a setter method
152: Expression rhs = assign.getRightHandSide();
153: String bodyVarName = ((SimpleName) rhs)
154: .getFullyQualifiedName().toString();
155:
156: // iterate over all method variable declarations
157: // to find the corrent parameter
158: List<SingleVariableDeclaration> parameters = node
159: .parameters();
160: for (Iterator<SingleVariableDeclaration> varIter = parameters
161: .iterator(); varIter.hasNext();) {
162: SingleVariableDeclaration varDecl = (SingleVariableDeclaration) varIter
163: .next();
164: String varDeclName = varDecl.getName()
165: .getFullyQualifiedName().toString();
166:
167: // check if it is the correct parameter
168: if (!varDeclName.equals(bodyVarName))
169: continue;
170:
171: // assume we found the right setter method
172: return node;
173: }
174: return null;
175: }
176:
177: /**
178: * Handle the Getter Method removing.
179: * This algorithm investigates the method body and searches for
180: * the assgin statement. If the assign statement uses the member
181: * variable to delete we assume that the getter method to delete
182: * has been found.
183: *
184: * @param node the method declaration to check
185: * @param statement the statement used for the check
186: * @return node the method declaration to delete
187: */
188: private MethodDeclaration findGetterMethod(
189: MethodDeclaration node, Statement statement) {
190: if (statement instanceof ReturnStatement == false)
191: return null;
192:
193: ReturnStatement retStatement = (ReturnStatement) statement;
194: Expression expr = retStatement.getExpression();
195: if (expr == null || expr instanceof FieldAccess == false)
196: return null;
197: String name = ((FieldAccess) expr).getName().toString();
198: if (name.equals(info.getNewVarName()))
199: return node;
200: return null;
201: }
202:
203: /**
204: * Starts the process.
205: *
206: * @param unit the AST root node. Bindings have to been resolved.
207: */
208: public void process(CompilationUnit unit) {
209: unit.accept(this);
210: }
211: }
212: }
|