001: /*
002: * Sun Public License Notice
003: *
004: * The contents of this file are subject to the Sun Public License
005: * Version 1.0 (the "License"). You may not use this file except in
006: * compliance with the License. A copy of the License is available at
007: * http://www.sun.com/
008: *
009: * The Original Code is NetBeans. The Initial Developer of the Original
010: * Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun
011: * Microsystems, Inc. All Rights Reserved.
012:
013: If you wish your version of this file to be governed by only the CDDL
014: or only the GPL Version 2, indicate your decision by adding
015: "[Contributor] elects to include this software in this distribution
016: under the [CDDL or GPL Version 2] license." If you do not indicate a
017: single choice of license, a recipient has the option to distribute
018: your version of this file under either the CDDL, the GPL Version 2 or
019: to extend the choice of license to its licensees as provided above.
020: However, if you add GPL Version 2 code and therefore, elected the GPL
021: Version 2 license, then the option applies only if the new code is
022: made subject to such option by the copyright holder.
023: */
024:
025: package org.netbeans.modules.refactoring.java.plugins;
026:
027: import org.netbeans.modules.refactoring.java.api.*;
028: import com.sun.source.tree.AssignmentTree;
029: import com.sun.source.tree.ExpressionTree;
030: import com.sun.source.tree.MemberSelectTree;
031: import com.sun.source.tree.Tree;
032: import com.sun.source.tree.VariableTree;
033: import com.sun.source.util.TreePath;
034: import com.sun.source.util.Trees;
035: import java.util.List;
036: import java.util.Set;
037: import javax.lang.model.element.Element;
038: import javax.lang.model.element.ElementKind;
039: import javax.lang.model.element.ExecutableElement;
040: import javax.lang.model.element.Modifier;
041: import javax.lang.model.element.TypeElement;
042: import javax.lang.model.element.VariableElement;
043: import javax.lang.model.type.DeclaredType;
044: import javax.lang.model.type.TypeKind;
045: import javax.lang.model.type.TypeMirror;
046: import javax.lang.model.util.Elements;
047: import javax.lang.model.util.Types;
048: import org.netbeans.api.java.source.WorkingCopy;
049: import org.netbeans.modules.refactoring.java.spi.RefactoringVisitor;
050: import org.netbeans.modules.refactoring.java.spi.ToPhaseException;
051: import org.openide.util.Exceptions;
052:
053: /**
054: * @author Jan Becicka, Bharath Ravi Kumar
055: */
056: class VarUsageVisitor extends RefactoringVisitor {
057:
058: private final TypeElement super TypeElement;
059: private final TypeElement subTypeElement;
060: private boolean isReplCandidate = true;
061:
062: VarUsageVisitor(TypeElement subTypeElement,
063: WorkingCopy workingCopy, TypeElement super TypeElem) {
064: try {
065: setWorkingCopy(workingCopy);
066: } catch (ToPhaseException ex) {
067: Exceptions.printStackTrace(ex);
068: }
069: this .super TypeElement = super TypeElem;
070: this .subTypeElement = subTypeElement;
071: }
072:
073: @Override
074: public Tree visitMemberSelect(MemberSelectTree memSelectTree,
075: Element refVarElem) {
076:
077: Element methodElement = this .asElement(memSelectTree);
078: Element varElement = asElement(memSelectTree.getExpression());
079: if (!refVarElem.equals(varElement)) {
080: return super .visitMemberSelect(memSelectTree, refVarElem);
081: }
082:
083: boolean isAssgCmptble = isMemberAvailable(subTypeElement,
084: methodElement, super TypeElement);
085: if (!isAssgCmptble) {
086: isReplCandidate = false;
087: }
088: return super .visitMemberSelect(memSelectTree, refVarElem);
089: }
090:
091: @Override
092: public Tree visitAssignment(AssignmentTree assgnTree,
093: Element refVarElem) {
094:
095: ExpressionTree exprnTree = assgnTree.getExpression();
096: Element exprElement = asElement(exprnTree);
097: if (!refVarElem.equals(exprElement)) {
098: return super .visitAssignment(assgnTree, refVarElem);
099: }
100: ExpressionTree varExprTree = assgnTree.getVariable();
101:
102: VariableElement varElement = (VariableElement) asElement(varExprTree);
103: isReplCandidate = isReplacableAssgnmt(varElement)
104: && isReplCandidate;
105: return super .visitAssignment(assgnTree, refVarElem);
106: }
107:
108: @Override
109: public Tree visitVariable(VariableTree varTree, Element refVarElem) {
110: ExpressionTree initTree = varTree.getInitializer();
111: if (null == initTree) {
112: return super .visitVariable(varTree, refVarElem);
113: }
114: Element exprElement = asElement(initTree);
115: if (!refVarElem.equals(exprElement)) {
116: return super .visitVariable(varTree, refVarElem);
117: }
118: VariableElement varElement = (VariableElement) asElement(varTree);
119: isReplCandidate = isReplacableAssgnmt(varElement)
120: && isReplCandidate;
121: return super .visitVariable(varTree, refVarElem);
122: }
123:
124: private boolean isMemberAvailable(TypeElement subTypeElement,
125: Element methodElement, TypeElement super TypeElement) {
126: ElementKind memberKind = methodElement.getKind();
127: if (ElementKind.METHOD.equals(memberKind)) {
128: return isMethodAvailable(subTypeElement,
129: (ExecutableElement) methodElement, super TypeElement);
130: } else {
131: return isHidingMember(subTypeElement, methodElement,
132: super TypeElement);
133: }
134: }
135:
136: private boolean isMethodAvailable(TypeElement subTypeElement,
137: ExecutableElement execElem, TypeElement super TypeElement) {
138: Elements elements = workingCopy.getElements();
139: List<? extends Element> memberElements = elements
140: .getAllMembers(super TypeElement);
141: for (Element elem : memberElements) {
142: if (ElementKind.METHOD.equals(elem.getKind())) {
143: if (isStatic(execElem)
144: && elements.hides(execElem, elem)) {
145: return true;
146: } else {
147: if (execElem.equals(elem)
148: || elements.overrides(execElem,
149: (ExecutableElement) elem,
150: subTypeElement)) {
151: return true;
152: }
153: }
154: }
155: }
156:
157: return false;
158: }
159:
160: private boolean isHidingMember(TypeElement subTypeElement,
161: Element variableElement, TypeElement super TypeElement) {
162: //TODO: We do not handle nested types yet (includes enums)
163: Elements elements = workingCopy.getElements();
164: List<? extends Element> memberElements = elements
165: .getAllMembers(super TypeElement);
166: for (Element elem : memberElements) {
167: if (variableElement.equals(elem)
168: || elements.hides(variableElement, elem)) {
169: return true;
170: }
171: }
172: return false;
173: }
174:
175: private boolean isReplacableAssgnmt(VariableElement varElement) {
176: if (isDeclaredType(varElement.asType())) {
177: DeclaredType declType = (DeclaredType) varElement.asType();
178: TypeElement varType = (TypeElement) declType.asElement();
179: if (isAssignable(super TypeElement, varType)) {
180: return true;
181: }
182: }
183: return false;
184: }
185:
186: boolean isReplaceCandidate() {
187: return isReplCandidate;
188: }
189:
190: private boolean isAssignable(TypeElement typeFrom,
191: TypeElement typeTo) {
192: Types types = workingCopy.getTypes();
193: return types.isAssignable(typeFrom.asType(), typeTo.asType());
194: }
195:
196: private Element asElement(Tree tree) {
197: Trees treeUtil = workingCopy.getTrees();
198: TreePath treePath = treeUtil.getPath(workingCopy
199: .getCompilationUnit(), tree);
200: Element element = treeUtil.getElement(treePath);
201: return element;
202: }
203:
204: private boolean isDeclaredType(TypeMirror type) {
205: return TypeKind.DECLARED.equals(type.getKind());
206: }
207:
208: //TODO: This method can be shared. Copied from UseSuperTypeRefactoringPlugin.
209: private boolean isStatic(Element element) {
210: Set<Modifier> modifiers = element.getModifiers();
211: return modifiers.contains(Modifier.STATIC);
212: }
213:
214: }
|