Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 287765 - [Viewers] getExpandedTreePaths in AbstractTreeViewer can fail when there are items with dummy children
Summary: [Viewers] getExpandedTreePaths in AbstractTreeViewer can fail when there are ...
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.4.2   Edit
Hardware: PC Windows Vista
: P3 normal (vote)
Target Milestone: 3.6 M4   Edit
Assignee: Boris Bokowski CLA
QA Contact: Boris Bokowski CLA
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-08-26 20:13 EDT by Chris Horneck CLA
Modified: 2010-04-26 10:56 EDT (History)
0 users

See Also:


Attachments
Exception stack trace (392 bytes, text/plain)
2009-08-26 20:13 EDT, Chris Horneck CLA
no flags Details
TestCase to reproduce the error (5.41 KB, application/octet-stream)
2009-08-27 14:38 EDT, Chris Horneck CLA
bokowski: iplog+
Details
patch (990 bytes, patch)
2009-11-13 14:32 EST, Boris Bokowski CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Horneck CLA 2009-08-26 20:13:57 EDT
Created attachment 145738 [details]
Exception stack trace

I don't have a test case or a sequence of events that everyone can use to reproduce this error because it occurs within our own RCP application, but I will try to explain it as best as I can.

It seem that you can have an AbstractTreeViewer that contains a TreeItem that is expandable, but has a dummy node as a child (i.e. its children have not been loaded yet; see AbstractTreeViewer#updateChildren(Widget, Object, Object[], boolean) for reference).  I'm not sure I understand exactly why a dummy node is needed, but I didn't dig into all of the code.

The problem occurs when that dummy node (a TreeItem) was previously expanded during its last use.  When getExpandedTreePaths is called, it subsequently calls internalCollectExpandedItems, which collects all expanded items, whether they are a dummy node or otherwise.  When getTreePathFromItem is then called on that dummy node that was collected, it pulls out the data from that TreeItem and does an Assert.isNotNull.  The data will always be null for a dummy node (I think), which causes getTreePathFromItem to fail.  I am attaching the relevant part of the exception stack trace for reference.

I took a quick peek at the 3.5 code and it seemed like it behaved the same way, although the flow was slightly different, but I haven't tested it out or investigated it thoroughly.
Comment 1 Chris Horneck CLA 2009-08-26 20:28:00 EDT
I meant to suggest a possible fix before I clicked submit. :)  

In AbstractTreeViewer#updateChildren:


Old Code
if (widget instanceof Item) {
	Item ti = (Item) widget;
	if (!getExpanded(ti)) {
		// need a dummy node if element is expandable;
		// but try to avoid recreating the dummy node
		boolean needDummy = isExpandable(ti, null, parent);
		boolean haveDummy = false;
		// remove all children
		Item[] items = getItems(ti);
		for (int i = 0; i < items.length; i++) {
			if (items[i].getData() != null) {
				disassociate(items[i]);
				items[i].dispose();
			} else {
				if (needDummy && !haveDummy) {
					haveDummy = true;
				} else {
					items[i].dispose();
				}
			}
		}

Proposed fix (haven't tested this)
		if (needDummy && !haveDummy) {
		   haveDummy = true;
                   setExpanded(items[i], false);
		}

Comment 2 Boris Bokowski CLA 2009-08-27 11:27:08 EDT
(In reply to comment #0)
> I'm not sure I understand exactly why a dummy node is
> needed, but I didn't dig into all of the code.

The dummy node is needed because tree items without children won't show the "+" with which you can expand them.

> The problem occurs when that dummy node (a TreeItem) was previously expanded
> during its last use.  When getExpandedTreePaths is called, it subsequently
> calls internalCollectExpandedItems, which collects all expanded items, whether
> they are a dummy node or otherwise.  When getTreePathFromItem is then called on
> that dummy node that was collected, it pulls out the data from that TreeItem
> and does an Assert.isNotNull.  The data will always be null for a dummy node (I
> think), which causes getTreePathFromItem to fail.  I am attaching the relevant
> part of the exception stack trace for reference.

Interesting - is this happening on multiple platforms, or just one?

> I took a quick peek at the 3.5 code and it seemed like it behaved the same way,
> although the flow was slightly different, but I haven't tested it out or
> investigated it thoroughly.

It would be good to write a test case or snippet which allows us to reproduce the problem, would you be able to do that?
Comment 3 Chris Horneck CLA 2009-08-27 11:51:59 EDT
I'll see if I can come up with a general test case that reproduces it.
Comment 4 Chris Horneck CLA 2009-08-27 14:38:41 EDT
Created attachment 145838 [details]
TestCase to reproduce the error
Comment 5 Chris Horneck CLA 2009-08-27 14:39:15 EDT
Posted a testcase that should illustrate the error...

This produces an error on Eclipse SDK Version: 3.4.2 Build id: M20090211-1700 as well as Eclipse 3.5 Build id: 20090619-0625 running on Windows Vista SP2 with the Sun 1.4.2_19 JDK.  I don't have any other suitable platforms to test on.

My earlier analysis wasn't completely correct.  For the error to occur, the viewer must be configured to use HashLookup ( setUseHashlookup(true) ).  This comes into play when items are being disassociated.

Additionally, my suggested fix does not seem to be adequate.  Just setting the expanded state of the dummy node is not sufficient, as that dummy node can still have child items that are expanded.  These expanded items will still get pulled in by getExpandedTreePaths and cause an exception.
Comment 6 Boris Bokowski CLA 2009-11-13 14:32:49 EST
Created attachment 152196 [details]
patch

I decided to fix this in the code that collects the expanded items.
Comment 7 Boris Bokowski CLA 2009-11-13 14:33:38 EST
Released to HEAD.
Comment 8 Boris Bokowski CLA 2009-11-13 14:39:35 EST
Test released as well. Thanks for contributing the test case!
Comment 9 Boris Bokowski CLA 2010-04-26 10:56:18 EDT
Verified using I20100425-2000 and by checking that the test case is run as part of our builds.