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.util.Trees;
045: import org.netbeans.modules.refactoring.java.spi.RefactoringVisitor;
046: import com.sun.source.tree.*;
047: import com.sun.source.util.TreePath;
048: import java.util.Iterator;
049: import java.util.Set;
050: import java.util.logging.Logger;
051: import javax.lang.model.element.*;
052: import javax.lang.model.type.TypeMirror;
053: import org.netbeans.api.java.lexer.JavaTokenId;
054: import org.netbeans.api.java.source.ElementHandle;
055: import org.netbeans.api.java.source.ElementUtilities;
056: import org.netbeans.api.java.source.SourceUtils;
057: import org.netbeans.api.lexer.Token;
058: import org.netbeans.api.lexer.TokenSequence;
059:
060: /**
061: *
062: * @author Jan Becicka
063: */
064: public class RenameTransformer extends RefactoringVisitor {
065:
066: private Set<ElementHandle<ExecutableElement>> allMethods;
067: private String newName;
068: private boolean renameInComments;
069:
070: public RenameTransformer(String newName,
071: Set<ElementHandle<ExecutableElement>> am,
072: boolean renameInComments) {
073: this .newName = newName;
074: this .allMethods = am;
075: this .renameInComments = renameInComments;
076: }
077:
078: @Override
079: public Tree visitCompilationUnit(CompilationUnitTree node, Element p) {
080: if (renameInComments) {
081: String originalName = getOldSimpleName(p);
082: if (originalName != null) {
083: TokenSequence<JavaTokenId> ts = workingCopy
084: .getTokenHierarchy().tokenSequence(
085: JavaTokenId.language());
086:
087: while (ts.moveNext()) {
088: Token t = ts.token();
089:
090: if (t.id() == JavaTokenId.BLOCK_COMMENT
091: || t.id() == JavaTokenId.LINE_COMMENT
092: || t.id() == JavaTokenId.JAVADOC_COMMENT) {
093: int index = -1;
094: String text = t.text().toString();
095:
096: while ((index = text.indexOf(originalName,
097: index + 1)) != (-1)) {
098: if (index > 0
099: && Character
100: .isJavaIdentifierPart(text
101: .charAt(index - 1))) {
102: continue;
103: }
104: if ((index + originalName.length() < text
105: .length())
106: && Character
107: .isJavaIdentifierPart(text
108: .charAt(index
109: + originalName
110: .length()))) {
111: continue;
112: }
113: workingCopy.rewriteInComment(ts.offset()
114: + index, originalName.length(),
115: newName);
116: }
117: }
118: }
119: }
120: }
121: return super .visitCompilationUnit(node, p);
122: }
123:
124: @Override
125: public Tree visitIdentifier(IdentifierTree node, Element p) {
126: renameUsageIfMatch(getCurrentPath(), node, p);
127: return super .visitIdentifier(node, p);
128: }
129:
130: @Override
131: public Tree visitMemberSelect(MemberSelectTree node, Element p) {
132: renameUsageIfMatch(getCurrentPath(), node, p);
133: return super .visitMemberSelect(node, p);
134: }
135:
136: private String getOldSimpleName(Element p) {
137: if (p != null) {
138: return p.getSimpleName().toString();
139: }
140: for (ElementHandle<ExecutableElement> mh : allMethods) {
141: ExecutableElement baseMethod = mh.resolve(workingCopy);
142: if (baseMethod == null) {
143: continue;
144: }
145: return baseMethod.getSimpleName().toString();
146: }
147: return null;
148: }
149:
150: private void renameUsageIfMatch(TreePath path, Tree tree,
151: Element elementToFind) {
152: if (workingCopy.getTreeUtilities().isSynthetic(path))
153: return;
154: Trees trees = workingCopy.getTrees();
155: Element el = workingCopy.getTrees().getElement(path);
156: if (el == null) {
157: path = path.getParentPath();
158: if (path != null
159: && path.getLeaf().getKind() == Tree.Kind.IMPORT) {
160: ImportTree impTree = (ImportTree) path.getLeaf();
161: if (!impTree.isStatic()) {
162: return;
163: }
164: Tree idTree = impTree.getQualifiedIdentifier();
165: if (idTree.getKind() != Tree.Kind.MEMBER_SELECT) {
166: return;
167: }
168: final Name id = ((MemberSelectTree) idTree)
169: .getIdentifier();
170: Tree classTree = ((MemberSelectTree) idTree)
171: .getExpression();
172: path = trees.getPath(workingCopy.getCompilationUnit(),
173: classTree);
174: el = trees.getElement(path);
175: if (el == null) {
176: return;
177: }
178: Iterator iter = workingCopy.getElementUtilities()
179: .getMembers(el.asType(),
180: new ElementUtilities.ElementAcceptor() {
181: public boolean accept(Element e,
182: TypeMirror type) {
183: return id.equals(e
184: .getSimpleName());
185: }
186: }).iterator();
187: if (iter.hasNext()) {
188: el = (Element) iter.next();
189: }
190: if (iter.hasNext()) {
191: return;
192: }
193: } else {
194: return;
195: }
196: }
197:
198: if (el.equals(elementToFind) || isMethodMatch(el)) {
199: String useThis = null;
200:
201: if (elementToFind != null
202: && elementToFind.getKind().isField()) {
203: Scope scope = workingCopy.getTrees().getScope(path);
204: for (Element ele : scope.getLocalElements()) {
205: if ((ele.getKind() == ElementKind.LOCAL_VARIABLE || ele
206: .getKind() == ElementKind.PARAMETER)
207: && ele.getSimpleName().toString().equals(
208: newName)) {
209: if (tree.getKind() == Tree.Kind.MEMBER_SELECT) {
210: String isThis = ((MemberSelectTree) tree)
211: .getExpression().toString();
212: if (isThis.equals("this")
213: || isThis.endsWith(".this")) { // NOI18N
214: break;
215: }
216: }
217: if (scope.getEnclosingClass().equals(
218: elementToFind.getEnclosingElement()))
219: useThis = "this."; // NOI18N
220: else
221: useThis = elementToFind
222: .getEnclosingElement()
223: .getSimpleName()
224: + ".this."; // NOI18N
225: break;
226: }
227: }
228: }
229: Tree nju;
230: if (useThis != null) {
231: nju = make.setLabel(tree, useThis + newName);
232: } else {
233: nju = make.setLabel(tree, newName);
234: }
235: rewrite(tree, nju);
236: }
237: }
238:
239: @Override
240: public Tree visitMethod(MethodTree tree, Element p) {
241: renameDeclIfMatch(getCurrentPath(), tree, p);
242: return super .visitMethod(tree, p);
243: }
244:
245: @Override
246: public Tree visitClass(ClassTree tree, Element p) {
247: renameDeclIfMatch(getCurrentPath(), tree, p);
248: return super .visitClass(tree, p);
249: }
250:
251: @Override
252: public Tree visitVariable(VariableTree tree, Element p) {
253: renameDeclIfMatch(getCurrentPath(), tree, p);
254: return super .visitVariable(tree, p);
255: }
256:
257: @Override
258: public Tree visitTypeParameter(TypeParameterTree arg0, Element arg1) {
259: renameDeclIfMatch(getCurrentPath(), arg0, arg1);
260: return super .visitTypeParameter(arg0, arg1);
261: }
262:
263: private void renameDeclIfMatch(TreePath path, Tree tree,
264: Element elementToFind) {
265: if (workingCopy.getTreeUtilities().isSynthetic(path))
266: return;
267: Element el = workingCopy.getTrees().getElement(path);
268: if (el == null) {
269: return;
270: }
271: if (el.equals(elementToFind) || isMethodMatch(el)) {
272: Tree nju = make.setLabel(tree, newName);
273: rewrite(tree, nju);
274: return;
275: }
276: }
277:
278: private boolean isMethodMatch(Element method) {
279: if (method.getKind() == ElementKind.METHOD
280: && allMethods != null) {
281: for (ElementHandle<ExecutableElement> mh : allMethods) {
282: ExecutableElement baseMethod = mh.resolve(workingCopy);
283: if (baseMethod == null) {
284: Logger.getLogger(
285: "org.netbeans.modules.refactoring.java")
286: .info(
287: "RenameTransformer cannot resolve "
288: + mh);
289: continue;
290: }
291: if (baseMethod.equals(method)
292: || workingCopy
293: .getElements()
294: .overrides(
295: (ExecutableElement) method,
296: baseMethod,
297: SourceUtils
298: .getEnclosingTypeElement(baseMethod))) {
299: return true;
300: }
301: }
302: }
303: return false;
304: }
305: }
|