diff --git a/java/java-usages/openidea-java-usages.jar b/java/java-usages/openidea-java-usages.jar index 63ca14d94..c2924301e 100644 Binary files a/java/java-usages/openidea-java-usages.jar and b/java/java-usages/openidea-java-usages.jar differ diff --git a/java/java-usages/src/ai/openidea/implementations/ImplementationsCommand.java b/java/java-usages/src/ai/openidea/implementations/ImplementationsCommand.java index 821af09c2..50bd541af 100644 --- a/java/java-usages/src/ai/openidea/implementations/ImplementationsCommand.java +++ b/java/java-usages/src/ai/openidea/implementations/ImplementationsCommand.java @@ -8,6 +8,11 @@ import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.jdt.core.*; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchEngine; +import org.eclipse.jdt.internal.core.CreateTypeHierarchyOperation; +import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner; +import org.eclipse.jdt.internal.core.JavaModelManager; import org.eclipse.jdt.internal.corext.util.MethodOverrideTester; import org.eclipse.jdt.ls.core.internal.IDelegateCommandHandler; import org.eclipse.jdt.ls.core.internal.JDTUtils; @@ -56,7 +61,7 @@ public final class ImplementationsCommand implements IDelegateCommandHandler { return false; } if (type == null || type.getJavaProject() == null) return false; - IRegion sources = JavaCore.newRegion(); + List sources = new ArrayList<>(); for (IJavaProject project : JavaCore.create(ResourcesPlugin.getWorkspace().getRoot()).getJavaProjects()) { for (IPackageFragmentRoot fragmentRoot : project.getPackageFragmentRoots()) { if (fragmentRoot.getKind() == IPackageFragmentRoot.K_SOURCE || isKotlinOutput(fragmentRoot)) { @@ -64,7 +69,13 @@ public final class ImplementationsCommand implements IDelegateCommandHandler { } } } - ITypeHierarchy hierarchy = type.getJavaProject().newTypeHierarchy(type, sources, monitor); + // IType.newTypeHierarchy's operation over the sources: the index narrows the subtypes to the + // files that name a supertype, where a region hierarchy resolves every type in the region. + ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(DefaultWorkingCopyOwner.PRIMARY, true); + IJavaSearchScope scope = SearchEngine.createJavaSearchScope(sources.toArray(IJavaElement[]::new)); + CreateTypeHierarchyOperation operation = new CreateTypeHierarchyOperation(type, workingCopies, scope, true); + operation.runOperation(monitor); + ITypeHierarchy hierarchy = operation.getResult(); for (IType subtype : hierarchy.getAllSubtypes(type)) { if (monitor.isCanceled()) throw new OperationCanceledException(); IMember found; diff --git a/java/java-usages/tests/implementations.py b/java/java-usages/tests/implementations.py index ed39b519d..5655fb6a8 100644 --- a/java/java-usages/tests/implementations.py +++ b/java/java-usages/tests/implementations.py @@ -72,6 +72,21 @@ public class Task implements Runnable { public void run() { } } +''', + 'Anon.java': '''package zoo; + +public class Anon { + Repo make() { + class Local implements Repo { + public void save(Double item) { + } + } + return new Repo() { + public void save(Double item) { + } + }; + } +} ''', 'Use.java': '''package zoo; @@ -174,11 +189,11 @@ try: request('java/buildWorkspace', True) # (implementations in the sources, whether they are all there are) cases = { - # Classes, abstract ones too, and those of the bridged Kotlin output; not the sub-interface. - ('Repo.java', 'Repo'): (['Base.java:2', 'Longs.java:0', 'Numbers.java:2', 'Words.java:2'], True), + # Classes, abstract, local and anonymous ones too, and those of the bridged Kotlin output; not the sub-interface. + ('Repo.java', 'Repo'): (['Anon.java:4', 'Anon.java:8', 'Base.java:2', 'Longs.java:0', 'Numbers.java:2', 'Words.java:2'], True), # Through the type arguments; not the abstract re-declaration. - ('Repo.java', 'save(T'): (['Longs.java:0', 'Numbers.java:3', 'Words.java:3'], True), - ('Use.java', 'save("x")'): (['Longs.java:0', 'Numbers.java:3', 'Words.java:3'], True), + ('Repo.java', 'save(T'): (['Anon.java:5', 'Anon.java:9', 'Longs.java:0', 'Numbers.java:3', 'Words.java:3'], True), + ('Use.java', 'save("x")'): (['Anon.java:5', 'Anon.java:9', 'Longs.java:0', 'Numbers.java:3', 'Words.java:3'], True), ('Repo.java', 'name()'): (['Words.java:6'], True), # A library type's implementations in the sources; the library has more. ('Use.java', 'Runnable task'): (['Task.java:2'], False),