package com.redhat.ceylon.eclipse.code.correct;
import java.util.Collection;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.ltk.core.refactoring.TextChange;
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 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.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.FunctionOrValue;
public class JoinDeclarationProposal {
static void addJoinDeclarationProposal(final Collection<ICompletionProposal> proposals,
Tree.CompilationUnit rootNode, final Tree.Statement statement, final IFile file) {
if (statement instanceof Tree.SpecifierStatement) {
final Tree.SpecifierStatement spec =
(Tree.SpecifierStatement) statement;
Tree.Term term = spec.getBaseMemberExpression();
while (term instanceof Tree.ParameterizedExpression) {
term = ((Tree.ParameterizedExpression) term).getPrimary();
}
if (term instanceof Tree.BaseMemberExpression) {
final Declaration dec =
((Tree.BaseMemberExpression) term).getDeclaration();
if (dec instanceof FunctionOrValue) {
class FindBodyVisitor extends Visitor {
@Override
public void visit(Tree.Body that) {
super.visit(that);
if (that.getStatements().contains(statement)) {
for (Tree.Statement st: that.getStatements()) {
if (st instanceof Tree.AttributeDeclaration) {
Tree.AttributeDeclaration ad =
(Tree.AttributeDeclaration) st;
if (ad.getDeclarationModel().equals(dec) &&
ad.getSpecifierOrInitializerExpression()==null) {
createJoinDeclarationProposal(proposals,
spec, file, dec, that,
that.getStatements().indexOf(st),
ad);
break;
}
}
else if (st instanceof Tree.MethodDeclaration) {
Tree.MethodDeclaration ad =
(Tree.MethodDeclaration) st;
if (ad.getDeclarationModel().equals(dec) &&
ad.getSpecifierExpression()==null) {
createJoinDeclarationProposal(proposals,
spec, file, dec, that,
that.getStatements().indexOf(st),
ad);
break;
}
}
}
}
}
}
new FindBodyVisitor().visit(rootNode);
}
}
}
if (statement instanceof Tree.AttributeDeclaration ||
statement instanceof Tree.MethodDeclaration) {
final Tree.TypedDeclaration ad =
(Tree.TypedDeclaration) statement;
Tree.SpecifierOrInitializerExpression sie = null;
if (statement instanceof Tree.AttributeDeclaration) {
sie = ((Tree.AttributeDeclaration) ad).getSpecifierOrInitializerExpression();
}
else if (statement instanceof Tree.MethodDeclaration) {
sie = ((Tree.MethodDeclaration) ad).getSpecifierExpression();
}
if (sie==null) {
final Declaration dec = ad.getDeclarationModel();
class FindBodyVisitor extends Visitor {
@Override
public void visit(Tree.Body that) {
super.visit(that);
if (that.getStatements().contains(statement)) {
for (Tree.Statement st: that.getStatements()) {
if (st instanceof Tree.SpecifierStatement) {
final Tree.SpecifierStatement spec =
(Tree.SpecifierStatement) st;
Tree.Term term = spec.getBaseMemberExpression();
while (term instanceof Tree.ParameterizedExpression) {
term = ((Tree.ParameterizedExpression) term).getPrimary();
}
if (term instanceof Tree.BaseMemberExpression) {
Declaration sd =
((Tree.BaseMemberExpression) term).getDeclaration();
if (sd!=null && sd.equals(dec)) {
createJoinDeclarationProposal(proposals,
spec, file, dec, that,
that.getStatements().indexOf(statement),
ad);
break;
}
}
}
}
}
}
}
new FindBodyVisitor().visit(rootNode);
}
}
}
private static void createJoinDeclarationProposal(
Collection<ICompletionProposal> proposals,
Tree.SpecifierStatement statement,
IFile file, Declaration dec,
Tree.Body that, int i, Tree.TypedDeclaration ad) {
TextChange change = new TextFileChange("Join Declaration", file);
change.setEdit(new MultiTextEdit());
IDocument document = EditorUtil.getDocument(change);
String text;
int declarationStart = ad.getStartIndex();
int declarationIdStart = ad.getIdentifier().getStartIndex();
int declarationLength = ad.getDistance();
if (that.getStatements().size()>i+1) {
Tree.Statement next = that.getStatements().get(i+1);
declarationLength=next.getStartIndex()-declarationStart;
}
try {
text = document.get(declarationStart,
declarationIdStart-declarationStart);
}
catch (BadLocationException e) {
e.printStackTrace();
return;
}
change.addEdit(new DeleteEdit(declarationStart, declarationLength));
int specifierStart = statement.getStartIndex();
change.addEdit(new InsertEdit(specifierStart, text));
String desc = "Join declaration of '" + dec.getName() + "' with specification";
proposals.add(new CorrectionProposal(desc, change,
new Region(specifierStart-declarationLength, 0)));
}
}