diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/BuildWorkspaceHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/BuildWorkspaceHandler.java index a0fc928fd5..30c2db7492 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/BuildWorkspaceHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/BuildWorkspaceHandler.java @@ -13,38 +13,25 @@ import static org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin.logError; import static org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin.logException; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; -import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; -import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaModelMarker; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.ls.core.internal.BuildWorkspaceStatus; import org.eclipse.jdt.ls.core.internal.JDTUtils; import org.eclipse.jdt.ls.core.internal.JavaClientConnection; -import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; import org.eclipse.jdt.ls.core.internal.ProjectUtils; import org.eclipse.jdt.ls.core.internal.ResourceUtils; import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager; -import org.eclipse.jface.text.IDocument; -import org.eclipse.lsp4j.Diagnostic; -import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.PublishDiagnosticsParams; -import org.eclipse.lsp4j.Range; /** * @author xuzho @@ -53,10 +40,12 @@ public class BuildWorkspaceHandler { private JavaClientConnection connection; private final ProjectsManager projectsManager; + private final WorkspaceDiagnosticsHandler workspaceDiagnosticsHandler; - public BuildWorkspaceHandler(JavaClientConnection connection, ProjectsManager projectsManager) { + public BuildWorkspaceHandler(JavaClientConnection connection, ProjectsManager projectsManager, WorkspaceDiagnosticsHandler workspaceDiagnosticHandler) { this.connection = connection; this.projectsManager = projectsManager; + this.workspaceDiagnosticsHandler = workspaceDiagnosticHandler; } public BuildWorkspaceStatus buildWorkspace(boolean forceReBuild, IProgressMonitor monitor) { @@ -73,8 +62,7 @@ public BuildWorkspaceStatus buildWorkspace(boolean forceReBuild, IProgressMonito } } ResourcesPlugin.getWorkspace().build(forceReBuild ? IncrementalProjectBuilder.FULL_BUILD : IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor); - List problemMarkers = getProblemMarkers(monitor); - publishDiagnostics(problemMarkers); + List problemMarkers = workspaceDiagnosticsHandler.publishDiagnostics(monitor); List errors = problemMarkers.stream().filter(m -> m.getAttribute(IMarker.SEVERITY, 0) == IMarker.SEVERITY_ERROR).map(e -> convertMarker(e)).collect(Collectors.toList()); if (errors.isEmpty()) { return BuildWorkspaceStatus.SUCCEED; @@ -92,58 +80,6 @@ public BuildWorkspaceStatus buildWorkspace(boolean forceReBuild, IProgressMonito } } - private static List getProblemMarkers(IProgressMonitor monitor) throws CoreException { - IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); - List markers = new ArrayList<>(); - for (IProject project : projects) { - if (monitor.isCanceled()) { - throw new OperationCanceledException(); - } - markers.addAll(Arrays.asList(project.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE))); - } - return markers; - } - - private void publishDiagnostics(List markers) { - Map> map = markers.stream().collect(Collectors.groupingBy(IMarker::getResource)); - for (Map.Entry> entry : map.entrySet()) { - IResource resource = entry.getKey(); - // ignore problems caused by standalone files - if (JavaLanguageServerPlugin.getProjectsManager().getDefaultProject().equals(resource.getProject())) { - continue; - } - if (resource instanceof IProject) { - String uri = JDTUtils.getFileURI(resource); - Range range = new Range(new Position(0, 0), new Position(0, 0)); - List diagnostics = WorkspaceDiagnosticsHandler.toDiagnosticArray(range, entry.getValue().toArray(new IMarker[0])); - connection.publishDiagnostics(new PublishDiagnosticsParams(ResourceUtils.toClientUri(uri), diagnostics)); - continue; - } - IFile file = resource.getAdapter(IFile.class); - if (file == null) { - continue; - } - IDocument document = null; - String uri = JDTUtils.getFileURI(resource); - if (JavaCore.isJavaLikeFileName(file.getName())) { - ICompilationUnit cu = JDTUtils.resolveCompilationUnit(uri); - try { - document = JsonRpcHelpers.toDocument(cu.getBuffer()); - } catch (JavaModelException e) { - logException("Failed to publish diagnostics.", e); - } - } - else if (projectsManager.isBuildFile(file)) { - document = JsonRpcHelpers.toDocument(file); - } - - if (document != null) { - List diagnostics = WorkspaceDiagnosticsHandler.toDiagnosticsArray(document, entry.getValue().toArray(new IMarker[0])); - connection.publishDiagnostics(new PublishDiagnosticsParams(ResourceUtils.toClientUri(uri), diagnostics)); - } - } - } - private static String convertMarker(IMarker marker) { StringBuilder builder = new StringBuilder(); String message = marker.getAttribute(IMarker.MESSAGE, ""); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/InitHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/InitHandler.java index 8aa335086f..d79af44154 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/InitHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/InitHandler.java @@ -21,7 +21,6 @@ import java.util.Map; import java.util.Set; -import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.WorkspaceJob; import org.eclipse.core.runtime.CoreException; @@ -66,7 +65,6 @@ final public class InitHandler { private ProjectsManager projectsManager; private JavaClientConnection connection; private PreferenceManager preferenceManager; - private static WorkspaceDiagnosticsHandler workspaceDiagnosticsHandler; public InitHandler(ProjectsManager manager, PreferenceManager preferenceManager, JavaClientConnection connection) { this.projectsManager = manager; @@ -123,7 +121,6 @@ InitializeResult initialize(InitializeParams param) { } preferenceManager.getPreferences().setRootPaths(rootPaths); triggerInitialization(rootPaths); - addWorkspaceDiagnosticsHandler(); Integer processId = param.getProcessId(); if (processId != null) { JavaLanguageServerPlugin.getLanguageServer().setParentProcessId(processId.longValue()); @@ -221,6 +218,7 @@ public IStatus runInWorkspace(IProgressMonitor monitor) { try { projectsManager.setAutoBuilding(false); projectsManager.initializeProjects(roots, subMonitor); + projectsManager.setAutoBuilding(preferenceManager.getPreferences().isAutobuildEnabled()); JavaLanguageServerPlugin.logInfo("Workspace initialized in " + (System.currentTimeMillis() - start) + "ms"); connection.sendStatus(ServiceStatus.Started, "Ready"); } catch (OperationCanceledException e) { @@ -261,17 +259,4 @@ private T getInitializationOption(Map initializationOptions, String ke return null; } - @Deprecated - public static void removeWorkspaceDiagnosticsHandler() { - if (workspaceDiagnosticsHandler != null) { - ResourcesPlugin.getWorkspace().removeResourceChangeListener(workspaceDiagnosticsHandler); - workspaceDiagnosticsHandler = null; - } - } - - public void addWorkspaceDiagnosticsHandler() { - removeWorkspaceDiagnosticsHandler(); - workspaceDiagnosticsHandler = new WorkspaceDiagnosticsHandler(connection, projectsManager); - ResourcesPlugin.getWorkspace().addResourceChangeListener(workspaceDiagnosticsHandler, IResourceChangeEvent.POST_CHANGE); - } } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java index e658667a8d..f608dceb6c 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java @@ -124,6 +124,7 @@ public class JDTLanguageServer implements LanguageServer, TextDocumentService, W private LanguageServerWorkingCopyOwner workingCopyOwner; private PreferenceManager preferenceManager; private DocumentLifeCycleHandler documentLifeCycleHandler; + private WorkspaceDiagnosticsHandler workspaceDiagnosticsHandler; private Set registeredCapabilities = new HashSet<>(3); @@ -205,12 +206,18 @@ public void initialized(InitializedParams params) { // we do not have the user setting initialized yet at this point but we should // still call to enable defaults in case client does not support configuration changes syncCapabilitiesToSettings(); - try { - boolean autoBuildChanged = pm.setAutoBuilding(preferenceManager.getPreferences().isAutobuildEnabled()); - buildWorkspace(autoBuildChanged); - } catch (CoreException e) { - JavaLanguageServerPlugin.logException(e.getMessage(), e); - } + + workspaceDiagnosticsHandler = new WorkspaceDiagnosticsHandler(this.client, pm); + workspaceDiagnosticsHandler.addResourceChangeListener(); + + computeAsync((monitor) -> { + try { + workspaceDiagnosticsHandler.publishDiagnostics(monitor); + } catch (CoreException e) { + logException(e.getMessage(), e); + } + return new Object(); + }); } /** @@ -250,7 +257,10 @@ public CompletableFuture shutdown() { logInfo(">> shutdown"); return computeAsync((monitor) -> { try { - InitHandler.removeWorkspaceDiagnosticsHandler(); + if (workspaceDiagnosticsHandler != null) { + workspaceDiagnosticsHandler.removeResourceChangeListener(); + workspaceDiagnosticsHandler = null; + } ResourcesPlugin.getWorkspace().save(true, monitor); } catch (CoreException e) { logException(e.getMessage(), e); @@ -687,7 +697,7 @@ public void projectConfigurationUpdate(TextDocumentIdentifier param) { @Override public CompletableFuture buildWorkspace(boolean forceReBuild) { logInfo(">> java/buildWorkspace (" + (forceReBuild ? "full)" : "incremental)")); - BuildWorkspaceHandler handler = new BuildWorkspaceHandler(client, pm); + BuildWorkspaceHandler handler = new BuildWorkspaceHandler(client, pm, workspaceDiagnosticsHandler); return computeAsync((monitor) -> handler.buildWorkspace(forceReBuild, monitor)); } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceDiagnosticsHandler.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceDiagnosticsHandler.java index bc21468a1c..632bf01ce0 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceDiagnosticsHandler.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceDiagnosticsHandler.java @@ -10,22 +10,29 @@ *******************************************************************************/ package org.eclipse.jdt.ls.core.internal.handlers; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaModelMarker; import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.ls.core.internal.JDTUtils; import org.eclipse.jdt.ls.core.internal.JavaClientConnection; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; @@ -56,6 +63,14 @@ public WorkspaceDiagnosticsHandler(JavaClientConnection connection, ProjectsMana this.projectsManager = projectsManager; } + public void addResourceChangeListener() { + ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE); + } + + public void removeResourceChangeListener() { + ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); + } + @Override public void resourceChanged(IResourceChangeEvent event) { try { @@ -128,6 +143,66 @@ else if (projectsManager.isBuildFile(file)) { return false; } + public List publishDiagnostics(IProgressMonitor monitor) throws CoreException { + List problemMarkers = getProblemMarkers(monitor); + publishDiagnostics(problemMarkers); + return problemMarkers; + } + + private List getProblemMarkers(IProgressMonitor monitor) throws CoreException { + IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); + List markers = new ArrayList<>(); + for (IProject project : projects) { + if (monitor != null && monitor.isCanceled()) { + throw new OperationCanceledException(); + } + markers.addAll(Arrays.asList(project.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE))); + markers.addAll(Arrays.asList(project.findMarkers(IJavaModelMarker.TASK_MARKER, true, IResource.DEPTH_INFINITE))); + } + return markers; + } + + private void publishDiagnostics(List markers) { + Map> map = markers.stream().collect(Collectors.groupingBy(IMarker::getResource)); + for (Map.Entry> entry : map.entrySet()) { + IResource resource = entry.getKey(); + // ignore problems caused by standalone files + if (JavaLanguageServerPlugin.getProjectsManager().getDefaultProject().equals(resource.getProject())) { + continue; + } + if (resource instanceof IProject) { + String uri = JDTUtils.getFileURI(resource); + Range range = new Range(new Position(0, 0), new Position(0, 0)); + List diagnostics = WorkspaceDiagnosticsHandler.toDiagnosticArray(range, entry.getValue().toArray(new IMarker[0])); + connection.publishDiagnostics(new PublishDiagnosticsParams(ResourceUtils.toClientUri(uri), diagnostics)); + continue; + } + IFile file = resource.getAdapter(IFile.class); + if (file == null) { + continue; + } + IDocument document = null; + String uri = JDTUtils.getFileURI(resource); + if (JavaCore.isJavaLikeFileName(file.getName())) { + ICompilationUnit cu = JDTUtils.resolveCompilationUnit(uri); + try { + document = JsonRpcHelpers.toDocument(cu.getBuffer()); + } catch (JavaModelException e) { + JavaLanguageServerPlugin.logException("Failed to publish diagnostics.", e); + } + } else if (projectsManager.isBuildFile(file)) { + document = JsonRpcHelpers.toDocument(file); + } + + if (document != null) { + List diagnostics = WorkspaceDiagnosticsHandler.toDiagnosticsArray(document, entry.getValue().toArray(new IMarker[0])); + connection.publishDiagnostics(new PublishDiagnosticsParams(ResourceUtils.toClientUri(uri), diagnostics)); + } + } + } + + + /** * Transforms {@link IMarker}s into a list of {@link Diagnostic}s * diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/BuildWorkspaceHandlerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/BuildWorkspaceHandlerTest.java index ebe8a4ae94..37428f6b69 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/BuildWorkspaceHandlerTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/BuildWorkspaceHandlerTest.java @@ -35,7 +35,7 @@ public class BuildWorkspaceHandlerTest extends AbstractProjectsManagerBasedTest @Before public void setUp() throws Exception { - handler = new BuildWorkspaceHandler(javaClient, projectsManager); + handler = new BuildWorkspaceHandler(javaClient, projectsManager, new WorkspaceDiagnosticsHandler(javaClient, projectsManager)); importProjects("maven/salut2"); file = linkFilesToDefaultProject("singlefile/Single.java"); } diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceDiagnosticsHandlerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceDiagnosticsHandlerTest.java index f396da1eb3..1d331111d9 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceDiagnosticsHandlerTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/handlers/WorkspaceDiagnosticsHandlerTest.java @@ -41,10 +41,10 @@ import org.eclipse.lsp4j.Range; import org.eclipse.m2e.core.internal.IMavenConstants; import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @@ -58,9 +58,14 @@ public class WorkspaceDiagnosticsHandlerTest extends AbstractProjectsManagerBase @Mock private JavaClientConnection connection; - @InjectMocks private WorkspaceDiagnosticsHandler handler; + @Before + public void setup() throws Exception { + handler = new WorkspaceDiagnosticsHandler(connection, projectsManager); + handler.addResourceChangeListener(); + } + @Test public void testToDiagnosticsArray() throws Exception { String msg1 = "Something's wrong Jim"; @@ -112,8 +117,6 @@ public void testToDiagnosticsArray() throws Exception { @Test public void testTaskMarkers() throws Exception { - InitHandler initHandler = new InitHandler(projectsManager, preferenceManager, connection); - initHandler.addWorkspaceDiagnosticsHandler(); //import project importProjects("eclipse/hello"); ArgumentCaptor captor = ArgumentCaptor.forClass(PublishDiagnosticsParams.class); @@ -179,8 +182,6 @@ public void testMavenMarkers() throws Exception { @Test public void testMarkerListening() throws Exception { - InitHandler initHandler = new InitHandler(projectsManager, preferenceManager, connection); - initHandler.addWorkspaceDiagnosticsHandler(); //import project importProjects("maven/broken"); @@ -220,8 +221,6 @@ public void testMarkerListening() throws Exception { @Test public void testProjectLevelMarkers() throws Exception { - InitHandler initHandler = new InitHandler(projectsManager, preferenceManager, connection); - initHandler.addWorkspaceDiagnosticsHandler(); //import project importProjects("maven/broken"); ArgumentCaptor captor = ArgumentCaptor.forClass(PublishDiagnosticsParams.class); @@ -246,8 +245,6 @@ public void testProjectLevelMarkers() throws Exception { @Test public void testProjectConfigurationIsNotUpToDate() throws Exception { - InitHandler initHandler = new InitHandler(projectsManager, preferenceManager, connection); - initHandler.addWorkspaceDiagnosticsHandler(); //import project importProjects("maven/salut"); IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("salut"); @@ -307,7 +304,7 @@ private IMarker createMavenMarker(int severity, String msg, int line, int start, @After public void removeResourceChangeListener() { - InitHandler.removeWorkspaceDiagnosticsHandler(); + handler.removeResourceChangeListener(); } } diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManagerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManagerTest.java index 6ae227c3d4..c32ebf414b 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManagerTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManagerTest.java @@ -26,6 +26,7 @@ import org.eclipse.jdt.ls.core.internal.JavaClientConnection.JavaLanguageClient; import org.eclipse.jdt.ls.core.internal.WorkspaceHelper; import org.eclipse.jdt.ls.core.internal.handlers.BuildWorkspaceHandler; +import org.eclipse.jdt.ls.core.internal.handlers.WorkspaceDiagnosticsHandler; import org.junit.Test; /** @@ -57,7 +58,7 @@ public void testCleanupDefaultProject() throws Exception { java.io.File physicalFile = new java.io.File(file.getLocationURI()); physicalFile.delete(); - BuildWorkspaceHandler handler = new BuildWorkspaceHandler(javaClient, projectsManager); + BuildWorkspaceHandler handler = new BuildWorkspaceHandler(javaClient, projectsManager, new WorkspaceDiagnosticsHandler(javaClient, projectsManager)); BuildWorkspaceStatus result = handler.buildWorkspace(true, monitor); waitForBackgroundJobs();