/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. * * Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common * Development and Distribution License("CDDL") (collectively, the * "License"). You may not use this file except in compliance with the * License. You can obtain a copy of the License at * http://www.netbeans.org/cddl-gplv2.html * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the * specific language governing permissions and limitations under the * License. When distributing the software, include this License Header * Notice in each file and include the License file at * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the * License Header, with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * If you wish your version of this file to be governed by only the CDDL * or only the GPL Version 2, indicate your decision by adding * "[Contributor] elects to include this software in this distribution * under the [CDDL or GPL Version 2] license." If you do not indicate a * single choice of license, a recipient has the option to distribute * your version of this file under either the CDDL, the GPL Version 2 or * to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. * * Contributor(s): * * Portions Copyrighted 2007 Sun Microsystems, Inc. */ package org.netbeans.modules.ruby.hints.introduce; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.jrubyparser.ast.BignumNode; import org.jrubyparser.ast.FixnumNode; import org.jrubyparser.ast.FloatNode; import org.jrubyparser.ast.Node; import org.jrubyparser.ast.NodeType; import org.jrubyparser.ast.StrNode; import org.jrubyparser.ast.SymbolNode; import org.jrubyparser.ast.XStrNode; import org.netbeans.editor.BaseDocument; import org.netbeans.modules.csl.api.OffsetRange; import org.netbeans.modules.csl.spi.ParserResult; import org.netbeans.modules.ruby.AstUtilities; /** * Detect duplicates of a given subtree in a large parse tree. * * @author Tor Norbye */ public class DuplicateDetector { private ParserResult info; private BaseDocument doc; private List<Node> nodes; private Node startNode; private Node endNode; private Node root; private int currentStart; private int currentEnd; private List<OffsetRange> duplicates = new ArrayList<OffsetRange>(); public DuplicateDetector(ParserResult info, BaseDocument doc, Node root, List<Node> nodes, Node startNode, Node endNode) { this.info = info; this.doc = doc; this.root = root; this.nodes = nodes; this.startNode = startNode; this.endNode = endNode; } public static List<OffsetRange> findDuplicates(ParserResult info, BaseDocument doc, Node root, List<Node> nodes, Node startNode, Node endNode) { // I only support trivial duplicates now (single node constants like strings, numbers etc. if (nodes.size() == 0 || startNode != endNode) { return Collections.emptyList(); } if (startNode.getNodeType() == NodeType.ARRAYNODE) { if (startNode.childNodes().size() == 1) { startNode = startNode.childNodes().get(0); } else { return Collections.emptyList(); } } DuplicateDetector detector = new DuplicateDetector(info, doc, root, nodes, startNode, endNode); detector.visit(root, startNode); return detector.duplicates; } private void visit(Node node, Node target) { if (node.getNodeType() == target.getNodeType()) { //OffsetRange range = getEquivalentTree(child); //if (range != OffsetRange.NONE) { // duplicates.add(range); //} // No useful equals implementations on these puppies yet //if (node.equals(target)) { // duplicates.add(AstUtilities.getRange(node)); //} else { boolean equal = false; switch (node.getNodeType()) { // TODO - compare HashNodes case FLOATNODE: { equal = (((FloatNode) node).getValue() == ((FloatNode) target).getValue()); break; } case BIGNUMNODE: { equal = (((BignumNode) node).getValue() == ((BignumNode) target).getValue()); break; } case FIXNUMNODE: { equal = (((FixnumNode) node).getValue() == ((FixnumNode) target).getValue()); break; } case SYMBOLNODE: { equal = ((SymbolNode) node).getName().equals(((SymbolNode) target).getName()); break; } case STRNODE: { equal = ((StrNode) node).getValue().equals(((StrNode) target).getValue()); break; } case XSTRNODE: { equal = ((XStrNode) node).getValue().equals(((XStrNode) target).getValue()); break; } //case DSTRNODE: { // equal = ((DStrNode)node).getValue().equals(((DStrNode)target).getValue()); // break; //} //case DREGEXPNODE: { // equal = ((DRegexpNode)node).getValue().equals(((DRegexpNode)target).getValue()); // break; //} } if (equal) { duplicates.add(AstUtilities.getRange(node)); } //} } List<Node> list = node.childNodes(); for (Node child : list) { if (child.isInvisible()) { continue; } visit(child, target); } } //private OffsetRange getEquivalentTree(Node top) { // // Recursively check the given top and if the trees are equivalent return the range // return OffsetRange.NONE; //} }