Parse candidate files locally on demand and present exact usages - may or may not work correctly for methods whose real parameters are not indexed
1.1 --- a/remoting/ide/usages/nbproject/genfiles.properties Tue Jun 28 13:41:05 2011 +0200
1.2 +++ b/remoting/ide/usages/nbproject/genfiles.properties Tue Jun 28 13:42:12 2011 +0200
1.3 @@ -1,8 +1,8 @@
1.4 -build.xml.data.CRC32=80c6633a
1.5 +build.xml.data.CRC32=dc8b4dc8
1.6 build.xml.script.CRC32=58a6b47a
1.7 build.xml.stylesheet.CRC32=a56c6a5b@1.47
1.8 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
1.9 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
1.10 -nbproject/build-impl.xml.data.CRC32=80c6633a
1.11 +nbproject/build-impl.xml.data.CRC32=dc8b4dc8
1.12 nbproject/build-impl.xml.script.CRC32=583fd407
1.13 nbproject/build-impl.xml.stylesheet.CRC32=238281d1@1.47
2.1 --- a/remoting/ide/usages/nbproject/project.xml Tue Jun 28 13:41:05 2011 +0200
2.2 +++ b/remoting/ide/usages/nbproject/project.xml Tue Jun 28 13:42:12 2011 +0200
2.3 @@ -76,6 +76,14 @@
2.4 </run-dependency>
2.5 </dependency>
2.6 <dependency>
2.7 + <code-name-base>org.openide.actions</code-name-base>
2.8 + <build-prerequisite/>
2.9 + <compile-dependency/>
2.10 + <run-dependency>
2.11 + <specification-version>6.23</specification-version>
2.12 + </run-dependency>
2.13 + </dependency>
2.14 + <dependency>
2.15 <code-name-base>org.openide.awt</code-name-base>
2.16 <build-prerequisite/>
2.17 <compile-dependency/>
2.18 @@ -116,6 +124,14 @@
2.19 </run-dependency>
2.20 </dependency>
2.21 <dependency>
2.22 + <code-name-base>org.openide.text</code-name-base>
2.23 + <build-prerequisite/>
2.24 + <compile-dependency/>
2.25 + <run-dependency>
2.26 + <specification-version>6.39</specification-version>
2.27 + </run-dependency>
2.28 + </dependency>
2.29 + <dependency>
2.30 <code-name-base>org.openide.util</code-name-base>
2.31 <build-prerequisite/>
2.32 <compile-dependency/>
3.1 --- a/remoting/ide/usages/src/org/netbeans/modules/jackpot30/ide/usages/Nodes.java Tue Jun 28 13:41:05 2011 +0200
3.2 +++ b/remoting/ide/usages/src/org/netbeans/modules/jackpot30/ide/usages/Nodes.java Tue Jun 28 13:42:12 2011 +0200
3.3 @@ -42,7 +42,13 @@
3.4
3.5 package org.netbeans.modules.jackpot30.ide.usages;
3.6
3.7 +import com.sun.source.tree.IdentifierTree;
3.8 +import com.sun.source.tree.MemberSelectTree;
3.9 +import com.sun.source.tree.Tree;
3.10 +import com.sun.source.util.SourcePositions;
3.11 +import com.sun.source.util.TreePathScanner;
3.12 import java.awt.Image;
3.13 +import java.io.IOException;
3.14 import java.util.ArrayList;
3.15 import java.util.Collection;
3.16 import java.util.HashMap;
3.17 @@ -51,23 +57,42 @@
3.18 import java.util.Map;
3.19 import java.util.logging.Level;
3.20 import java.util.logging.Logger;
3.21 +import javax.lang.model.element.Element;
3.22 +import javax.lang.model.element.ElementKind;
3.23 +import javax.lang.model.element.ExecutableElement;
3.24 +import javax.lang.model.element.TypeElement;
3.25 import javax.swing.Action;
3.26 +import org.netbeans.api.java.source.CompilationController;
3.27 +import org.netbeans.api.java.source.CompilationInfo;
3.28 +import org.netbeans.api.java.source.ElementHandle;
3.29 +import org.netbeans.api.java.source.JavaSource;
3.30 +import org.netbeans.api.java.source.JavaSource.Phase;
3.31 +import org.netbeans.api.java.source.Task;
3.32 +import org.netbeans.api.java.source.UiUtils;
3.33 import org.netbeans.api.project.FileOwnerQuery;
3.34 import org.netbeans.api.project.Project;
3.35 import org.netbeans.api.project.ProjectUtils;
3.36 import org.netbeans.spi.project.ui.LogicalViewProvider;
3.37 +import org.openide.actions.OpenAction;
3.38 +import org.openide.cookies.EditorCookie;
3.39 +import org.openide.cookies.LineCookie;
3.40 +import org.openide.cookies.OpenCookie;
3.41 import org.openide.filesystems.FileObject;
3.42 import org.openide.filesystems.FileUtil;
3.43 import org.openide.loaders.DataObject;
3.44 import org.openide.loaders.DataObjectNotFoundException;
3.45 import org.openide.nodes.AbstractNode;
3.46 +import org.openide.nodes.ChildFactory;
3.47 import org.openide.nodes.Children;
3.48 import org.openide.nodes.FilterNode;
3.49 import org.openide.nodes.Node;
3.50 import org.openide.nodes.NodeOp;
3.51 +import org.openide.text.Line;
3.52 import org.openide.util.Exceptions;
3.53 import org.openide.util.ImageUtilities;
3.54 import org.openide.util.NbBundle;
3.55 +import org.openide.util.lookup.AbstractLookup;
3.56 +import org.openide.util.lookup.InstanceContent;
3.57
3.58 /**
3.59 *
3.60 @@ -75,7 +100,7 @@
3.61 */
3.62 public class Nodes {
3.63
3.64 - public static Node constructSemiLogicalView(Iterable<? extends FileObject> filesWithOccurrences) {
3.65 + public static Node constructSemiLogicalView(Iterable<? extends FileObject> filesWithOccurrences, ElementHandle<?> eh) {
3.66 Map<Project, Collection<FileObject>> projects = new HashMap<Project, Collection<FileObject>>();
3.67
3.68 for (FileObject file : filesWithOccurrences) {
3.69 @@ -99,13 +124,13 @@
3.70 List<Node> nodes = new LinkedList<Node>();
3.71
3.72 for (Project p : projects.keySet()) {
3.73 - nodes.add(constructSemiLogicalView(p, projects.get(p)));
3.74 + nodes.add(constructSemiLogicalView(p, projects.get(p), eh));
3.75 }
3.76
3.77 return new AbstractNode(new DirectChildren(nodes));
3.78 }
3.79
3.80 - private static Node constructSemiLogicalView(final Project p, Iterable<? extends FileObject> files) {
3.81 + private static Node constructSemiLogicalView(final Project p, Iterable<? extends FileObject> files, ElementHandle<?> eh) {
3.82 LogicalViewProvider lvp = p.getLookup().lookup(LogicalViewProvider.class);
3.83 final Node view;
3.84
3.85 @@ -151,7 +176,7 @@
3.86 fileNodes.add(foundChild);
3.87 }
3.88
3.89 - return new Wrapper(view, fileNodes);
3.90 + return new Wrapper(view, fileNodes, eh);
3.91 }
3.92
3.93 private static Node locateChild(Node parent, LogicalViewProvider lvp, FileObject file) {
3.94 @@ -164,8 +189,8 @@
3.95
3.96 private static class Wrapper extends FilterNode {
3.97
3.98 - public Wrapper(Node orig, Collection<? extends Node> fileNodes) {
3.99 - super(orig, new WrapperChildren(orig, fileNodes));
3.100 + public Wrapper(Node orig, Collection<? extends Node> fileNodes, ElementHandle<?> eh) {
3.101 + super(orig, new WrapperChildren(orig, fileNodes, eh));
3.102 }
3.103
3.104 @Override
3.105 @@ -193,10 +218,12 @@
3.106
3.107 private final Node orig;
3.108 private final Collection<? extends Node> fileNodes;
3.109 + private final ElementHandle<?> eh;
3.110
3.111 - public WrapperChildren(Node orig, Collection<? extends Node> fileNodes) {
3.112 + public WrapperChildren(Node orig, Collection<? extends Node> fileNodes, ElementHandle<?> eh) {
3.113 this.orig = orig;
3.114 this.fileNodes = fileNodes;
3.115 + this.eh = eh;
3.116
3.117 }
3.118
3.119 @@ -225,9 +252,12 @@
3.120 @Override
3.121 protected Node[] createNodes(Node key) {
3.122 if (fileNodes.contains(key)) {
3.123 - return new Node[] {new FilterNode(key)}; //XXX
3.124 + FileObject file = key.getLookup().lookup(FileObject.class);
3.125 + Children c = file != null ? Children.create(new UsagesChildren(file, eh), true) : Children.LEAF;
3.126 +
3.127 + return new Node[] {new FilterNode(key, c)}; //XXX
3.128 }
3.129 - return new Node[] {new Wrapper(key, fileNodes)};
3.130 + return new Node[] {new Wrapper(key, fileNodes, eh)};
3.131 }
3.132
3.133 }
3.134 @@ -244,4 +274,162 @@
3.135 }
3.136 }
3.137
3.138 + private static Node noOccurrencesNode() {
3.139 + AbstractNode noOccurrences = new AbstractNode(Children.LEAF);
3.140 +
3.141 + noOccurrences.setDisplayName("No Occurrences Found");
3.142 +
3.143 + return noOccurrences;
3.144 + }
3.145 +
3.146 + private static final class UsagesChildren extends ChildFactory<Node> {
3.147 +
3.148 + private final FileObject file;
3.149 + private final ElementHandle<?> eh;
3.150 +
3.151 + public UsagesChildren(FileObject file, ElementHandle<?> eh) {
3.152 + this.file = file;
3.153 + this.eh = eh;
3.154 + }
3.155 +
3.156 + @Override
3.157 + protected boolean createKeys(final List<Node> toPopulate) {
3.158 + try {
3.159 + JavaSource.forFileObject(file).runUserActionTask(new Task<CompilationController>() {
3.160 + @Override public void run(final CompilationController parameter) throws Exception {
3.161 + parameter.toPhase(Phase.RESOLVED);
3.162 +
3.163 + final Element toFind = eh.resolve(parameter);
3.164 +
3.165 + if (toFind == null) {
3.166 + return;
3.167 + }
3.168 +
3.169 + new TreePathScanner<Void, Void>() {
3.170 + @Override public Void visitIdentifier(IdentifierTree node, Void p) {
3.171 + handleNode();
3.172 + return super.visitIdentifier(node, p);
3.173 + }
3.174 + @Override public Void visitMemberSelect(MemberSelectTree node, Void p) {
3.175 + handleNode();
3.176 + return super.visitMemberSelect(node, p);
3.177 + }
3.178 + private void handleNode() {
3.179 + Element el = parameter.getTrees().getElement(getCurrentPath());
3.180 +
3.181 + if (Nodes.equals(parameter, toFind, el)) {
3.182 + toPopulate.add(new OccurrenceNode(parameter, getCurrentPath().getLeaf()));
3.183 + }
3.184 + }
3.185 + }.scan(parameter.getCompilationUnit(), null);
3.186 + }
3.187 + }, true);
3.188 + } catch (IOException ex) {
3.189 + Exceptions.printStackTrace(ex);
3.190 + }
3.191 +
3.192 + if (toPopulate.isEmpty()) toPopulate.add(noOccurrencesNode());
3.193 +
3.194 + return true;
3.195 + }
3.196 +
3.197 + @Override
3.198 + protected Node createNodeForKey(Node key) {
3.199 + return key;
3.200 + }
3.201 +
3.202 + }
3.203 +
3.204 + private static boolean equals(CompilationInfo info, Element toFind, Element what) {
3.205 + if (toFind == what) return true;
3.206 + if (what == null) return false;
3.207 + if (toFind.getKind() != what.getKind()) return false;
3.208 + if (toFind.getKind() != ElementKind.METHOD) return false;
3.209 +
3.210 + return info.getElements().overrides((ExecutableElement) what, (ExecutableElement) toFind, (TypeElement) what.getEnclosingElement());
3.211 + }
3.212 +
3.213 + private static final class OccurrenceNode extends AbstractNode {
3.214 + private final FileObject file;
3.215 + private final int pos;
3.216 + private final String htmlDisplayName;
3.217 +
3.218 + public OccurrenceNode(CompilationInfo info, Tree occurrence) {
3.219 + this(info, occurrence, new InstanceContent());
3.220 + }
3.221 +
3.222 + private OccurrenceNode(CompilationInfo info, Tree occurrence, InstanceContent content) {
3.223 + super(Children.LEAF, new AbstractLookup(content));
3.224 +
3.225 + int[] span;
3.226 +
3.227 + switch (occurrence.getKind()) {
3.228 + case MEMBER_SELECT: span = info.getTreeUtilities().findNameSpan((MemberSelectTree) occurrence); break;
3.229 + default:
3.230 + SourcePositions sp = info.getTrees().getSourcePositions();
3.231 +
3.232 + span = new int[] {(int) sp.getStartPosition(info.getCompilationUnit(), occurrence),
3.233 + (int) sp.getEndPosition(info.getCompilationUnit(), occurrence)};
3.234 + break;
3.235 + }
3.236 +
3.237 + long startLine = info.getCompilationUnit().getLineMap().getLineNumber(span[0]);
3.238 + long startLineStart = info.getCompilationUnit().getLineMap().getStartPosition(startLine);
3.239 +
3.240 + String dn;
3.241 +
3.242 + try {
3.243 + DataObject od = DataObject.find(info.getFileObject());
3.244 + LineCookie lc = od.getLookup().lookup(LineCookie.class);
3.245 + Line l = lc.getLineSet().getCurrent((int) startLine - 1);
3.246 + od.getLookup().lookup(EditorCookie.class).openDocument();
3.247 + String line = l.getText();
3.248 + int endOnLine = (int) Math.min(line.length(), span[1] - startLineStart);
3.249 +
3.250 + dn = translate(line.substring(0, (int) (span[0] - startLineStart))) + "<b>" + translate(line.substring((int) (span[0] - startLineStart), endOnLine)) + "</b>" + translate(line.substring(endOnLine));
3.251 + } catch (IOException ex) {
3.252 + Exceptions.printStackTrace(ex);
3.253 + dn = "Occurrence";
3.254 + }
3.255 +
3.256 + this.htmlDisplayName = dn;
3.257 + this.file = info.getFileObject();
3.258 + this.pos = span[0];
3.259 +
3.260 + content.add(new OpenCookie() {
3.261 + @Override public void open() {
3.262 + UiUtils.open(file, pos);
3.263 + }
3.264 + });
3.265 + }
3.266 +
3.267 + @Override
3.268 + public String getHtmlDisplayName() {
3.269 + return htmlDisplayName;
3.270 + }
3.271 +
3.272 + @Override
3.273 + public Action[] getActions(boolean context) {
3.274 + return new Action[] {
3.275 + OpenAction.get(OpenAction.class)
3.276 + };
3.277 + }
3.278 +
3.279 + @Override
3.280 + public Action getPreferredAction() {
3.281 + return OpenAction.get(OpenAction.class);
3.282 + }
3.283 +
3.284 + }
3.285 +
3.286 + private static String[] c = new String[] {"&", "<", ">", "\n", "\""}; // NOI18N
3.287 + private static String[] tags = new String[] {"&", "<", ">", "<br>", """}; // NOI18N
3.288 +
3.289 + private static String translate(String input) {
3.290 + for (int cntr = 0; cntr < c.length; cntr++) {
3.291 + input = input.replaceAll(c[cntr], tags[cntr]);
3.292 + }
3.293 +
3.294 + return input;
3.295 + }
3.296 }
4.1 --- a/remoting/ide/usages/src/org/netbeans/modules/jackpot30/ide/usages/RemoteUsages.java Tue Jun 28 13:41:05 2011 +0200
4.2 +++ b/remoting/ide/usages/src/org/netbeans/modules/jackpot30/ide/usages/RemoteUsages.java Tue Jun 28 13:42:12 2011 +0200
4.3 @@ -88,6 +88,7 @@
4.4 final int pos = comp.getCaretPosition();
4.5
4.6 try {
4.7 + final ElementHandle<?>[] handle = new ElementHandle<?>[1];
4.8 final String[] serialized = new String[1];
4.9
4.10 JavaSource.forFileObject(file).runUserActionTask(new Task<CompilationController>() {
4.11 @@ -98,7 +99,7 @@
4.12 Element el = parameter.getTrees().getElement(tp);
4.13
4.14 if (el != null && Common.SUPPORTED_KINDS.contains(el.getKind())) {
4.15 - serialized[0] = serialize(ElementHandle.create(el));
4.16 + serialized[0] = serialize(handle[0] = ElementHandle.create(el));
4.17 }
4.18 }
4.19 }, true);
4.20 @@ -117,7 +118,7 @@
4.21 }
4.22 }
4.23
4.24 - RemoteUsagesWindowTopComponent.openFor(Nodes.constructSemiLogicalView(result));
4.25 + RemoteUsagesWindowTopComponent.openFor(Nodes.constructSemiLogicalView(result, handle[0]));
4.26 } catch (URISyntaxException ex) {
4.27 Exceptions.printStackTrace(ex);
4.28 } catch (IOException ex) {