blob: ba11d51630598575650b43471c2c7ef3af98798b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.dltk.internal.javascript.corext.refactoring.code;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.manipulation.RefactoringChecks;
import org.eclipse.dltk.core.manipulation.SourceModuleChange;
import org.eclipse.dltk.internal.corext.refactoring.ScriptRefactoringDescriptor;
import org.eclipse.dltk.internal.corext.refactoring.util.ResourceUtil;
import org.eclipse.dltk.internal.javascript.core.manipulation.JavascriptManipulationPlugin;
import org.eclipse.dltk.internal.javascript.core.manipulation.Messages;
import org.eclipse.dltk.internal.javascript.corext.refactoring.Checks;
import org.eclipse.dltk.internal.javascript.corext.refactoring.RefactoringCoreMessages;
import org.eclipse.dltk.javascript.core.dom.BlockStatement;
import org.eclipse.dltk.javascript.core.dom.DomFactory;
import org.eclipse.dltk.javascript.core.dom.DomPackage;
import org.eclipse.dltk.javascript.core.dom.Expression;
import org.eclipse.dltk.javascript.core.dom.ExpressionStatement;
import org.eclipse.dltk.javascript.core.dom.Identifier;
import org.eclipse.dltk.javascript.core.dom.Node;
import org.eclipse.dltk.javascript.core.dom.Source;
import org.eclipse.dltk.javascript.core.dom.Statement;
import org.eclipse.dltk.javascript.core.dom.VariableDeclaration;
import org.eclipse.dltk.javascript.core.dom.VariableReference;
import org.eclipse.dltk.javascript.core.dom.VariableStatement;
import org.eclipse.dltk.javascript.core.dom.rewrite.ASTConverter;
import org.eclipse.dltk.javascript.core.dom.rewrite.NodeFinder;
import org.eclipse.dltk.javascript.core.dom.rewrite.RewriteAnalyzer;
import org.eclipse.dltk.javascript.core.dom.rewrite.VariableLookup;
import org.eclipse.dltk.javascript.core.refactoring.descriptors.ExtractLocalDescriptor;
import org.eclipse.dltk.javascript.parser.JavaScriptParserUtil;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.change.ChangeDescription;
import org.eclipse.emf.ecore.change.util.ChangeRecorder;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.text.edits.TextEditGroup;
/**
* Extract Local Variable (from selected expression inside method or
* initializer).
*/
public class ExtractTempRefactoring extends Refactoring {
//private static final String ATTRIBUTE_REPLACE = "replace"; //$NON-NLS-1$
//private static final String ATTRIBUTE_FINAL = "final"; //$NON-NLS-1$
/*private static final class ForStatementChecker extends ASTVisitor {
private final Collection fForInitializerVariables;
private boolean fReferringToForVariable = false;
public ForStatementChecker(Collection forInitializerVariables) {
Assert.isNotNull(forInitializerVariables);
fForInitializerVariables = forInitializerVariables;
}
public boolean isReferringToForVariable() {
return fReferringToForVariable;
}
public boolean visit(SimpleName node) {
IBinding binding = node.resolveBinding();
if (binding != null && fForInitializerVariables.contains(binding)) {
fReferringToForVariable = true;
}
return false;
}
}
private static boolean allArraysEqual(Object[][] arrays, int position) {
Object element = arrays[0][position];
for (int i = 0; i < arrays.length; i++) {
Object[] array = arrays[i];
if (!element.equals(array[position]))
return false;
}
return true;
}
private static boolean canReplace(IASTFragment fragment) {
ASTNode node = fragment.getAssociatedNode();
ASTNode parent = node.getParent();
if (parent instanceof VariableDeclarationFragment) {
VariableDeclarationFragment vdf = (VariableDeclarationFragment) parent;
if (node.equals(vdf.getName()))
return false;
}
if (isMethodParameter(node))
return false;
if (isThrowableInCatchBlock(node))
return false;
if (parent instanceof ExpressionStatement)
return false;
if (isLeftValue(node))
return false;
if (isReferringToLocalVariableFromFor((Expression) node))
return false;
if (isUsedInForInitializerOrUpdater((Expression) node))
return false;
if (parent instanceof SwitchCase)
return false;
return true;
}
private static Object[] getArrayPrefix(Object[] array, int prefixLength) {
Assert.isTrue(prefixLength <= array.length);
Assert.isTrue(prefixLength >= 0);
Object[] prefix = new Object[prefixLength];
for (int i = 0; i < prefix.length; i++) {
prefix[i] = array[i];
}
return prefix;
}
// return List<IVariableBinding>
private static List getForInitializedVariables(
VariableDeclarationExpression variableDeclarations) {
List forInitializerVariables = new ArrayList(1);
for (Iterator iter = variableDeclarations.fragments().iterator(); iter
.hasNext();) {
VariableDeclarationFragment fragment = (VariableDeclarationFragment) iter
.next();
IVariableBinding binding = fragment.resolveBinding();
if (binding != null)
forInitializerVariables.add(binding);
}
return forInitializerVariables;
}
private static Object[] getLongestArrayPrefix(Object[][] arrays) {
int length = -1;
if (arrays.length == 0)
return new Object[0];
int minArrayLength = arrays[0].length;
for (int i = 1; i < arrays.length; i++)
minArrayLength = Math.min(minArrayLength, arrays[i].length);
for (int i = 0; i < minArrayLength; i++) {
if (!allArraysEqual(arrays, i))
break;
length++;
}
if (length == -1)
return new Object[0];
return getArrayPrefix(arrays[0], length + 1);
}
private static ASTNode[] getParents(ASTNode node) {
ASTNode current = node;
List parents = new ArrayList();
do {
parents.add(current.getParent());
current = current.getParent();
} while (current.getParent() != null);
Collections.reverse(parents);
return (ASTNode[]) parents.toArray(new ASTNode[parents.size()]);
}
private static boolean isLeftValue(ASTNode node) {
ASTNode parent = node.getParent();
if (parent instanceof Assignment) {
Assignment assignment = (Assignment) parent;
if (assignment.getLeftHandSide() == node)
return true;
}
if (parent instanceof PostfixExpression)
return true;
if (parent instanceof PrefixExpression) {
PrefixExpression.Operator op = ((PrefixExpression) parent)
.getOperator();
if (op.equals(PrefixExpression.Operator.DECREMENT))
return true;
if (op.equals(PrefixExpression.Operator.INCREMENT))
return true;
return false;
}
return false;
}
private static boolean isMethodParameter(ASTNode node) {
return (node instanceof SimpleName)
&& (node.getParent() instanceof SingleVariableDeclaration)
&& (node.getParent().getParent() instanceof MethodDeclaration);
}*/
/*private static boolean isThrowableInCatchBlock(ASTNode node) {
return (node instanceof SimpleName)
&& (node.getParent() instanceof SingleVariableDeclaration)
&& (node.getParent().getParent() instanceof CatchClause);
}*/
private static boolean isUsedInFor(Expression expression) {
EStructuralFeature sf = expression.eContainingFeature();
if (sf == DomPackage.eINSTANCE.getForStatement_Initialization()) return true;
if (sf == DomPackage.eINSTANCE.getForStatement_Condition()) return true;
if (sf == DomPackage.eINSTANCE.getForStatement_Increment()) return true;
if (sf == DomPackage.eINSTANCE.getForInStatement_Item()) return true;
if (sf == DomPackage.eINSTANCE.getForEachInStatement_Item()) return true;
return false;
}
/*private static IASTFragment[] retainOnlyReplacableMatches(
IASTFragment[] allMatches) {
List result = new ArrayList(allMatches.length);
for (int i = 0; i < allMatches.length; i++) {
if (canReplace(allMatches[i]))
result.add(allMatches[i]);
}
return (IASTFragment[]) result.toArray(new IASTFragment[result.size()]);
}*/
private Source fCompilationUnitNode;
//private CompilationUnitRewrite fCURewrite;
private ISourceModule fCu;
private String fSource;
//private boolean fDeclareFinal;
private String[] fExcludedVariableNames;
private boolean fReplaceAllOccurrences;
// caches:
private Expression fSelectedExpression;
private int fSelectionLength;
private int fSelectionStart;
private String fTempName;
/*private String[] fGuessedTempNames;
private boolean fCheckResultForCompileProblems;*/
private SourceModuleChange fChange;
//private LinkedProposalModel fLinkedProposalModel;
//private static final String KEY_NAME = "name"; //$NON-NLS-1$
//private static final String KEY_TYPE = "type"; //$NON-NLS-1$
/**
* Creates a new extract temp refactoring
*
* @param unit
* the compilation unit, or <code>null</code> if invoked by
* scripting
* @param selectionStart
* start of selection
* @param selectionLength
* length of selection
*/
public ExtractTempRefactoring(ISourceModule unit, int selectionStart,
int selectionLength) {
Assert.isTrue(selectionStart >= 0);
Assert.isTrue(selectionLength >= 0);
fSelectionStart = selectionStart;
fSelectionLength = selectionLength;
fCu = unit;
fCompilationUnitNode = null;
fReplaceAllOccurrences = true; // default
//fDeclareFinal = false; // default
fTempName = ""; //$NON-NLS-1$
//fLinkedProposalModel = null;
//fCheckResultForCompileProblems = true;
}
/*public ExtractTempRefactoring(CompilationUnit astRoot, int selectionStart,
int selectionLength) {
Assert.isTrue(selectionStart >= 0);
Assert.isTrue(selectionLength >= 0);
Assert.isTrue(astRoot.getTypeRoot() instanceof ISourceModule);
fSelectionStart = selectionStart;
fSelectionLength = selectionLength;
fCu = (ISourceModule) astRoot.getTypeRoot();
fCompilationUnitNode = astRoot;
fReplaceAllOccurrences = true; // default
fDeclareFinal = false; // default
fTempName = ""; //$NON-NLS-1$
fLinkedProposalModel = null;
fCheckResultForCompileProblems = true;
}
public ExtractTempRefactoring(JavaRefactoringArguments arguments,
RefactoringStatus status) {
this((ISourceModule) null, 0, 0);
RefactoringStatus initializeStatus = initialize(arguments);
status.merge(initializeStatus);
}
public void setCheckResultForCompileProblems(
boolean checkResultForCompileProblems) {
fCheckResultForCompileProblems = checkResultForCompileProblems;
}
public void setLinkedProposalModel(LinkedProposalModel linkedProposalModel) {
fLinkedProposalModel = linkedProposalModel;
}
private void addReplaceExpressionWithTemp() throws JavaModelException {
IASTFragment[] fragmentsToReplace = retainOnlyReplacableMatches(getMatchingFragments());
// TODO: should not have to prune duplicates here...
ASTRewrite rewrite = fCURewrite.getASTRewrite();
HashSet seen = new HashSet();
for (int i = 0; i < fragmentsToReplace.length; i++) {
IASTFragment fragment = fragmentsToReplace[i];
if (!seen.add(fragment))
continue;
SimpleName tempName = fCURewrite.getAST().newSimpleName(fTempName);
TextEditGroup description = fCURewrite
.createGroupDescription(RefactoringCoreMessages.ExtractTempRefactoring_replace);
fragment.replace(rewrite, tempName, description);
if (fLinkedProposalModel != null)
fLinkedProposalModel.getPositionGroup(KEY_NAME, true)
.addPosition(rewrite.track(tempName), false);
}
}*/
// !! Same as in ExtractConstantRefactoring
/*private RefactoringStatus checkExpressionFragmentIsRValue() throws ModelException {
switch (Checks.checkExpressionIsRValue(getSelectedExpression()
.getAssociatedExpression())) {
case Checks.NOT_RVALUE_MISC:
return RefactoringStatus
.createStatus(
RefactoringStatus.FATAL,
RefactoringCoreMessages.ExtractTempRefactoring_select_expression,
null, Corext.getPluginId(),
RefactoringStatusCodes.EXPRESSION_NOT_RVALUE, null);
case Checks.NOT_RVALUE_VOID:
return RefactoringStatus.createStatus(RefactoringStatus.FATAL,
RefactoringCoreMessages.ExtractTempRefactoring_no_void,
null, Corext.getPluginId(),
RefactoringStatusCodes.EXPRESSION_NOT_RVALUE_VOID, null);
case Checks.IS_RVALUE_GUESSED:
case Checks.IS_RVALUE:
return new RefactoringStatus();
default:
Assert.isTrue(false);
return null;
}
}*/
/*private ITypeBinding guessBindingForReference(Expression expression) {
ITypeBinding binding = expression.resolveTypeBinding();
if (binding == null) {
binding = ASTResolving.guessBindingForReference(expression);
}
return binding;
}*/
public RefactoringStatus checkFinalConditions(IProgressMonitor pm)
throws CoreException {
try {
pm.beginTask(
RefactoringCoreMessages.ExtractTempRefactoring_checking_preconditions,
4);
ChangeRecorder cr = new ChangeRecorder(fCompilationUnitNode);
// Expression
Expression selected = getSelectedExpression();
Expression[] expressions;
if (fReplaceAllOccurrences) {
expressions = findSimilarExpressions(selected);
} else {
expressions = new Expression[]{ selected };
}
// Statement
Statement stmt = findFirstStatement(expressions[0],expressions[expressions.length-1]);
EReference stmtRef = stmt.eContainmentFeature();
// Expression -> Reference
for(Expression expr : expressions) {
Identifier refId = DomFactory.eINSTANCE.createIdentifier();
refId.setName(fTempName);
VariableReference varRef = DomFactory.eINSTANCE.createVariableReference();
varRef.setVariable(refId);
EReference exprRef = expr.eContainmentFeature();
if (exprRef.isMany()) {
EList<Expression> exprList = (EList<Expression>)expr.eContainer().eGet(exprRef);
exprList.set(exprList.lastIndexOf(expr), varRef);
} else {
expr.eContainer().eSet(exprRef, varRef);
}
}
// Declaration
Identifier declId = DomFactory.eINSTANCE.createIdentifier();
declId.setName(fTempName);
VariableDeclaration decl = DomFactory.eINSTANCE.createVariableDeclaration();
decl.setIdentifier(declId);
decl.setInitializer(selected);
VariableStatement varStmt = DomFactory.eINSTANCE.createVariableStatement();
varStmt.getDeclarations().add(decl);
// << Declaration
if (stmtRef.isMany()) {
EList<Statement> stmtList = (EList<Statement>)stmt.eContainer().eGet(stmtRef);
stmtList.add(stmtList.lastIndexOf(stmt), varStmt);
} else {
BlockStatement block = DomFactory.eINSTANCE.createBlockStatement();
block.getStatements().add(varStmt);
stmt.eContainer().eSet(stmtRef, block);
block.getStatements().add(stmt);
}
ChangeDescription cd = cr.endRecording();
final SourceModuleChange change = new SourceModuleChange(RefactoringCoreMessages.ExtractTempRefactoring_name, fCu);
final TextEditGroup addDecl = new TextEditGroup(RefactoringCoreMessages.ExtractTempRefactoring_declare_local_variable);
RewriteAnalyzer ra = new RewriteAnalyzer(cd, fCu.getSource()) {
@Override
protected void addEdit(TextEdit edit, Node node) {
if (node instanceof VariableReference)
change.addTextEditGroup(new TextEditGroup(RefactoringCoreMessages.ExtractTempRefactoring_replace, edit));
else
addDecl.addTextEdit(edit);
super.addEdit(edit, node);
}
};
change.setEdit(ra.getEdit());
ra.rewrite(fCompilationUnitNode);
change.addTextEditGroup(addDecl);
cd.apply();
fChange = change;
return new RefactoringStatus();
} finally {
pm.done();
}
}
private static Expression[] findSimilarExpressions(Expression expr) {
List<Expression> res = new ArrayList<Expression>();
Node root = (Node)expr.eContainer();
while (true) {
int cl = root.eClass().getClassifierID();
if (cl == DomPackage.GETTER_ASSIGNMENT
|| cl == DomPackage.SETTER_ASSIGNMENT
|| cl == DomPackage.FUNCTION_EXPRESSION
|| cl == DomPackage.SOURCE) break;
root = (Node)root.eContainer();
}
Set<Identifier> set = new HashSet<Identifier>();
set.addAll(VariableLookup.findReferences(root, VariableLookup.getVisibleNames(expr)));
TreeIterator<EObject> it = root.eAllContents();
while(it.hasNext()) {
Node cur = (Node)it.next();
if (match(expr,cur,set)) {
res.add((Expression)cur);
it.prune();
}
}
return res.toArray(new Expression[res.size()]);
}
private static boolean match(Node one, Node another, Set<Identifier> resolved) {
if (one == null)
return another == null;
EClass cl = one.eClass();
if (cl != another.eClass()) {
return false;
}
if (resolved.contains(one) != resolved.contains(another))
return false;
for(EAttribute attr : cl.getEAllAttributes()) {
if (attr.getFeatureID() == DomPackage.NODE__BEGIN
|| attr.getFeatureID() == DomPackage.NODE__END
|| attr == DomPackage.eINSTANCE.getBinaryExpression_OperatorPosition()
|| attr == DomPackage.eINSTANCE.getFunctionExpression_ParametersPosition()) continue;
if (!one.eGet(attr).equals(another.eGet(attr)))
return false;
}
for(EReference ref : cl.getEAllReferences()) {
if (ref.isMany()) {
List<? extends Node> first = (List<? extends Node>)one.eGet(ref);
List<? extends Node> second = (List<? extends Node>)another.eGet(ref);
if (first.size() != second.size())
return false;
for(int i=0;i<first.size();i++)
if (!match(first.get(i),second.get(i),resolved))
return false;
} else
if (!match((Node)one.eGet(ref),(Node)another.eGet(ref),resolved))
return false;
}
return true;
}
private static Statement findFirstStatement(EObject first,EObject last) {
int x = getDepth(first);
int y = getDepth(last);
while (x>y) {
x--;
first = first.eContainer();
}
while (y>x) {
y--;
last = last.eContainer();
}
while (first.eContainer() != last.eContainer()) {
first = first.eContainer();
last = last.eContainer();
}
while (first.eContainmentFeature().getEReferenceType() != DomPackage.eINSTANCE.getStatement())
first = first.eContainer();
return (Statement)first;
}
private static int getDepth(EObject node) {
int i=0;
while (node != null) {
i++;
node = node.eContainer();
}
return i;
}
private ExtractLocalDescriptor createRefactoringDescriptor() {
String project = null;
IScriptProject scriptProject = fCu.getScriptProject();
if (scriptProject != null)
project = scriptProject.getElementName();
//final String description = Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_descriptor_description_short,
// BasicElementLabels.getModelElementName(fTempName));
final String description = Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_descriptor_description_short,fTempName);
//final String expression = ASTNodes.asString(fSelectedExpression.getAssociatedExpression());
//final String header = Messages
// .format(RefactoringCoreMessages.ExtractTempRefactoring_descriptor_description,
// new String[] {
// BasicElementLabels
// .getJavaElementName(fTempName),
// BasicElementLabels
// .getJavaCodeString(expression) });
//final ScriptRefactoringDescriptorComment comment = new JDTRefactoringDescriptorComment(
// project, this, header);
//comment.addSetting(Messages.format(
// RefactoringCoreMessages.ExtractTempRefactoring_name_pattern,
// BasicElementLabels.getJavaElementName(fTempName)));
//final BodyDeclaration decl = (BodyDeclaration) ASTNodes.getParent(
// fSelectedExpression.getAssociatedExpression(),
// BodyDeclaration.class);
//if (decl instanceof MethodDeclaration) {
// final IMethodBinding method = ((MethodDeclaration) decl)
// .resolveBinding();
// final String label = method != null ? BindingLabelProvider
// .getBindingLabel(method,
// JavaElementLabels.ALL_FULLY_QUALIFIED)
// : BasicElementLabels
// .getJavaElementName('{' + JavaElementLabels.ELLIPSIS_STRING + '}');
// comment.addSetting(Messages
// .format(RefactoringCoreMessages.ExtractTempRefactoring_destination_pattern,
// label));
//}
//comment.addSetting(Messages
// .format(RefactoringCoreMessages.ExtractTempRefactoring_expression_pattern,
// BasicElementLabels.getJavaCodeString(expression)));
//if (fReplaceAllOccurrences)
// comment.addSetting(RefactoringCoreMessages.ExtractTempRefactoring_replace_occurrences);
//if (fDeclareFinal)
// comment.addSetting(RefactoringCoreMessages.ExtractTempRefactoring_declare_final);
final Map arguments = new HashMap();
arguments.put(ScriptRefactoringDescriptor.ATTRIBUTE_INPUT,
ScriptRefactoringDescriptor.elementToHandle(project, fCu));
arguments.put(ScriptRefactoringDescriptor.ATTRIBUTE_NAME, fTempName);
arguments.put(ScriptRefactoringDescriptor.ATTRIBUTE_SELECTION,
new Integer(fSelectionStart).toString()
+ " " + new Integer(fSelectionLength).toString()); //$NON-NLS-1$
//arguments.put(ATTRIBUTE_REPLACE, Boolean
// .valueOf(fReplaceAllOccurrences).toString());
//arguments.put(ATTRIBUTE_FINAL, Boolean.valueOf(fDeclareFinal)
// .toString());
final ExtractLocalDescriptor descriptor = new ExtractLocalDescriptor(project, description, /*comment.asString()*/ "", arguments, RefactoringDescriptor.NONE);
return descriptor;
}
/*private void doCreateChange(IProgressMonitor pm) throws CoreException {
try {
pm.beginTask(
RefactoringCoreMessages.ExtractTempRefactoring_checking_preconditions,
1);
try {
createTempDeclaration();
} catch (CoreException exception) {
JavaPlugin.log(exception);
}
addReplaceExpressionWithTemp();
} finally {
pm.done();
}
}
private void checkNewSource(SubProgressMonitor monitor,
RefactoringStatus result) throws CoreException {
String newCuSource = fChange
.getPreviewContent(new NullProgressMonitor());
CompilationUnit newCUNode = new RefactoringASTParser(AST.JLS3).parse(
newCuSource, fCu, true, true, monitor);
IProblem[] newProblems = RefactoringAnalyzeUtil
.getIntroducedCompileProblems(newCUNode, fCompilationUnitNode);
for (int i = 0; i < newProblems.length; i++) {
IProblem problem = newProblems[i];
if (problem.isError())
result.addEntry(new RefactoringStatusEntry(
(problem.isError() ? RefactoringStatus.ERROR
: RefactoringStatus.WARNING), problem
.getMessage(),
new JavaStringStatusContext(newCuSource,
SourceRangeFactory.create(problem))));
}
}*/
public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
throws CoreException {
try {
pm.beginTask("", 6); //$NON-NLS-1$
RefactoringStatus result = RefactoringChecks.validateModifiesFiles(
ResourceUtil.getFiles(new ISourceModule[] { fCu }),
getValidationContext());
if (result.hasFatalError())
return result;
if (fCompilationUnitNode == null) {
fCompilationUnitNode = (Source)ASTConverter.convert(JavaScriptParserUtil.parse(fCu));
}
pm.worked(3);
fSource = fCu.getSource();
result.merge(checkSelection(new SubProgressMonitor(pm, 3)));
//if (!result.hasFatalError() && isLiteralNodeSelected())
// fReplaceAllOccurrences = false;
return result;
} finally {
pm.done();
}
}
/*private RefactoringStatus checkMatchingFragments()
throws JavaModelException {
RefactoringStatus result = new RefactoringStatus();
IASTFragment[] matchingFragments = getMatchingFragments();
for (int i = 0; i < matchingFragments.length; i++) {
ASTNode node = matchingFragments[i].getAssociatedNode();
if (isLeftValue(node)
&& !isReferringToLocalVariableFromFor((Expression) node)) {
String msg = RefactoringCoreMessages.ExtractTempRefactoring_assigned_to;
result.addWarning(msg, JavaStatusContext.create(fCu, node));
}
}
return result;
}*/
private RefactoringStatus checkSelection(IProgressMonitor pm) throws ModelException {
try {
pm.beginTask("", 2); //$NON-NLS-1$
Expression selectedExpression = getSelectedExpression();
if (selectedExpression == null) {
String message = RefactoringCoreMessages.ExtractTempRefactoring_select_expression;
//return CodeRefactoringUtil.checkMethodSyntaxErrors(
// fSelectionStart, fSelectionLength,
// fCompilationUnitNode, message);
return RefactoringStatus.createFatalErrorStatus(message);
}
pm.worked(1);
if (isUsedInFor(getSelectedExpression()))
return RefactoringStatus
.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_for_initializer_updater);
pm.worked(1);
return new RefactoringStatus();
} finally {
pm.done();
}
}
public RefactoringStatus checkTempName(String newName) {
RefactoringStatus status = Checks.validateIdentifier(newName);
if (status.hasFatalError())
return status;
if (Arrays.asList(getExcludedVariableNames()).contains(newName))
status.addWarning(Messages
.format(RefactoringCoreMessages.ExtractTempRefactoring_another_variable,
newName /*BasicElementLabels.getJavaElementName(newName)*/));
return status;
}
/*private void createAndInsertTempDeclaration() throws CoreException {
Expression initializer = getSelectedExpression().createCopyTarget(
fCURewrite.getASTRewrite(), true);
VariableDeclarationStatement vds = createTempDeclaration(initializer);
if ((!fReplaceAllOccurrences)
|| (retainOnlyReplacableMatches(getMatchingFragments()).length <= 1)) {
insertAt(getSelectedExpression().getAssociatedNode(), vds);
return;
}
ASTNode[] firstReplaceNodeParents = getParents(getFirstReplacedExpression()
.getAssociatedNode());
ASTNode[] commonPath = findDeepestCommonSuperNodePathForReplacedNodes();
Assert.isTrue(commonPath.length <= firstReplaceNodeParents.length);
ASTNode deepestCommonParent = firstReplaceNodeParents[commonPath.length - 1];
if (deepestCommonParent instanceof Block)
insertAt(firstReplaceNodeParents[commonPath.length], vds);
else
insertAt(deepestCommonParent, vds);
}
private VariableDeclarationStatement createTempDeclaration(
Expression initializer) throws CoreException {
AST ast = fCURewrite.getAST();
VariableDeclarationFragment vdf = ast.newVariableDeclarationFragment();
vdf.setName(ast.newSimpleName(fTempName));
vdf.setInitializer(initializer);
VariableDeclarationStatement vds = ast
.newVariableDeclarationStatement(vdf);
if (fDeclareFinal) {
vds.modifiers().add(ast.newModifier(ModifierKeyword.FINAL_KEYWORD));
}
vds.setType(createTempType());
if (fLinkedProposalModel != null) {
ASTRewrite rewrite = fCURewrite.getASTRewrite();
LinkedProposalPositionGroup nameGroup = fLinkedProposalModel
.getPositionGroup(KEY_NAME, true);
nameGroup.addPosition(rewrite.track(vdf.getName()), true);
String[] nameSuggestions = guessTempNames();
if (nameSuggestions.length > 0
&& !nameSuggestions[0].equals(fTempName)) {
nameGroup.addProposal(fTempName, null,
nameSuggestions.length + 1);
}
for (int i = 0; i < nameSuggestions.length; i++) {
nameGroup.addProposal(nameSuggestions[i], null,
nameSuggestions.length - i);
}
}
return vds;
}
private void insertAt(ASTNode target, Statement declaration) {
ASTRewrite rewrite = fCURewrite.getASTRewrite();
TextEditGroup groupDescription = fCURewrite
.createGroupDescription(RefactoringCoreMessages.ExtractTempRefactoring_declare_local_variable);
ASTNode parent = target.getParent();
StructuralPropertyDescriptor locationInParent = target
.getLocationInParent();
while (locationInParent != Block.STATEMENTS_PROPERTY
&& locationInParent != SwitchStatement.STATEMENTS_PROPERTY) {
if (locationInParent == IfStatement.THEN_STATEMENT_PROPERTY
|| locationInParent == IfStatement.ELSE_STATEMENT_PROPERTY
|| locationInParent == ForStatement.BODY_PROPERTY
|| locationInParent == EnhancedForStatement.BODY_PROPERTY
|| locationInParent == DoStatement.BODY_PROPERTY
|| locationInParent == WhileStatement.BODY_PROPERTY) {
// create intermediate block if target was the body property of
// a control statement:
Block replacement = rewrite.getAST().newBlock();
ListRewrite replacementRewrite = rewrite.getListRewrite(
replacement, Block.STATEMENTS_PROPERTY);
replacementRewrite.insertFirst(declaration, null);
replacementRewrite.insertLast(rewrite.createMoveTarget(target),
null);
rewrite.replace(target, replacement, groupDescription);
return;
}
target = parent;
parent = parent.getParent();
locationInParent = target.getLocationInParent();
}
ListRewrite listRewrite = rewrite.getListRewrite(parent,
(ChildListPropertyDescriptor) locationInParent);
listRewrite.insertBefore(declaration, target, groupDescription);
}*/
public Change createChange(IProgressMonitor pm) throws CoreException {
try {
pm.beginTask(
RefactoringCoreMessages.ExtractTempRefactoring_checking_preconditions,
1);
ExtractLocalDescriptor descriptor = createRefactoringDescriptor();
fChange.setDescriptor(new RefactoringChangeDescriptor(descriptor));
return fChange;
} finally {
pm.done();
}
}
private String[] getExcludedVariableNames() {
if (fExcludedVariableNames == null) {
try {
//ScopeLookup look = new ScopeLookup();
//look.findNamesInScope(getSelectedExpression());
Set<String> visible = VariableLookup.getVisibleNames(getSelectedExpression());
fExcludedVariableNames = visible.toArray(new String[visible.size()]);
} catch (ModelException e) {
JavascriptManipulationPlugin.log(e); //who cares, but still
fExcludedVariableNames = new String[0];
}
}
return fExcludedVariableNames;
}
/*private IExpressionFragment getFirstReplacedExpression()
throws JavaModelException {
if (!fReplaceAllOccurrences)
return getSelectedExpression();
IASTFragment[] nodesToReplace = retainOnlyReplacableMatches(getMatchingFragments());
if (nodesToReplace.length == 0)
return getSelectedExpression();
Comparator comparator = new Comparator() {
public int compare(Object o1, Object o2) {
return ((IASTFragment) o1).getStartPosition()
- ((IASTFragment) o2).getStartPosition();
}
};
Arrays.sort(nodesToReplace, comparator);
return (IExpressionFragment) nodesToReplace[0];
}
private IASTFragment[] getMatchingFragments() throws JavaModelException {
if (fReplaceAllOccurrences) {
IASTFragment[] allMatches = ASTFragmentFactory
.createFragmentForFullSubtree(getEnclosingBodyNode())
.getSubFragmentsMatching(getSelectedExpression());
return allMatches;
} else
return new IASTFragment[] { getSelectedExpression() };
}
private ASTNode[] getMatchNodes() throws JavaModelException {
IASTFragment[] matches = retainOnlyReplacableMatches(getMatchingFragments());
ASTNode[] result = new ASTNode[matches.length];
for (int i = 0; i < matches.length; i++)
result[i] = matches[i].getAssociatedNode();
return result;
}*/
public String getName() {
return RefactoringCoreMessages.ExtractTempRefactoring_name;
}
private Expression getSelectedExpression() throws ModelException {
if (fSelectedExpression != null)
return fSelectedExpression;
Node node = NodeFinder.findNode(fCompilationUnitNode, fSelectionStart, fSelectionStart+fSelectionLength);
if (node == null) return null;
for(int i=fSelectionStart;i<node.getBegin();i++)
if (!Character.isWhitespace(fSource.charAt(i))) return null;
for(int i=node.getEnd();i<fSelectionStart+fSelectionLength;i++)
if (!Character.isWhitespace(fSource.charAt(i))) return null;
if (node instanceof ExpressionStatement)
return fSelectedExpression = ((ExpressionStatement)node).getExpression();
if (node instanceof Expression)
return fSelectedExpression = (Expression)node;
return null;
/*IASTFragment selectedFragment = ASTFragmentFactory
.createFragmentForSourceRange(new SourceRange(fSelectionStart,
fSelectionLength), fCompilationUnitNode, fCu);
if (selectedFragment instanceof IExpressionFragment
&& !Checks
.isInsideJavadoc(selectedFragment.getAssociatedNode())) {
fSelectedExpression = (IExpressionFragment) selectedFragment;
} else if (selectedFragment != null) {
if (selectedFragment.getAssociatedNode() instanceof ExpressionStatement) {
ExpressionStatement exprStatement = (ExpressionStatement) selectedFragment
.getAssociatedNode();
Expression expression = exprStatement.getExpression();
fSelectedExpression = (IExpressionFragment) ASTFragmentFactory
.createFragmentForFullSubtree(expression);
} else if (selectedFragment.getAssociatedNode() instanceof Assignment) {
Assignment assignment = (Assignment) selectedFragment
.getAssociatedNode();
fSelectedExpression = (IExpressionFragment) ASTFragmentFactory
.createFragmentForFullSubtree(assignment);
}
}
if (fSelectedExpression != null
&& Checks.isEnumCase(fSelectedExpression
.getAssociatedExpression().getParent())) {
fSelectedExpression = null;
}
return fSelectedExpression;*/
}
/*private Type createTempType() throws CoreException {
Expression expression = getSelectedExpression()
.getAssociatedExpression();
Type resultingType = null;
ITypeBinding typeBinding = expression.resolveTypeBinding();
ASTRewrite rewrite = fCURewrite.getASTRewrite();
AST ast = rewrite.getAST();
if (expression instanceof ClassInstanceCreation) {
resultingType = (Type) rewrite
.createCopyTarget(((ClassInstanceCreation) expression)
.getType());
} else if (expression instanceof CastExpression) {
resultingType = (Type) rewrite
.createCopyTarget(((CastExpression) expression).getType());
} else {
if (typeBinding == null) {
typeBinding = ASTResolving.guessBindingForReference(expression);
}
if (typeBinding != null) {
typeBinding = Bindings.normalizeForDeclarationUse(typeBinding,
ast);
ImportRewrite importRewrite = fCURewrite.getImportRewrite();
ImportRewriteContext context = new ContextSensitiveImportRewriteContext(
expression, importRewrite);
resultingType = importRewrite.addImport(typeBinding, ast,
context);
} else {
resultingType = ast.newSimpleType(ast.newSimpleName("Object")); //$NON-NLS-1$
}
}
if (fLinkedProposalModel != null) {
LinkedProposalPositionGroup typeGroup = fLinkedProposalModel
.getPositionGroup(KEY_TYPE, true);
typeGroup.addPosition(rewrite.track(resultingType), false);
if (typeBinding != null) {
ITypeBinding[] relaxingTypes = ASTResolving.getNarrowingTypes(
ast, typeBinding);
for (int i = 0; i < relaxingTypes.length; i++) {
typeGroup.addProposal(relaxingTypes[i], fCURewrite.getCu(),
relaxingTypes.length - i);
}
}
}
return resultingType;
}
public String guessTempName() {
String[] proposals = guessTempNames();
if (proposals.length == 0)
return fTempName;
else
return proposals[0];
}*/
/**
* @return proposed variable names (may be empty, but not null). The first
* proposal should be used as "best guess" (if it exists).
*/
/*public String[] guessTempNames() {
if (fGuessedTempNames == null) {
try {
Expression expression = getSelectedExpression()
.getAssociatedExpression();
if (expression != null) {
ITypeBinding binding = guessBindingForReference(expression);
fGuessedTempNames = StubUtility.getVariableNameSuggestions(
NamingConventions.VK_LOCAL, fCu.getJavaProject(),
binding, expression,
Arrays.asList(getExcludedVariableNames()));
}
} catch (JavaModelException e) {
}
if (fGuessedTempNames == null)
fGuessedTempNames = new String[0];
}
return fGuessedTempNames;
}
private boolean isLiteralNodeSelected() throws JavaModelException {
IExpressionFragment fragment = getSelectedExpression();
if (fragment == null)
return false;
Expression expression = fragment.getAssociatedExpression();
if (expression == null)
return false;
switch (expression.getNodeType()) {
case ASTNode.BOOLEAN_LITERAL:
case ASTNode.CHARACTER_LITERAL:
case ASTNode.NULL_LITERAL:
case ASTNode.NUMBER_LITERAL:
return true;
default:
return false;
}
}
private boolean isUsedInExplicitConstructorCall() throws JavaModelException {
Expression selectedExpression = getSelectedExpression()
.getAssociatedExpression();
if (ASTNodes.getParent(selectedExpression, ConstructorInvocation.class) != null)
return true;
if (ASTNodes.getParent(selectedExpression,
SuperConstructorInvocation.class) != null)
return true;
return false;
}*/
public boolean replaceAllOccurrences() {
return fReplaceAllOccurrences;
}
/*private void replaceSelectedExpressionWithTempDeclaration()
throws CoreException {
ASTRewrite rewrite = fCURewrite.getASTRewrite();
Expression selectedExpression = getSelectedExpression()
.getAssociatedExpression(); // whole expression selected
Expression initializer = (Expression) rewrite
.createMoveTarget(selectedExpression);
ASTNode replacement = createTempDeclaration(initializer); // creates a
// VariableDeclarationStatement
ExpressionStatement parent = (ExpressionStatement) selectedExpression
.getParent();
if (ASTNodes.isControlStatementBody(parent.getLocationInParent())) {
Block block = rewrite.getAST().newBlock();
block.statements().add(replacement);
replacement = block;
}
rewrite.replace(
parent,
replacement,
fCURewrite
.createGroupDescription(RefactoringCoreMessages.ExtractTempRefactoring_declare_local_variable));
}
public void setDeclareFinal(boolean declareFinal) {
fDeclareFinal = declareFinal;
}*/
public void setReplaceAllOccurrences(boolean replaceAllOccurrences) {
fReplaceAllOccurrences = replaceAllOccurrences;
}
public void setTempName(String newName) {
fTempName = newName;
}
/*private boolean shouldReplaceSelectedExpressionWithTempDeclaration()
throws JavaModelException {
IExpressionFragment selectedFragment = getSelectedExpression();
return selectedFragment.getAssociatedNode().getParent() instanceof ExpressionStatement
&& selectedFragment.matches(ASTFragmentFactory
.createFragmentForFullSubtree(selectedFragment
.getAssociatedNode()));
}
private RefactoringStatus initialize(RefactoringArguments arguments) {
final String selection = arguments
.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION);
if (selection != null) {
int offset = -1;
int length = -1;
final StringTokenizer tokenizer = new StringTokenizer(selection);
if (tokenizer.hasMoreTokens())
offset = Integer.valueOf(tokenizer.nextToken()).intValue();
if (tokenizer.hasMoreTokens())
length = Integer.valueOf(tokenizer.nextToken()).intValue();
if (offset >= 0 && length >= 0) {
fSelectionStart = offset;
fSelectionLength = length;
} else
return RefactoringStatus
.createFatalErrorStatus(Messages
.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument,
new Object[] {
selection,
JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION }));
} else
return RefactoringStatus
.createFatalErrorStatus(Messages
.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION));
final String handle = arguments
.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
if (handle != null) {
final IJavaElement element = JavaRefactoringDescriptorUtil
.handleToElement(arguments.getProject(), handle, false);
if (element == null
|| !element.exists()
|| element.getElementType() != IJavaElement.COMPILATION_UNIT)
return JavaRefactoringDescriptorUtil.createInputFatalStatus(
element, getName(),
IJavaRefactorings.EXTRACT_LOCAL_VARIABLE);
else
fCu = (ISourceModule) element;
} else
return RefactoringStatus
.createFatalErrorStatus(Messages
.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
final String name = arguments
.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME);
if (name != null && !"".equals(name)) //$NON-NLS-1$
fTempName = name;
else
return RefactoringStatus
.createFatalErrorStatus(Messages
.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME));
final String replace = arguments.getAttribute(ATTRIBUTE_REPLACE);
if (replace != null) {
fReplaceAllOccurrences = Boolean.valueOf(replace).booleanValue();
} else
return RefactoringStatus
.createFatalErrorStatus(Messages
.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
ATTRIBUTE_REPLACE));
final String declareFinal = arguments.getAttribute(ATTRIBUTE_FINAL);
if (declareFinal != null) {
fDeclareFinal = Boolean.valueOf(declareFinal).booleanValue();
} else
return RefactoringStatus
.createFatalErrorStatus(Messages
.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
ATTRIBUTE_FINAL));
return new RefactoringStatus();
}*/
}