diff --git a/org.eclipse.jdt.debug.tests/console tests/org/eclipse/jdt/debug/tests/console/JavaStackTraceAmbiguityTest.java b/org.eclipse.jdt.debug.tests/console tests/org/eclipse/jdt/debug/tests/console/JavaStackTraceAmbiguityTest.java new file mode 100644 index 0000000000..fcb814f3fd --- /dev/null +++ b/org.eclipse.jdt.debug.tests/console tests/org/eclipse/jdt/debug/tests/console/JavaStackTraceAmbiguityTest.java @@ -0,0 +1,411 @@ +/******************************************************************************* + * Copyright (c) 2024 IBM Corporation. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - Implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.tests.console; + +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.debug.testplugin.JavaProjectHelper; +import org.eclipse.jdt.debug.tests.TestUtil; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.console.IHyperlink; +import org.eclipse.ui.texteditor.ITextEditor; + +public class JavaStackTraceAmbiguityTest extends AbstractJavaStackTraceConsoleTest { + + public JavaStackTraceAmbiguityTest(String name) { + super(name); + } + + public void testLinkNavigationTrueForNoParameters() throws Exception { + String projectName = "StackTest"; + IJavaProject project = createProject(projectName, "testfiles/Ambiguity/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false); + waitForBuild(); + waitForJobs(); + consoleDocumentWithText("Sample.tes3() line: 31"); + IHyperlink[] hyperlinks = fConsole.getHyperlinks(); + assertEquals("Wrong hyperlinks, listing all links: " + allLinks(), 2, hyperlinks.length); + String expectedText = "System.out.println(\"Expected_Zero_Parameter\");"; + try { + for (IHyperlink hyperlink : hyperlinks) { + closeAllEditors(); + hyperlink.linkActivated(); + IEditorPart editor = waitForEditorOpen(); + String[] selectedText = new String[1]; + sync(() -> selectedText[0] = getSelectedText(editor)); + selectedText[0] = selectedText[0].trim(); + assertEquals("Wrong text selected after hyperlink navigation", expectedText, selectedText[0]); + + } + } finally { + closeAllEditors(); + boolean force = true; + project.getProject().delete(force, new NullProgressMonitor()); + } + } + + public void testLinkNavigationTrueForSingleParameter() throws Exception { + String projectName = "StackTest"; + IJavaProject project = createProject(projectName, "testfiles/Ambiguity/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false); + waitForBuild(); + waitForJobs(); + consoleDocumentWithText("Sample.tes3(int) line: 31"); + IHyperlink[] hyperlinks = fConsole.getHyperlinks(); + assertEquals("Wrong hyperlinks, listing all links: " + allLinks(), 2, hyperlinks.length); + String expectedText = "System.out.println(\"Expected_Single_Parameter\");"; + try { + for (IHyperlink hyperlink : hyperlinks) { + closeAllEditors(); + hyperlink.linkActivated(); + IEditorPart editor = waitForEditorOpen(); + String[] selectedText = new String[1]; + sync(() -> selectedText[0] = getSelectedText(editor)); + selectedText[0] = selectedText[0].trim(); + assertEquals("Wrong text selected after hyperlink navigation", expectedText, selectedText[0]); + + } + } finally { + closeAllEditors(); + boolean force = true; + project.getProject().delete(force, new NullProgressMonitor()); + } + } + + public void testLinkNavigationTrueForMultipleParameters() throws Exception { + String projectName = "StackTest"; + IJavaProject project = createProject(projectName, "testfiles/Ambiguity/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false); + waitForBuild(); + waitForJobs(); + consoleDocumentWithText("Sample.tes3(int, String) line: 31"); + IHyperlink[] hyperlinks = fConsole.getHyperlinks(); + assertEquals("Wrong hyperlinks, listing all links: " + allLinks(), 2, hyperlinks.length); + String expectedText = "System.out.println(\"Expected_Multiple_Parameter\");"; + try { + for (IHyperlink hyperlink : hyperlinks) { + closeAllEditors(); + hyperlink.linkActivated(); + IEditorPart editor = waitForEditorOpen(); + String[] selectedText = new String[1]; + sync(() -> selectedText[0] = getSelectedText(editor)); + selectedText[0] = selectedText[0].trim(); + assertEquals("Wrong text selected after hyperlink navigation", expectedText, selectedText[0]); + + } + } finally { + closeAllEditors(); + boolean force = true; + project.getProject().delete(force, new NullProgressMonitor()); + } + } + + public void testLinkNavigationTrueForMultipleParameters_Three() throws Exception { + String projectName = "StackTest"; + IJavaProject project = createProject(projectName, "testfiles/Ambiguity/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false); + waitForBuild(); + waitForJobs(); + consoleDocumentWithText("Sample.tes3(int, String,Sample) line: 34"); + IHyperlink[] hyperlinks = fConsole.getHyperlinks(); + assertEquals("Wrong hyperlinks, listing all links: " + allLinks(), 2, hyperlinks.length); + String expectedText = "System.out.println(\"Expected_Multiple_Parameter_Three\");"; + try { + for (IHyperlink hyperlink : hyperlinks) { + closeAllEditors(); + hyperlink.linkActivated(); + IEditorPart editor = waitForEditorOpen(); + String[] selectedText = new String[1]; + sync(() -> selectedText[0] = getSelectedText(editor)); + selectedText[0] = selectedText[0].trim(); + assertEquals("Wrong text selected after hyperlink navigation", expectedText, selectedText[0]); + + } + } finally { + closeAllEditors(); + boolean force = true; + project.getProject().delete(force, new NullProgressMonitor()); + } + } + + public void testLinkNavigationTrueForOneNormalAndOneFullyQualifiedArguments() throws Exception { + String projectName = "StackTest"; + IJavaProject project = createProject(projectName, "testfiles/Ambiguity/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false); + waitForBuild(); + waitForJobs(); + consoleDocumentWithText("Sample.tesComplex(String[], URL[]) line: 37"); + IHyperlink[] hyperlinks = fConsole.getHyperlinks(); + assertEquals("Wrong hyperlinks, listing all links: " + allLinks(), 2, hyperlinks.length); + String expectedText = "System.out.println(\"Expected_One_normal_&_One_fully_qualified\");"; + try { + for (IHyperlink hyperlink : hyperlinks) { + closeAllEditors(); + hyperlink.linkActivated(); + IEditorPart editor = waitForEditorOpen(); + String[] selectedText = new String[1]; + sync(() -> selectedText[0] = getSelectedText(editor)); + selectedText[0] = selectedText[0].trim(); + assertEquals("Wrong text selected after hyperlink navigation", expectedText, selectedText[0]); + + } + } finally { + closeAllEditors(); + boolean force = true; + project.getProject().delete(force, new NullProgressMonitor()); + } + } + + public void testLinkNavigationTrueForBothFullyQualifiedArguments() throws Exception { + String projectName = "StackTest"; + IJavaProject project = createProject(projectName, "testfiles/Ambiguity/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false); + waitForBuild(); + waitForJobs(); + consoleDocumentWithText("Sample.tesComplex(Object, URL[]) line: 37"); + IHyperlink[] hyperlinks = fConsole.getHyperlinks(); + assertEquals("Wrong hyperlinks, listing all links: " + allLinks(), 2, hyperlinks.length); + String expectedText = "System.out.println(\"Expected_both_fully_qualified\");"; + try { + for (IHyperlink hyperlink : hyperlinks) { + closeAllEditors(); + hyperlink.linkActivated(); + IEditorPart editor = waitForEditorOpen(); + String[] selectedText = new String[1]; + sync(() -> selectedText[0] = getSelectedText(editor)); + selectedText[0] = selectedText[0].trim(); + assertEquals("Wrong text selected after hyperlink navigation", expectedText, selectedText[0]); + + } + } finally { + closeAllEditors(); + boolean force = true; + project.getProject().delete(force, new NullProgressMonitor()); + } + } + + public void testLinkNavigationTrueForSingleVarArgs() throws Exception { + String projectName = "StackTest"; + IJavaProject project = createProject(projectName, "testfiles/Ambiguity/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false); + waitForBuild(); + waitForJobs(); + consoleDocumentWithText("Sample.testMethod(Object...) line: 43"); + IHyperlink[] hyperlinks = fConsole.getHyperlinks(); + assertEquals("Wrong hyperlinks, listing all links: " + allLinks(), 2, hyperlinks.length); + String expectedText = "System.out.println(\"Expected_oneVarArgs\");"; + try { + for (IHyperlink hyperlink : hyperlinks) { + closeAllEditors(); + hyperlink.linkActivated(); + IEditorPart editor = waitForEditorOpen(); + String[] selectedText = new String[1]; + sync(() -> selectedText[0] = getSelectedText(editor)); + selectedText[0] = selectedText[0].trim(); + assertEquals("Wrong text selected after hyperlink navigation", expectedText, selectedText[0]); + + } + } finally { + closeAllEditors(); + boolean force = true; + project.getProject().delete(force, new NullProgressMonitor()); + } + } + + public void testLinkNavigationTrueForSingleVarArgsAndOneNormal() throws Exception { + String projectName = "StackTest"; + IJavaProject project = createProject(projectName, "testfiles/Ambiguity/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false); + waitForBuild(); + waitForJobs(); + consoleDocumentWithText("Sample.testMethod(Object,Object...) line: 40"); + IHyperlink[] hyperlinks = fConsole.getHyperlinks(); + assertEquals("Wrong hyperlinks, listing all links: " + allLinks(), 2, hyperlinks.length); + String expectedText = "System.out.println(\"Expected_oneNormal&oneVarArgs\");"; + try { + for (IHyperlink hyperlink : hyperlinks) { + closeAllEditors(); + hyperlink.linkActivated(); + IEditorPart editor = waitForEditorOpen(); + String[] selectedText = new String[1]; + sync(() -> selectedText[0] = getSelectedText(editor)); + selectedText[0] = selectedText[0].trim(); + assertEquals("Wrong text selected after hyperlink navigation", expectedText, selectedText[0]); + + } + } finally { + closeAllEditors(); + boolean force = true; + project.getProject().delete(force, new NullProgressMonitor()); + } + } + + public void testLinkNavigationTrueForGenerics() throws Exception { + String projectName = "StackTest"; + IJavaProject project = createProject(projectName, "testfiles/Ambiguity/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false); + waitForBuild(); + waitForJobs(); + consoleDocumentWithText("SampleGenerics(SampleGenerics).remove() line: 25"); + IHyperlink[] hyperlinks = fConsole.getHyperlinks(); + assertEquals("Wrong hyperlinks, listing all links: " + allLinks(), 2, hyperlinks.length); + String expectedText = "System.out.print(\"EXPECTED_GENERICS\");"; + try { + for (IHyperlink hyperlink : hyperlinks) { + closeAllEditors(); + hyperlink.linkActivated(); + IEditorPart editor = waitForEditorOpen(); + String[] selectedText = new String[1]; + sync(() -> selectedText[0] = getSelectedText(editor)); + selectedText[0] = selectedText[0].trim(); + assertEquals("Wrong text selected after hyperlink navigation", expectedText, selectedText[0]); + + } + } finally { + closeAllEditors(); + boolean force = true; + project.getProject().delete(force, new NullProgressMonitor()); + } + } + + public void testLinkNavigationTrueForComplexGenerics() throws Exception { + String projectName = "StackTest"; + IJavaProject project = createProject(projectName, "testfiles/Ambiguity/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false); + waitForBuild(); + waitForJobs(); + consoleDocumentWithText("ReferencePipeline$Head.forEach(Consumer) line: 1"); + IHyperlink[] hyperlinks = fConsole.getHyperlinks(); + assertEquals("Wrong hyperlinks, listing all links: " + allLinks(), 2, hyperlinks.length); + String expectedText = "/*"; + try { + for (IHyperlink hyperlink : hyperlinks) { + closeAllEditors(); + hyperlink.linkActivated(); + IEditorPart editor = waitForEditorOpen(); + String[] selectedText = new String[1]; + sync(() -> selectedText[0] = getSelectedText(editor)); + selectedText[0] = selectedText[0].trim(); + assertEquals("Wrong text selected after hyperlink navigation", expectedText, selectedText[0]); + + } + } finally { + closeAllEditors(); + boolean force = true; + project.getProject().delete(force, new NullProgressMonitor()); + } + } + + public void testLinkNavigationTrueForInnerClass() throws Exception { + String projectName = "StackTest"; + IJavaProject project = createProject(projectName, "testfiles/Ambiguity/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false); + waitForBuild(); + waitForJobs(); + consoleDocumentWithText("InnerClassTest$innerL1.check() line: 23"); + IHyperlink[] hyperlinks = fConsole.getHyperlinks(); + assertEquals("Wrong hyperlinks, listing all links: " + allLinks(), 2, hyperlinks.length); + String expectedText = "System.out.println(\"EXPECTED_INNERCLASS\");"; + try { + for (IHyperlink hyperlink : hyperlinks) { + closeAllEditors(); + hyperlink.linkActivated(); + IEditorPart editor = waitForEditorOpen(); + String[] selectedText = new String[1]; + sync(() -> selectedText[0] = getSelectedText(editor)); + selectedText[0] = selectedText[0].trim(); + assertEquals("Wrong text selected after hyperlink navigation", expectedText, selectedText[0]); + + } + } finally { + closeAllEditors(); + boolean force = true; + project.getProject().delete(force, new NullProgressMonitor()); + } + } + + public void testLinkNavigationTrueForInnerClassMultilevel() throws Exception { + String projectName = "StackTest"; + IJavaProject project = createProject(projectName, "testfiles/Ambiguity/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false); + waitForBuild(); + waitForJobs(); + consoleDocumentWithText("InnerClassTest$innerL1$innerL2.check2() line: 27"); + IHyperlink[] hyperlinks = fConsole.getHyperlinks(); + assertEquals("Wrong hyperlinks, listing all links: " + allLinks(), 2, hyperlinks.length); + String expectedText = "System.out.println(\"EXPECTED_INNER-INNER_CLASS\");"; + try { + for (IHyperlink hyperlink : hyperlinks) { + closeAllEditors(); + hyperlink.linkActivated(); + IEditorPart editor = waitForEditorOpen(); + String[] selectedText = new String[1]; + sync(() -> selectedText[0] = getSelectedText(editor)); + selectedText[0] = selectedText[0].trim(); + assertEquals("Wrong text selected after hyperlink navigation", expectedText, selectedText[0]); + + } + } finally { + closeAllEditors(); + boolean force = true; + project.getProject().delete(force, new NullProgressMonitor()); + } + } + + public void testLinkNavigationTrueForInnerClassParameters() throws Exception { + String projectName = "StackTest"; + IJavaProject project = createProject(projectName, "testfiles/Ambiguity/", JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false); + waitForBuild(); + waitForJobs(); + consoleDocumentWithText("ScheduledThreadPoolExecutor(ThreadPoolExecutor).runWorker(ThreadPoolExecutor$Worker) line: 36"); + IHyperlink[] hyperlinks = fConsole.getHyperlinks(); + assertEquals("Wrong hyperlinks, listing all links: " + allLinks(), 2, hyperlinks.length); + String expectedText = "package java.util.concurrent;"; + try { + for (IHyperlink hyperlink : hyperlinks) { + closeAllEditors(); + hyperlink.linkActivated(); + IEditorPart editor = waitForEditorOpen(); + String[] selectedText = new String[1]; + sync(() -> selectedText[0] = getSelectedText(editor)); + selectedText[0] = selectedText[0].trim(); + assertEquals("Wrong text selected after hyperlink navigation", expectedText, selectedText[0]); + + } + } finally { + closeAllEditors(); + boolean force = true; + project.getProject().delete(force, new NullProgressMonitor()); + } + } + private void waitForJobs() throws Exception { + TestUtil.waitForJobs(getName(), 250, 10_000); + } + + private static String getSelectedText(IEditorPart editor) { + ITextEditor textEditor = (ITextEditor) editor; + ISelectionProvider selectionProvider = textEditor.getSelectionProvider(); + ISelection selection = selectionProvider.getSelection(); + ITextSelection textSelection = (ITextSelection) selection; + String selectedText = textSelection.getText(); + return selectedText; + } + + private IEditorPart waitForEditorOpen() throws Exception { + waitForJobs(); + IEditorPart[] editor = new IEditorPart[1]; + sync(() -> editor[0] = getActivePage().getActiveEditor()); + long timeout = 30_000; + long start = System.currentTimeMillis(); + while (editor[0] == null && System.currentTimeMillis() - start < timeout) { + waitForJobs(); + sync(() -> editor[0] = getActivePage().getActiveEditor()); + } + if (editor[0] == null) { + throw new AssertionError("Timeout occurred while waiting for editor to open"); + } + return editor[0]; + } +} diff --git a/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/InnerClassTest.java b/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/InnerClassTest.java new file mode 100644 index 0000000000..26bafa709f --- /dev/null +++ b/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/InnerClassTest.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2024 IBM Corporation. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +/** + * Test class + */ +class InnerClassTest { + public static void main(String[] ar) { + + } + class innerL1 { + void check() { + System.out.println("EXPECTED_INNERCLASS"); + } + class innerL2 { + void check2() { + System.out.println("EXPECTED_INNER-INNER_CLASS"); + } + } + } +} + \ No newline at end of file diff --git a/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/SampleGenerics.java b/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/SampleGenerics.java new file mode 100644 index 0000000000..a06e4d6414 --- /dev/null +++ b/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/SampleGenerics.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2024 IBM Corporation. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +/** + * Test class + */ +class Node { + E data; + Node next; + Node(E data){}; +} +public class SampleGenerics { + private Node head; + public E remove() { + System.out.print("EXPECTED_GENERICS"); + return null; + } + +} diff --git a/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/a/Sample.java b/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/a/Sample.java new file mode 100644 index 0000000000..55f31cbe9e --- /dev/null +++ b/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/a/Sample.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2024 IBM Corporation. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package a; +import java.net.URL; +/** + * Test class + */ +public class Sample { + public static void main(String[] args) { + System.out.println("Main Method"); + test(); + } + public static void test() { + System.out.println("Testing.."); + } + public void testMethod() { + System.out.println("Random"); + } + public static void tes3(int x) { + System.out.println("Expected_Single_Parameter"); + } + public void tes2() { + + } + public static void tesComplex(String[] x, java.net.URL[] sx) { + System.out.println("Expected_One_normal_&_One_fully_qualified"); + } + +} diff --git a/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/b/Sample.java b/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/b/Sample.java new file mode 100644 index 0000000000..4f92cc2d5e --- /dev/null +++ b/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/b/Sample.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2024 IBM Corporation. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package b; + +/** + * Test class + */ +public class Sample { + public static void main(String[] args) { + System.out.println("Main Method"); + test(); + } + public static void test() { + System.out.println("Testing.."); + } + public void testMethod() { + System.out.println("Random"); + } + public static void tes3() { + System.out.println("Expected_Zero_Parameter"); + } + public void tes2() { + + } + public static void tesComplex(java.lang.Object x, java.net.URL[] sx) { + System.out.println("Expected_both_fully_qualified"); + } +} diff --git a/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/c/Sample.java b/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/c/Sample.java new file mode 100644 index 0000000000..df2db10b4b --- /dev/null +++ b/org.eclipse.jdt.debug.tests/testfiles/Ambiguity/c/Sample.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2024 IBM Corporation. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package c; + +/** + * Test class + */ +public class Sample { + public static void main(String[] args) { + System.out.println("Main Method"); + test(); + } + public static void test() { + System.out.println("Testing.."); + } + public void testMethod() { + System.out.println("Random"); + } + public static void tes3(int x, String v) { + System.out.println("Expected_Multiple_Parameter"); + } + public static void tes3(int x, String v, Sample s) { + System.out.println("Expected_Multiple_Parameter_Three"); + } + public void tes2() { + + } + public void testMethod(Object s,Object... sd) { + System.out.println("Expected_oneNormal&oneVarArgs"); + } + public void testMethod(Object... sd) { + System.out.println("Expected_oneVarArgs"); + } + +} diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java index 19fb79975a..3acddf70c6 100644 --- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java +++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java @@ -56,6 +56,7 @@ import org.eclipse.jdt.debug.tests.console.ConsoleTerminateAllActionTests; import org.eclipse.jdt.debug.tests.console.IOConsoleTests; import org.eclipse.jdt.debug.tests.console.JavaDebugStackTraceConsoleTest; +import org.eclipse.jdt.debug.tests.console.JavaStackTraceAmbiguityTest; import org.eclipse.jdt.debug.tests.console.JavaStackTraceConsoleTest; import org.eclipse.jdt.debug.tests.core.AlternateStratumTests; import org.eclipse.jdt.debug.tests.core.ArgumentTests; @@ -273,6 +274,7 @@ public AutomatedSuite() { addTest(new TestSuite(JavaDebugStackTraceConsoleTest.class)); addTest(new TestSuite(IOConsoleTests.class)); addTest(new TestSuite(ConsoleTerminateAllActionTests.class)); + addTest(new TestSuite(JavaStackTraceAmbiguityTest.class)); //Core tests addTest(new TestSuite(DebugEventTests.class)); diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaStackTraceHyperlink.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaStackTraceHyperlink.java index 63d2e41fc5..96f197dbef 100644 --- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaStackTraceHyperlink.java +++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaStackTraceHyperlink.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. + * Copyright (c) 2000, 2024 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -14,7 +14,6 @@ *******************************************************************************/ package org.eclipse.jdt.internal.debug.ui.console; - import java.util.ArrayList; import java.util.List; @@ -25,10 +24,13 @@ import org.eclipse.core.runtime.jobs.Job; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.internal.ui.DebugUIPlugin; import org.eclipse.debug.ui.IDebugModelPresentation; import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.IJavaSearchConstants; import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jdt.core.search.TypeNameMatch; @@ -37,6 +39,8 @@ import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin; import org.eclipse.jdt.internal.debug.ui.actions.OpenFromClipboardAction; import org.eclipse.jdt.internal.debug.ui.actions.OpenTypeAction; +import org.eclipse.jdt.launching.IVMInstall; +import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.BadLocationException; @@ -57,10 +61,13 @@ public class JavaStackTraceHyperlink implements IHyperlink { private final TextConsole fConsole; + private String originalHyperLink; /** * Constructor - * @param console the {@link TextConsole} this link detector is attached to + * + * @param console + * the {@link TextConsole} this link detector is attached to */ public JavaStackTraceHyperlink(TextConsole console) { fConsole = console; @@ -86,15 +93,16 @@ public void linkExited() { @Override public void linkActivated() { String typeName; - int lineNumber; - try { - String linkText = getLinkText(); - typeName = getTypeName(linkText); - lineNumber = getLineNumber(linkText); - } catch (CoreException e1) { - ErrorDialog.openError(JDIDebugUIPlugin.getActiveWorkbenchShell(), ConsoleMessages.JavaStackTraceHyperlink_Error, ConsoleMessages.JavaStackTraceHyperlink_Error, e1.getStatus()); - return; - } + int lineNumber; + try { + String linkText = getLinkText(); + originalHyperLink = linkText; + typeName = getTypeName(linkText); + lineNumber = getLineNumber(linkText); + } catch (CoreException e1) { + ErrorDialog.openError(JDIDebugUIPlugin.getActiveWorkbenchShell(), ConsoleMessages.JavaStackTraceHyperlink_Error, ConsoleMessages.JavaStackTraceHyperlink_Error, e1.getStatus()); + return; + } // documents start at 0 if (lineNumber > 0) { @@ -106,8 +114,10 @@ public void linkActivated() { /** * Starts a search for the type with the given name. Reports back to 'searchCompleted(...)'. * - * @param typeName the type to search for - * @param lineNumber the line number to open the editor on + * @param typeName + * the type to search for + * @param lineNumber + * the line number to open the editor on */ protected void startSourceSearch(final String typeName, final int lineNumber) { Job search = new Job(ConsoleMessages.JavaStackTraceHyperlink_2) { @@ -168,13 +178,18 @@ public void acceptTypeNameMatch(TypeNameMatch match) { searchEngine.searchAllTypeNames(qualifications, typeNames, SearchEngine.createWorkspaceScope(), requestor, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, null); return matchingTypes; } + /** * Reported back to from {@link JavaStackTraceHyperlink#startSourceSearch(String, int)} when results are found * - * @param source the source object - * @param typeName the fully qualified type name - * @param lineNumber the line number in the type - * @param status the error status or null if none + * @param source + * the source object + * @param typeName + * the fully qualified type name + * @param lineNumber + * the line number in the type + * @param status + * the error status or null if none */ protected void searchCompleted(final Object source, final String typeName, final int lineNumber, final IStatus status) { UIJob job = new UIJob("link search complete") { //$NON-NLS-1$ @@ -183,18 +198,209 @@ public IStatus runInUIThread(IProgressMonitor monitor) { if (source == null) { if (status == null) { // did not find source - MessageDialog.openInformation(JDIDebugUIPlugin.getActiveWorkbenchShell(), ConsoleMessages.JavaStackTraceHyperlink_Information_1, NLS.bind(ConsoleMessages.JavaStackTraceHyperlink_Source_not_found_for__0__2, new String[] {typeName})); + MessageDialog.openInformation(JDIDebugUIPlugin.getActiveWorkbenchShell(), ConsoleMessages.JavaStackTraceHyperlink_Information_1, NLS.bind(ConsoleMessages.JavaStackTraceHyperlink_Source_not_found_for__0__2, new String[] { + typeName })); } else { JDIDebugUIPlugin.statusDialog(ConsoleMessages.JavaStackTraceHyperlink_3, status); } - } else if (source instanceof List) { // ambiguous + } else if (source instanceof List) { // ambiguous results @SuppressWarnings("unchecked") List matches = (List) source; + List exactMatchesFiltered = new ArrayList<>(); + String originalHyperLink2 = originalHyperLink; + int firstMethodStartIndex = originalHyperLink2.indexOf('.'); + int firstMethodClosing = originalHyperLink2.lastIndexOf(')'); + + if (firstMethodStartIndex != -1 && firstMethodClosing != -1) { + String methodSignature = originalHyperLink2.substring(firstMethodStartIndex + 1, firstMethodClosing + 1).replaceAll(" ", ""); //$NON-NLS-1$//$NON-NLS-2$ + String methodNameExtracted = methodSignature.substring(0, methodSignature.indexOf('(')); + for (Object obj : matches) { + if (obj instanceof IType type) { + try { + IMethod[] methods = type.getMethods(); + for (IMethod method : methods) { + int indexOfClosing = method.toString().indexOf(')'); + int indexOfStart = method.toString().indexOf(method.getElementName()); + String methodName = method.toString().substring(indexOfStart, indexOfClosing + 1).replaceAll(" ", ""); //$NON-NLS-1$//$NON-NLS-2$ + int paramCount = methodSignature.substring(methodSignature.indexOf('(') + + 1, methodSignature.lastIndexOf(')')).split(",").length; //$NON-NLS-1$ + if (methodName.equals(methodSignature)) { + exactMatchesFiltered.add(obj); + } else if (methodNameExtracted.equals(method.getElementName()) + && paramCount == method.getNumberOfParameters()) { + // Further mining from fully qualified parameter names in method signature + StringBuilder s = new StringBuilder(method.getElementName()); + s.append('('); + String[] params = methodName.split(","); //$NON-NLS-1$ + for (String block : params) { + if (block.contains("...")) { //$NON-NLS-1$ Parameter is var args + if (params.length > 1) { + String sub1 = block.substring(0, block.indexOf("...")); //$NON-NLS-1$ + sub1 = sub1.substring(sub1.lastIndexOf('.') + 1); + s.append(sub1); + s.append('.'); + s.append('.'); + s.append('.'); + s.append(','); + } + } else { + if (block.indexOf('.') == -1) { + s.append(block.substring(block.lastIndexOf('(') + 1)); + s.append(','); + } else { + s.append(block.substring(block.lastIndexOf('.') + 1)); + s.append(','); + } + } + } + s.deleteCharAt(s.length() - 1); + + if (s.charAt(s.length() - 1) != ')') { + s.append(')'); + } + if (s.toString().equals(methodSignature)) { + exactMatchesFiltered.add(obj); + } + + // If paramters includes innerclass + if (methodSignature.indexOf('$') != -1) { + StringBuilder newSignature = new StringBuilder(methodNameExtracted + "("); //$NON-NLS-1$ + String paramsExtracted = methodSignature.substring(methodSignature.indexOf('(') + + 1, methodSignature.indexOf(')')); + if (paramsExtracted.indexOf(',') != -1) { + String[] parameters = paramsExtracted.split(","); //$NON-NLS-1$ + for (String param : parameters) { + newSignature.append(param.substring(param.indexOf('$') + 1)); + newSignature.append(","); //$NON-NLS-1$ + } + newSignature.deleteCharAt(newSignature.length() - 1); + if (newSignature.charAt(newSignature.length() - 1) != ')') { + newSignature.append(')'); + } + if (newSignature.toString().equals(s.toString())) { + exactMatchesFiltered.add(obj); + } + } else { + String param = paramsExtracted.substring(paramsExtracted.indexOf('$') + 1); + newSignature.append(param); + newSignature.append(')'); + if (newSignature.toString().equals(s.toString())) { + exactMatchesFiltered.add(obj); + } + + } + } + } + } + if (exactMatchesFiltered.isEmpty()) { + if (originalHyperLink2.indexOf('$') != -1) { + + IType[] inner = type.getTypes(); + while (inner.length > 0) { + for (IType innerType : inner) { + if (inner.length > 0) { + inner = innerType.getTypes(); + } + IMethod[] innerMethods = innerType.getMethods(); + for (IMethod innerMethod : innerMethods) { + int indexOfClosing = innerMethod.toString().indexOf(')'); + int indexOfStart = innerMethod.toString().indexOf(innerMethod.getElementName()); + String methodName = innerMethod.toString().substring(indexOfStart, indexOfClosing + + 1).replaceAll(" ", ""); //$NON-NLS-1$//$NON-NLS-2$ + int paramCount = methodSignature.substring(methodSignature.indexOf('(') + + 1, methodSignature.lastIndexOf(')')).split(",").length; //$NON-NLS-1$ + if (methodName.equals(methodSignature)) { + exactMatchesFiltered.add(obj); + } else if (methodNameExtracted.equals(innerMethod.getElementName()) + && paramCount == innerMethod.getNumberOfParameters()) { + // Further mining from fully qualified parameter names in method signature + StringBuilder s = new StringBuilder(innerMethod.getElementName()); + s.append('('); + String[] params = methodName.split(","); //$NON-NLS-1$ + for (String block : params) { + if (block.contains("...")) { //$NON-NLS-1$ Parameter is var args + if (params.length > 1) { + String sub1 = block.substring(0, block.indexOf("...")); //$NON-NLS-1$ + sub1 = sub1.substring(sub1.lastIndexOf('.') + 1); + s.append(sub1); + s.append('.'); + s.append('.'); + s.append('.'); + s.append(','); + } + } else { + if (block.indexOf('.') == -1) { + s.append(block.substring(block.lastIndexOf('(') + 1)); + s.append(','); + } else { + s.append(block.substring(block.lastIndexOf('.') + 1)); + s.append(','); + } + } + } + + s.deleteCharAt(s.length() - 1); + + if (s.charAt(s.length() - 1) != ')') { + s.append(')'); + } + if (s.toString().equals(methodSignature)) { + exactMatchesFiltered.add(obj); + } + } + } + } + + } + + } + } + + } catch (JavaModelException e) { + JDIDebugUIPlugin.log(e); + } + } + } + } int line = lineNumber + 1; // lineNumber starts with 0, but line with 1, see #linkActivated - OpenFromClipboardAction.handleMatches(matches, line, typeName, ConsoleMessages.JavaDebugStackTraceHyperlink_dialog_title); + if (exactMatchesFiltered.size() == 1) { + processSearchResult(exactMatchesFiltered.get(0), typeName, lineNumber); + return Status.OK_STATUS; + } + if (exactMatchesFiltered.size() == 2) { + try { // Occurred only in child eclipse + + if (exactMatchesFiltered.get(0) instanceof IType b1 && exactMatchesFiltered.get(1) instanceof IType b2) { + + if ((b1.getClass().getSimpleName().equals("BinaryType") && b2.getClass().getSimpleName().equals("BinaryType")) //$NON-NLS-1$ //$NON-NLS-2$ + && (b1.getFullyQualifiedName().equals(b2.getFullyQualifiedName()))) { + IVMInstall curr = JavaRuntime.getDefaultVMInstall(); + String vmPath = curr.getInstallLocation().getAbsolutePath(); + IVMInstall vmPath1 = JavaRuntime.getVMInstall(b1.getJavaProject()); + String path1 = vmPath1.getInstallLocation().getAbsolutePath(); + if (path1.equals(vmPath)) { + processSearchResult(exactMatchesFiltered.get(0), typeName, lineNumber); + return Status.OK_STATUS; + } + processSearchResult(exactMatchesFiltered.get(1), typeName, lineNumber); + return Status.OK_STATUS; + } + } + OpenFromClipboardAction.handleMatches(exactMatchesFiltered, line, typeName, ConsoleMessages.JavaDebugStackTraceHyperlink_dialog_title); + return Status.OK_STATUS; + + } catch (CoreException e) { + DebugUIPlugin.log(e); + OpenFromClipboardAction.handleMatches(exactMatchesFiltered, line, typeName, ConsoleMessages.JavaDebugStackTraceHyperlink_dialog_title); + return Status.OK_STATUS; + } + } + OpenFromClipboardAction.handleMatches(exactMatchesFiltered, line, typeName, ConsoleMessages.JavaDebugStackTraceHyperlink_dialog_title); return Status.OK_STATUS; + } else { processSearchResult(source, typeName, lineNumber); + } return Status.OK_STATUS; } @@ -206,9 +412,12 @@ public IStatus runInUIThread(IProgressMonitor monitor) { /** * The search succeeded with the given result * - * @param source resolved source object for the search - * @param typeName type name searched for - * @param lineNumber line number on link + * @param source + * resolved source object for the search + * @param typeName + * type name searched for + * @param lineNumber + * line number on link */ protected void processSearchResult(Object source, String typeName, int lineNumber) { IDebugModelPresentation presentation = JDIDebugUIPlugin.getDefault().getModelPresentation(); @@ -219,7 +428,7 @@ protected void processSearchResult(Object source, String typeName, int lineNumbe try { IEditorPart editorPart = JDIDebugUIPlugin.getActivePage().openEditor(editorInput, editorId); if (editorPart instanceof ITextEditor && lineNumber >= 0) { - ITextEditor textEditor = (ITextEditor)editorPart; + ITextEditor textEditor = (ITextEditor) editorPart; IDocumentProvider provider = textEditor.getDocumentProvider(); provider.connect(editorInput); IDocument document = provider.getDocument(editorInput); @@ -227,7 +436,8 @@ protected void processSearchResult(Object source, String typeName, int lineNumbe IRegion line = document.getLineInformation(lineNumber); textEditor.selectAndReveal(line.getOffset(), line.getLength()); } catch (BadLocationException e) { - MessageDialog.openInformation(JDIDebugUIPlugin.getActiveWorkbenchShell(), ConsoleMessages.JavaStackTraceHyperlink_0, NLS.bind("{0}{1}{2}", new String[] {(lineNumber+1)+"", ConsoleMessages.JavaStackTraceHyperlink_1, typeName})); //$NON-NLS-2$ //$NON-NLS-1$ + MessageDialog.openInformation(JDIDebugUIPlugin.getActiveWorkbenchShell(), ConsoleMessages.JavaStackTraceHyperlink_0, NLS.bind("{0}{1}{2}", new String[] { //$NON-NLS-1$ + (lineNumber + 1) + "", ConsoleMessages.JavaStackTraceHyperlink_1, typeName })); //$NON-NLS-1$ } provider.disconnect(editorInput); } @@ -239,16 +449,14 @@ protected void processSearchResult(Object source, String typeName, int lineNumbe } /** - * Returns the launch associated with this hyper-link, or - * null if none + * Returns the launch associated with this hyper-link, or null if none * - * @return the launch associated with this hyper-link, or - * null if none + * @return the launch associated with this hyper-link, or null if none */ private ILaunch getLaunch() { IProcess process = (IProcess) getConsole().getAttribute(IDebugUIConstants.ATTR_CONSOLE_PROCESS); if (process != null) { - return process.getLaunch(); + return process.getLaunch(); } return null; } @@ -264,54 +472,56 @@ private ILaunch getLaunch() { */ protected String getTypeName(String linkText) throws CoreException { int start = linkText.lastIndexOf('('); - int end = linkText.indexOf(':'); - if (start >= 0 && end > start) { - //linkText could be something like packageA.TypeB(TypeA.java:45) - //need to look in packageA.TypeA for line 45 since TypeB is defined - //in TypeA.java - //Inner classes can be ignored because we're using file and line number - - // get File name (w/o .java) - String typeName = linkText.substring(start + 1, end); - typeName = JavaCore.removeJavaLikeExtension(typeName); + int end = linkText.indexOf(':'); + if (start >= 0 && end > start) { + // linkText could be something like packageA.TypeB(TypeA.java:45) + // need to look in packageA.TypeA for line 45 since TypeB is defined + // in TypeA.java + // Inner classes can be ignored because we're using file and line number + + // get File name (w/o .java) + String typeName = linkText.substring(start + 1, end); + typeName = JavaCore.removeJavaLikeExtension(typeName); typeName = removeModuleInfo(typeName); - String qualifier = linkText.substring(0, start); - // remove the method name - start = qualifier.lastIndexOf('.'); - - if (start >= 0) { - // remove the class name - start = new String((String) qualifier.subSequence(0, start)).lastIndexOf('.'); - if (start == -1) { - start = 0; // default package - } - } - - if (start >= 0) { - qualifier = qualifier.substring(0, start); - } - - if (qualifier.length() > 0) { - typeName = qualifier + "." + typeName; //$NON-NLS-1$ - } - // Remove the module name if exists + String qualifier = linkText.substring(0, start); + // remove the method name + start = qualifier.lastIndexOf('.'); + + if (start >= 0) { + // remove the class name + start = new String((String) qualifier.subSequence(0, start)).lastIndexOf('.'); + if (start == -1) { + start = 0; // default package + } + } + + if (start >= 0) { + qualifier = qualifier.substring(0, start); + } + + if (qualifier.length() > 0) { + typeName = qualifier + "." + typeName; //$NON-NLS-1$ + } + // Remove the module name if exists int index = typeName.lastIndexOf('/'); if (index != -1) { typeName = typeName.substring(index + 1); } - return typeName; - } - IStatus status = new Status(IStatus.ERROR, JDIDebugUIPlugin.getUniqueIdentifier(), 0, ConsoleMessages.JavaStackTraceHyperlink_Unable_to_parse_type_name_from_hyperlink__5, null); - throw new CoreException(status); - } + return typeName; + } + IStatus status = new Status(IStatus.ERROR, JDIDebugUIPlugin.getUniqueIdentifier(), 0, ConsoleMessages.JavaStackTraceHyperlink_Unable_to_parse_type_name_from_hyperlink__5, null); + throw new CoreException(status); + } /** * Returns the line number associated with the stack trace or -1 if none. * - * @param linkText the complete text of the link to be parsed + * @param linkText + * the complete text of the link to be parsed * @return the line number for the stack trace or -1 if one cannot be computed or has not been provided - * @exception CoreException if unable to parse the number + * @exception CoreException + * if unable to parse the number */ protected int getLineNumber(String linkText) throws CoreException { int index = linkText.lastIndexOf(':'); @@ -345,28 +555,29 @@ protected TextConsole getConsole() { * Returns this link's text * * @return the complete text of the link, never null - * @exception CoreException if unable to retrieve the text + * @exception CoreException + * if unable to retrieve the text */ protected String getLinkText() throws CoreException { - try { - IDocument document = getConsole().getDocument(); - IRegion region = getConsole().getRegion(this); - int regionOffset = region.getOffset(); + try { + IDocument document = getConsole().getDocument(); + IRegion region = getConsole().getRegion(this); + int regionOffset = region.getOffset(); - int lineNumber = document.getLineOfOffset(regionOffset); - IRegion lineInformation = document.getLineInformation(lineNumber); - int lineOffset = lineInformation.getOffset(); - String line = document.get(lineOffset, lineInformation.getLength()); + int lineNumber = document.getLineOfOffset(regionOffset); + IRegion lineInformation = document.getLineInformation(lineNumber); + int lineOffset = lineInformation.getOffset(); + String line = document.get(lineOffset, lineInformation.getLength()); - int regionOffsetInLine = regionOffset - lineOffset; + int regionOffsetInLine = regionOffset - lineOffset; - int linkEnd = line.indexOf(')', regionOffsetInLine); - int linkStart = line.lastIndexOf(' ', regionOffsetInLine); + int linkEnd = line.indexOf(')', regionOffsetInLine); + int linkStart = line.lastIndexOf(' ', regionOffsetInLine); if (linkStart == -1) { linkStart = line.lastIndexOf('\t', regionOffsetInLine); } - return line.substring(linkStart==-1?0:linkStart+1,linkEnd+1).trim(); + return line.substring(linkStart == -1 ? 0 : linkStart + 1, linkEnd + 1).trim(); } catch (BadLocationException e) { IStatus status = new Status(IStatus.ERROR, JDIDebugUIPlugin.getUniqueIdentifier(), 0, ConsoleMessages.JavaStackTraceHyperlink_Unable_to_retrieve_hyperlink_text__8, e); throw new CoreException(status);