blob: 43be78ee74f9506c7efbb5844ff5d64b814202d1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.refactoring.java;
import com.sun.source.tree.*;
import com.sun.source.util.SourcePositions;
import com.sun.source.util.TreePath;
import com.sun.source.util.Trees;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.swing.Icon;
import javax.swing.text.Position.Bias;
import org.netbeans.api.java.source.CompilationInfo;
import org.netbeans.api.java.source.TreeUtilities;
import org.netbeans.modules.refactoring.java.plugins.JavaWhereUsedQueryPlugin;
import org.netbeans.modules.refactoring.java.spi.JavaWhereUsedFilters;
import org.netbeans.modules.refactoring.java.spi.JavaWhereUsedFilters.ReadWrite;
import org.netbeans.modules.refactoring.java.ui.UIUtilities;
import org.netbeans.modules.refactoring.java.ui.WhereUsedPanel;
import org.netbeans.modules.refactoring.java.ui.tree.ElementGripFactory;
import org.netbeans.modules.refactoring.spi.FiltersManager;
import org.netbeans.modules.refactoring.spi.SimpleRefactoringElementImplementation;
import org.openide.ErrorManager;
import org.openide.awt.StatusDisplayer;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.text.CloneableEditorSupport;
import org.openide.text.PositionBounds;
import org.openide.text.PositionRef;
import org.openide.util.Exceptions;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import static org.netbeans.modules.refactoring.java.Bundle.*;
@NbBundle.Messages({"WARN_ElementNotFound=The destination was not found."})
public class WhereUsedElement extends SimpleRefactoringElementImplementation implements FiltersManager.Filterable {
private final PositionBounds bounds;
private final String htmlText;
private final String elementText;
private final FileObject parentFile;
private final JavaWhereUsedFilters.ReadWrite access;
private final boolean inComment;
private final boolean inImport;
private final boolean inPlatform;
private final boolean inDependency;
private final boolean inTestclass;
public WhereUsedElement(PositionBounds bounds, String htmlText, String elementText, FileObject parentFile, TreePath tp, CompilationInfo info, ReadWrite access, boolean inTestclass, boolean inPlatform, boolean inDependency, boolean inComment, boolean inImport) {
this.bounds = bounds;
this.htmlText = htmlText;
this.elementText = elementText;
this.parentFile = parentFile;
if (tp != null) {
ElementGripFactory.getDefault().put(parentFile, tp, info);
}
ElementGripFactory.getDefault().put(parentFile, inTestclass);
this.access = access;
this.inTestclass = inTestclass;
this.inPlatform = inPlatform;
this.inDependency = inDependency;
this.inComment = inComment;
this.inImport = inImport;
}
@Override
public String getDisplayText() {
return htmlText;
}
@Override
public Lookup getLookup() {
Object composite = null;
if(bounds != null) {
composite = ElementGripFactory.getDefault().get(parentFile, bounds.getBegin().getOffset());
}
if (composite==null) {
composite = parentFile;
}
Icon icon = null;
if(access != null) {
switch(access) {
case WRITE:
icon = ImageUtilities.loadImageIcon("org/netbeans/modules/refactoring/java/resources/found_item_write.png", false);
break;
case READ_WRITE:
icon = ImageUtilities.loadImageIcon("org/netbeans/modules/refactoring/java/resources/found_item_readwrite.png", false);
break;
default:
case READ:
icon = ImageUtilities.loadImageIcon("org/netbeans/modules/refactoring/java/resources/found_item_read.png", false);
break;
}
} else if(inComment) {
icon = ImageUtilities.loadImageIcon("org/netbeans/modules/refactoring/java/resources/found_item_comment.png", false);
} else if(inImport) {
icon = ImageUtilities.loadImageIcon("org/netbeans/modules/refactoring/java/resources/found_item_import.png", false);
}
return icon != null ? Lookups.fixed(composite, icon) : Lookups.singleton(composite);
}
@Override
public PositionBounds getPosition() {
return bounds;
}
@Override
public String getText() {
return elementText;
}
@Override
public void performChange() {
}
@Override
public void openInEditor() {
if(parentFile == null || !parentFile.isValid()) {
StatusDisplayer.getDefault().setStatusText(WARN_ElementNotFound());
} else {
super.openInEditor();
}
}
@Override
public FileObject getParentFile() {
return parentFile;
}
public JavaWhereUsedFilters.ReadWrite getAccess() {
return access;
}
public static WhereUsedElement create(CompilationInfo compiler, TreePath tree, boolean inTest) {
return create(compiler, tree, inTest, false, false);
}
public static WhereUsedElement create(CompilationInfo compiler, TreePath tree, boolean inTest, boolean inPlatform, boolean inDependency) {
return create(compiler, tree, null, inTest, inPlatform, inDependency, new AtomicBoolean());
}
public static WhereUsedElement create(CompilationInfo compiler, TreePath tree, boolean inTest, boolean inPlatform, boolean inDependency, AtomicBoolean inImport) {
return create(compiler, tree, null, inTest, inPlatform, inDependency, inImport);
}
public static WhereUsedElement create(CompilationInfo compiler, TreePath tree, JavaWhereUsedFilters.ReadWrite access, boolean inTest, boolean inPlatform, boolean inDependency, AtomicBoolean inImport) {
CompilationUnitTree unit = tree.getCompilationUnit();
CharSequence content = compiler.getSnapshot().getText();
SourcePositions sp = compiler.getTrees().getSourcePositions();
Tree t= tree.getLeaf();
int start;
int end;
boolean anonClassNameBug128074 = false;
TreeUtilities treeUtils = compiler.getTreeUtilities();
if (t.getKind() == Tree.Kind.IDENTIFIER
&& "super".contentEquals(((IdentifierTree) t).getName()) // NOI18N
&& treeUtils.isSynthetic(tree)) {
// in case of synthetic constructor call find real constructor or class declaration
tree = getEnclosingTree(tree);
if (treeUtils.isSynthetic(tree)) {
tree = getEnclosingTree(tree.getParentPath());
}
t = tree.getLeaf();
}
boolean elementInImport = false;
if(t.getKind() == Tree.Kind.IDENTIFIER || t.getKind() == Tree.Kind.MEMBER_SELECT) {
TreePath enclosingTree = getEnclosingImportTree(tree);
if(enclosingTree != null) {
elementInImport = true;
inImport.set(true);
}
}
if (TreeUtilities.CLASS_TREE_KINDS.contains(t.getKind())) {
int[] pos = treeUtils.findNameSpan((ClassTree)t);
if (pos == null) {
Tree tr = tree.getParentPath().getLeaf();
if (tr instanceof NewClassTree) {
NewClassTree newClass = (NewClassTree) tr;
start = (int) sp.getStartPosition(unit, newClass.getIdentifier());
end = (int) sp.getEndPosition(unit, newClass.getIdentifier());
} else {
//#121084 hotfix
//happens for anonymous innerclasses
anonClassNameBug128074 = true;
start = end = (int) sp.getStartPosition(unit, t);
}
// #213723 hotfix, happens for enum values
if(start < 0) {
TreePath parentPath = tree.getParentPath();
if(parentPath != null && (parentPath = parentPath.getParentPath()) != null
&& parentPath.getLeaf().getKind() == Tree.Kind.VARIABLE) {
VariableTree enum_var = (VariableTree) parentPath.getLeaf();
pos = treeUtils.findNameSpan(enum_var);
if (pos == null) {
//#121084 hotfix
start = end = (int) sp.getStartPosition(unit, enum_var);
} else {
start = pos[0];
end = pos[1];
}
}
}
} else {
start = pos[0];
end = pos[1];
}
} else if (t.getKind() == Tree.Kind.METHOD) {
int[] pos = treeUtils.findNameSpan((MethodTree)t);
if (pos == null) {
//#121084 hotfix
start = end = (int) sp.getStartPosition(unit, t);
} else {
start = pos[0];
end = pos[1];
}
} else if (t.getKind() == Tree.Kind.NEW_CLASS) {
Tree ident = ((NewClassTree)t).getIdentifier();
if (ident.getKind() == Tree.Kind.PARAMETERIZED_TYPE) {
ident = ((ParameterizedTypeTree)ident).getType();
}
if (ident.getKind()== Tree.Kind.MEMBER_SELECT) {
int[] pos = treeUtils.findNameSpan((MemberSelectTree) ident);
if (pos == null) {
//#121084 hotfix
start = end = (int) sp.getStartPosition(unit, ident);
} else {
start = pos[0];
end = pos[1];
}
} else {
TreePath varTreePath = tree.getParentPath();
Tree varTree = varTreePath.getLeaf();
Trees trees = compiler.getTrees();
Element element = trees.getElement(varTreePath);
if (element != null && varTree.getKind() == Tree.Kind.VARIABLE && element.getKind() == ElementKind.ENUM_CONSTANT) {
int[] pos = treeUtils.findNameSpan((VariableTree)varTree);
if (pos == null) {
//#121084 hotfix
start = end = (int) sp.getStartPosition(unit, varTree);
} else {
start = pos[0];
end = pos[1];
}
} else {
start = (int) sp.getStartPosition(unit, ident);
end = (int) sp.getEndPosition(unit, ident);
}
}
} else if (t.getKind() == Tree.Kind.MEMBER_SELECT) {
int[] pos = treeUtils.findNameSpan((MemberSelectTree) t);
if (pos == null) {
//#121084 hotfix
start = end = (int) sp.getStartPosition(unit, t);
} else {
start = pos[0];
end = pos[1];
}
} else {
start = (int) sp.getStartPosition(unit, t);
end = (int) sp.getEndPosition(unit, t);
if (end == -1) {
if (!compiler.getTreeUtilities().isSynthetic(tree)) {
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, new RuntimeException("Cannot get end position for " + t.getClass().getName() + " " + t + " file:" + compiler.getFileObject().getPath())); // NOI18N
}
end = start;
}
}
assert start>0:"Cannot find start position in file " + unit.getSourceFile().getName() + "\n tree=" + tree.toString();
assert end>0:"Cannot find end position in file " + unit.getSourceFile().getName() + "\n tree=" + tree.toString();
LineMap lm = tree.getCompilationUnit().getLineMap();
long line = lm.getLineNumber(start);
long endLine = lm.getLineNumber(end);
long sta = lm.getStartPosition(line);
int eof = content.length();
long lastLine = lm.getLineNumber(eof);
long en = lastLine > endLine ? lm.getStartPosition(endLine + 1) - 1 : eof;
StringBuilder sb = new StringBuilder();
sb.append(UIUtilities.getHtml(trimStart(content.subSequence((int) sta, start).toString())));
sb.append("<b>"); //NOI18N
sb.append(content.subSequence(start, end));
sb.append("</b>");//NOI18N
sb.append(UIUtilities.getHtml(trimEnd(content.subSequence(end, (int) en).toString())));
DataObject dob = null;
try {
dob = DataObject.find(compiler.getFileObject());
} catch (DataObjectNotFoundException ex) {
Exceptions.printStackTrace(ex);
}
CloneableEditorSupport ces = JavaWhereUsedQueryPlugin.findCloneableEditorSupport(dob);
PositionRef ref1 = ces.createPositionRef(start, Bias.Forward);
PositionRef ref2 = ces.createPositionRef(end, Bias.Forward);
PositionBounds bounds = new PositionBounds(ref1, ref2);
TreePath tr = getEnclosingTree(tree);
return new WhereUsedElement(
bounds,
start==end && anonClassNameBug128074 ? NbBundle.getMessage(WhereUsedPanel.class, "LBL_AnonymousClass"):sb.toString().trim(),
start==end && anonClassNameBug128074 ? NbBundle.getMessage(WhereUsedPanel.class, "LBL_AnonymousClass"):content.subSequence((int)sta, (int)en).toString().trim(),
compiler.getFileObject(),
tr,
compiler, access, inTest, inPlatform,inDependency, false, elementInImport);
}
private static String trimStart(String s) {
for (int x = 0; x < s.length(); x++) {
if (!Character.isWhitespace(s.charAt(x))) {
return s.substring(x, s.length());
}
}
return "";
}
private static String trimEnd(String s) {
for (int x = s.length()-1; x >=0; x--) {
if (!Character.isWhitespace(s.charAt(x))) {
return s.substring(0, x + 1);
}
}
return "";
}
public static WhereUsedElement create(int start, int end, CompilationInfo compiler, boolean inTest, boolean inPlatform, boolean inDependency) {
CharSequence content = compiler.getSnapshot().getText();
LineMap lm = compiler.getCompilationUnit().getLineMap();
long line = lm.getLineNumber(start);
long endLine = lm.getLineNumber(end);
long sta = lm.getStartPosition(line);
int eof = content.length();
long lastLine = lm.getLineNumber(eof);
long en = lastLine > endLine ? lm.getStartPosition(endLine + 1) - 1 : eof;
StringBuilder sb = new StringBuilder();
sb.append(UIUtilities.getHtml(trimStart(content.subSequence((int) sta, start).toString())));
sb.append("<b>"); //NOI18N
sb.append(content.subSequence(start, end));
sb.append("</b>");//NOI18N
sb.append(UIUtilities.getHtml(trimEnd(content.subSequence(end, (int) en).toString())));
DataObject dob = null;
try {
dob = DataObject.find(compiler.getFileObject());
} catch (DataObjectNotFoundException ex) {
Exceptions.printStackTrace(ex);
}
CloneableEditorSupport ces = JavaWhereUsedQueryPlugin.findCloneableEditorSupport(dob);
PositionRef ref1 = ces.createPositionRef(start, Bias.Forward);
PositionRef ref2 = ces.createPositionRef(end, Bias.Forward);
PositionBounds bounds = new PositionBounds(ref1, ref2);
return new WhereUsedElement(bounds, sb.toString().trim(),
content.subSequence((int)sta, (int)en).toString(),
compiler.getFileObject(), null, compiler, null, inTest, inPlatform, inDependency, true, false);
}
private static TreePath getEnclosingImportTree(TreePath tp) {
while(tp != null) {
Tree tree = tp.getLeaf();
if (tree.getKind() == Tree.Kind.IMPORT) {
return tp;
}
tp = tp.getParentPath();
}
return null;
}
private static TreePath getEnclosingTree(TreePath tp) {
while(tp != null) {
Tree tree = tp.getLeaf();
if (TreeUtilities.CLASS_TREE_KINDS.contains(tree.getKind()) || tree.getKind() == Tree.Kind.METHOD || tree.getKind() == Tree.Kind.IMPORT || tree.getKind() == Tree.Kind.VARIABLE) {
return tp;
}
tp = tp.getParentPath();
}
return null;
}
@Override
public boolean filter(FiltersManager manager) {
boolean show = true;
if(JavaWhereUsedQueryPlugin.DEPENDENCIES) {
if (inPlatform) {
show = show && manager.isSelected(JavaWhereUsedFilters.PLATFORM.getKey());
}
if (inDependency) {
show = show && manager.isSelected(JavaWhereUsedFilters.DEPENDENCY.getKey());
}
}
if (inTestclass) {
show = show && manager.isSelected(JavaWhereUsedFilters.TESTFILE.getKey());
}
show = show && manager.isSelected(JavaWhereUsedFilters.SOURCEFILE.getKey());
if (access != null) {
show = show && manager.isSelected(access.getKey());
}
if (inComment) {
show = show && manager.isSelected(JavaWhereUsedFilters.COMMENT.getKey());
}
if (inImport) {
show = show && manager.isSelected(JavaWhereUsedFilters.IMPORT.getKey());
}
return show;
}
}