package com.redhat.ceylon.eclipse.code.correct;
import static com.redhat.ceylon.eclipse.code.complete.CodeCompletions.appendParameterText;
import static com.redhat.ceylon.eclipse.code.correct.ImportProposals.importProposals;
import static com.redhat.ceylon.eclipse.util.Nodes.findDeclaration;
import static com.redhat.ceylon.eclipse.util.Nodes.findStatement;
import static com.redhat.ceylon.eclipse.util.Types.getRefinedDeclaration;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.text.edits.DeleteEdit;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.eclipse.platform.platformJ2C;
import com.redhat.ceylon.ide.common.platform.TextChange;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Functional;
import com.redhat.ceylon.model.typechecker.model.Parameter;
import com.redhat.ceylon.model.typechecker.model.ParameterList;
import com.redhat.ceylon.model.typechecker.model.Reference;
import com.redhat.ceylon.model.typechecker.model.Scope;
import com.redhat.ceylon.model.typechecker.model.Type;
import com.redhat.ceylon.model.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.model.typechecker.model.TypedDeclaration;
import com.redhat.ceylon.model.typechecker.model.Unit;
@Deprecated
public class ChangeRefiningTypeProposal {
static void addChangeRefiningTypeProposal(IFile file,
Tree.CompilationUnit cu,
Collection<ICompletionProposal> proposals,
Node node) {
Tree.Declaration decNode = findDeclaration(cu, node);
if (decNode instanceof Tree.TypedDeclaration) {
Tree.TypedDeclaration td =
(Tree.TypedDeclaration) decNode;
TypedDeclaration dec = td.getDeclarationModel();
//TODO: this can return the wrong member when
// there are multiple ... better to look
// at what RefinementVisitor does
Declaration rd = getRefinedDeclaration(dec);
if (rd instanceof TypedDeclaration) {
TypeDeclaration decContainer =
(TypeDeclaration)
dec.getContainer();
TypeDeclaration rdContainer =
(TypeDeclaration)
rd.getContainer();
Type supertype =
decContainer.getType()
.getSupertype(rdContainer);
Reference ref =
rd.appliedReference(supertype,
Collections.<Type>emptyList());
Type t = ref.getType();
String type =
t.asSourceCodeString(
decNode.getUnit());
Set<Declaration> declarations =
new HashSet<Declaration>();
importProposals().importType(declarations, t, cu);
TextFileChange change =
new TextFileChange("Change Type",
file);
int offset = node.getStartIndex();
int length = node.getDistance();
change.setEdit(new MultiTextEdit());
TextChange chg2 = new platformJ2C().newChange(change.getName(), change);
importProposals().applyImports(chg2, declarations, cu,
chg2.getDocument());
change.addEdit(new ReplaceEdit(
offset, length, type));
Region selection =
new Region(offset, type.length());
proposals.add(new CorrectionProposal(
"Change type to '" + type + "'",
change, selection));
}
}
}
static void addChangeRefiningParametersProposal(
IFile file, Tree.CompilationUnit cu,
Collection<ICompletionProposal> proposals,
Node node) {
Tree.Statement decNode =
(Tree.Statement)
findStatement(cu, node);
Tree.ParameterList list;
Declaration dec;
if (decNode instanceof Tree.AnyMethod) {
Tree.AnyMethod am = (Tree.AnyMethod) decNode;
list = am.getParameterLists().get(0);
dec = am.getDeclarationModel();
}
else if (decNode instanceof Tree.AnyClass) {
Tree.AnyClass ac = (Tree.AnyClass) decNode;
list = ac.getParameterList();
dec = ac.getDeclarationModel();
}
else if (decNode instanceof Tree.SpecifierStatement) {
Tree.SpecifierStatement ss =
(Tree.SpecifierStatement) decNode;
Tree.Term lhs = ss.getBaseMemberExpression();
if (lhs instanceof Tree.ParameterizedExpression) {
Tree.ParameterizedExpression pe =
(Tree.ParameterizedExpression) lhs;
list = pe.getParameterLists().get(0);
dec = ss.getDeclaration();
}
else {
return;
}
}
else {
return;
}
Declaration rd = dec.getRefinedDeclaration();
if (dec==rd) {
rd = dec.getContainer()
.getDirectMember(dec.getName(),
null, false);
}
if (rd instanceof Functional &&
dec instanceof Functional) {
Functional rf = (Functional) rd;
Functional f = (Functional) dec;
List<ParameterList> rdPls =
rf.getParameterLists();
List<ParameterList> decPls =
f.getParameterLists();
if (rdPls.isEmpty() || decPls.isEmpty()) {
return;
}
List<Parameter> rdpl =
rdPls.get(0)
.getParameters();
List<Parameter> dpl =
decPls.get(0)
.getParameters();
Scope decContainer = dec.getContainer();
Scope rdContainer = rd.getContainer();
Type supertype;
if (decContainer instanceof TypeDeclaration &&
rdContainer instanceof TypeDeclaration) {
TypeDeclaration dctd =
(TypeDeclaration)
decContainer;
TypeDeclaration rdctd =
(TypeDeclaration)
rdContainer;
supertype =
dctd.getType()
.getSupertype(rdctd);
}
else {
supertype = null;
}
Reference pr =
rd.appliedReference(supertype,
Collections.<Type>emptyList());
List<Tree.Parameter> params =
list.getParameters();
TextFileChange change =
new TextFileChange(
"Fix Refining Parameter List",
file);
change.setEdit(new MultiTextEdit());
Unit unit = decNode.getUnit();
Set<Declaration> declarations =
new HashSet<Declaration>();
for (int i=0; i<params.size(); i++) {
Tree.Parameter p = params.get(i);
if (rdpl.size()<=i) {
int start = i==0 ?
list.getStartIndex()+1 :
params.get(i-1)
.getEndIndex();
int stop =
params.get(params.size()-1)
.getEndIndex();
change.addEdit(new DeleteEdit(start, stop-start));
break;
}
else {
Parameter rdp = rdpl.get(i);
Type pt =
pr.getTypedParameter(rdp)
.getFullType();
Type dt =
dpl.get(i).getModel()
.getTypedReference()
.getFullType();
if (!dt.isExactly(pt)) {
change.addEdit(new ReplaceEdit(
p.getStartIndex(),
p.getDistance(),
//TODO: better handling for callable parameters
pt.asSourceCodeString(unit) + " " + rdp.getName()));
importProposals().importType(declarations, pt, cu);
}
}
}
if (rdpl.size()>params.size()) {
StringBuilder buf = new StringBuilder();
for (int i=params.size();
i<rdpl.size();
i++) {
Parameter rdp = rdpl.get(i);
if (i>0) {
buf.append(", ");
}
appendParameterText(buf, pr, rdp, unit);
Type pt =
pr.getTypedParameter(rdp).getFullType();
importProposals().importType(declarations, pt, cu);
}
Integer offset =
params.isEmpty() ?
list.getStartIndex()+1 :
params.get(params.size()-1)
.getEndIndex();
change.addEdit(new InsertEdit(offset,
buf.toString()));
}
TextChange chg2 = new platformJ2C().newChange(change.getName(), change);
importProposals().applyImports(chg2, declarations, cu, chg2.getDocument());
if (change.getEdit().hasChildren()) {
Region selection =
new Region(list.getStartIndex()+1,
0);
proposals.add(new CorrectionProposal(
"Fix refining parameter list",
change, selection));
}
}
}
}