Skip to content

Commit

Permalink
Merge pull request #8094 from matthiasblaesing/groovy-occurrences
Browse files Browse the repository at this point in the history
[Groovy] Prevent NPE for mark occurrences
  • Loading branch information
matthiasblaesing authored Dec 27, 2024
2 parents e60cf75 + 294f4af commit 2844d32
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 11 deletions.
2 changes: 1 addition & 1 deletion groovy/groovy.editor/nbproject/project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# specific language governing permissions and limitations
# under the License.
javac.compilerargs=-Xlint -Xlint:-serial
javac.source=1.8
javac.release=17

javadoc.arch=${basedir}/arch.xml
javadoc.apichanges=${basedir}/apichanges.xml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package org.netbeans.modules.groovy.editor.api.parser;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
Expand All @@ -41,7 +42,7 @@
/**
* The (call-)proctocol for OccurrencesFinder is always:
*
* 1.) setCaretPosition() = <number>
* 1.) setCaretPosition() = NUMBER
* 2.) run()
* 3.) getOccurrences()
*
Expand All @@ -52,7 +53,7 @@ public class GroovyOccurrencesFinder extends OccurrencesFinder<GroovyParserResul

private boolean cancelled;
private int caretPosition;
private Map<OffsetRange, ColoringAttributes> occurrences;
private Map<OffsetRange, ColoringAttributes> occurrences = Map.of();
private FileObject file;
private static final Logger LOG = Logger.getLogger(GroovyOccurrencesFinder.class.getName());

Expand All @@ -61,6 +62,7 @@ public GroovyOccurrencesFinder() {
}

@Override
@SuppressWarnings("ReturnOfCollectionOrArrayField") // immutable collection
public Map<OffsetRange, ColoringAttributes> getOccurrences() {
LOG.log(Level.FINEST, "getOccurrences()\n"); //NOI18N
return occurrences;
Expand Down Expand Up @@ -102,7 +104,7 @@ public void run(GroovyParserResult result, SchedulerEvent event) {
// FIXME parsing API - null file
if (currentFile != file) {
// Ensure that we don't reuse results from a different file
occurrences = null;
occurrences = Map.of();
file = currentFile;
}

Expand Down Expand Up @@ -130,25 +132,25 @@ public void run(GroovyParserResult result, SchedulerEvent event) {
return;
}

Map<OffsetRange, ColoringAttributes> highlights = new HashMap<OffsetRange, ColoringAttributes>(100);
Map<OffsetRange, ColoringAttributes> highlights = new HashMap<>(100);
highlight(path, highlights, document, caretPosition);

if (isCancelled()) {
return;
}

if (highlights.size() > 0) {
Map<OffsetRange, ColoringAttributes> translated = new HashMap<OffsetRange, ColoringAttributes>(2 * highlights.size());
if (!highlights.isEmpty()) {
Map<OffsetRange, ColoringAttributes> translated = new HashMap<>(2 * highlights.size());
for (Map.Entry<OffsetRange, ColoringAttributes> entry : highlights.entrySet()) {
OffsetRange range = LexUtilities.getLexerOffsets(result, entry.getKey());
if (range != OffsetRange.NONE) {
translated.put(range, entry.getValue());
}
}
highlights = translated;
this.occurrences = highlights;
this.occurrences = Collections.unmodifiableMap(highlights);
} else {
this.occurrences = null;
this.occurrences = Map.of();
}

}
Expand All @@ -171,9 +173,9 @@ private static void highlight(AstPath path, Map<OffsetRange, ColoringAttributes>
scopeVisitor.collect();
for (ASTNode astNode : scopeVisitor.getOccurrences()) {
OffsetRange range;
if (astNode instanceof FakeASTNode) {
if (astNode instanceof FakeASTNode fakeASTNode) {
String text = astNode.getText();
ASTNode orig = ((FakeASTNode) astNode).getOriginalNode();
ASTNode orig = fakeASTNode.getOriginalNode();
int line = orig.getLineNumber();
int column = orig.getColumnNumber();
if (line > 0 && column > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ List<OffsetRange> processImpl(ParserResult info, Document doc, int caretPosition

Map<OffsetRange, ColoringAttributes> highlights = finder.getOccurrences();

// Many implementatios of the OccurencesFinder don't follow the contract,
// that getOccurrences must not return null. Instead of blowing up with
// a NullPointer exception, log that problem and continue execution.
if (highlights == null) {
LOG.log(Level.WARNING, "org.netbeans.modules.csl.api.OccurrencesFinder.getOccurrences() non-null contract violation by {0}", language.getMimeType());
highlights = Map.of();
}

return List.copyOf(highlights.keySet());
}

Expand Down

0 comments on commit 2844d32

Please sign in to comment.