Bug 552622 - Wrong use of model object in staging view (RepositoryNode)
Summary: Wrong use of model object in staging view (RepositoryNode)
Status: RESOLVED FIXED
Alias: None
Product: EGit
Classification: Technology
Component: UI (show other bugs)
Version: 5.6   Edit
Hardware: PC All
: P3 normal (vote)
Target Milestone: 5.6   Edit
Assignee: Thomas Wolf CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-11-01 11:52 EDT by Thomas Wolf CLA
Modified: 2019-11-02 05:45 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Thomas Wolf CLA 2019-11-01 11:52:58 EDT
Discovered when testing https://git.eclipse.org/r/#/c/150328/ : somehow the RepositoryNode allocated in the staging view ends up being referenced also from the tree in the repository viewer. The staging view assumes it's the sole owner of that node and clears it when it doesn't use it anymore. But the node may then still be in use in the repository view, which then has a RepositoryNode with a null repository, which breaks subsequent operations.

This has never occurred until now as far as I know (I really wish we still had AERI, then I could search for relevant exceptions) but it's actually very easy to provoke:

1. Run Eclipse and prepare it: Java perspective; open repo view, add a few
   repos. Keep staging view closed. Quit.
2. Start Eclipse on that workspace. Comes up with Java perspective and repo
   view open, staging view closed. There's no repo selected in the repo view.
3. Go to Windows->Show-View->Others..., select the staging view.
4. Staging view comes up, shows "[No repository]". Check "follow selection"
   if not already checked.
6. Click on one of the repos (let's call is R) in the repo view.
7. Staging view shows status of repo R. Title shows the repo name (and branch
   state).
8. Close the staging view by clicking the "x" icon in its tab.
9. Mouse over to the repo view and try to expand the repo node for R (click on
   the triangle).
10. Ka-boom. Repo view is broken.
Comment 1 Thomas Wolf CLA 2019-11-01 12:00:00 EDT
This is related to lightweight decorators.

The DecoratorManager fires an event containing _all_ objects, from anywhere, whose decorations have arrived. When I examine the events gotten in the repo view, I even see two WorkingSets from the package explorer in there!

The StagingView uses its own instance of RepositoryNode (called titleNode) and its own instance of RepositoryTreeNodeLabelProvider, which uses the lightweight decorator. But when that lightweight decorator gets the decoration, the DecoratorManager fires an event with this titleNode. All label providers using the DecoratorManager will get that event and propagate it, causing the viewers that use them to update their items for this RepositoryNode.

So the repo view updates in response to a LabelProviderChangedEvent from the DecoratorManager, caused by a decoration scheduled for the label provider of the staging view. The repo view's tree viewer now gets a RepositoryNode from elsewhere that compares equal to a RepositoryNode already in the view. In AbstractTreeViewer.associate() the binding from the TreeItem to the RepositoryNode (and back) is then updated. That's how this node from the staging view ends up in the repo view tree!

And then when the staging view clears its node, which it thought to be the sole owner of, we suddenly have a RepositoryNode in the repo view with a null repository.

This is a problem with the general design of that repo view. Typically, input to a viewer is the model you want to show. In our case that would be the actual Repository. So when the label of a unique model object has changed, it's fine to notify all views (or their label providers) that the visual representation of that object needs to be updated, and it's even ok to put a different but equal instance in some particular tree. But in our case there's a separate layer, the RepositoryTreeNodes, which is a view-specific view model. Which is fine as long as this view model is used only in that view. But we use RepositoryTreeNodes elsewhere, too, and consider different instances really different even though they compare equal, and that breaks things now.

Given that from a model-view point of view the operation of the DecoratorManager is correct (well, if it could avoid notifying the repo view when a WorkingSet decoration has arrived, that'd be nice), the staging view must not assume it was the sole owner of that RepositoryNode. Therefore don't clear it; the view model RepositoryNode may still be used elsewhere.
Comment 2 Eclipse Genie CLA 2019-11-01 14:53:46 EDT
New Gerrit change created: https://git.eclipse.org/r/151887
Comment 3 Eclipse Genie CLA 2019-11-01 18:15:12 EDT
Gerrit change https://git.eclipse.org/r/151887 was merged to [master].
Commit: http://git.eclipse.org/c/egit/egit.git/commit/?id=09354fca29aefb20f03c9cde775905878b2b165f
Comment 4 Thomas Wolf CLA 2019-11-02 05:45:25 EDT
P.S.: it's unclear to me why AbstractTreeViewer.associate() links foreign objects into its tree in the first place. There's a comment there that this was done because of bug "PR 1FV62BT". Where can I find out what that was?

I didn't see similar code in AbstractTableViewer.