This Bugzilla instance is deprecated, and most Eclipse projects now use GitHub or Eclipse GitLab. Please see the deprecation plan for details.
Bug 223315 - [breakpoints] Inner class defined in a method can produce multiple breakpoints in the same line
Summary: [breakpoints] Inner class defined in a method can produce multiple breakpoint...
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Debug (show other bugs)
Version: 3.4   Edit
Hardware: PC Windows 2000
: P3 normal (vote)
Target Milestone: 3.6 M3   Edit
Assignee: Michael Rennie CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 252090 (view as bug list)
Depends on:
Blocks:
 
Reported: 2008-03-20 04:26 EDT by Xevi Serrats CLA
Modified: 2009-10-29 11:59 EDT (History)
6 users (show)

See Also:
curtis.windatt.public: review+


Attachments
Capute (46.71 KB, image/png)
2008-03-20 04:26 EDT, Xevi Serrats CLA
no flags Details
Example Java File (630 bytes, text/x-java)
2008-03-20 04:27 EDT, Xevi Serrats CLA
no flags Details
proposed fix (23.50 KB, patch)
2009-09-24 13:41 EDT, Michael Rennie CLA
no flags Details | Diff
updated fix (29.56 KB, patch)
2009-09-24 16:23 EDT, Michael Rennie CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Xevi Serrats CLA 2008-03-20 04:26:43 EDT
Created attachment 93003 [details]
Capute

Build ID: Eclipse Europa

Steps To Reproduce:
1. Define a class inside a method.,
2. Put a breakpoint inside a method of this new inner class.
3. If I try to remove the breakpoint (clicking again), another breakpoint is added.

I must remove the breakpoints in the "breakpoint" view.


More information:
Comment 1 Xevi Serrats CLA 2008-03-20 04:27:24 EDT
Created attachment 93005 [details]
Example Java File
Comment 2 Remy Suen CLA 2009-06-09 11:15:59 EDT
This is very annoying. :|
Comment 3 Markus Keller CLA 2009-06-09 11:43:46 EDT
I20090605-1444

It's only a problem for local classes, but not for other inner classes
(anonymous and member classes).

In the example below, it's only a problem for breakpoint 1, and only when the
class is being debugged.

Steps with snippet below:
- terminate all debug targets
- doubleclick in gutter of line //breakpoint 1
=> breakpoint created:
    Snippet$EnterListener [line: 18] - mouseEnter(MouseEvent)
- doubleclicking again toggles breakpoint as expected

- debug snippet
- doubleclick in gutter of line //breakpoint 1
=> different breakpoint created (additional $1 in name):
    Snippet$1$EnterListener [line: 18] - mouseEnter(MouseEvent)
- each additional doubleclick adds another copy of the breakpoint


package snippet;

import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;

public class Snippet {
    public static void main(String[] args) {
        Display display= new Display();
        final Shell shell= new Shell(display);
        shell.setLayout(new FillLayout());

        final Text text= new Text(shell, SWT.MULTI);

        class EnterListener extends MouseTrackAdapter {
            public void mouseEnter(MouseEvent e) {
                String msg= e.toString() + '\n'; // breakpoint 1
                text.append(msg);
            }
        }
        text.addMouseTrackListener(new EnterListener());

        text.addMouseTrackListener(new MouseTrackAdapter() {
            public void mouseExit(MouseEvent e) {
                String msg= e.toString() + '\n'; // breakpoint 2 (OK)
                text.append(msg);
            }
        });

        text.addMouseTrackListener(new Snippet().new HoverListener(text));

        shell.setSize(640, 480);
        shell.open();
        while (!shell.isDisposed())
            if (!display.readAndDispatch())
                display.sleep();
        shell.dispose();
    }

    class HoverListener extends MouseTrackAdapter {
        private final Text fText;

        public HoverListener(Text text) {
            fText= text;
        }

        public void mouseHover(MouseEvent e) {
            String msg= e.toString() + '\n'; // breakpoint 3 (OK)
            fText.append(msg);
        }
    }
}
Comment 4 Remy Suen CLA 2009-06-09 12:37:27 EDT
While the problem occurs for me in other cases too, I _can_ reproduce the problem from Markus's comment 3. It seems that for whatever reasons, the name retrieved from ReferenceTypeImpl includes extra character(s).

See ReferenceTypeImpl's nestedTypes() method.
Comment 5 Remy Suen CLA 2009-09-18 19:40:11 EDT
Please consider fixing/investigating for 3.6. ;_;
Comment 6 Michael Rennie CLA 2009-09-21 09:46:11 EDT
(In reply to comment #5)
> Please consider fixing/investigating for 3.6. ;_;

This should be somewhat easy to fix, as we have code in API tools to resolve a similar issue for the placement of error markers. Handling local types is always somewhat tricky...
Comment 7 Michael Rennie CLA 2009-09-21 10:42:32 EDT
I20090917-0100

other weirdness:

put a brekapoint on the  

 final Text text= new Text(shell, SWT.MULTI);

line from Markus' example and debug the snippet. When the snippet suspends, create a breakpoint at the //breakpoint 1 location. 

Breakpoint 

  Snippet$EnterListener [line: 18] - mouseEnter(MouseEvent)

is created (OK).

Then press F8 and watch as the breakpoint is changed to be 

  Snippet$1EnterListener [line: 18] - mouseEnter(MouseEvent)
Comment 8 Michael Rennie CLA 2009-09-21 11:30:52 EDT
(In reply to comment #7)
> I20090917-0100
> 
> other weirdness:

The problems are coming from when we respond to the classload event for Snippet$EnterListener to make sure the breakpoint is installed correctly. We end up setting the type name for the breakpoint to be Snippet$1EnterListener which is what ReferenceType tells us the name is (which differs from what the AST tells us when we create the breakpoint). 

Now if you try to remove the breakpoint (while debuging) we compare the type name in the breakpoint (Snippet$1$EnterListener) to the one we get from the AST (Snippet$EnterListener) and POOF you get a new breakpoint, as we think there is not one there for Snippet$EnterListener. 

Investigating a fix...
Comment 9 Michael Rennie CLA 2009-09-21 12:41:22 EDT
Hit a bit of a snag. It seems that when reconciling the compilation unit we are not getting back an AST that has bindings resolved. Speaking with Olivier he feels we should be getting bindings in the AST from a call to: 

CompilationUnit cunit = unit.reconcile(AST.JLS3, true, true, unit.getOwner(), null);

Markus, can we ever expect to get bindings in the AST returned like this?
Comment 10 Olivier Thomann CLA 2009-09-21 13:38:36 EDT
Snippet$EnterListener is computed inside org.eclipse.jdt.internal.debug.ui.actions.ToggleBreakpointAdapter.createQualifiedTypeName(IType).
So this has nothing to do with the type qualified name we could return from the model.
However in this case, the type qualified name doesn't insert a occurrence count into the type name.

In your case, what you really want is the "resolved" name for the local type.
i.e. Snippet$1EnterListener for >= 1.5
Snippet$1$EnterListener for < 1.5.
Comment 11 Michael Rennie CLA 2009-09-21 14:25:08 EDT
(In reply to comment #10)
> Snippet$EnterListener is computed inside
> org.eclipse.jdt.internal.debug.ui.actions.ToggleBreakpointAdapter.createQualifiedTypeName(IType).
> So this has nothing to do with the type qualified name we could return from the
> model.

This is correct, but I was investigating moving away from having to piece together our own names - as it is error prone in uncommon cases.
Comment 12 Markus Keller CLA 2009-09-22 06:47:21 EDT
(In reply to comment #9)
> CompilationUnit cunit = unit.reconcile(AST.JLS3, true, true, unit.getOwner(),
> null);
> 
> Markus, can we ever expect to get bindings in the AST returned like this?

Yes, I would expect you to get bindings in that AST. But I think a better solution would be for you to get the AST via SharedASTProvider.getAST(cu, SharedASTProvider.WAIT_YES, progressMonitor). As for the generated class name, I guess ITypeBinding#getBinaryName() is your friend (should work for local types from source and binary, with and without source attachments).
Comment 13 Michael Rennie CLA 2009-09-24 13:41:30 EDT
Created attachment 148040 [details]
proposed fix

The patch converts our toggle breakpoint adapter to use the ITypeBindings to get qualified names instead of trying to compose them ourselves. If for whatever reason bindings cannot be resolved we revert to the old method of composing type names. The patch also updates our breakpoint location verifier and our breakpoint marker updater to use bindings.

I also found that when toggling a line breakpoint from the editor, we were running our location verifier twice and getting the qualified name twice, with the net effect of creating an AST 4 times.

Location tests have been updated, all tests pass.
Comment 14 Michael Rennie CLA 2009-09-24 16:23:10 EDT
Created attachment 148055 [details]
updated fix

further testing of the proposed fix I found that importing breakpoints on local types was totally hosed as well, so this patch contains a fix for that as well.
Comment 15 Michael Rennie CLA 2009-09-25 11:12:01 EDT
applied patch to HEAD, please verify Curtis
Comment 16 Curtis Windatt CLA 2009-09-28 13:04:26 EDT
Verified.
Comment 17 Michael Rennie CLA 2009-10-29 11:59:50 EDT
*** Bug 252090 has been marked as a duplicate of this bug. ***