/** * 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; } }