From ce2ac52895a8674dc0025534a707a726b05d5167 Mon Sep 17 00:00:00 2001 From: Michael Bien Date: Tue, 17 Feb 2026 05:40:25 +0100 Subject: [PATCH] Fix NPE on goto to invalid method reference - check if element is a record before listing components - removed reflective method calls and updated logic - added regression test --- .../modules/editor/java/GoToSupport.java | 35 ++++++------------- .../modules/editor/java/GoToSupportTest.java | 30 ++++++++++++++++ 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java b/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java index 31baf4708af2..4f2ace2b9268 100644 --- a/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java +++ b/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java @@ -45,8 +45,6 @@ import java.awt.Toolkit; import java.awt.event.KeyEvent; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.Collections; @@ -478,30 +476,17 @@ public static Context resolveContext(CompilationInfo controller, Document doc, i } } if (el != null && el.getKind() == ElementKind.METHOD) { - for (Element peer : el.getEnclosingElement().getEnclosedElements()) { - if (peer.getKind().name().contains("RECORD_COMPONENT")) { - try { - Class recordComponent = Class.forName("javax.lang.model.element.RecordComponentElement", true, VariableTree.class.getClassLoader()); - Method getAccessor = recordComponent.getDeclaredMethod("getAccessor"); - Method getRecordComponents = TypeElement.class.getDeclaredMethod("getRecordComponents"); - for (Element component : (Iterable) getRecordComponents.invoke(peer.getEnclosingElement())) { - if (Objects.equals(el, getAccessor.invoke(component))) { - el = component; - break; + Element enclosing = el.getEnclosingElement(); + if (enclosing.getKind() == ElementKind.RECORD) { + OUTER: + for (Element peer : enclosing.getEnclosedElements()) { + if (peer.getKind() == ElementKind.RECORD_COMPONENT) { + for (RecordComponentElement rc : ((TypeElement)enclosing).getRecordComponents()) { + if (Objects.equals(el, rc.getAccessor())) { + el = rc; + break OUTER; } } - } catch (ClassNotFoundException ex) { - Exceptions.printStackTrace(ex); - } catch (IllegalAccessException ex) { - Exceptions.printStackTrace(ex); - } catch (IllegalArgumentException ex) { - Exceptions.printStackTrace(ex); - } catch (InvocationTargetException ex) { - Exceptions.printStackTrace(ex); - } catch (NoSuchMethodException ex) { - Exceptions.printStackTrace(ex); - } catch (SecurityException ex) { - Exceptions.printStackTrace(ex); } } } @@ -869,7 +854,7 @@ public Void scan(Tree tree, Void p) { if (found != null) { return null; } - if (tree != null && "BINDING_PATTERN".equals(tree.getKind().name())) { + if (tree != null && tree.getKind() == Kind.BINDING_PATTERN) { if (process(new TreePath(getCurrentPath(), tree))) { return null; } diff --git a/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/GoToSupportTest.java b/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/GoToSupportTest.java index a506190feb74..a30a62edb932 100644 --- a/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/GoToSupportTest.java +++ b/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/GoToSupportTest.java @@ -72,6 +72,7 @@ import org.openide.util.Exceptions; import org.openide.util.lookup.ServiceProvider; import static java.nio.file.StandardCopyOption.*; +import java.util.concurrent.atomic.AtomicBoolean; /** * @@ -1620,6 +1621,35 @@ public void run(CompilationController parameter) throws Exception { assertTrue(wasCalled[0]); } + public void testNoExceptionOnInvalidMethodReference() throws Exception { + this.sourceLevel = getLatestSourceVersion(); + JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true; + final String code = """ + package test; + public class Test { + private static void method() { + javax.swing.event.ChangeListener l = Test::in|valid; + } + } + """; + AtomicBoolean called = new AtomicBoolean(); + performTest(code, new UiUtilsCaller() { + @Override public boolean open(FileObject fo, int pos) { + return false; + } + @Override public boolean open(ClasspathInfo info, ElementHandle el, String fileName) { + return false; + } + @Override public void beep(boolean goToSource, boolean goToJavadoc) { + fail("Should not be called."); + } + @Override public void warnCannotOpen(String displayName) { + called.set(true); + } + }, false, false); + assertTrue(called.get()); + } + private static boolean hasPatterns() { try { SourceVersion.valueOf("RELEASE_14"); //NOI18N