Skip to content

Add copy refactoring infrastructure to LTK#4047

Open
Felix-Schmid wants to merge 1 commit into
eclipse-platform:masterfrom
Felix-Schmid:copy-refactoring
Open

Add copy refactoring infrastructure to LTK#4047
Felix-Schmid wants to merge 1 commit into
eclipse-platform:masterfrom
Felix-Schmid:copy-refactoring

Conversation

@Felix-Schmid

Copy link
Copy Markdown

LTK is missing infrastructure for copy refactoring, e.g., a CopyResourcesProcessor. Eclipse RCP developers can define their own copy participants (similar to move/delete/rename participants), but they are never called.

This PR adds copy refactoring to LTK based on the existing implementation of move/delete refactoring, the existing refactoring for copying projects, and the copy processor implementation of JDT.

The changes were tested in Eclipse 4diac, where we could now perform refactoring operations (via participants) during copying of resources.

@vogella

vogella commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

I see no tests, please add them.

@eclipse-platform-bot

Copy link
Copy Markdown
Contributor

This pull request changes some projects for the first time in this development cycle.
Therefore the following files need a version increment:

bundles/org.eclipse.ltk.core.refactoring/META-INF/MANIFEST.MF
bundles/org.eclipse.ltk.ui.refactoring/META-INF/MANIFEST.MF

An additional commit containing all the necessary changes was pushed to the top of this PR's branch. To obtain these changes (for example if you want to push more changes) either fetch from your fork or apply the git patch.

Git patch
From f274e2b6b5aaa22194d573806ad9e2f060564129 Mon Sep 17 00:00:00 2001
From: Eclipse Platform Bot <platform-bot@eclipse.org>
Date: Mon, 1 Jun 2026 14:38:55 +0000
Subject: [PATCH] Version bump(s) for 4.41 stream


diff --git a/bundles/org.eclipse.ltk.core.refactoring/META-INF/MANIFEST.MF b/bundles/org.eclipse.ltk.core.refactoring/META-INF/MANIFEST.MF
index 9f0f659919..0933dc953b 100644
--- a/bundles/org.eclipse.ltk.core.refactoring/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.ltk.core.refactoring/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Automatic-Module-Name: org.eclipse.ltk.core.refactoring
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.ltk.core.refactoring; singleton:=true
-Bundle-Version: 3.15.200.qualifier
+Bundle-Version: 3.15.300.qualifier
 Bundle-Activator: org.eclipse.ltk.internal.core.refactoring.RefactoringCorePlugin
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: %providerName
diff --git a/bundles/org.eclipse.ltk.ui.refactoring/META-INF/MANIFEST.MF b/bundles/org.eclipse.ltk.ui.refactoring/META-INF/MANIFEST.MF
index dea006509a..ae7f9a413c 100644
--- a/bundles/org.eclipse.ltk.ui.refactoring/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.ltk.ui.refactoring/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Automatic-Module-Name: org.eclipse.ltk.ui.refactoring
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.ltk.ui.refactoring; singleton:=true
-Bundle-Version: 3.14.100.qualifier
+Bundle-Version: 3.14.200.qualifier
 Bundle-Activator: org.eclipse.ltk.internal.ui.refactoring.RefactoringUIPlugin
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: %providerName
-- 
2.54.0

Further information are available in Common Build Issues - Missing version increments.

* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* IBM Corporation - initial API and implementation

I assume the header is copied from somewhere. I did you put IBM in here by intention?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This class needed to be very similar to the DeleteResourcesDescriptor, so I copied the file and made the necessary changes. I kept the original header to show that this was not all my creation. The same principle also applies to CopyResourcesHandler & CopyResourcesRefactoringContribution.
I can change the headers if this was incorrect or if there is a better way to do it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That’s okay. Increase the upper year to the current year.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done.

import org.eclipse.ltk.internal.core.refactoring.BasicElementLabels;
import org.eclipse.ltk.internal.core.refactoring.RefactoringCoreMessages;

public class CopyResourceChange extends ResourceChange {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If this is supposed to be a public API, you must bump bundle version to 3.16.0 and add since 3.16 javadoc tags on every new API type

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for the heads-up, done.
Everything that was made public was done to align in with how the move/delete classes do it, a discussion about this was also had here #2262 (comment).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

API tooling complains, and I see now the package is not exported as API. Is this intentional?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Should be fixed now.

@Felix-Schmid Felix-Schmid force-pushed the copy-refactoring branch 2 times, most recently from b7cd868 to e74e7e7 Compare June 2, 2026 12:01
@merks

merks commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Note that you're generally best to maintain a single commit which you amend and force push until it's done...

@Felix-Schmid

Copy link
Copy Markdown
Author

I see no tests, please add them.

Tests have now been added.

Note that you're generally best to maintain a single commit which you amend and force push until it's done...

Understood, I will do that with the next commit.

@vogella

vogella commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

org.eclipse.e4.ui.tests.workbench.PartRenderingEngineTests.testBut336225 is unrelated, see eclipse-platform/eclipse.platform#2700

Version bump(s) for 4.41 stream

Add "since" to javadoc of new APIs

Fix copyright header year

Fix bundle version

Improve entry location for LTK copy refactoring

Add tests for LTK copy refactoring

Fix
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Test Results

   861 files  ± 0     861 suites  ±0   55m 53s ⏱️ + 2m 18s
 8 043 tests + 9   7 800 ✅ + 9  243 💤 ±0  0 ❌ ±0 
20 568 runs  +27  19 913 ✅ +27  655 💤 ±0  0 ❌ ±0 

Results for commit 139cf04. ± Comparison against base commit ae3df73.

@vogella

vogella commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

@Felix-Schmid can you think about a usage in platform or PDE for this new API? It would be really nice to have a user for this API in our own code base

@Felix-Schmid

Copy link
Copy Markdown
Author

can you think about a usage in platform or PDE for this new API? It would be really nice to have a user for this API in our own code base

I am not too familiar with the platform or PDE, but maybe copy refactoring could be used to update certain properties of MANIFEST, plugin, or *.product files? I am open to a more concrete suggestion here.

For an example of how this copy refactoring could be used, I can link to the CopyTypeParticipant in 4diac, which updates the package name for copied type files.
This infrastructure would also be needed elsewhere; e.g., this PR for Xtext has to reuse the copy refactoring from JDT, since the platform does not provide it.

@vogella

vogella commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

IMHO the projects leads of platform should decide here if this API should be accepted without platform or pde or JDT consumers.

cc @HeikoKlare @akurtakov @iloveeclipse

@akurtakov

Copy link
Copy Markdown
Member

While it's best to have Platform/PDE/JDT user if the API is generic enough and improves situation for multiple other simrel projects - I can see this as good enough situation. Review should be stressing on "generic enough" solution.

@vogella

vogella commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Given that one PL gave his OK and the missing review activity of other committers, I plan to help @Felix-Schmid to finish this one and merge it once I'm ok with it.

@vogella

vogella commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Thanks again @Felix-Schmid, first of all this PR needs a rebase.

And here are some findings:

Routing all IDE copies through LTK is too broad

CopyFilesAndFoldersOperation.performCopy / performCopyWithAutoRename now call LTKLauncher.copyResources(...) and return true before the existing logic runs. That short-circuit causes three problems:

  1. "Create Link" / "Create Virtual Folder" is silently turned into a physical copy.
    performCopy applies setCreateLinks / setVirtualFolders / setRelativeVariable after the new early return.
    The Project Explorer drop handler (ResourceDropAdapterAssistant) sets createLinks = true and then calls the public copyResources(IResource[], IContainer), which reaches performCopy.
    With the LTK UI bundle installed (the default IDE), the LTK path copies the files physically and the link / virtual folder the user requested is never created.

  2. A failed or fatal LTK copy is reported as success and suppresses the fallback.
    LTKLauncher.runCommand returns true whenever the command is defined and the handler does not throw, and CopyResourcesHandler.execute always returns null (it catches CoreException, shows a dialog, and does nothing when the selection/destination guard is false).
    So on a fatal condition (destination is the workspace root, destination inside the copied resource, multiple destinations, etc.) copyResources returns true, performCopy returns true, and the real copy below is skipped: the resource is silently not copied, where the old path always copied.

Suggestion: gate the LTK route (skip it when createLinks || createVirtualFoldersAndLinks) and fall through to the legacy operation when the refactoring produced no executed change, rather than short-circuiting unconditionally.

Folder overwrite replaces instead of merges (possible data loss)

CopyResourceChange.deleteIfAlreadyExists deletes the whole existing destination folder and then recreates it via origin.copy(...).
The legacy CopyFilesAndFoldersOperation merges homogeneous folders file by file, so after the user accepts the overwrite prompt (expecting a merge) any files that existed only in the destination folder are lost.
CopyResourcesProcessor.checkFinalConditions returns an empty status, so unlike MoveResourcesProcessor there is no overwrite warning and no ResourceChangeChecker participation.
(Undo restores correctly via history.)

The participant test does not run

CopyRefactoringWithRefUpdateTest provides no coverage for two independent reasons:

  1. It is not referenced by AllTests / ParticipantTests, and Tycho pins the root suite via testClass, so nothing discovers it.
  2. It imports JUnit 4 org.junit.Test while using Jupiter @beforeeach / @AfterEach, and testCopyRefactoringWithParticipants() is package-private; Jupiter ignores the JUnit 4 @test and junit-vintage is not on the bundle's imports.

The sibling MoveRefactoringWithRefUpdateTest it was copied from uses org.junit.jupiter.api.Test and is registered in ParticipantTests.
(The additions to ResourceRefactoringTests do run.)

Minor

  • CopyResourceChange.perform calls pm.beginTask(getName(), 2) and then two separate SubMonitor.convert(pm, 1) calls, each re-calling beginTask on the same monitor, so the progress reporting is wrong. MoveResourceChange uses one SubMonitor.convert(monitor, getName(), 4) plus newChild(...).
  • CopyResourcesProcessor: destination = (IContainer) ...findMember(destPath) can throw ClassCastException for a malformed/replayed descriptor whose destination parent is a file. MoveResourcesProcessor avoids this by taking a typed IContainer.
  • CopyResourceChange returns NullChange in the "identical resource already present" branch without calling log.markAsProcessed(origin), inconsistent with the normal path.
  • CopyResourcesProcessor.createDescriptor() sets setProject(null) where Move uses the destination's project name (affects refactoring-history metadata only).

@Felix-Schmid

Copy link
Copy Markdown
Author

Thank you very much for the detailed review, I will get back with an updated PR.

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.

7 participants