Skip to content

Commit

Permalink
feat: Workspace symbols for JAX-RS endpoints
Browse files Browse the repository at this point in the history
Fixes #1363

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Aug 7, 2024
1 parent f55035d commit 869ead4
Show file tree
Hide file tree
Showing 20 changed files with 506 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Optional;

import javax.ws.rs.GET;
import javax.ws.rs.PATCH;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
Expand Down Expand Up @@ -40,4 +41,9 @@ public String hello2() {
public String hello3() {
return message + " 4 " + name.orElse("world") + suffix;
}

@PATCH
@Path("hello5")
public String hello5() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.Computable;
Expand All @@ -27,21 +28,15 @@
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.completion.JavaCompletionContext;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.definition.IJavaDefinitionParticipant;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.definition.JavaDefinitionContext;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.symbols.IJavaWorkspaceSymbolsParticipant;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.IPsiUtils;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.diagnostics.IJavaDiagnosticsParticipant;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.diagnostics.JavaDiagnosticsContext;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.hover.IJavaHoverParticipant;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.hover.JavaHoverContext;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.internal.core.java.codeaction.CodeActionHandler;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.CodeLens;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionList;
import org.eclipse.lsp4j.*;
import org.eclipse.lsp4mp.commons.*;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.Hover;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.PublishDiagnosticsParams;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
Expand Down Expand Up @@ -637,4 +632,43 @@ public CodeAction resolveCodeAction(CodeAction unresolved, IPsiUtils utils) {
return codeActionHandler.resolveCodeAction(unresolved, utils);
}

/**
* Returns the workspace symbols for the given java project.
*
* @param projectUri the uri of the java project
* @param utils the JDT utils
* @param monitor the progress monitor
* @return the workspace symbols for the given java project
*/
public List<SymbolInformation> workspaceSymbols(String projectUri, IPsiUtils utils, ProgressIndicator monitor) {
List<SymbolInformation> symbols = new ArrayList<>();
Module module = getModule(projectUri, utils);
if (module != null) {
collectWorkspaceSymbols(module, utils, symbols, monitor);
}
return symbols;
}

private static @Nullable Module getModule(String uri, IPsiUtils utils) {
Module[] modules = ModuleManager.getInstance(utils.getProject()).getModules();
for (Module module : modules) {
if (uri.equals(module.getName())) {
return module;
}
}
return null;
}

private void collectWorkspaceSymbols(Module project, IPsiUtils utils, List<SymbolInformation> symbols,
ProgressIndicator monitor) {
if (monitor.isCanceled()) {
return;
}

List<IJavaWorkspaceSymbolsParticipant> definitions = IJavaWorkspaceSymbolsParticipant.EP_NAME.getExtensionList();
if (definitions.isEmpty()) {
return;
}
definitions.forEach(definition -> definition.collectSymbols(project, utils, symbols, monitor));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
*
*/
public interface IJavaCodeLensParticipant {
public static final ExtensionPointName<IJavaCodeLensParticipant> EP_NAME = ExtensionPointName.create("com.redhat.devtools.intellij.quarkus.javaCodeLensParticipant");

ExtensionPointName<IJavaCodeLensParticipant> EP_NAME = ExtensionPointName.create("com.redhat.devtools.intellij.quarkus.javaCodeLensParticipant");


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
* @author datho7561
*/
public interface IJavaCompletionParticipant {
public static final ExtensionPointName<IJavaCompletionParticipant> EP_NAME = ExtensionPointName.create("com.redhat.devtools.intellij.quarkus.javaCompletionParticipant");

ExtensionPointName<IJavaCompletionParticipant> EP_NAME = ExtensionPointName.create("com.redhat.devtools.intellij.quarkus.javaCompletionParticipant");

/**
* Returns true if this completion feature should be active in this context, and false otherwise
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
*
*/
public interface IJavaDefinitionParticipant {
public static final ExtensionPointName<IJavaDefinitionParticipant> EP_NAME = ExtensionPointName.create("com.redhat.devtools.intellij.quarkus.javaDefinitionParticipant");

ExtensionPointName<IJavaDefinitionParticipant> EP_NAME = ExtensionPointName.create("com.redhat.devtools.intellij.quarkus.javaDefinitionParticipant");

/**
* Returns true if definition must be collected for the given context and false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
*/
public interface IJavaDiagnosticsParticipant {

public static final ExtensionPointName<IJavaDiagnosticsParticipant> EP_NAME = ExtensionPointName.create("com.redhat.devtools.intellij.quarkus.javaDiagnosticsParticipant");
ExtensionPointName<IJavaDiagnosticsParticipant> EP_NAME = ExtensionPointName.create("com.redhat.devtools.intellij.quarkus.javaDiagnosticsParticipant");

/**
* Returns true if diagnostics must be collected for the given context and false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
*/
public interface IJavaHoverParticipant {

public static final ExtensionPointName<IJavaHoverParticipant> EP_NAME = ExtensionPointName.create("com.redhat.devtools.intellij.quarkus.javaHoverParticipant");
ExtensionPointName<IJavaHoverParticipant> EP_NAME = ExtensionPointName.create("com.redhat.devtools.intellij.quarkus.javaHoverParticipant");

/**
* Returns true if hover must be collected for the given context and false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*******************************************************************************
* Copyright (c) 2024 Red Hat Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.symbols;

import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressIndicator;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.IPsiUtils;
import org.eclipse.lsp4j.SymbolInformation;

import java.util.List;

/**
* Represents an object that can collect workspace symbols for java projects.
*/
public interface IJavaWorkspaceSymbolsParticipant {

ExtensionPointName<IJavaWorkspaceSymbolsParticipant> EP_NAME = ExtensionPointName.create("com.redhat.devtools.intellij.quarkus.javaWorkspaceSymbolsParticipant");

/**
* Fill in <code>symbols</code> with workspace symbols of the given project.
*
* @param project the project to collect workspace symbols from
* @param utils the JDT utils
* @param symbols the list of symbols to add to
* @param monitor the progress monitor
*/
void collectSymbols(Module project, IPsiUtils utils, List<SymbolInformation> symbols,
ProgressIndicator monitor);

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,17 @@ public interface IJaxRsInfoProvider {
* Returns a non-null set of all the classes in the given project that this provider can provide JAX-RS method information for.
*
* @param javaProject the project to check for JAX-RS method information
* @param utils the Psi utilities.
* @param monitor the progress monitor
* @return a non-null set of all the classes in the given project that this provider can provide JAX-RS method information for
*/
@NotNull Set<PsiClass> getAllJaxRsClasses(@NotNull Module javaProject, @NotNull ProgressIndicator monitor);
@NotNull Set<PsiClass> getAllJaxRsClasses(@NotNull Module javaProject, @NotNull IPsiUtils utils, @NotNull ProgressIndicator monitor);

/**
* Returns a list of all the JAX-RS methods in the given type.
*
* @param type the type to check for JAX-RS methods
* @param jaxrsContext the JAX-RS context.
* @param monitor the progress monitor
* @return a list of all the JAX-RS methods in the given type
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,20 @@
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.psi.*;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.AnnotatedElementsSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.MergeQuery;
import com.intellij.util.Query;
import com.redhat.devtools.lsp4ij.LSPIJUtils;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.jaxrs.*;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.IPsiUtils;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.PsiTypeUtils;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand All @@ -49,14 +51,58 @@ public class DefaultJaxRsInfoProvider implements IJaxRsInfoProvider {
private static final Logger LOGGER = Logger.getLogger(DefaultJaxRsInfoProvider.class.getName());

@Override
public boolean canProvideJaxRsMethodInfoForClass(PsiFile typeRoot, Module javaProject, ProgressIndicator monitor) {
public boolean canProvideJaxRsMethodInfoForClass(@NotNull PsiFile typeRoot, Module javaProject, ProgressIndicator monitor) {
return PsiTypeUtils.findType(javaProject, JAVAX_WS_RS_PATH_ANNOTATION) != null
|| PsiTypeUtils.findType(javaProject, JAKARTA_WS_RS_PATH_ANNOTATION) != null;
}

@Override
public Set<PsiClass> getAllJaxRsClasses(Module javaProject, ProgressIndicator monitor) {
// TODO: implement when LSP4IJ will support workspace symbols
public Set<PsiClass> getAllJaxRsClasses(Module javaProject, IPsiUtils utils, ProgressIndicator monitor) {
if (monitor.isCanceled()) {
return Collections.emptySet();
}

try {
SearchScope scope = javaProject.getModuleScope(false);

Query<PsiModifierListOwner> query = null;
for (var httpAnnotation : JaxRsConstants.HTTP_METHOD_ANNOTATIONS) {
PsiClass annotationClass = utils.findClass(javaProject, httpAnnotation);
if (annotationClass != null) {
Query<PsiModifierListOwner> annotationQuery = AnnotatedElementsSearch.searchElements(annotationClass, scope, PsiModifierListOwner.class);
if (query == null) {
query = annotationQuery;
} else {
query = new MergeQuery<>(query, annotationQuery);
}
}
}
if (query == null) {
return Collections.emptySet();
}

Set<PsiClass> jaxRsClasses = new HashSet<>();
query.forEach((Consumer<? super PsiModifierListOwner>) item -> {
if (item instanceof PsiMember) {
PsiClass cl = ((PsiMember) item).getContainingClass();
if (cl != null) {
jaxRsClasses.add(cl);
}
}
});
if (monitor.isCanceled()) {
return Collections.emptySet();
}
return jaxRsClasses;
} catch (ProcessCanceledException e) {
//Since 2024.2 ProcessCanceledException extends CancellationException so we can't use multicatch to keep backward compatibility
//TODO delete block when minimum required version is 2024.2
throw e;
} catch (IndexNotReadyException | CancellationException e) {
throw e;
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "While collecting JAX-RS method information for project " + javaProject.getName(), e);
}
return Collections.emptySet();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public static JaxRsInfoProviderRegistry getInstance() {
return null;
}

private List<IJaxRsInfoProvider> getProviders() {
public List<IJaxRsInfoProvider> getProviders() {
if (!initialized) {
providers = loadProviders();
return providers;
Expand Down
Loading

0 comments on commit 869ead4

Please sign in to comment.