Skip to content

Commit 0d6fb1a

Browse files
committed
LSP: Push diagnostics collected on project indexing.
1 parent 68010b0 commit 0d6fb1a

File tree

8 files changed

+145
-75
lines changed

8 files changed

+145
-75
lines changed

enterprise/micronaut/src/org/netbeans/modules/micronaut/hints/MicronautConfigErrorProvider.java

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,6 @@
1818
*/
1919
package org.netbeans.modules.micronaut.hints;
2020

21-
import java.io.File;
22-
import java.io.FileOutputStream;
23-
import java.io.IOException;
24-
import java.io.OutputStreamWriter;
25-
import java.io.PrintWriter;
26-
import java.nio.charset.StandardCharsets;
2721
import java.util.ArrayList;
2822
import java.util.Collections;
2923
import java.util.List;
@@ -47,10 +41,10 @@
4741
import org.netbeans.modules.parsing.spi.Parser;
4842
import org.netbeans.modules.parsing.spi.indexing.CustomIndexer;
4943
import org.netbeans.modules.parsing.spi.indexing.CustomIndexerFactory;
44+
import org.netbeans.modules.parsing.spi.indexing.ErrorsCache;
5045
import org.netbeans.modules.parsing.spi.indexing.Indexable;
5146
import org.netbeans.spi.lsp.ErrorProvider;
5247
import org.openide.filesystems.FileObject;
53-
import org.openide.filesystems.FileUtil;
5448
import org.openide.util.Exceptions;
5549
import org.openide.util.NbBundle;
5650

@@ -61,6 +55,8 @@
6155
public class MicronautConfigErrorProvider extends CustomIndexer implements ErrorProvider {
6256

6357
private static final MicronautConfigErrorProvider INSTANCE = new MicronautConfigErrorProvider();
58+
private static final ErrorsCache.Convertor<Diagnostic> ERROR_CONVERTOR = new ErrorConvertorImpl();
59+
private static final String ERR_CODE_PREFIX = "WARN_PropertyWithoutValue:";
6460

6561
@MimeRegistrations({
6662
@MimeRegistration(mimeType = MicronautConfigUtilities.YAML_MIME, service = ErrorProvider.class),
@@ -90,7 +86,7 @@ protected void index(Iterable<? extends Indexable> files, org.netbeans.modules.p
9086
for (Indexable file : files) {
9187
FileObject fo = root.getFileObject(file.getRelativePath());
9288
if (fo != null && MicronautConfigUtilities.isMicronautConfigFile(fo)) {
93-
store(context.getIndexFolder(), file.getRelativePath(), computeErrors(fo));
89+
ErrorsCache.setErrors(context.getRootURI(), file, computeErrors(fo), ERROR_CONVERTOR);
9490
}
9591
}
9692
}
@@ -109,12 +105,13 @@ public void run(ResultIterator it) throws Exception {
109105
if (language != null) {
110106
StructureScanner scanner = language.getStructure();
111107
if (scanner != null && result instanceof ParserResult) {
112-
scan(snapshot.getText().toString(), scanner.scan((ParserResult) result), structure -> {
108+
String text = snapshot.getText().toString();
109+
scan(text, scanner.scan((ParserResult) result), structure -> {
113110
int start = (int) structure.getPosition();
114111
int end = (int) structure.getEndPosition();
115112
diags.add(Diagnostic.Builder.create(() -> start, () -> end, Bundle.ERR_PropertyWithoutValue())
116113
.setSeverity(Diagnostic.Severity.Warning)
117-
.setCode("WARN_PropertyWithoutValue " + start + " - " + end)
114+
.setCode(ERR_CODE_PREFIX + text.substring(0, start).split("\n").length)
118115
.build());
119116
});
120117
}
@@ -127,7 +124,9 @@ public void run(ResultIterator it) throws Exception {
127124
}
128125
} else {
129126
int offset = 0;
130-
for(String line : Source.create(fo).createSnapshot().getText().toString().split("\n")) {
127+
String[] lines = Source.create(fo).createSnapshot().getText().toString().split("\n");
128+
for (int i = 0; i < lines.length; i++) {
129+
String line = lines[i];
131130
if (line.length() > 0 && !line.startsWith("#") && !line.startsWith("!")) {
132131
int eqIdx = line.indexOf('=');
133132
if (eqIdx > 0) {
@@ -136,7 +135,7 @@ public void run(ResultIterator it) throws Exception {
136135
int end = offset + line.length();
137136
diags.add(Diagnostic.Builder.create(() -> start, () -> end, Bundle.ERR_PropertyWithoutValue())
138137
.setSeverity(Diagnostic.Severity.Warning)
139-
.setCode("WARN_PropertyWithoutValue " + start + " - " + end)
138+
.setCode(ERR_CODE_PREFIX + (i + 1))
140139
.build());
141140
}
142141
}
@@ -147,29 +146,6 @@ public void run(ResultIterator it) throws Exception {
147146
return diags;
148147
}
149148

150-
private void store(FileObject indexFolder, String resourceName, List<? extends Diagnostic> diags) {
151-
File cacheRoot = FileUtil.toFile(indexFolder);
152-
File output = new File(cacheRoot, resourceName + ".err"); //NOI18N
153-
if (diags.isEmpty()) {
154-
if (output.exists()) {
155-
output.delete();
156-
}
157-
} else {
158-
output.getParentFile().mkdirs();
159-
try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(output), StandardCharsets.UTF_8))) {
160-
for (Diagnostic diag : diags) {
161-
pw.print(diag.getCode());
162-
pw.print(':'); //NOI18N
163-
pw.print(diag.getStartPosition().getOffset());
164-
pw.print('-'); //NOI18N
165-
pw.println(diag.getEndPosition().getOffset());
166-
}
167-
} catch (IOException ex) {
168-
Exceptions.printStackTrace(ex);
169-
}
170-
}
171-
}
172-
173149
private static void scan(String sourceText, List<? extends StructureItem> structures, Consumer<StructureItem> callback) {
174150
if (structures != null) {
175151
for (StructureItem structure : structures) {
@@ -221,4 +197,19 @@ public int getIndexVersion() {
221197
return MicronautSymbolFinder.VERSION;
222198
}
223199
}
200+
201+
private static final class ErrorConvertorImpl implements ErrorsCache.Convertor<Diagnostic> {
202+
@Override
203+
public ErrorsCache.ErrorKind getKind(Diagnostic t) {
204+
return t.getSeverity() == Diagnostic.Severity.Error ? ErrorsCache.ErrorKind.ERROR : ErrorsCache.ErrorKind.WARNING;
205+
}
206+
@Override
207+
public int getLineNumber(Diagnostic t) {
208+
return Integer.parseInt(t.getCode().substring(ERR_CODE_PREFIX.length()));
209+
}
210+
@Override
211+
public String getMessage(Diagnostic t) {
212+
return t.getDescription();
213+
}
214+
}
224215
}

enterprise/micronaut/src/org/netbeans/modules/micronaut/symbol/MicronautSymbolSearcher.java

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,6 @@ public Set<? extends Descriptor> getSymbols(Project project, String textForQuery
8686
if (!duplicates.isEmpty()) {
8787
control.diagnosticChanged(duplicates, "text/x-java");
8888
}
89-
Set<FileObject> errs = getResourcesWithErrors(project);
90-
if (!errs.isEmpty()) {
91-
control.diagnosticChanged(errs, null);
92-
}
9389
} catch (IOException ex) {
9490
Exceptions.printStackTrace(ex);
9591
}
@@ -129,35 +125,6 @@ static Set<SymbolDescriptor> getSymbolsWithPathDuplicates(Project project, FileO
129125
return duplicates;
130126
}
131127

132-
private static Set<FileObject> getResourcesWithErrors(Project project) {
133-
Set<FileObject> files = new HashSet<>();
134-
for (SourceGroup sg : ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_RESOURCES)) {
135-
try {
136-
FileObject root = sg.getRootFolder();
137-
FileObject cacheRoot = getCacheRoot(root.toURL());
138-
if (cacheRoot != null) {
139-
cacheRoot.refresh();
140-
Enumeration<? extends FileObject> children = cacheRoot.getChildren(true);
141-
while (children.hasMoreElements()) {
142-
FileObject child = children.nextElement();
143-
if (child.hasExt("err")) { //NOI18N
144-
String path = FileUtil.getRelativePath(cacheRoot, child);
145-
if (path != null) {
146-
FileObject fo = root.getFileObject(path.substring(0, path.length() - 4));
147-
if (fo != null) {
148-
files.add(fo);
149-
}
150-
}
151-
}
152-
}
153-
}
154-
} catch (IOException ex) {
155-
Exceptions.printStackTrace(ex);
156-
}
157-
}
158-
return files;
159-
}
160-
161128
private static Set<SymbolDescriptor> getSymbols(Project project, String textForQuery) {
162129
Set<SymbolDescriptor> symbols = new HashSet<>();
163130
for (SourceGroup sg : ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA)) {

ide/parsing.indexing/apichanges.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,20 @@ is the proper place.
8787
<!-- ACTUAL CHANGES BEGIN HERE: -->
8888

8989
<changes>
90+
<change id="ErrorsCache.getAllFilesWithRecord">
91+
<api name="IndexingAPI"/>
92+
<summary>Added method to ErrorsCache to return all files with error or warning</summary>
93+
<version major="9" minor="36"/>
94+
<date day="3" month="9" year="2024"/>
95+
<author login="dbalek"/>
96+
<compatibility source="compatible" binary="compatible" semantic="compatible" addition="yes"/>
97+
<description>
98+
<p>
99+
Added the <a href="@TOP@/org/netbeans/modules/parsing/spi/indexing/ErrorsCache.html#getAllFilesWithRecord-java.net.URL-">getAllFilesWithRecord()</a> method to return all files with error or warning.
100+
</p>
101+
</description>
102+
<class package="org.netbeans.modules.parsing.spi.indexing" name="ErrorsCache"/>
103+
</change>
90104
<change id="IndexabilityQuery">
91105
<api name="IndexingAPI"/>
92106
<summary>Allow plugins to exclude files from being indexed.</summary>

ide/parsing.indexing/nbproject/project.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# under the License.
1717
javac.source=1.8
1818
javac.compilerargs=-Xlint -Xlint:-serial
19-
spec.version.base=9.35.0
19+
spec.version.base=9.36.0
2020
is.autoload=true
2121
javadoc.apichanges=${basedir}/apichanges.xml
2222
javadoc.arch=${basedir}/arch.xml

ide/parsing.indexing/src/org/netbeans/modules/parsing/spi/indexing/ErrorsCache.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ public static Collection<? extends URL> getAllFilesInError(URL root) throws IOEx
6464
return Collections.unmodifiableCollection(TaskCache.getDefault().getAllFilesInError(root));
6565
}
6666

67+
/**Return all files with error or warning badge under the given source root
68+
*
69+
* @param root source root to test
70+
* @return all files with error or warning badge under the given root
71+
* @since 9.36
72+
*/
73+
public static Collection<? extends URL> getAllFilesWithRecord(URL root) throws IOException {
74+
return Collections.unmodifiableCollection(TaskCache.getDefault().getAllFilesWithRecord(root));
75+
}
76+
6777
/**Getter for properties of the given error description.
6878
*/
6979
public static interface Convertor<T> {
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.netbeans.modules.java.lsp.server.protocol;
20+
21+
import java.net.URL;
22+
import java.util.ArrayList;
23+
import java.util.Collection;
24+
import java.util.List;
25+
import java.util.Map;
26+
import java.util.WeakHashMap;
27+
import java.util.concurrent.Future;
28+
import java.util.stream.Collectors;
29+
import org.netbeans.api.lsp.Diagnostic;
30+
import org.netbeans.api.project.FileOwnerQuery;
31+
import org.netbeans.api.project.Project;
32+
import org.netbeans.modules.java.lsp.server.LspServerState;
33+
import org.netbeans.modules.parsing.spi.indexing.ErrorsCache;
34+
import org.openide.filesystems.URLMapper;
35+
import org.openide.util.Exceptions;
36+
import org.openide.util.lookup.Lookups;
37+
38+
/**
39+
*
40+
* @author Dusan Balek
41+
*/
42+
public final class ErrorsNotifier {
43+
44+
private final Map<LspServerState, Future<Void>> servers = new WeakHashMap<>();
45+
46+
public void connect(LspServerState server, Future<Void> future) {
47+
synchronized (servers) {
48+
servers.put(server, future);
49+
}
50+
}
51+
52+
public void notifyErrors(URL root) {
53+
List<LspServerState> toRemove = new ArrayList<>();
54+
List<LspServerState> toProcess = new ArrayList<>();
55+
synchronized (servers) {
56+
for (Map.Entry<LspServerState, Future<Void>> entry : servers.entrySet()) {
57+
if (entry.getValue().isDone()) {
58+
toRemove.add(entry.getKey());
59+
} else {
60+
toProcess.add(entry.getKey());
61+
}
62+
}
63+
servers.keySet().removeAll(toRemove);
64+
}
65+
try {
66+
Collection<? extends URL> filesWithErrors = ErrorsCache.getAllFilesWithRecord(root);
67+
if (!filesWithErrors.isEmpty()) {
68+
Project project = FileOwnerQuery.getOwner(root.toURI());
69+
for (LspServerState server : toProcess) {
70+
for (Project p : server.openedProjects().getNow(new Project[0])) {
71+
if (p == project) {
72+
Diagnostic.ReporterControl control = Diagnostic.findReporterControl(Lookups.fixed(server), null);
73+
control.diagnosticChanged(filesWithErrors.stream().map(url -> URLMapper.findFileObject(url)).filter(fo -> fo != null).collect(Collectors.toList()), null);
74+
}
75+
}
76+
}
77+
}
78+
} catch (Exception ex) {
79+
Exceptions.printStackTrace(ex);
80+
}
81+
}
82+
}

java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
import java.util.prefs.Preferences;
5050
import java.util.LinkedHashSet;
5151
import java.util.Objects;
52-
import java.util.WeakHashMap;
5352
import java.util.concurrent.CompletionException;
5453
import java.util.stream.Collectors;
5554
import java.util.concurrent.atomic.AtomicBoolean;
@@ -161,6 +160,7 @@
161160
public final class Server {
162161
private static final Logger LOG = Logger.getLogger(Server.class.getName());
163162
private static final LspServerTelemetryManager LSP_SERVER_TELEMETRY = new LspServerTelemetryManager();
163+
private static final ErrorsNotifier ERR_NOTIFIER = new ErrorsNotifier();
164164

165165
private Server() {
166166
}
@@ -183,7 +183,8 @@ public static NbLspServer launchServer(Pair<InputStream, OutputStream> io, LspSe
183183
((LanguageClientAware) server).connect(remote);
184184
msgProcessor.attachClient(server.client);
185185
Future<Void> runningServer = serverLauncher.startListening();
186-
LSP_SERVER_TELEMETRY.connect(server.client, runningServer);
186+
LSP_SERVER_TELEMETRY.connect(server.client, runningServer);
187+
ERR_NOTIFIER.connect(server, runningServer);
187188
return new NbLspServer(server, runningServer);
188189
}
189190

@@ -1405,13 +1406,14 @@ private CustomIndexerTelemetryFactory() {
14051406

14061407
@Override
14071408
public synchronized boolean scanStarted(Context context) {
1408-
LSP_SERVER_TELEMETRY.sendTelemetry(new TelemetryEvent(MessageType.Info.toString(), LSP_SERVER_TELEMETRY.SCAN_START_EVT, "nbls.scanStarted"));
1409-
return true;
1409+
LSP_SERVER_TELEMETRY.sendTelemetry(new TelemetryEvent(MessageType.Info.toString(), LSP_SERVER_TELEMETRY.SCAN_START_EVT, "nbls.scanStarted"));
1410+
return true;
14101411
}
14111412

14121413
@Override
14131414
public synchronized void scanFinished(Context context) {
1414-
LSP_SERVER_TELEMETRY.sendTelemetry(new TelemetryEvent(MessageType.Info.toString(),LSP_SERVER_TELEMETRY.SCAN_END_EVT,"nbls.scanFinished"));
1415+
LSP_SERVER_TELEMETRY.sendTelemetry(new TelemetryEvent(MessageType.Info.toString(),LSP_SERVER_TELEMETRY.SCAN_END_EVT,"nbls.scanFinished"));
1416+
ERR_NOTIFIER.notifyErrors(context.getRootURI());
14151417
}
14161418

14171419
@Override

java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2175,7 +2175,11 @@ public void diagnosticChanged(Collection<FileObject> files, String mimeType) {
21752175
try {
21762176
String uriString = url.toURI().toString();
21772177
String lspUri = URITranslator.getDefault().uriToLSP(uriString);
2178-
runDiagnosticTasks(lspUri);
2178+
server.asyncOpenFileOwner(f).thenRun(() -> {
2179+
Lookups.executeWith(new ProxyLookup(Lookups.singleton(client), Lookup.getDefault()), () -> {
2180+
runDiagnosticTasks(lspUri);
2181+
});
2182+
});
21792183
} catch (URISyntaxException ex) {
21802184
// should not happen
21812185
}

0 commit comments

Comments
 (0)