Community
Participate
Working Groups
I20110111-0800. Copy From Clipboard throws ArrayIndexOutOfBoundsException. 1. paste this: package pp; public class A$ { void a() { } } 2. select "a" in the editor 3. Copy > Copy Qualified Name STRANGE: sometimes nothing at all happens 4. Copy > Copy Qualified Name still no feedback but: !ENTRY org.eclipse.ui 4 0 2011-01-12 15:53:48.908 !MESSAGE Unhandled event loop exception !STACK 0 java.lang.ArrayIndexOutOfBoundsException: 0 at org.eclipse.jdt.internal.core.util.BindingKeyParser.parseInnerType(BindingKeyParser.java:734) at org.eclipse.jdt.internal.core.util.BindingKeyParser.parse(BindingKeyParser.java:608) at org.eclipse.jdt.internal.core.util.BindingKeyParser.parse(BindingKeyParser.java:590) at org.eclipse.jdt.core.BindingKey.toSignature(BindingKey.java:305) at org.eclipse.jdt.internal.ui.viewsupport.JavaElementLabelComposer.appendMethodLabel(JavaElementLabelComposer.java:322) at org.eclipse.jdt.internal.ui.viewsupport.JavaElementLabelComposer.appendElementLabel(JavaElementLabelComposer.java:257) at org.eclipse.jdt.ui.JavaElementLabels.getElementLabel(JavaElementLabels.java:510) at org.eclipse.jdt.ui.JavaElementLabels.getElementLabel(JavaElementLabels.java:483) at org.eclipse.jdt.ui.JavaElementLabels.getTextLabel(JavaElementLabels.java:387) at org.eclipse.jdt.internal.ui.actions.CopyQualifiedNameAction.getQualifiedName(CopyQualifiedNameAction.java:261) at org.eclipse.jdt.internal.ui.actions.CopyQualifiedNameAction.run(CopyQualifiedNameAction.java:193) at org.eclipse.jface.action.Action.runWithEvent(Action.java:498) at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:584) at org.eclipse.jface.action.ActionContributionItem.access$2(ActionContributionItem.java:501) at org.eclipse.jface.action.ActionContributionItem$5.handleEvent(ActionContributionItem.java:411) at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84) at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1053) at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:4089) at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3680) at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2697) at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2661) at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2495) at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:674) at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332) at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:667) at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149) at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:115) at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:344) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:592) at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:622) at org.eclipse.equinox.launcher.Main.basicRun(Main.java:577) at org.eclipse.equinox.launcher.Main.run(Main.java:1410) at org.eclipse.equinox.launcher.Main.main(Main.java:1386) !ENTRY org.eclipse.ui 4 0 2011-01-12 15:53:57.346 !MESSAGE Unhandled event loop exception !STACK 0 java.lang.ArrayIndexOutOfBoundsException: 0 at org.eclipse.jdt.internal.core.util.BindingKeyParser.parseInnerType(BindingKeyParser.java:734) at org.eclipse.jdt.internal.core.util.BindingKeyParser.parse(BindingKeyParser.java:608) at org.eclipse.jdt.internal.core.util.BindingKeyParser.parse(BindingKeyParser.java:590) at org.eclipse.jdt.core.BindingKey.isParameterizedType(BindingKey.java:279) at org.eclipse.jdt.internal.ui.viewsupport.JavaElementLabelComposer.appendTypeLabel(JavaElementLabelComposer.java:855) at org.eclipse.jdt.internal.ui.viewsupport.JavaElementLabelComposer.appendElementLabel(JavaElementLabelComposer.java:272) at org.eclipse.jdt.ui.JavaElementLabels.getElementLabel(JavaElementLabels.java:510) at org.eclipse.jdt.ui.JavaElementLabels.getElementLabel(JavaElementLabels.java:483) at org.eclipse.jdt.ui.JavaElementLabels.getTextLabel(JavaElementLabels.java:387) at org.eclipse.jdt.internal.ui.actions.CopyQualifiedNameAction.getQualifiedName(CopyQualifiedNameAction.java:261) at org.eclipse.jdt.internal.ui.actions.CopyQualifiedNameAction.run(CopyQualifiedNameAction.java:193) at org.eclipse.jface.action.Action.runWithEvent(Action.java:498) at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:584) at org.eclipse.jface.action.ActionContributionItem.access$2(ActionContributionItem.java:501) at org.eclipse.jface.action.ActionContributionItem$5.handleEvent(ActionContributionItem.java:411) at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84) at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1053) at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:4089) at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3680) at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2697) at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2661) at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2495) at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:674) at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332) at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:667) at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149) at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:115) at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:344) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:592) at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:622) at org.eclipse.equinox.launcher.Main.basicRun(Main.java:577) at org.eclipse.equinox.launcher.Main.run(Main.java:1410) at org.eclipse.equinox.launcher.Main.main(Main.java:1386)
The problem is that JDT/Core assumes everywhere that a $ in the binding key would imply an innner type, and so a binding key such as A$B is always treated as type B enclosed by type A. Because of this whenever there's actually a $ in the type name, we split the type name at $. We should ideally change the representation of binding key for type names containing $ by inserting some escape character (preferably '\'), but this might break a lot of existing things which wouldnt expect a '\' in the binding key. Specifically in this bug, the problem starts at SourceTypeBinding.computeUniqueKey(boolean). Since here we have the binding we can always query it for binding.isMemberType() and treat the dollar correctly, but then again in BindingKeyParser$Scanner.getNextToken(), we fumble on the dollar!
(In reply to comment #1) Just an aferthought, why should java allow specifying a '$' in the name at all. I wish this could be changed. There are other currencies one can use. ;)
(In reply to comment #2) > (In reply to comment #1) > Just an aferthought, why should java allow specifying a '$' in the name at all. > I wish this could be changed. There are other currencies one can use. ;) The name is indeed discouraged (see new wizard).
An extreme case -------------------------------- class $ { class $$ extends ${ class $$$ { } } } ------------------------------- Try Copy qualified name, Type Hierarchy on '$$' etc :)
(In reply to comment #2) > (In reply to comment #1) > Just an aferthought, why should java allow specifying a '$' in the name at all. > I wish this could be changed. There are other currencies one can use. ;) For Java, '$' is just a normal char, it's the encoding of inner types that's a major PITA introduced in Java 1.1. Some related bugs: bug 127739, bug 127749, bug 145598. We'll be adding workarounds for the rest of our lives :-/ Note that bug 127749 isn't resolved as of today.
Created attachment 186715 [details] proposed fix This patch takes care of all the above cases by making sure that the generated key from SourceTypeBinding.getUniqueKey() isn't bad in case of $ occuring in the name. But this isn't fullproof. There can be other places that still break because of '$'. Like Stephan said, we could be coming across this forever, unless we add an escape character to the binding key. But since this is exposed to the outside world, doing so would break client code.
(In reply to comment #6) > But this isn't fullproof. Even with the patch, the following still throws an exception: class A$$ { void a() { } } at a completely different place: java.lang.IllegalArgumentException at org.eclipse.jdt.core.Signature.getParameterCount(Signature.java:995)
Created attachment 187170 [details] proposed fix + regression tests Same patch with tests.
Released in HEAD for 3.7M5
To verify, use comment 0 and comment 4
Verified in I20110124-1800.