Skip to content

Refresh dependency error decorations on target platform changes - #2412

Open
vogella wants to merge 1 commit into
eclipse-pde:masterfrom
vogella:dependencies-tab-stale-decorations
Open

Refresh dependency error decorations on target platform changes#2412
vogella wants to merge 1 commit into
eclipse-pde:masterfrom
vogella:dependencies-tab-stale-decorations

Conversation

@vogella

@vogella vogella commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

The error decorations on the Dependencies tab of the manifest editor are computed on the fly from isResolved(), so they are only correct if the result is recomputed and if the sections learn that the target platform changed. Neither held: PluginReference memoized the plug-in it looked up and never invalidated it, so a required bundle that vanished from the target kept reporting itself as resolved and no error marker ever appeared. On top of that a target reload fires no PluginModelDelta, which is the only notification RequiresSection listened to, and ImportPackageSection listened to nothing beyond its own bundle model.

The reference now looks the id up on every call (a hash lookup on the model entry table, cheaper than the exported-package scan the imported-package labels already do), and both sections additionally listen to IStateDeltaListener.stateChanged, which is what a reload does fire. ImportPackageSection also gained the plug-in model listener it was missing for ordinary workspace changes, so both halves of the tab now stay in sync instead of disagreeing. The practical effect is that fixing a missing dependency and reloading the target clears the marker, rather than requiring the editor to be closed and reopened.

StaleDependencyResolutionTest covers the recomputation and pins down the notification contract the sections depend on.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

Test Results

  129 files  +    4    129 suites  +4   38m 43s ⏱️ + 7m 30s
3 534 tests +    3  3 480 ✅ +    4   54 💤 ± 0  0 ❌  - 1 
9 405 runs  +2 148  9 275 ✅ +2 125  130 💤 +24  0 ❌  - 1 

Results for commit 9b4df21. ± Comparison against base commit f6968e0.

♻️ This comment has been updated with latest results.

The error decorations on the Dependencies tab of the manifest editor are
computed on the fly from isResolved(), so they only stay correct if the
result is recomputed and if the sections learn that the world changed.
Two things prevented that.

PluginReference memoized the plug-in it looked up and never invalidated
it, so a required bundle that disappeared from the target kept reporting
itself as resolved and no error decoration ever appeared. Only an
explicitly assigned plug-in is cached now; the id is looked up on every
call, which is a hash lookup on the model entry table.

RequiresSection listened to plug-in model deltas only, and
ImportPackageSection listened to nothing beyond its own bundle model.
A target reload fires neither, so both kept painting the previous
resolution result until the editor was reopened. Both now also listen to
IStateDeltaListener.stateChanged, which is what a reload does fire, and
ImportPackageSection gained the plug-in model listener it was missing for
ordinary workspace changes.
@vogella
vogella force-pushed the dependencies-tab-stale-decorations branch from d9a9553 to 9b4df21 Compare August 10, 2026 05:58
@vogella
vogella marked this pull request as ready for review August 10, 2026 07:52
@vogella
vogella requested a lite review from Copilot August 10, 2026 07:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves PDE manifest editor dependency error decorations so they stay accurate when the target platform is reloaded or workspace plug-in models change, by ensuring dependency resolution is recomputed and the UI refreshes on relevant model/state notifications.

Changes:

  • Stop PluginReference from memoizing looked-up plug-ins so isResolved() reflects current target contents.
  • Make both dependency sections react to target reloads by listening to IStateDeltaListener.stateChanged (and add the missing plug-in model listener to ImportPackageSection).
  • Add StaleDependencyResolutionTest to cover recomputation and the notification contract, and register it in the core test suite.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/RequiresSection.java Adds state-delta listening to refresh dependency decorations when the target state changes.
ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/ImportPackageSection.java Adds plug-in model + state-delta listeners and refresh logic to keep imported-package decorations in sync.
ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/core/tests/internal/StaleDependencyResolutionTest.java New regression test covering stale resolution and target reload notifications.
ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/core/tests/internal/AllPDECoreTests.java Registers the new regression test in the PDE core test suite.
ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/plugin/PluginReference.java Changes plug-in lookup to be non-caching so resolution status tracks target changes.
Suppressed comments (1)

ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/RequiresSection.java:699

  • modelsChanged/stateChanged callbacks can be invoked off the UI thread (they are fired directly by PluginModelManager). refreshImports() currently calls SWT widget APIs (getControl(), isDisposed(), getDisplay()) on the calling thread, which can throw SWTException: Invalid thread access during target reloads or workspace model updates. Schedule the UI work via Display.getDefault().asyncExec(...) and only touch the viewer/control inside the runnable.
	private void refreshImports() {
		fImports = null;
		final Control control = fImportViewer.getControl();
		if (!control.isDisposed()) {
			control.getDisplay().asyncExec(() -> {

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +307 to +316
private void refreshPackages() {
Control control = fPackageViewer.getControl();
if (!control.isDisposed()) {
control.getDisplay().asyncExec(() -> {
if (!control.isDisposed()) {
fPackageViewer.refresh();
}
});
}
}
Comment on lines +44 to +48
// Only an explicitly assigned plug-in is cached. Looking the id up on
// every call keeps isResolved() in sync with the current target
// platform, which the error decorations in the editor rely on.
if (fPlugin != null || fId == null) {
return fPlugin;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants