package com.redhat.ceylon.eclipse.code.refactor;
/*import static com.redhat.ceylon.eclipse.code.correct.ImportProposals.importProposals;
import static org.eclipse.ltk.core.refactoring.RefactoringStatus.createWarningStatus;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextChange;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.ui.IEditorPart;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;
import com.redhat.ceylon.eclipse.util.EditorUtil;
import com.redhat.ceylon.eclipse.util.Nodes;
import com.redhat.ceylon.ide.common.refactoring.ExtractLinkedModeEnabled;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Type;
public class ExtractParameterRefactoring extends AbstractRefactoring implements ExtractLinkedModeEnabled<IRegion> {
private String newName;
private Tree.Declaration methodOrClass;
private Type type;
private static class FindFunctionVisitor
extends Visitor {
private final Node term;
private Tree.Declaration declaration;
private Tree.Declaration current;
public FindFunctionVisitor(Node term) {
this.term = term;
}
public Tree.Declaration getDefinitionNode() {
return declaration;
}
@Override
public void visit(Tree.MethodDefinition that) {
Tree.Declaration outer = current;
current = that;
super.visit(that);
current = outer;
}
@Override
public void visit(Tree.ClassDefinition that) {
Tree.Declaration outer = current;
current = that;
super.visit(that);
current = outer;
}
@Override
public void visit(Tree.Constructor that) {
Tree.Declaration outer = current;
current = that;
super.visit(that);
current = outer;
}
@Override
public void visitAny(Node node) {
if (node == term) {
declaration = current;
}
if (declaration == null) {
super.visitAny(node);
}
}
}
public ExtractParameterRefactoring(IEditorPart editor) {
super(editor);
if (rootNode!=null) {
newName = Nodes.nameProposals(node)[0];
FindFunctionVisitor ffv = new FindFunctionVisitor(node);
ffv.visit(rootNode);
methodOrClass = ffv.getDefinitionNode();
}
}
@Override
public boolean getEnabled() {
return node instanceof Tree.Term &&
methodOrClass!=null &&
methodOrClass.getDeclarationModel()!=null &&
!methodOrClass.getDeclarationModel().isActual() &&
!isWithinParameterList();
}
private boolean isWithinParameterList() {
Tree.ParameterList pl1, pl2;
if (methodOrClass instanceof Tree.AnyClass) {
Tree.AnyClass anyClass = (Tree.AnyClass) methodOrClass;
Tree.ParameterList pl = anyClass.getParameterList();
if (pl==null) return false;
pl1 = pl2 = pl;
}
else if (methodOrClass instanceof Tree.Constructor) {
Tree.Constructor constructor = (Tree.Constructor) methodOrClass;
Tree.ParameterList pl = constructor.getParameterList();
if (pl==null) return false;
pl1 = pl2 = pl;
}
else if (methodOrClass instanceof Tree.AnyMethod) {
Tree.AnyMethod anyMethod = (Tree.AnyMethod) methodOrClass;
List<Tree.ParameterList> pls =
anyMethod.getParameterLists();
if (pls.isEmpty()) return false;
pl1 = pls.get(0);
pl2 = pls.get(pls.size()-1);
}
else {
return false;
}
return node.getStartIndex()>=pl1.getStartIndex() &&
node.getEndIndex()<=pl2.getEndIndex();
}
public String getName() {
return "Extract Parameter";
}
public boolean forceWizardMode() {
Declaration existing = node.getScope()
.getMemberOrParameter(node.getUnit(), newName, null, false);
return existing!=null;
}
public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
throws CoreException, OperationCanceledException {
// Check parameters retrieved from editor context
return new RefactoringStatus();
}
public RefactoringStatus checkFinalConditions(IProgressMonitor pm)
throws CoreException, OperationCanceledException {
Declaration existing = node.getScope()
.getMemberOrParameter(node.getUnit(), newName, null, false);
if (null!=existing) {
return createWarningStatus("An existing declaration named '" +
newName + "' already exists in the same scope");
}
return new RefactoringStatus();
}
public Change createChange(IProgressMonitor pm)
throws CoreException,
OperationCanceledException {
TextChange tfc = newLocalChange();
extractInFile(tfc);
return tfc;
}
private IRegion decRegion;
private IRegion refRegion;
private IRegion typeRegion;
@Override
public IRegion getTypeRegion() {
return typeRegion;
}
@Override
public void setTypeRegion(IRegion region) {
typeRegion = region;
}
@Override
public IRegion getDecRegion() {
return decRegion;
}
@Override
public void setDecRegion(IRegion region) {
decRegion = region;
}
@Override
public IRegion getRefRegion() {
return refRegion;
}
@Override
public void setRefRegion(IRegion region) {
refRegion=region;
}
public void setType(Type type) {
this.type = type;
}
private boolean isParameterOfMethodOrClass(Declaration d) {
return d.isParameter() &&
d.getContainer().equals(methodOrClass.getDeclarationModel());
}
public void extractInFile(TextChange tfc) {
tfc.setEdit(new MultiTextEdit());
IDocument doc = EditorUtil.getDocument(tfc);
Tree.ParameterList pl;
if (methodOrClass instanceof Tree.MethodDefinition) {
Tree.MethodDefinition methodDefinition =
(Tree.MethodDefinition) methodOrClass;
List<Tree.ParameterList> pls =
methodDefinition.getParameterLists();
if (pls.isEmpty()) {
return; //TODO
}
pl = pls.get(0);
}
else if (methodOrClass instanceof Tree.ClassDefinition) {
Tree.ClassDefinition classDefinition =
(Tree.ClassDefinition) methodOrClass;
pl = classDefinition.getParameterList();
if (pl==null) {
return; //TODO
}
}
else if (methodOrClass instanceof Tree.Constructor) {
Tree.Constructor constructor =
(Tree.Constructor) methodOrClass;
pl = constructor.getParameterList();
if (pl==null) {
return; //TODO
}
}
else {
return;
}
Tree.Term term = (Tree.Term) node;
Tree.Term unparened = unparenthesize(term);
boolean anonfun = unparened instanceof Tree.FunctionArgument &&
((Tree.FunctionArgument) unparened).getExpression()!=null;
String text;
int il = 0;
if (anonfun) {
Tree.FunctionArgument fa =
(Tree.FunctionArgument)
unparened;
if (type==null) {
type = fa.getType().getTypeModel();
}
text = Nodes.text(fa.getExpression(), tokens);
}
else {
if (type==null) {
type = node.getUnit()
.denotableType(term.getTypeModel());
}
text = Nodes.text(unparened, tokens);
}
String typeDec;
if (type==null || type.isUnknown()) {
typeDec = "dynamic";
}
else {
StringBuilder builder = new StringBuilder();
il+=addType(tfc, doc, type, builder);
typeDec = builder.toString();
}
final List<Tree.BaseMemberExpression> localRefs =
new ArrayList<Tree.BaseMemberExpression>();
node.visit(new Visitor() {
private Set<Declaration> decs = new HashSet<Declaration>();
@Override
public void visit(Tree.BaseMemberExpression that) {
super.visit(that);
Declaration d = that.getDeclaration();
if (d!=null && !isParameterOfMethodOrClass(d) &&
!decs.contains(d) &&
d.isDefinedInScope(node.getScope()) &&
!d.isDefinedInScope(methodOrClass.getScope().getContainer())) {
localRefs.add(that);
decs.add(d);
}
}
});
String decl;
String call;
int refStart;
if (localRefs.isEmpty()) {
decl = typeDec + " " + newName + " = " + text;
call = newName;
refStart = 0;
}
else {
StringBuilder params = new StringBuilder();
StringBuilder args = new StringBuilder();
for (Tree.BaseMemberExpression bme: localRefs) {
if (params.length()!=0) {
params.append(", ");
args.append(", ");
}
String n = bme.getIdentifier().getText();
il+=addType(tfc, doc, bme.getTypeModel(), params);
params.append(" ").append(n);
args.append(n);
}
decl = typeDec + " " + newName + "(" + params + ") => " + text;
if (anonfun) {
Tree.FunctionArgument fa = (Tree.FunctionArgument) node;
Tree.ParameterList cpl = fa.getParameterLists().get(0);
if (cpl.getParameters().size()==localRefs.size()) {
call = newName;
refStart = 0;
}
else {
String header = Nodes.text(cpl, tokens) + " => ";
call = header + newName + "(" + args + ")";
refStart = header.length();
}
}
else {
call = newName + "(" + args + ")";
refStart = 0;
}
}
int start = pl.getEndIndex() - 1;
String dectext = (pl.getParameters().isEmpty()?"":", ") + decl;
tfc.addEdit(new InsertEdit(start, dectext));
tfc.addEdit(new ReplaceEdit(node.getStartIndex(), node.getDistance(), call));
int buffer = pl.getParameters().isEmpty()?0:2;
decRegion = new Region(start+il+typeDec.length()+buffer+1, newName.length());
refRegion = new Region(node.getStartIndex()+il+dectext.length()+refStart,
newName.length());
typeRegion = new Region(start+il+buffer, typeDec.length());
}
private int addType(TextChange tfc, IDocument doc,
Type tm, StringBuilder builder) {
Type type = node.getUnit().denotableType(tm);
HashSet<Declaration> decs = new HashSet<Declaration>();
importProposals().importType(decs, type, rootNode);
int il = (int) importProposals().applyImports(tfc, decs, rootNode, doc);
builder.append(type.asSourceCodeString(rootNode.getUnit()));
return il;
}
public void setNewName(String text) {
newName = text;
}
public String getNewName() {
return newName;
}
Type getType() {
return type;
}
public String[] getNameProposals() {
return Nodes.nameProposals(node);
}
@Override
public IRegion newRegion(long start, long length) {
return new Region((int) start, (int) length);
}
}*/