package com.redhat.ceylon.eclipse.code.correct;
import static com.redhat.ceylon.eclipse.code.refactor.InvertBooleanRefactoring.invertTerm;
import static com.redhat.ceylon.eclipse.util.EditorUtil.getDocument;
import java.util.Collection;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.text.IDocument;
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 org.eclipse.text.edits.ReplaceEdit;
import com.redhat.ceylon.compiler.typechecker.parser.CeylonLexer;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;
@Deprecated
public class OperatorProposals {
static void addSwapBinaryOperandsProposal(
Collection<ICompletionProposal> proposals,
IFile file,
Tree.BinaryOperatorExpression boe) {
TextChange change =
new TextFileChange("Swap Operands",
file);
change.setEdit(new MultiTextEdit());
Tree.Term lt = boe.getLeftTerm();
Tree.Term rt = boe.getRightTerm();
if (lt!=null && rt!=null) {
int lto = lt.getStartIndex();
int ltl = lt.getDistance();
int rto = rt.getStartIndex();
int rtl = rt.getDistance();
IDocument document = getDocument(change);
try {
change.addEdit(new ReplaceEdit(lto, ltl,
document.get(rto, rtl)));
change.addEdit(new ReplaceEdit(rto, rtl,
document.get(lto, ltl)));
proposals.add(new CorrectionProposal(
"Swap operands of " +
boe.getMainToken().getText() +
" expression", change, null));
}
catch(Exception e) {
e.printStackTrace();
}
}
}
static void addReverseOperatorProposal(
Collection<ICompletionProposal> proposals,
IFile file,
Tree.BinaryOperatorExpression boe) {
if (boe instanceof Tree.ComparisonOp) {
TextChange change =
new TextFileChange("Reverse Operator",
file);
change.setEdit(new MultiTextEdit());
Tree.Term lt = boe.getLeftTerm();
Tree.Term rt = boe.getRightTerm();
if (lt!=null && rt!=null) {
int lto = lt.getStartIndex();
int ltl = lt.getDistance();
int rto = rt.getStartIndex();
int rtl = rt.getDistance();
CommonToken op =
(CommonToken) boe.getMainToken();
String ot = op.getText();
String iot = reversed(ot);
change.addEdit(new ReplaceEdit(
op.getStartIndex(),
ot.length(), iot));
if (boe instanceof Tree.ComparisonOp) {
IDocument document = getDocument(change);
try {
change.addEdit(new ReplaceEdit(
lto, ltl,
document.get(rto, rtl)));
change.addEdit(new ReplaceEdit(
rto, rtl,
document.get(lto, ltl)));
}
catch(Exception e) {
e.printStackTrace();
return;
}
}
proposals.add(new CorrectionProposal(
"Convert " + ot + " to " + iot,
change, null));
}
}
}
static void addInvertOperatorProposal(
Collection<ICompletionProposal> proposals,
IFile file,
Tree.BinaryOperatorExpression boe) {
if (boe instanceof Tree.ComparisonOp ||
boe instanceof Tree.LogicalOp) {
TextChange change =
new TextFileChange("Invert Operator",
file);
change.setEdit(new MultiTextEdit());
Tree.Term lt = boe.getLeftTerm();
Tree.Term rt = boe.getRightTerm();
if (lt!=null && rt!=null) {
CommonToken op =
(CommonToken) boe.getMainToken();
String ot = op.getText();
String iot = inverted(ot);
change.addEdit(new ReplaceEdit(
op.getStartIndex(),
ot.length(), iot));
change.addEdit(new InsertEdit(
boe.getStartIndex(), "!("));
change.addEdit(new InsertEdit(
boe.getEndIndex(), ")"));
if (boe instanceof Tree.LogicalOp) {
invertTerm(boe.getLeftTerm(), change);
invertTerm(boe.getRightTerm(), change);
}
proposals.add(new CorrectionProposal(
"Convert " + ot + " to " + iot,
change, null));
}
}
}
private static String inverted(String ot) {
switch (ot) {
case ">": return "<=";
case ">=": return "<";
case "<": return ">=";
case "<=": return ">";
case "||": return "&&";
case "&&": return "||";
default: return ot;
}
}
private static String reversed(String ot) {
switch (ot) {
case ">": return "<";
case ">=": return "<=";
case "<": return ">";
case "<=": return ">=";
default: return ot;
}
}
static void addParenthesesProposals(
Collection<ICompletionProposal> proposals,
IFile file, Node node,
Tree.CompilationUnit rootNode,
Tree.OperatorExpression oe) {
if (node instanceof Tree.ArgumentList) {
final Tree.ArgumentList argList =
(Tree.ArgumentList) node;
class FindInvocationVisitor extends Visitor {
Tree.InvocationExpression current;
Tree.InvocationExpression result;
@Override
public void visit(Tree.InvocationExpression that) {
Tree.InvocationExpression old = current;
current = that;
super.visit(that);
current = old;
}
@Override
public void visit(Tree.ArgumentList that) {
if (argList==that) {
result = current;
}
else {
super.visit(that);
}
}
}
FindInvocationVisitor fiv = new FindInvocationVisitor();
fiv.visit(rootNode);
node = fiv.result;
}
if (node instanceof Tree.Expression) {
addRemoveParenthesesProposal(proposals, file, node);
}
else if (node instanceof Tree.Term) {
addAddParenthesesProposal(proposals, file, node);
if (oe!=null && oe!=node) {
addAddParenthesesProposal(proposals, file, oe);
}
}
}
private static void addAddParenthesesProposal(
Collection<ICompletionProposal> proposals,
IFile file, Node node) {
String desc;
if (node instanceof Tree.OperatorExpression) {
desc = node.getMainToken().getText() +
" expression";
}
else if (node instanceof Tree.QualifiedMemberOrTypeExpression) {
desc = "member reference";
}
else if (node instanceof Tree.BaseMemberOrTypeExpression) {
desc = "base reference";
}
else if (node instanceof Tree.Literal) {
desc = "literal";
}
else if (node instanceof Tree.InvocationExpression) {
desc = "invocation";
}
else {
desc = "expression";
}
TextChange change =
new TextFileChange("Add Parentheses",
file);
change.setEdit(new MultiTextEdit());
change.addEdit(new InsertEdit(
node.getStartIndex(), "("));
change.addEdit(new InsertEdit(
node.getEndIndex(), ")"));
proposals.add(new CorrectionProposal(
"Parenthesize " + desc, change, null));
}
private static void addRemoveParenthesesProposal(
Collection<ICompletionProposal> proposals,
IFile file, Node node) {
Token token = node.getToken();
Token endToken = node.getEndToken();
if (token!=null && endToken!=null &&
token.getType()==CeylonLexer.LPAREN &&
endToken.getType()==CeylonLexer.RPAREN) {
TextChange change =
new TextFileChange("Remove Parentheses",
file);
change.setEdit(new MultiTextEdit());
change.addEdit(new DeleteEdit(
node.getStartIndex(), 1));
change.addEdit(new DeleteEdit(
node.getEndIndex()-1, 1));
proposals.add(new CorrectionProposal(
"Remove parentheses", change, null));
}
}
}