import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.core.refactoring.participants.MoveRefactoring;
+/**
+ * This class composes the refactorings known as
+ * Extract Method and Move Method.
+ *
+ * Before extracting, it finds the possible targets for the move
+ * with the help of a PropertyExtractor (see {@link ExtractAndMoveMethodPrefixesExtractor}),
+ * that extracts both the candidates, in the form prefixes (see {@link Prefix}),
+ * and the non-candidates, called unfixes. They are collected into sets
+ * of prefixes (see {@link PrefixSet}).The set of prefixes that
+ * are not enclosing any unfixes is put in the set of safe prefixes.
+ *
+ * The changer then tries to analyze which of the safe prefixes
+ * that is the best candidate. The best candidate is used to find the
+ * target of the composed refactoring.
+ */
@SuppressWarnings("restriction")
public class ExtractAndMoveMethodChanger extends RefaktorChanger {
private ExtractMethodRefactoring makeExtractMethodRefactoring(Prefix prefix, ICompilationUnit cu) throws CoreException {
- // ExtractMethodRefactoring refactoring = new ExtractMethodRefactoring(cu, prefix.statementStartPosition(), prefix.statementLength());
ExtractMethodRefactoring refactoring = new ExtractMethodRefactoring(cu, extractor.getSelection().getOffset(), extractor.getSelection().getLength());
refactoring.setMethodName(getNewMethodName());
import org.eclipse.ltk.core.refactoring.PerformChangeOperation;
import org.eclipse.ltk.core.refactoring.RefactoringCore;
+/**
+ * A range of classes that is responsible for composing
+ * refactorings that are to be executed on a workspace.
+ */
public abstract class RefaktorChanger {
private boolean isExecuted = false;
Expression expression = statement.getExpression();
// TODO: support more expression types
if (expression instanceof MethodInvocation)
- return new Prefix(((MethodInvocation) expression).getExpression(), statement, getDocument());
+ return new Prefix(((MethodInvocation) expression).getExpression(), getDocument());
else
return null;
}
import no.uio.ifi.refaktor.utils.SmartTextSelection;
import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.Expression;
-import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.SimpleName;
+/**
+ * A property extractor that extracts both the union of expression prefixes
+ * (see {@link UnionOfLongestCommonPrefixesExtractor}), but also the unfixes
+ * that are not candidates for a move refactoring. It is responsible for
+ * calculating the safe targets of an Extract and Move Method refactoring
+ * on the base of this knowledge.
+ */
public class ExtractAndMoveMethodPrefixesExtractor extends UnionOfLongestCommonPrefixesExtractor {
private final PrefixSet unfixes = new PrefixSet();
Name name = (Name) lhs;
if (name.isSimpleName()) {
SimpleName simpleName = (SimpleName) name;
- ASTNode parent = node.getParent();
- assert parent instanceof ExpressionStatement;
- Prefix p = new Prefix(simpleName, (ExpressionStatement) parent, getDocument());
+ Prefix p = new Prefix(simpleName, getDocument());
RefaktorDebug.println("Unfix string: " + p.toString());
unfixes.add(p);
}
}
private PrefixSet createSafePrefixes() {
- return getPrefixSet().minusShadowedPrefixes(unfixes);
+ return getPrefixSet().minusEnclosedPrefixesFrom(unfixes);
}
@Override
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.Name;
-import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jface.text.IDocument;
+/**
+ * A class for representing a prefix of an Expression/Statement.
+ *
+ * It has an Expression member for the prefix.
+ */
public class Prefix {
private class SubExpressionsFinder extends ASTVisitor {
private final IDocument document;
private final String prefixString;
private int count;
- private final Statement statement;
private PrefixSet possiblePrefixes;
/**
* Represent a prefix on the base of an Expression.
*
* @param expression the Expression that is the base of the prefix.
- * @param document the IDocument that is the base of the expression.
+ * @param document the IDocument that is the base of the source code
+ * that contains the expression.
*/
- public Prefix(Expression expression, Statement statement, IDocument document) {
+ public Prefix(Expression expression, IDocument document) {
this.prefixExpression = expression;
- this.statement = statement;
this.document = document;
this.count = 1;
*/
public Prefix intersectWith(Prefix other) {
if (prefixIsEmpty(other))
- return new Prefix(null, null, document);
+ return new Prefix(null, document);
if (this.equals(other))
// TODO: return this?
- return new Prefix(prefixExpression, statement, document);
+ return new Prefix(prefixExpression, document);
// TODO: statement??
- return new Prefix(longestCommonExpressionWith(other), statement, document);
+ return new Prefix(longestCommonExpressionWith(other), document);
}
private boolean prefixIsEmpty(Prefix prefix) {
if (possiblePrefixes == null) {
possiblePrefixes = new PrefixSet();
for (Expression exp: getSubExpressions(prefixExpression))
- possiblePrefixes.add(new Prefix(exp, statement, document));
+ possiblePrefixes.add(new Prefix(exp, document));
}
return possiblePrefixes;
}
return subExpressions.get(0);
}
- public boolean shadows(Prefix other) {
+ /**
+ * Tests if this prefix encloses another prefix.
+ *
+ * Example: "a.b.c" encloses "a.b"
+ * @param other
+ * @return
+ */
+ public boolean encloses(Prefix other) {
return getSubPrefixes().contains(other);
}
import java.util.Map;
import java.util.Set;
-// TODO: move more functionality into this class
+/**
+ * A set for collecting prefixes (see {@link Prefix}}).
+ *
+ * It is based on a regular Set<Prefix>, but is used to
+ * add some more functionality to the basic set, like
+ * incrementing a counter in a prefix each time an equal
+ * prefix is registered with the set. In addition
+ * it can produce the set that is this set, minus the
+ * prefixes from another set that are enclosed by the
+ * prefixes in this set.
+ */
public class PrefixSet implements Iterable<Prefix> {
private final Set<Prefix> prefixes = new HashSet<Prefix>();
return prefixes.add(prefix);
}
- public void addAll(PrefixSet other) {
- prefixes.addAll(other.prefixes);
- }
-
- public void remove(Prefix prefix) {
+ private void remove(Prefix prefix) {
prefixes.remove(prefix);
}
return null;
}
- public void registerAllSubPrefixes(Prefix prefix) {
+ public void registerAllSubPrefixesOf(Prefix prefix) {
for (Prefix p: prefix.getSubPrefixes())
register(p);
}
return map;
}
- public PrefixSet shallowCopy() {
+ private PrefixSet shallowCopy() {
return new PrefixSet(this);
}
- public PrefixSet minusShadowedPrefixes(PrefixSet subtractSet) {
+ /**
+ * Creates a set of prefixes that are the prefixes of this set,
+ * minus the prefixes that are enclosing the prefixes of the
+ * other set.
+ *
+ * @param other The set of prefixes that are to be checked against this one.
+ * @return The set of prefixes that are not enclosing the ones in the subtract set.
+ */
+ public PrefixSet minusEnclosedPrefixesFrom(PrefixSet other) {
PrefixSet prefixSet = shallowCopy();
- for (Prefix subtrahend: subtractSet) {
+ for (Prefix subtrahend: other) {
for (Prefix prefix: this) {
- if (prefix.shadows(subtrahend))
+ if (prefix.encloses(subtrahend))
prefixSet.remove(prefix);
}
}
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
+/**
+ * A hierarchy of classes that are used
+ * to extract properties from source code.
+ */
public abstract class PropertyExtractor extends ASTVisitor {
private SmartTextSelection selection;
import org.eclipse.jdt.core.ICompilationUnit;
+/**
+ * This class extracts the union of the prefixes found among the expressions
+ * within the selection.
+ */
public class UnionOfLongestCommonPrefixesExtractor extends CommonPrefixExtractor {
private final PrefixSet prefixes = new PrefixSet();
}
protected void registerPrefix(Prefix prefix) {
- prefixes.registerAllSubPrefixes(prefix);
+ prefixes.registerAllSubPrefixesOf(prefix);
}
public PrefixSet getPrefixSet() {
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.TextSelection;
+/**
+ * A custom TextSelection that enforces the presence of
+ * a document to back the selection.
+ */
public class SmartTextSelection extends TextSelection implements ITextSelection {
public SmartTextSelection(IDocument document, int offset, int length) {