NullPointerException: Cannot invoke "java.util.List.get(int)" because "this.tokenElementTypes" is null
When building my plugin, there is a NullPointerException in the ANTLR adaptor. It seems benign because the build continues, is eventually successful, and the built plugin works correctly.
Steps to reproduce
- Clean gradle cache
- execute the gradle task
buildPlugin(actually, it should suffice to execute the gradle taskbuildSearchableOptions)
Expected behavior
Build completes successfully and without any errors
Actual behavior
Build completes successfully but with one error due to the following NullPointerException:
> Task :myModule:buildSearchableOptions
CompileCommand: exclude com/intellij/openapi/vfs/impl/FilePartNodeRoot.trieDescend bool exclude = true
2023-04-05 14:00:17,534 [ 4793] SEVERE - #c.i.u.u.EdtInvocationManager - null
java.lang.reflect.InvocationTargetException
at java.desktop/java.awt.EventQueue.invokeAndWait(EventQueue.java:1379)
at java.desktop/java.awt.EventQueue.invokeAndWait(EventQueue.java:1354)
at com.intellij.util.ui.EdtInvocationManager$SwingEdtInvocationManager.invokeAndWait(EdtInvocationManager.java:103)
at com.intellij.util.ui.EdtInvocationManager.invokeAndWaitIfNeeded(EdtInvocationManager.java:84)
at com.intellij.ide.ui.search.TraverseUIStarter.startup(TraverseUIStarter.java:115)
at com.intellij.ide.ui.search.TraverseUIStarter.main(TraverseUIStarter.java:93)
at com.intellij.idea.ApplicationLoader.initApplicationImpl$lambda-3(ApplicationLoader.kt:174)
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1804)
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1796)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Caused by: java.lang.NullPointerException: Cannot invoke "java.util.List.get(int)" because "this.tokenElementTypes" is null
at org.antlr.intellij.adaptor.lexer.ANTLRLexerAdaptor.getTokenType(ANTLRLexerAdaptor.java:188)
at org.antlr.intellij.adaptor.lexer.ANTLRLexerAdaptor.getTokenType(ANTLRLexerAdaptor.java:178)
at com.intellij.openapi.editor.ex.util.ValidatingLexerWrapper.getTokenType(ValidatingLexerWrapper.java:50)
at com.intellij.openapi.editor.ex.util.LexerEditorHighlighter.doSetText(LexerEditorHighlighter.java:441)
at com.intellij.openapi.editor.ex.util.LexerEditorHighlighter.setText(LexerEditorHighlighter.java:418)
at com.intellij.openapi.editor.impl.EditorImpl.setHighlighter(EditorImpl.java:1359)
at com.intellij.application.options.colors.SimpleEditorPreview.updateView(SimpleEditorPreview.java:192)
at com.intellij.application.options.colors.NewColorAndFontPanel$3.schemeChanged(NewColorAndFontPanel.java:105)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at com.intellij.util.EventDispatcher.dispatchVoidMethod(EventDispatcher.java:120)
at com.intellij.util.EventDispatcher.lambda$createMulticaster$1(EventDispatcher.java:85)
at jdk.proxy2/jdk.proxy2.$Proxy80.schemeChanged(Unknown Source)
at com.intellij.application.options.colors.SchemesPanel.resetSchemesCombo(SchemesPanel.java:56)
at com.intellij.application.options.colors.NewColorAndFontPanel.resetSchemesCombo(NewColorAndFontPanel.java:156)
at com.intellij.application.options.colors.NewColorAndFontPanel.reset(NewColorAndFontPanel.java:144)
at com.intellij.application.options.colors.ColorAndFontOptions$InnerSearchableConfigurable.createPanel(ColorAndFontOptions.java:1333)
at com.intellij.application.options.colors.ColorAndFontOptions$InnerSearchableConfigurable.createComponent(ColorAndFontOptions.java:1363)
at com.intellij.ide.ui.search.SearchUtil.processConfigurables(SearchUtil.java:75)
at com.intellij.ide.ui.search.TraverseUIStarter.lambda$startup$0(TraverseUIStarter.java:120)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:308)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:779)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:730)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:724)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:749)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:909)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:756)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$5(IdeEventQueue.java:437)
at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:774)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:436)
at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:105)
at com.intellij.ide.IdeEventQueue.performActivity(IdeEventQueue.java:615)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:434)
at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:813)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:480)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)
Suggested fix
I think the fix is rather straight forward. Here is the code in question:
https://github.com/antlr/antlr4-intellij-adaptor/blob/e002d4d7cadb9f3a0a5db9202fed8533417b8cf5/src/main/java/org/antlr/intellij/adaptor/lexer/ANTLRLexerAdaptor.java#L56
https://github.com/antlr/antlr4-intellij-adaptor/blob/e002d4d7cadb9f3a0a5db9202fed8533417b8cf5/src/main/java/org/antlr/intellij/adaptor/lexer/ANTLRLexerAdaptor.java#L132
https://github.com/antlr/antlr4-intellij-adaptor/blob/e002d4d7cadb9f3a0a5db9202fed8533417b8cf5/src/main/java/org/antlr/intellij/adaptor/lexer/ANTLRLexerAdaptor.java#L181-L189
If tokenElementTypes is null (on line 188), then I think this method should return null. I had a similar problem in my code, and returning null in this case seems to have fixed the problem.
Other
For the record, this happens with the 0.1 release, which is currently the only release.
This exception stopped happening when I upgraded the version of IntelliJ from 2022.3 to 2023.1. Specifically, in my build.gradle file, I changed
intellij {
version = "2023.1"
plugins = ["PsiViewer:231-SNAPSHOT", "com.intellij.java"]
}
to
intellij {
version = "2022.3"
plugins = ["PsiViewer:223-SNAPSHOT", "com.intellij.java"]
}
Same problem on IC233
2023-10-26 20:41:10,558 [ 42461] SEVERE - #c.i.o.a.i.ActionUpdater - IntelliJ IDEA 2023.3 EAP Build #IC-233.10527.20
2023-10-26 20:41:10,558 [ 42461] SEVERE - #c.i.o.a.i.ActionUpdater - JDK: 17.0.8.1; VM: OpenJDK 64-Bit Server VM; Vendor: JetBrains s.r.o.
2023-10-26 20:41:10,558 [ 42461] SEVERE - #c.i.o.a.i.ActionUpdater - OS: Windows 11
2023-10-26 20:41:10,558 [ 42461] SEVERE - #c.i.o.a.i.ActionUpdater - Last Action: ShowSettings
Hi, and sorry for the late reply. I believe this error can happen when an ANTLRLexerAdaptor is instantiated automatically by the IDE before the plugin is finished loading. In your case, it's even possible that the buildSearchableOptions task doesn't load your plugin at all, otherwise your custom ParserDefinition would have called PSIElementTypeFactory.defineLanguageIElementTypes() and tokenElementTypes wouldn't be null.
We had a similar problem in the StringTemplate 4 plugin, and a contributor ended up using a lazy value to ensure the initialization is done even when the ParserDefinition is not instantiated.
However, I think the problem could also be fixed by creating your ANTLRLexerAdaptors in a single place, for example a static factory method:
class AntlrLexerFactory {
static {
PSIElementTypeFactory.defineLanguageIElementTypes(
YourLanguage.INSTANCE,
YourLexer.tokenNames,
YourParser.ruleNames
);
}
public static ANTLRLexerAdaptor createLexer(Lexer lexer) {
return new ANTLRLexerAdaptor(YourLanguage.INSTANCE, lexer);
}
}
This way, the static block will ensure a proper initialization before a lexer is created. Then you can remove this initialization from your ParserDefinition's constructor.
However, I think the problem could also be fixed by creating your
ANTLRLexerAdaptorsin a single place, for example a static factory method: [...] This way, the static block will ensure a proper initialization before a lexer is created. Then you can remove this initialization from yourParserDefinition's constructor.
Yes, this is a good suggestion.
Closing with this as the recommended solution.