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: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.refactoring.java.plugins;
043:
044: import com.sun.source.tree.*;
045: import com.sun.source.tree.Tree.Kind;
046: import com.sun.source.util.TreePath;
047: import com.sun.source.util.Trees;
048: import java.util.ArrayList;
049: import java.util.Collection;
050: import java.util.Collections;
051: import java.util.Iterator;
052: import java.util.Scanner;
053: import java.util.logging.Logger;
054: import javax.lang.model.element.*;
055: import javax.lang.model.type.TypeMirror;
056: import javax.lang.model.util.ElementFilter;
057: import org.netbeans.api.java.lexer.JavaTokenId;
058: import org.netbeans.api.java.source.ElementUtilities;
059: import org.netbeans.api.java.source.WorkingCopy;
060: import org.netbeans.api.lexer.Token;
061: import org.netbeans.api.lexer.TokenSequence;
062:
063: /**
064: *
065: * @author Jan Becicka
066: */
067: public class FindUsagesVisitor extends FindVisitor {
068:
069: private boolean findInComments = false;
070: private Collection<UsageInComment> usagesInComments = Collections
071: .<UsageInComment> emptyList();
072:
073: public FindUsagesVisitor(WorkingCopy workingCopy) {
074: super (workingCopy);
075: }
076:
077: public Collection<UsageInComment> getUsagesInComments() {
078: return usagesInComments;
079: }
080:
081: public FindUsagesVisitor(WorkingCopy workingCopy,
082: boolean findInComments) {
083: super (workingCopy);
084: this .findInComments = findInComments;
085: if (findInComments) {
086: usagesInComments = new ArrayList<UsageInComment>();
087: }
088: }
089:
090: @Override
091: public Tree visitCompilationUnit(CompilationUnitTree node, Element p) {
092: if (findInComments) {
093: String originalName = p.getSimpleName().toString();
094: TokenSequence<JavaTokenId> ts = workingCopy
095: .getTokenHierarchy().tokenSequence(
096: JavaTokenId.language());
097:
098: while (ts.moveNext()) {
099: Token t = ts.token();
100:
101: if (t.id() == JavaTokenId.BLOCK_COMMENT
102: || t.id() == JavaTokenId.LINE_COMMENT
103: || t.id() == JavaTokenId.JAVADOC_COMMENT) {
104: Scanner tokenizer = new Scanner(t.text().toString());
105: tokenizer.useDelimiter("[^a-zA-Z_]"); //NO18N
106:
107: while (tokenizer.hasNext()) {
108: String current = tokenizer.next();
109: if (current.equals(originalName)) {
110: usagesInComments.add(new UsageInComment(ts
111: .offset()
112: + tokenizer.match().start(), ts
113: .offset()
114: + tokenizer.match().end()));
115: }
116: }
117: }
118: }
119: }
120: return super .visitCompilationUnit(node, p);
121: }
122:
123: @Override
124: public Tree visitIdentifier(IdentifierTree node, Element p) {
125: addIfMatch(getCurrentPath(), node, p);
126: return super .visitIdentifier(node, p);
127: }
128:
129: @Override
130: public Tree visitMemberSelect(MemberSelectTree node, Element p) {
131: addIfMatch(getCurrentPath(), node, p);
132: return super .visitMemberSelect(node, p);
133: }
134:
135: @Override
136: public Tree visitNewClass(NewClassTree node, Element p) {
137: Trees trees = workingCopy.getTrees();
138: ClassTree classTree = ((NewClassTree) node).getClassBody();
139: if (classTree != null && p.getKind() == ElementKind.CONSTRUCTOR) {
140: Element anonClass = workingCopy.getTrees().getElement(
141: TreePath.getPath(workingCopy.getCompilationUnit(),
142: classTree));
143: if (anonClass == null) {
144: Logger.getLogger(
145: "org.netbeans.modules.refactoring.java")
146: .severe(
147: "FindUsages cannot resolve "
148: + classTree);
149: } else {
150: for (ExecutableElement c : ElementFilter
151: .constructorsIn(anonClass.getEnclosedElements())) {
152: MethodTree t = workingCopy.getTrees().getTree(c);
153: TreePath super Call = trees.getPath(workingCopy
154: .getCompilationUnit(),
155: ((ExpressionStatementTree) t.getBody()
156: .getStatements().get(0))
157: .getExpression());
158: Element super CallElement = trees
159: .getElement(super Call);
160: if (super CallElement != null
161: && super CallElement.equals(p)) {
162: addUsage(super Call);
163: }
164: }
165: }
166: } else {
167: addIfMatch(getCurrentPath(), node, p);
168: }
169: return super .visitNewClass(node, p);
170: }
171:
172: private void addIfMatch(TreePath path, Tree tree,
173: Element elementToFind) {
174: if (workingCopy.getTreeUtilities().isSynthetic(path)) {
175: return;
176: }
177: Trees trees = workingCopy.getTrees();
178: Element el = trees.getElement(path);
179: if (el == null) {
180: path = path.getParentPath();
181: if (path != null && path.getLeaf().getKind() == Kind.IMPORT) {
182: ImportTree impTree = (ImportTree) path.getLeaf();
183: if (!impTree.isStatic()) {
184: return;
185: }
186: Tree idTree = impTree.getQualifiedIdentifier();
187: if (idTree.getKind() != Kind.MEMBER_SELECT) {
188: return;
189: }
190: final Name id = ((MemberSelectTree) idTree)
191: .getIdentifier();
192: Tree classTree = ((MemberSelectTree) idTree)
193: .getExpression();
194: path = trees.getPath(workingCopy.getCompilationUnit(),
195: classTree);
196: el = trees.getElement(path);
197: if (el == null) {
198: return;
199: }
200: Iterator iter = workingCopy.getElementUtilities()
201: .getMembers(el.asType(),
202: new ElementUtilities.ElementAcceptor() {
203: public boolean accept(Element e,
204: TypeMirror type) {
205: return id.equals(e
206: .getSimpleName());
207: }
208: }).iterator();
209: if (iter.hasNext()) {
210: el = (Element) iter.next();
211: }
212: if (iter.hasNext()) {
213: return;
214: }
215: } else {
216: return;
217: }
218: }
219: if (elementToFind != null
220: && elementToFind.getKind() == ElementKind.METHOD
221: && el.getKind() == ElementKind.METHOD) {
222: if (el.equals(elementToFind)
223: || workingCopy.getElements().overrides(
224: (ExecutableElement) el,
225: (ExecutableElement) elementToFind,
226: (TypeElement) elementToFind
227: .getEnclosingElement())) {
228: addUsage(getCurrentPath());
229: }
230: } else if (el.equals(elementToFind)) {
231: addUsage(getCurrentPath());
232: }
233: }
234:
235: public static class UsageInComment {
236: int from;
237: int to;
238:
239: public UsageInComment(int from, int to) {
240: this.from = from;
241: this.to = to;
242: }
243: }
244: }
|