001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * If you wish your version of this file to be governed by only the CDDL
025: * or only the GPL Version 2, indicate your decision by adding
026: * "[Contributor] elects to include this software in this distribution
027: * under the [CDDL or GPL Version 2] license." If you do not indicate a
028: * single choice of license, a recipient has the option to distribute
029: * your version of this file under either the CDDL, the GPL Version 2 or
030: * to extend the choice of license to its licensees as provided above.
031: * However, if you add GPL Version 2 code and therefore, elected the GPL
032: * Version 2 license, then the option applies only if the new code is
033: * made subject to such option by the copyright holder.
034: *
035: * Contributor(s):
036: *
037: * Portions Copyrighted 2007 Sun Microsystems, Inc.
038: */
039: package org.netbeans.modules.ruby.hints.introduce;
040:
041: import java.util.ArrayList;
042: import java.util.Collections;
043: import java.util.List;
044: import org.jruby.ast.BignumNode;
045: import org.jruby.ast.DRegexpNode;
046: import org.jruby.ast.DStrNode;
047: import org.jruby.ast.FixnumNode;
048: import org.jruby.ast.FloatNode;
049: import org.jruby.ast.Node;
050: import org.jruby.ast.NodeTypes;
051: import org.jruby.ast.StrNode;
052: import org.jruby.ast.SymbolNode;
053: import org.jruby.ast.XStrNode;
054: import org.netbeans.modules.gsf.api.CompilationInfo;
055: import org.netbeans.modules.gsf.api.OffsetRange;
056: import org.netbeans.editor.BaseDocument;
057: import org.netbeans.modules.ruby.AstUtilities;
058:
059: /**
060: * Detect duplicates of a given subtree in a large parse tree.
061: *
062: * @author Tor Norbye
063: */
064: public class DuplicateDetector {
065:
066: private CompilationInfo info;
067: private BaseDocument doc;
068: private List<Node> nodes;
069: private Node startNode;
070: private Node endNode;
071: private Node root;
072: private int currentStart;
073: private int currentEnd;
074: private List<OffsetRange> duplicates = new ArrayList<OffsetRange>();
075:
076: public DuplicateDetector(CompilationInfo info, BaseDocument doc,
077: Node root, List<Node> nodes, Node startNode, Node endNode) {
078: this .info = info;
079: this .doc = doc;
080: this .root = root;
081: this .nodes = nodes;
082: this .startNode = startNode;
083: this .endNode = endNode;
084: }
085:
086: public static List<OffsetRange> findDuplicates(
087: CompilationInfo info, BaseDocument doc, Node root,
088: List<Node> nodes, Node startNode, Node endNode) {
089: // I only support trivial duplicates now (single node constants like strings, numbers etc.
090: if (nodes.size() == 0 || startNode != endNode) {
091: return Collections.emptyList();
092: }
093:
094: if (startNode.nodeId == NodeTypes.ARRAYNODE) {
095: if (startNode.childNodes().size() == 1) {
096: startNode = (Node) startNode.childNodes().get(0);
097: } else {
098: return Collections.emptyList();
099: }
100: }
101: DuplicateDetector detector = new DuplicateDetector(info, doc,
102: root, nodes, startNode, endNode);
103: detector.visit(root, startNode);
104: return detector.duplicates;
105: }
106:
107: private void visit(Node node, Node target) {
108: if (node.nodeId == target.nodeId) {
109: //OffsetRange range = getEquivalentTree(child);
110: //if (range != OffsetRange.NONE) {
111: // duplicates.add(range);
112: //}
113: // No useful equals implementations on these puppies yet
114: //if (node.equals(target)) {
115: // duplicates.add(AstUtilities.getRange(node));
116: //} else {
117: boolean equal = false;
118: switch (node.nodeId) {
119: // TODO - compare HashNodes
120: case NodeTypes.FLOATNODE: {
121: equal = (((FloatNode) node).getValue() == ((FloatNode) target)
122: .getValue());
123: break;
124: }
125: case NodeTypes.BIGNUMNODE: {
126: equal = (((BignumNode) node).getValue() == ((BignumNode) target)
127: .getValue());
128: break;
129: }
130: case NodeTypes.FIXNUMNODE: {
131: equal = (((FixnumNode) node).getValue() == ((FixnumNode) target)
132: .getValue());
133: break;
134: }
135: case NodeTypes.SYMBOLNODE: {
136: equal = ((SymbolNode) node).getName().equals(
137: ((SymbolNode) target).getName());
138: break;
139: }
140: case NodeTypes.STRNODE: {
141: equal = ((StrNode) node).getValue().equals(
142: ((StrNode) target).getValue());
143: break;
144: }
145: case NodeTypes.XSTRNODE: {
146: equal = ((XStrNode) node).getValue().equals(
147: ((XStrNode) target).getValue());
148: break;
149: }
150: //case NodeTypes.DSTRNODE: {
151: // equal = ((DStrNode)node).getValue().equals(((DStrNode)target).getValue());
152: // break;
153: //}
154: //case NodeTypes.DREGEXPNODE: {
155: // equal = ((DRegexpNode)node).getValue().equals(((DRegexpNode)target).getValue());
156: // break;
157: //}
158: }
159:
160: if (equal) {
161: duplicates.add(AstUtilities.getRange(node));
162: }
163: //}
164: }
165: @SuppressWarnings("unchecked")
166: List<Node> list = node.childNodes();
167:
168: for (Node child : list) {
169: visit(child, target);
170: }
171: }
172: //private OffsetRange getEquivalentTree(Node top) {
173: // // Recursively check the given top and if the trees are equivalent return the range
174: // return OffsetRange.NONE;
175: //}
176: }
|