/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package org.python.pydev.refactoring.ast.visitors;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.TextSelection;
import org.python.pydev.core.docutils.ParsingUtils;
import org.python.pydev.core.docutils.PySelection;
import org.python.pydev.parser.jython.SimpleNode;
import org.python.pydev.parser.jython.ast.Assert;
import org.python.pydev.parser.jython.ast.Assign;
import org.python.pydev.parser.jython.ast.Attribute;
import org.python.pydev.parser.jython.ast.AugAssign;
import org.python.pydev.parser.jython.ast.BinOp;
import org.python.pydev.parser.jython.ast.BoolOp;
import org.python.pydev.parser.jython.ast.Break;
import org.python.pydev.parser.jython.ast.Call;
import org.python.pydev.parser.jython.ast.ClassDef;
import org.python.pydev.parser.jython.ast.Compare;
import org.python.pydev.parser.jython.ast.Comprehension;
import org.python.pydev.parser.jython.ast.Continue;
import org.python.pydev.parser.jython.ast.Delete;
import org.python.pydev.parser.jython.ast.Dict;
import org.python.pydev.parser.jython.ast.DictComp;
import org.python.pydev.parser.jython.ast.Ellipsis;
import org.python.pydev.parser.jython.ast.Exec;
import org.python.pydev.parser.jython.ast.Expr;
import org.python.pydev.parser.jython.ast.Expression;
import org.python.pydev.parser.jython.ast.ExtSlice;
import org.python.pydev.parser.jython.ast.For;
import org.python.pydev.parser.jython.ast.FunctionDef;
import org.python.pydev.parser.jython.ast.GeneratorExp;
import org.python.pydev.parser.jython.ast.Global;
import org.python.pydev.parser.jython.ast.If;
import org.python.pydev.parser.jython.ast.IfExp;
import org.python.pydev.parser.jython.ast.Import;
import org.python.pydev.parser.jython.ast.ImportFrom;
import org.python.pydev.parser.jython.ast.Index;
import org.python.pydev.parser.jython.ast.Interactive;
import org.python.pydev.parser.jython.ast.Lambda;
import org.python.pydev.parser.jython.ast.ListComp;
import org.python.pydev.parser.jython.ast.Module;
import org.python.pydev.parser.jython.ast.Name;
import org.python.pydev.parser.jython.ast.NameTok;
import org.python.pydev.parser.jython.ast.NonLocal;
import org.python.pydev.parser.jython.ast.Num;
import org.python.pydev.parser.jython.ast.Pass;
import org.python.pydev.parser.jython.ast.Print;
import org.python.pydev.parser.jython.ast.Raise;
import org.python.pydev.parser.jython.ast.Repr;
import org.python.pydev.parser.jython.ast.Return;
import org.python.pydev.parser.jython.ast.Set;
import org.python.pydev.parser.jython.ast.SetComp;
import org.python.pydev.parser.jython.ast.Slice;
import org.python.pydev.parser.jython.ast.Starred;
import org.python.pydev.parser.jython.ast.Str;
import org.python.pydev.parser.jython.ast.StrJoin;
import org.python.pydev.parser.jython.ast.Subscript;
import org.python.pydev.parser.jython.ast.Suite;
import org.python.pydev.parser.jython.ast.TryExcept;
import org.python.pydev.parser.jython.ast.TryFinally;
import org.python.pydev.parser.jython.ast.UnaryOp;
import org.python.pydev.parser.jython.ast.VisitorIF;
import org.python.pydev.parser.jython.ast.While;
import org.python.pydev.parser.jython.ast.With;
import org.python.pydev.parser.jython.ast.WithItem;
import org.python.pydev.parser.jython.ast.Yield;
import org.python.pydev.parser.jython.ast.exprType;
import org.python.pydev.parser.visitors.NodeUtils;
import com.aptana.shared_core.string.FastStringBuffer;
import com.aptana.shared_core.structure.Tuple;
/**
* @author fabioz
*
*/
public class FindDuplicatesVisitor implements VisitorIF {
private final exprType expression;
private final ITextSelection selection;
private final List<Tuple<ITextSelection, SimpleNode>> duplicates = new ArrayList<Tuple<ITextSelection, SimpleNode>>();
private final IDocument doc;
private final PySelection ps;
private final char[] selectedText;
private SimpleNode lastFound = null;
private ParsingUtils parsingUtils;
public FindDuplicatesVisitor(ITextSelection selection, exprType expression, IDocument doc) {
this.selection = selection;
this.expression = expression;
this.doc = doc;
this.ps = new PySelection(this.doc, selection);
FastStringBuffer buf = new FastStringBuffer(ps.getSelectedText(), 0);
ParsingUtils.removeCommentsAndWhitespaces(buf);
buf.replaceAll("\\", ""); //Remove all the \\
selectedText = buf.toCharArray();
parsingUtils = ParsingUtils.create(this.doc);
}
protected boolean unhandled_node(SimpleNode node) throws Exception {
this.addLastFound(node);
if (node.equals(expression)) {
lastFound = node;
return false;
}
return true;
}
public void finish() {
addLastFound(null);
}
private int getLineDefinition(SimpleNode ast2) {
while (ast2 instanceof Attribute || ast2 instanceof Call) {
if (ast2 instanceof Attribute) {
ast2 = ((Attribute) ast2).value;
} else {
Call c = (Call) ast2;
if (c.func != null) {
ast2 = c.func;
} else {
break;
}
}
}
return ast2.beginLine;
}
private void addLastFound(SimpleNode nextNode) {
if (lastFound != null) {
int offset = ps.getAbsoluteCursorOffset(getLineDefinition(lastFound) - 1,
NodeUtils.getColDefinition(lastFound) - 1);
//OK, we have the start point, let's calculate the match based on the document
//(with the next node as a boundary if it was provided)
int maxOffset = doc.getLength();
if (nextNode != null) {
int nextTokenOffset = ps.getAbsoluteCursorOffset(NodeUtils.getLineDefinition(nextNode) - 1,
NodeUtils.getColDefinition(nextNode) - 1) + 1;
if (nextTokenOffset < maxOffset) {
maxOffset = nextTokenOffset;
}
}
int j = 0;
int len = 0;
for (int i = offset; i < maxOffset && j < selectedText.length; i++, len++) {
char c;
try {
c = doc.getChar(i);
} catch (BadLocationException e) {
break;
}
//Let's see if we have the match
char c1 = selectedText[j];
if (c == c1) {
j++;
} else {
if (c == '#') {
int start = i;
i = parsingUtils.eatComments(null, i);
len += i - start;
} else if (!Character.isWhitespace(c) && c != '\\') {
//We removed comments and whitespaces from the original, so, we can ignore it
//here too, but if we found some other char, it's NOT a match...
break;
}
}
}
if (j == selectedText.length) {
if (!ps.intersects(offset, len)) {
ITextSelection sel = new TextSelection(this.doc, offset, len);
duplicates.add(new Tuple<ITextSelection, SimpleNode>(sel, lastFound));
}
}
lastFound = null;
}
}
/**
* Visit each of the children one by one.
* @args node The node whose children will be visited.
*/
public void traverse(SimpleNode node) throws Exception {
node.traverse(this);
}
/**
* @return
*/
public List<Tuple<ITextSelection, SimpleNode>> getDuplicates() {
return duplicates;
}
public Object visitFunctionDef(FunctionDef node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitClassDef(ClassDef node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitModule(Module node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitInteractive(Interactive node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitExpression(Expression node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitNameTok(NameTok node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitSuite(Suite node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitWithItem(WithItem node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitReturn(Return node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitDelete(Delete node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitAssign(Assign node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitAugAssign(AugAssign node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitPrint(Print node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitFor(For node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitWhile(While node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitIf(If node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitWith(With node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitRaise(Raise node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitTryExcept(TryExcept node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitTryFinally(TryFinally node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitAssert(Assert node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitImport(Import node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitImportFrom(ImportFrom node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitExec(Exec node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitGlobal(Global node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitNonLocal(NonLocal node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitExpr(Expr node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitPass(Pass node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitBreak(Break node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitContinue(Continue node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitBoolOp(BoolOp node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitBinOp(BinOp node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitUnaryOp(UnaryOp node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitLambda(Lambda node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitIfExp(IfExp node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitDict(Dict node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitSet(Set node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitListComp(ListComp node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitSetComp(SetComp node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitDictComp(DictComp node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitGeneratorExp(GeneratorExp node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitYield(Yield node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitCompare(Compare node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitCall(Call node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitRepr(Repr node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitNum(Num node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitStr(Str node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitStrJoin(StrJoin node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitAttribute(Attribute node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitSubscript(Subscript node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitStarred(Starred node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitName(Name node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitList(org.python.pydev.parser.jython.ast.List node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitTuple(org.python.pydev.parser.jython.ast.Tuple node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitEllipsis(Ellipsis node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitSlice(Slice node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitExtSlice(ExtSlice node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitIndex(Index node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
public Object visitComprehension(Comprehension node) throws Exception {
boolean ret = unhandled_node(node);
if (ret) {
traverse(node);
}
return null;
}
}