You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by db...@apache.org on 2021/05/10 13:02:33 UTC

[netbeans] branch master updated: LSP: "Go to Type" should open also types in project dependencies. (#2936)

This is an automated email from the ASF dual-hosted git repository.

dbalek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 07a82fa  LSP: "Go to Type" should open also types in project dependencies. (#2936)
07a82fa is described below

commit 07a82fa3fb774eaa4f15e38bbf08d59b5f932101
Author: Dusan Balek <du...@oracle.com>
AuthorDate: Mon May 10 15:02:00 2021 +0200

    LSP: "Go to Type" should open also types in project dependencies. (#2936)
---
 .../editor/java/JavaCompletionCollector.java       |   4 +-
 .../lsp/server/protocol/WorkspaceServiceImpl.java  | 159 ++++++++++++++-------
 .../java/lsp/server/protocol/ServerTest.java       |  28 ++--
 java/java.sourceui/nbproject/project.xml           |  10 ++
 .../netbeans/api/java/source/ui/ElementOpen.java   |   2 +-
 .../modules/java/source/ui/JavaTypeProvider.java   | 157 +++++++++++++-------
 6 files changed, 245 insertions(+), 115 deletions(-)

diff --git a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
index c14a408..db635f5 100644
--- a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
+++ b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
@@ -586,8 +586,10 @@ public class JavaCompletionCollector implements CompletionCollector {
                     .kind(elementKind2CompletionItemKind(memberElem.getKind()))
                     .insertText(label)
                     .insertTextFormat(Completion.TextFormat.PlainText)
-                    .additionalTextEdits(Collections.singletonList(currentClassImport))
                     .sortText(String.format("%04d%s", memberElem.getKind().isField() ? 720 : 750, sortText));
+            if (currentClassImport != null) {
+                builder.additionalTextEdits(Collections.singletonList(currentClassImport));
+            }
             ElementHandle<Element> handle = SUPPORTED_ELEMENT_KINDS.contains(memberElem.getKind().name()) ? ElementHandle.create(memberElem) : null;
             if (handle != null) {
                 builder.documentation(getDocumentation(doc, handle));
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
index e09ac8f..6eefa4d 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java
@@ -48,6 +48,7 @@ import org.eclipse.lsp4j.DidChangeWatchedFilesParams;
 import org.eclipse.lsp4j.ExecuteCommandParams;
 import org.eclipse.lsp4j.Location;
 import org.eclipse.lsp4j.Position;
+import org.eclipse.lsp4j.Range;
 import org.eclipse.lsp4j.SymbolInformation;
 import org.eclipse.lsp4j.WorkspaceSymbolParams;
 import org.eclipse.lsp4j.services.LanguageClient;
@@ -66,6 +67,7 @@ import org.netbeans.api.java.source.ElementHandle;
 import org.netbeans.api.java.source.JavaSource;
 import org.netbeans.api.java.source.JavaSource.Phase;
 import org.netbeans.api.java.source.SourceUtils;
+import org.netbeans.api.java.source.ui.ElementOpen;
 import org.netbeans.api.project.Project;
 import org.netbeans.api.project.ProjectUtils;
 import org.netbeans.api.project.SourceGroup;
@@ -74,8 +76,7 @@ import org.netbeans.modules.gsf.testrunner.ui.api.TestMethodController;
 import org.netbeans.modules.java.lsp.server.LspServerState;
 import org.netbeans.modules.java.lsp.server.Utils;
 import org.netbeans.modules.java.source.ui.JavaSymbolProvider;
-import org.netbeans.modules.java.source.ui.JavaSymbolProvider.ResultHandler;
-import org.netbeans.modules.java.source.ui.JavaSymbolProvider.ResultHandler.Exec;
+import org.netbeans.modules.java.source.ui.JavaTypeProvider;
 import org.netbeans.modules.java.source.usages.ClassIndexImpl;
 import org.netbeans.modules.java.testrunner.ui.spi.ComputeTestMethods;
 import org.netbeans.modules.parsing.api.ParserManager;
@@ -287,7 +288,8 @@ public final class WorkspaceServiceImpl implements WorkspaceService, LanguageCli
         WORKER.post(() -> {
             try {
                 List<SymbolInformation> symbols = new ArrayList<>();
-                ResultHandler handler = new ResultHandler() {
+                SearchType searchType = getSearchType(queryFin, exactFin, false, null, null);
+                JavaSymbolProvider.ResultHandler symbolHandler = new JavaSymbolProvider.ResultHandler() {
                     @Override
                     public void setHighlightText(String text) {
                     }
@@ -308,49 +310,49 @@ public final class WorkspaceServiceImpl implements WorkspaceService, LanguageCli
                             }
                             if (!sources.isEmpty()) {
                                 JavaSource.create(cpInfo, sources.keySet())
-                                          .runUserActionTask(cc -> {
-                                              if (Phase.ELEMENTS_RESOLVED.compareTo(cc.toPhase(Phase.ELEMENTS_RESOLVED))> 0) {
-                                                  return ;
-                                              }
-                                              for (Entry<ElementHandle<TypeElement>, List<String>> e : sources.get(cc.getFileObject()).entrySet()) {
-                                                  TypeElement te = e.getKey().resolve(cc);
-
-                                                  if (te == null) {
-                                                      //cannot resolve
-                                                      continue;
-                                                  }
-
-                                                  for (String ident : e.getValue()) {
-                                                      if (ident.equals(getSimpleName(te, null, false))) {
-                                                          TreePath path = cc.getTrees().getPath(te);
-
-                                                          if (path != null) {
-                                                              final String symbolName = te.getSimpleName().toString();
-                                                              final ElementKind kind = te.getKind();
-                                                              SymbolInformation symbol = new SymbolInformation(symbolName, Utils.elementKind2SymbolKind(kind), tree2Location(cc, path), te.getQualifiedName().toString());
-
-                                                              symbol.setDeprecated(false);
-                                                              symbols.add(symbol);
-                                                          }
-                                                      }
-                                                      for (Element ne : te.getEnclosedElements()) {
-                                                          if (ident.equals(getSimpleName(ne, te, false))) {
-                                                              TreePath path = cc.getTrees().getPath(ne);
-
-                                                              if (path != null) {
-                                                                  final Pair<String,String> name = JavaSymbolProvider.getDisplayName(ne, te);
-                                                                  final String symbolName = name.first() + (name.second() != null ? name.second() : "");
-                                                                  final ElementKind kind = ne.getKind();
-                                                                  SymbolInformation symbol = new SymbolInformation(symbolName, Utils.elementKind2SymbolKind(kind), tree2Location(cc, path), te.getQualifiedName().toString());
-
-                                                                  symbol.setDeprecated(false);
-                                                                  symbols.add(symbol);
-                                                              }
-                                                          }
-                                                      }
-                                                  }
-                                              }
-                                          }, true);
+                                        .runUserActionTask(cc -> {
+                                            if (Phase.ELEMENTS_RESOLVED.compareTo(cc.toPhase(Phase.ELEMENTS_RESOLVED))> 0) {
+                                                return ;
+                                            }
+                                            for (Entry<ElementHandle<TypeElement>, List<String>> e : sources.get(cc.getFileObject()).entrySet()) {
+                                                TypeElement te = e.getKey().resolve(cc);
+
+                                                if (te == null) {
+                                                    //cannot resolve
+                                                    continue;
+                                                }
+
+                                                for (String ident : e.getValue()) {
+                                                    if (ident.equals(getSimpleName(te, null, false))) {
+                                                        TreePath path = cc.getTrees().getPath(te);
+
+                                                        if (path != null) {
+                                                            final String symbolName = te.getSimpleName().toString();
+                                                            final ElementKind kind = te.getKind();
+                                                            if (!kind.isClass() && !kind.isInterface()) {
+                                                                SymbolInformation symbol = new SymbolInformation(symbolName, Utils.elementKind2SymbolKind(kind), tree2Location(cc, path), te.getQualifiedName().toString());
+                                                                symbols.add(symbol);
+                                                            }
+                                                        }
+                                                    }
+                                                    for (Element ne : te.getEnclosedElements()) {
+                                                        if (ident.equals(getSimpleName(ne, te, false))) {
+                                                            TreePath path = cc.getTrees().getPath(ne);
+
+                                                            if (path != null) {
+                                                                final Pair<String,String> name = JavaSymbolProvider.getDisplayName(ne, te);
+                                                                final String symbolName = name.first() + (name.second() != null ? name.second() : "");
+                                                                final ElementKind kind = ne.getKind();
+                                                                if (!kind.isClass() && !kind.isInterface()) {
+                                                                    SymbolInformation symbol = new SymbolInformation(symbolName, Utils.elementKind2SymbolKind(kind), tree2Location(cc, path), te.getQualifiedName().toString());
+                                                                    symbols.add(symbol);
+                                                                }
+                                                            }
+                                                        }
+                                                    }
+                                                }
+                                            }
+                                        }, true);
                             }
                             //TODO: handle exceptions
                         } finally {
@@ -363,9 +365,68 @@ public final class WorkspaceServiceImpl implements WorkspaceService, LanguageCli
                         type2Idents.computeIfAbsent(owner, s -> new ArrayList<>()).add(ident);
                     }
                 };
-                JavaSymbolProvider.doComputeSymbols(getSearchType(queryFin, exactFin, false, null, null), queryFin, handler, true, cancel);
-                Collections.sort(symbols, (i1, i2) -> i1.getName().compareToIgnoreCase(i2.getName()));
-                result.complete(symbols);
+                JavaSymbolProvider.doComputeSymbols(searchType, queryFin, symbolHandler, true, cancel);
+                List<Pair<ElementHandle<TypeElement>, ClasspathInfo>> pairs = new ArrayList<>();
+                JavaTypeProvider.ResultHandler<Pair<ElementHandle<TypeElement>, ClasspathInfo>> typeHandler = new JavaTypeProvider.ResultHandler<Pair<ElementHandle<TypeElement>, ClasspathInfo>>() {
+                    private ClasspathInfo cpInfo;
+
+                    @Override
+                    public void setMessage(String msg) {
+                    }
+
+                    @Override
+                    public void setHighlightText(String text) {
+                    }
+
+                    @Override
+                    public void pendingResult() {
+                    }
+
+                    @Override
+                    public void runRoot(FileObject root, JavaTypeProvider.ResultHandler.Exec exec) throws IOException, InterruptedException {
+                        cpInfo = ClasspathInfo.create(root);
+                        try {
+                            exec.run();
+                        } finally {
+                            cpInfo = null;
+                        }
+                    }
+
+                    @Override
+                    public Pair<ElementHandle<TypeElement>, ClasspathInfo> create(JavaTypeProvider.CacheItem cacheItem, ElementHandle<TypeElement> handle, String simpleName, String relativePath) {
+                        return Pair.of(handle, cpInfo);
+                    }
+
+                    @Override
+                    public void addResult(List<? extends Pair<ElementHandle<TypeElement>, ClasspathInfo>> types) {
+                        pairs.addAll(types);
+                    }
+                };
+                JavaTypeProvider.doComputeTypes(searchType, queryFin, typeHandler, cancel);
+                Map<CompletableFuture<ElementOpen.Location>, ElementHandle<TypeElement>> location2Handles = new HashMap<>();
+                CompletableFuture<ElementOpen.Location>[] futures = pairs.stream().map(pair -> {
+                    CompletableFuture<ElementOpen.Location> future = ElementOpen.getLocation(pair.second(), pair.first(), pair.first().getQualifiedName().replace('.', '/') + ".class");
+                    location2Handles.put(future, pair.first());
+                    return future;
+                }).toArray(CompletableFuture[]::new);
+                CompletableFuture.allOf(futures).thenRun(() -> {
+                    for (CompletableFuture<ElementOpen.Location> future : futures) {
+                        ElementOpen.Location loc = future.getNow(null);
+                        ElementHandle<TypeElement> handle = location2Handles.get(future);
+                        if (loc != null && handle != null) {
+                            FileObject fo = loc.getFileObject();
+                            Location location = new Location(Utils.toUri(fo), new Range(Utils.createPosition(fo, loc.getStartOffset()), Utils.createPosition(fo, loc.getEndOffset())));
+                            String fqn = handle.getQualifiedName();
+                            int idx = fqn.lastIndexOf('.');
+                            String simpleName = idx < 0 ? fqn : fqn.substring(idx + 1);
+                            String contextName = idx < 0 ? null : fqn.substring(0, idx);
+                            SymbolInformation symbol = new SymbolInformation(simpleName, Utils.elementKind2SymbolKind(handle.getKind()), location, contextName);
+                            symbols.add(symbol);
+                        }
+                    }
+                    Collections.sort(symbols, (i1, i2) -> i1.getName().compareToIgnoreCase(i2.getName()));
+                    result.complete(symbols);
+                });
             } catch (Throwable t) {
                 result.completeExceptionally(t);
             }
diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
index d3d6076..159d74a 100644
--- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
+++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
@@ -1324,8 +1324,8 @@ public class ServerTest extends NbTestCase {
             assertEquals("length()", lengthItem.get().getInsertText());
             Optional<CompletionItem> substringItem = completion.getRight().getItems().stream().filter(ci -> ci.getLabel().startsWith("substring(") && ci.getLabel().contains(",")).findAny();
             assertTrue(substringItem.isPresent());
-            assertEquals(InsertTextFormat.PlainText, substringItem.get().getInsertTextFormat());
-            assertEquals("substring(", substringItem.get().getInsertText());
+            assertEquals(InsertTextFormat.Snippet, substringItem.get().getInsertTextFormat());
+            assertEquals("substring(${1:i}, ${2:i1})$0", substringItem.get().getInsertText());
         }
 
         {
@@ -1351,9 +1351,9 @@ public class ServerTest extends NbTestCase {
                 Either<List<CompletionItem>, CompletionList> completion = server.getTextDocumentService().completion(new CompletionParams(new TextDocumentIdentifier(toURI(src)), afterJavaLangAnnotation)).get();
                 assertTrue(completion.isRight());
                 completion.getRight().getItems().stream().forEach(ci -> System.err.println(ci.getLabel()));
-                Optional<CompletionItem> targetItem = completion.getRight().getItems().stream().filter(ci -> "Target".equals(ci.getLabel())).findAny();
+                Optional<CompletionItem> targetItem = completion.getRight().getItems().stream().filter(ci -> "Target (java.lang.annotation)".equals(ci.getLabel())).findAny();
                 assertTrue(targetItem.isPresent());
-                assertEquals("Target", targetItem.get().getLabel()); //TODO: insert text '('!
+                assertEquals("Target (java.lang.annotation)", targetItem.get().getLabel()); //TODO: insert text '('!
                 assertEquals(CompletionItemKind.Interface, targetItem.get().getKind());
             }
 
@@ -1388,7 +1388,7 @@ public class ServerTest extends NbTestCase {
                 assertTrue(methodItem.isPresent());
                 assertEquals(InsertTextFormat.PlainText, methodItem.get().getInsertTextFormat());
                 assertEquals("ElementType.METHOD", methodItem.get().getInsertText());
-                assertEquals(0, methodItem.get().getAdditionalTextEdits().size());
+                assertNull(methodItem.get().getAdditionalTextEdits());
             }
         }
     }
@@ -1454,7 +1454,7 @@ public class ServerTest extends NbTestCase {
 
             Either<List<CompletionItem>, CompletionList> completion = server.getTextDocumentService().completion(new CompletionParams(new TextDocumentIdentifier(toURI(src)), new Position(2, 8 + "ArrayL".length()))).get();
             assertTrue(completion.isRight());
-            Optional<CompletionItem> arrayListItem = completion.getRight().getItems().stream().filter(ci -> "ArrayList".equals(ci.getLabel())).findAny();
+            Optional<CompletionItem> arrayListItem = completion.getRight().getItems().stream().filter(ci -> "ArrayList (java.util)".equals(ci.getLabel())).findAny();
             assertTrue(arrayListItem.isPresent());
             assertNull(arrayListItem.get().getAdditionalTextEdits());
             CompletableFuture<CompletionItem> resolvedItem = server.getTextDocumentService().resolveCompletionItem(arrayListItem.get());
@@ -1473,7 +1473,7 @@ public class ServerTest extends NbTestCase {
 
             Either<List<CompletionItem>, CompletionList> completion = server.getTextDocumentService().completion(new CompletionParams(new TextDocumentIdentifier(toURI(src)), new Position(3, 8 + "ArrayL".length()))).get();
             assertTrue(completion.isRight());
-            Optional<CompletionItem> arrayListItem = completion.getRight().getItems().stream().filter(ci -> "ArrayList".equals(ci.getLabel())).findAny();
+            Optional<CompletionItem> arrayListItem = completion.getRight().getItems().stream().filter(ci -> "ArrayList (java.util)".equals(ci.getLabel())).findAny();
             assertTrue(arrayListItem.isPresent());
             assertNull(arrayListItem.get().getAdditionalTextEdits());
             CompletableFuture<CompletionItem> resolvedItem = server.getTextDocumentService().resolveCompletionItem(arrayListItem.get());
@@ -1743,12 +1743,12 @@ public class ServerTest extends NbTestCase {
         InitializeResult result = server.initialize(initParams).get();
         indexingComplete.await();
         List<? extends SymbolInformation> symbols = server.getWorkspaceService().symbol(new WorkspaceSymbolParams("Tes")).get();
-        List<String> actual = symbols.stream().map(si -> si.getKind() + ":" + si.getName() + ":" + si.getContainerName() + ":" + si.getDeprecated() + ":" + toString(si.getLocation())).collect(Collectors.toList());
-        assertEquals(Arrays.asList("Class:Test:Test:false:Test.java:0:0-3:1",
-                                   "Constructor:Test():Test:false:Test.java:0:7-0:7",
-                                   "Method:testMethod():Test:false:Test.java:2:4-2:38",
-                                   "Class:TestNested:Test.TestNested:false:Test.java:1:4-1:37",
-                                   "Constructor:TestNested():Test.TestNested:false:Test.java:1:18-1:18"),
+        List<String> actual = symbols.stream().map(si -> si.getKind() + ":" + si.getName() + ":" + si.getContainerName() + ":" + toString(si.getLocation())).collect(Collectors.toList());
+        assertEquals(Arrays.asList("Class:Test:null:Test.java:0:13-0:17",
+                                   "Constructor:Test():Test:Test.java:0:7-0:7",
+                                   "Method:testMethod():Test:Test.java:2:4-2:38",
+                                   "Class:TestNested:Test:Test.java:1:24-1:34",
+                                   "Constructor:TestNested():Test.TestNested:Test.java:1:18-1:18"),
                      actual);
     }
 
@@ -3984,7 +3984,7 @@ public class ServerTest extends NbTestCase {
         Either<List<CompletionItem>, CompletionList> completion = server.getTextDocumentService().completion(new CompletionParams(new TextDocumentIdentifier(toURI(src)), new Position(0, 15))).get();
         assertTrue(completion.isRight());
         List<String> actualItems = completion.getRight().getItems().stream().map(ci -> ci.getKind() + ":" + ci.getLabel()).collect(Collectors.toList());
-        assertEquals(Arrays.asList("Interface:SuppressWarnings"), actualItems);
+        assertEquals(Arrays.asList("Interface:SuppressWarnings (java.lang)"), actualItems);
         VersionedTextDocumentIdentifier id = new VersionedTextDocumentIdentifier(1);
         id.setUri(toURI(src));
         server.getTextDocumentService().didChange(new DidChangeTextDocumentParams(id, Arrays.asList(new TextDocumentContentChangeEvent(new Range(new Position(0, 1), new Position(0, 15)), 14, "SuppressWarnings(v"))));
diff --git a/java/java.sourceui/nbproject/project.xml b/java/java.sourceui/nbproject/project.xml
index 9558ec0..60cd86a 100644
--- a/java/java.sourceui/nbproject/project.xml
+++ b/java/java.sourceui/nbproject/project.xml
@@ -323,6 +323,11 @@
                         <compile-dependency/>
                     </test-dependency>
                     <test-dependency>
+                        <code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
+                        <compile-dependency/>
+                        <test/>
+                    </test-dependency>
+                    <test-dependency>
                         <code-name-base>org.netbeans.modules.java.lexer</code-name-base>
                         <compile-dependency/>
                     </test-dependency>
@@ -350,6 +355,11 @@
                         <test/>
                     </test-dependency>
                     <test-dependency>
+                        <code-name-base>org.netbeans.modules.parsing.indexing</code-name-base>
+                        <compile-dependency/>
+                        <test/>
+                    </test-dependency>
+                    <test-dependency>
                         <code-name-base>org.netbeans.modules.parsing.nb</code-name-base>
                         <compile-dependency/>
                     </test-dependency>
diff --git a/java/java.sourceui/src/org/netbeans/api/java/source/ui/ElementOpen.java b/java/java.sourceui/src/org/netbeans/api/java/source/ui/ElementOpen.java
index 50a5cbf..f445072 100644
--- a/java/java.sourceui/src/org/netbeans/api/java/source/ui/ElementOpen.java
+++ b/java/java.sourceui/src/org/netbeans/api/java/source/ui/ElementOpen.java
@@ -415,7 +415,7 @@ public final class ElementOpen {
             result[0] = fo;
             getOffset(fo, handle, result, cancel);
             return result;
-        } catch (IOException e) {
+        } catch (Exception e) {
             Exceptions.printStackTrace(e);
             return null;
         }
diff --git a/java/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaTypeProvider.java b/java/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaTypeProvider.java
index 27a8942..a252c2c 100644
--- a/java/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaTypeProvider.java
+++ b/java/java.sourceui/src/org/netbeans/modules/java/source/ui/JavaTypeProvider.java
@@ -25,6 +25,7 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Logger;
 import java.util.logging.Level;
 import java.util.regex.Pattern;
@@ -85,7 +86,7 @@ public class JavaTypeProvider implements TypeProvider {
     //@NotThreadSafe //Confinement within a thread
     private Map<URI,CacheItem> rootCache;
 
-    private volatile boolean isCanceled = false;
+    private final AtomicBoolean canceled = new AtomicBoolean();
     private ClasspathInfo cpInfo;
 
     private final TypeElementFinder.Customizer customizer;
@@ -103,14 +104,14 @@ public class JavaTypeProvider implements TypeProvider {
 
     @Override
     public void cleanup() {
-        isCanceled = false;
+        canceled.set(false);
         DataCache.clear();
         setRootCache(null);
     }
 
     @Override
     public void cancel() {
-        isCanceled = true;
+        canceled.set(true);
     }
 
     public JavaTypeProvider() {
@@ -124,10 +125,43 @@ public class JavaTypeProvider implements TypeProvider {
 
     @Override
     public void computeTypeNames(Context context, final Result res) {
-        isCanceled = false;
+        canceled.set(false);
         String originalText = context.getText();
         SearchType searchType = context.getSearchType();
+        doComputeTypeNames(searchType, originalText, new ResultHandler<JavaTypeDescription>() {
+            @Override
+            public void setMessage(String msg) {
+                res.setMessage(msg);
+            }
 
+            @Override
+            public void setHighlightText(String text) {
+                res.setHighlightText(text);
+            }
+
+            @Override
+            public void pendingResult() {
+                res.pendingResult();
+            }
+
+            @Override
+            public void runRoot(FileObject root, ResultHandler.Exec exec) throws IOException, InterruptedException {
+                exec.run();
+            }
+
+            @Override
+            public JavaTypeDescription create(CacheItem cacheItem, ElementHandle<TypeElement> handle, String simpleName, String relativePath) {
+                return new JavaTypeDescription(cacheItem, handle, simpleName, relativePath);
+            }
+
+            @Override
+            public void addResult(List<? extends JavaTypeDescription> types) {
+                res.addResult(types);
+            }
+        }, canceled);
+    }
+
+    public <T> void doComputeTypeNames(SearchType searchType, String originalText, ResultHandler<T> handler, AtomicBoolean canceled) {
         final DataCache dataCache = DataCache.forText(originalText, searchType);
         assert dataCache != null;
         final CacheItem.DataCacheCallback callBack = new CacheItem.DataCacheCallback() {
@@ -152,7 +186,8 @@ public class JavaTypeProvider implements TypeProvider {
         default: throw new RuntimeException("Unexpected search type: " + searchType);
         }
 
-        if (getRootCache() == null) {
+        Map<URI, CacheItem> rootCache = getRootCache();
+        if (rootCache == null) {
             Map<URI,CacheItem> sources = null;
 
             if (cpInfo == null) {
@@ -166,11 +201,11 @@ public class JavaTypeProvider implements TypeProvider {
                         Collections.<String>emptySet());
 
                 for(FileObject root : srcRoots) {
-                    if ( isCanceled ) {
+                    if (canceled.get()) {
                         return;
                     }
                     final URL rootUrl = root.toURL();
-                    if ( isCanceled ) {
+                    if (canceled.get()) {
                         return;
                     } else {
                         try {
@@ -189,7 +224,7 @@ public class JavaTypeProvider implements TypeProvider {
                         Arrays.asList(new String [] { ClassPath.COMPILE, ClassPath.BOOT}));
 
                 for(FileObject root : binRoots) {
-                    if ( isCanceled ) {
+                    if (canceled.get()) {
                         return;
                     }
                     URL rootUrl = root.toURL();
@@ -199,7 +234,7 @@ public class JavaTypeProvider implements TypeProvider {
                             continue;
                         }
                     }
-                    if ( isCanceled ) {
+                    if (canceled.get()) {
                         return;
                     }
                     else {
@@ -222,7 +257,7 @@ public class JavaTypeProvider implements TypeProvider {
                 // bootPath
                 final String[] cpType = new String[1];
                 for (ClassPath.Entry entry : bootRoots) {
-                    if ( isCanceled ) {
+                    if (canceled.get()) {
                         return;
                     }
                     cpType[0] = ClassPath.BOOT;
@@ -237,7 +272,7 @@ public class JavaTypeProvider implements TypeProvider {
 
                 // classPath
                 for (ClassPath.Entry entry : compileRoots) {
-                    if ( isCanceled ) {
+                    if (canceled.get()) {
                         return;
                     }
                     cpType[0] = ClassPath.COMPILE;
@@ -252,7 +287,7 @@ public class JavaTypeProvider implements TypeProvider {
 
                 // sourcePath
                 for (ClassPath.Entry entry : sourceRoots) {
-                    if ( isCanceled ) {
+                    if (canceled.get()) {
                         return;
                     }
                     try {
@@ -263,7 +298,7 @@ public class JavaTypeProvider implements TypeProvider {
                 }
             }
 
-            if ( !isCanceled ) {
+            if (!canceled.get()) {
 //                cache = sources;
                 if (LOGGER.isLoggable(LEVEL)) {
                     LOGGER.log(LEVEL, "Querying following roots:"); //NOI18N
@@ -282,7 +317,7 @@ public class JavaTypeProvider implements TypeProvider {
 
         final Map<URI,CacheItem> c = getRootCache();
         if (c == null) return;
-        final ArrayList<JavaTypeDescription> types = new ArrayList<>(c.size() * 20);
+        final ArrayList<T> types = new ArrayList<>(c.size() * 20);
 
         // is scan in progress? If so, provide a message to user.
         final boolean scanInProgress = SourceUtils.isScanInProgress();
@@ -290,9 +325,9 @@ public class JavaTypeProvider implements TypeProvider {
             // ui message
             final String warningKind = NbBundle.getMessage(JavaTypeProvider.class, "LBL_TypeKind");
             final String message = NbBundle.getMessage(JavaTypeProvider.class, "LBL_ScanInProgress_warning", warningKind);
-            res.setMessage(message);
+            handler.setMessage(message);
         } else {
-            res.setMessage(null);
+            handler.setMessage(null);
         }
         int lastIndexOfDot = originalText.lastIndexOf("."); //NOI18N
         boolean isFullyQualifiedName = -1 != lastIndexOfDot;
@@ -301,12 +336,12 @@ public class JavaTypeProvider implements TypeProvider {
         if (isFullyQualifiedName) {
             packageName = createPackageRegExp(originalText.substring(0, lastIndexOfDot));
             typeName = originalText.substring(lastIndexOfDot + 1);
-            res.setHighlightText(typeName);
+            handler.setHighlightText(typeName);
         } else {
             packageName = null;
             typeName = originalText;
         }
-        final String textForQuery = getTextForQuery(typeName, nameKind, context.getSearchType());
+        final String textForQuery = getTextForQuery(typeName, nameKind, searchType);
 
         LOGGER.log(Level.FINE, "Text For Query ''{0}''.", originalText);
         if (customizer != null) {
@@ -323,9 +358,8 @@ public class JavaTypeProvider implements TypeProvider {
                 }
                 for (ElementHandle<TypeElement> name : names) {
                     ci.initIndex();
-                    JavaTypeDescription td = new JavaTypeDescription(ci, name);
-                    types.add(td);
-                    if (isCanceled) {
+                    types.add(handler.create(ci, name, null, null));
+                    if (canceled.get()) {
                         return;
                     }
                 }
@@ -333,7 +367,7 @@ public class JavaTypeProvider implements TypeProvider {
         } else {
             final Collection<CacheItem> nonCached = new ArrayDeque<>(c.size());
             for (CacheItem ci : c.values()) {
-                Collection<? extends JavaTypeDescription> cacheLine = dataCache.get(ci);
+                Collection<? extends T> cacheLine = dataCache.get(ci);
                 if (cacheLine != null) {
                     types.addAll(cacheLine);
                 } else {
@@ -347,16 +381,16 @@ public class JavaTypeProvider implements TypeProvider {
                         @Override
                         public Void run() throws IOException, InterruptedException {
                             for (final CacheItem ci : nonCached) {
-                                if (isCanceled) {
+                                if (canceled.get()) {
                                     return null;
                                 }
                                 try {
-                                    final Collection<JavaTypeDescription> ct = new ArrayList<>();
+                                    final Collection<T> ct = new ArrayList<>();
                                     boolean exists = false;
                                     //WB(dataCache[ci], ACTIVE)
                                     dataCache.put(ci, ACTIVE);
                                     try {
-                                        exists = ci.collectDeclaredTypes(packageName, textForQuery,nameKind, ct);
+                                        exists = ci.collectDeclaredTypes(packageName, textForQuery, nameKind, handler, ct);
                                         if (exists) {
                                             types.addAll(ct);
                                         }
@@ -366,7 +400,7 @@ public class JavaTypeProvider implements TypeProvider {
                                             dataCache.compareAndSet(
                                                 ci,
                                                 ACTIVE,
-                                                ct.isEmpty() ? Collections.<JavaTypeDescription>emptySet() : ct);
+                                                ct.isEmpty() ? Collections.<T>emptySet() : ct);
                                         } else {
                                             //WB(dataCache[ci], NULL)
                                             dataCache.put(ci, null);
@@ -387,17 +421,34 @@ public class JavaTypeProvider implements TypeProvider {
                     throw new AssertionError(ex);
                 }
             }
-            if ( isCanceled ) {
+            if (canceled.get()) {
                 return;
             }
             if (scanInProgress) {
-                res.pendingResult();
+                handler.pendingResult();
             }
         }
-        if ( !isCanceled ) {
+        if (!canceled.get()) {
             // Sorting is now done on the Go To Tpe dialog side
             // Collections.sort(types);
-            res.addResult(types);
+            handler.addResult(types);
+        }
+    }
+
+    public static void doComputeTypes(SearchType searchType, String originalText, ResultHandler handler, AtomicBoolean canceled) {
+        new JavaTypeProvider().doComputeTypeNames(searchType, originalText, handler, canceled);
+    }
+
+    public interface ResultHandler<T> {
+        public void setMessage(String msg);
+        public void setHighlightText(String text);
+        public void pendingResult();
+        public void runRoot(FileObject root, Exec exec) throws IOException, InterruptedException;
+        public T create(@NonNull final JavaTypeProvider.CacheItem cacheItem, @NonNull final ElementHandle<TypeElement> handle,
+                @NullAllowed final String simpleName, @NullAllowed final String relativePath);
+        public void addResult(List<? extends T> types);
+        public interface Exec {
+            public void run() throws IOException, InterruptedException;
         }
     }
 
@@ -544,7 +595,7 @@ public class JavaTypeProvider implements TypeProvider {
     }
 
     //@NotTreadSafe
-    static final class CacheItem implements ClassIndexImplListener {
+    public static final class CacheItem implements ClassIndexImplListener {
 
         private final URI rootURI;
         private final boolean isBinary;
@@ -647,11 +698,12 @@ public class JavaTypeProvider implements TypeProvider {
             return true;
         }
 
-        public  boolean collectDeclaredTypes(
+        public <T> boolean collectDeclaredTypes(
             @NullAllowed final Pattern packageName,
             @NonNull final String typeName,
             @NonNull NameKind kind,
-            @NonNull Collection<? super JavaTypeDescription> collector) throws IOException, InterruptedException {
+            @NonNull ResultHandler<T> resultHandler,
+            @NonNull Collection<? super T> collector) throws IOException, InterruptedException {
             if (!initIndex()) {
                 return false;
             }
@@ -668,14 +720,17 @@ public class JavaTypeProvider implements TypeProvider {
                 //simple name
                 searchScope = baseSearchScope;
             }
+            NameKind finalKind = kind;
             try {
-                index.getDeclaredElements(
-                    typeName,
-                    kind,
-                    Collections.unmodifiableSet(Collections.<SearchScopeType>singleton(searchScope)),
-                    DocumentUtil.declaredTypesFieldSelector(true, true),
-                    new JavaTypeDescriptionConvertor(this),
-                    collector);
+                resultHandler.runRoot(getRoot(), () -> {
+                    index.getDeclaredElements(
+                        typeName,
+                        finalKind,
+                        Collections.unmodifiableSet(Collections.<SearchScopeType>singleton(searchScope)),
+                        DocumentUtil.declaredTypesFieldSelector(true, true),
+                        new JavaConvertor(this, resultHandler),
+                        collector);
+                });
             } catch (Index.IndexClosedException ice) {
                 //Closed after put into rootCache, ignore
             }
@@ -765,20 +820,22 @@ public class JavaTypeProvider implements TypeProvider {
             void handleDataCacheChange(@NonNull final CacheItem ci);
         }
 
-        private static class JavaTypeDescriptionConvertor implements Convertor<Document, JavaTypeDescription> {
+        private static class JavaConvertor<T> implements Convertor<Document, T> {
 
             private static final Pattern ANONYMOUS = Pattern.compile(".*\\$\\d+(\\$.+)?");   //NOI18N
             private static final Convertor<Document,ElementHandle<TypeElement>> HANDLE_CONVERTOR = DocumentUtil.typeElementConvertor();
             private static final Convertor<Document,String> SOURCE_CONVERTOR = DocumentUtil.sourceNameConvertor();
 
             private final CacheItem ci;
+            private final ResultHandler<T> handler;
 
-            JavaTypeDescriptionConvertor(@NonNull final CacheItem ci) {
+            JavaConvertor(@NonNull final CacheItem ci, @NonNull ResultHandler<T> handler) {
                 this.ci = ci;
+                this.handler = handler;
             }
 
             @Override
-            public JavaTypeDescription convert(Document p) {
+            public T convert(Document p) {
                 final String binName = DocumentUtil.getSimpleBinaryName(p);
                 //The regexp still needed for class files older than 1.5 which has no enclosingMethod attr
                 if (binName == null || ANONYMOUS.matcher(binName).matches() || DocumentUtil.isLocal(p)) {
@@ -786,7 +843,7 @@ public class JavaTypeProvider implements TypeProvider {
                 }
                 final ElementHandle<TypeElement> eh = HANDLE_CONVERTOR.convert(p);
                 final String sourceName = SOURCE_CONVERTOR.convert(p);
-                return eh == null ? null : new JavaTypeDescription(
+                return eh == null ? null : handler.create(
                         ci,
                         eh,
                         DocumentUtil.getSimpleName(p),
@@ -798,7 +855,7 @@ public class JavaTypeProvider implements TypeProvider {
     }
 
     //@ThreadSafe
-    private static final class DataCache {
+    private static final class DataCache<T> {
 
         //@GuardedBy("DataCache.class")
         private static String forText;
@@ -807,26 +864,26 @@ public class JavaTypeProvider implements TypeProvider {
             new EnumMap<>(SearchType.class);
 
         //@GuardedBy("this")
-        private final Map<CacheItem,Collection<? extends JavaTypeDescription>> dataCache = new HashMap<>();
+        private final Map<CacheItem,Collection<? extends T>> dataCache = new HashMap<>();
 
 
         private DataCache() {}
 
         @CheckForNull
-        synchronized Collection<? extends JavaTypeDescription> get(@NonNull final CacheItem item) {
+        synchronized Collection<? extends T> get(@NonNull final CacheItem item) {
             return dataCache.get(item);
         }
 
         synchronized void put (
             @NonNull final CacheItem item,
-            @NullAllowed final Collection<? extends JavaTypeDescription> data) {
+            @NullAllowed final Collection<? extends T> data) {
             dataCache.put(item, data);
         }
 
         synchronized boolean compareAndSet(
             @NonNull final CacheItem item,
-            @NullAllowed final Collection<? extends JavaTypeDescription> expected,
-            @NullAllowed final Collection<? extends JavaTypeDescription> update) {
+            @NullAllowed final Collection<? extends T> expected,
+            @NullAllowed final Collection<? extends T> update) {
             if (dataCache.get(item) == expected) {
                 dataCache.put(item,update);
                 return true;

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists