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.field;
010:
011: import java.io.File;
012: import net.sourceforge.jrefactory.ast.ASTFieldDeclaration;
013: import net.sourceforge.jrefactory.ast.ASTName;
014: import net.sourceforge.jrefactory.ast.ASTPrimitiveType;
015: import net.sourceforge.jrefactory.ast.ASTType;
016: import net.sourceforge.jrefactory.ast.SimpleNode;
017: import net.sourceforge.jrefactory.ast.ModifierHolder;
018: import org.acm.seguin.refactor.AddImportTransform;
019: import org.acm.seguin.refactor.ComplexTransform;
020: import org.acm.seguin.refactor.Refactoring;
021: import org.acm.seguin.refactor.RefactoringException;
022: import org.acm.seguin.summary.FileSummary;
023: import org.acm.seguin.summary.PackageSummary;
024: import org.acm.seguin.summary.Summary;
025: import org.acm.seguin.summary.TypeDeclSummary;
026: import org.acm.seguin.summary.TypeSummary;
027: import org.acm.seguin.summary.query.FieldQuery;
028: import org.acm.seguin.summary.query.GetTypeSummary;
029:
030: /**
031: * Performs the pullup field refactoring
032: *
033: *@author Chris Seguin
034: */
035: public class PushUpFieldRefactoring extends FieldRefactoring {
036: private TypeSummary parentType;
037:
038: /**
039: * Constructor for the PushUpFieldRefactoring object
040: */
041: protected PushUpFieldRefactoring() {
042: }
043:
044: /**
045: * Gets the description of the refactoring
046: *
047: *@return the description
048: */
049: public String getDescription() {
050: return "Moves a field " + field + " into parent class named "
051: + parentType.getName();
052: }
053:
054: /**
055: * Gets the ID attribute of the PushUpFieldRefactoring object
056: *
057: *@return The ID value
058: */
059: public int getID() {
060: return PUSH_UP_FIELD;
061: }
062:
063: /**
064: * Preconditions that must be true for the refactoring to work
065: *
066: *@exception RefactoringException a problem with performing this
067: * refactoring
068: */
069: protected void preconditions() throws RefactoringException {
070: if (field == null) {
071: throw new RefactoringException("No field specified");
072: }
073:
074: if (typeSummary == null) {
075: throw new RefactoringException("No type specified");
076: }
077:
078: if (FieldQuery.query(typeSummary, field, FieldQuery.PRIVATE) == null) {
079: throw new RefactoringException("Field named " + field
080: + " does not exist in " + typeSummary.getName());
081: }
082:
083: TypeDeclSummary parentDecl = typeSummary.getParentClass();
084: parentType = GetTypeSummary.query(parentDecl);
085:
086: if (parentType == null) {
087: throw new RefactoringException(
088: "Can't push up a field into source code that you don't have");
089: }
090:
091: checkDestinationFile(parentType,
092: "Can't push up a field into source code that you don't have");
093:
094: if (FieldQuery.query(parentType, field, FieldQuery.PRIVATE) != null) {
095: throw new RefactoringException("Field named " + field
096: + " already exists in parent class");
097: }
098:
099: if (FieldQuery.queryAncestors(typeSummary, field,
100: FieldQuery.PRIVATE) != null) {
101: throw new RefactoringException("Field named " + field
102: + " already exists in an ancestor class");
103: }
104:
105: if (((FileSummary) parentType.getParent()).getFile() == null) {
106: throw new RefactoringException(
107: "Can't push up a field into source code that you don't have");
108: }
109:
110: if (((FileSummary) typeSummary.getParent()).getFile() == null) {
111: throw new RefactoringException(
112: "Can't push up a field from source code that you don't have");
113: }
114: }
115:
116: /**
117: * Actually update the files
118: */
119: protected void transform() {
120: FileSummary fileSummary = (FileSummary) getFileSummary(typeSummary);
121: RemoveFieldTransform rft = new RemoveFieldTransform(field);
122: ComplexTransform transform = getComplexTransform();
123: transform.add(rft);
124: transform.apply(fileSummary.getFile(), fileSummary.getFile());
125:
126: // Update the field declaration to have the proper permissions
127: SimpleNode fieldDecl = rft.getFieldDeclaration();
128: if (fieldDecl == null) {
129: return;
130: }
131:
132: ASTFieldDeclaration decl = (ASTFieldDeclaration) fieldDecl
133: .jjtGetFirstChild();
134: //ModifierHolder holder = decl.getModifiers();
135: if (!decl.isPublic()) {
136: decl.setPrivate(false);
137: decl.setProtected(true);
138: }
139:
140: AddFieldTransform aft = new AddFieldTransform(fieldDecl);
141: transform.clear();
142: transform.add(aft);
143: Object fieldType = getFieldType(fieldDecl, fileSummary);
144: if (fieldType == null) {
145: // Do nothing
146: } else if ((fieldType instanceof TypeSummary)
147: && !isInJavaLang((TypeSummary) fieldType)) {
148: transform.add(new AddImportTransform(
149: (TypeSummary) fieldType));
150: } else if ((fieldType instanceof ASTName)
151: && !isInJavaLang((ASTName) fieldType)) {
152: transform.add(new AddImportTransform((ASTName) fieldType));
153: }
154: FileSummary parentFileSummary = (FileSummary) parentType
155: .getParent();
156: transform.apply(parentFileSummary.getFile(), parentFileSummary
157: .getFile());
158:
159: // Remove the field from all child classes
160: (new RemoveFieldFromSubclassVisitor(parentType, typeSummary
161: .getField(field), typeSummary, transform)).visit(null);
162: }
163: }
|