Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ui/org.eclipse.pde.ui/plugin.properties
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ rename.type.participant = Manifest Rename Type Participant
rename.package.participant = Manifest Rename Package Participant
move.type.participant = Manifest Move Type Participant
move.package.participant = Manifest Move Package Participant
delete.type.participant = Manifest Delete Type Participant
delete.package.participant = Manifest Delete Package Participant

queryParticipant.name.0 = PDE Java Search Participant
new.profile.name = Target Definition
Expand Down
32 changes: 32 additions & 0 deletions ui/org.eclipse.pde.ui/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,38 @@
</enablement>
</renameParticipant>
</extension>
<extension
point="org.eclipse.ltk.core.refactoring.deleteParticipants">
<deleteParticipant
class="org.eclipse.pde.internal.ui.refactoring.ManifestTypeDeleteParticipant"
id="org.eclipse.pde.ui.manifestTypeDeleteParticipant"
name="%delete.type.participant">
<enablement>
<with
variable="element">
<instanceof
value="org.eclipse.jdt.core.IType">
</instanceof>
</with>
</enablement>
</deleteParticipant>
</extension>
<extension
point="org.eclipse.ltk.core.refactoring.deleteParticipants">
<deleteParticipant
class="org.eclipse.pde.internal.ui.refactoring.ManifestPackageDeleteParticipant"
id="org.eclipse.pde.ui.manifestPackageDeleteParticipant"
name="%delete.package.participant">
<enablement>
<with
variable="element">
<instanceof
value="org.eclipse.jdt.core.IPackageFragment">
</instanceof>
</with>
</enablement>
</deleteParticipant>
</extension>
<extension
point="org.eclipse.ltk.core.refactoring.moveParticipants">
<moveParticipant
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2389,6 +2389,10 @@ public class PDEUIMessages extends NLS {

public static String ManifestTypeRenameParticipant_composite;

public static String ManifestTypeDeleteParticipant_composite;

public static String ManifestPackageDeleteParticipant_packageDelete;

public static String LauncherPage_title;

public static String WindowImagesSection_16;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,8 @@ MainPreferencePage_test_plugin_pattern_note=This pattern is matched against the
ManifestEditorContributor_externStringsActionName=Externalize Strings...

ManifestTypeRenameParticipant_composite=Rename classes referenced in plug-in manifest files
ManifestTypeDeleteParticipant_composite=Remove packages emptied by class deletion from plug-in manifest
ManifestPackageDeleteParticipant_packageDelete=Delete packages referenced in plug-in manifest

ManifestEditor_MatchSection_optional = Optional
ManifestEditor_MatchSection_reexport = Re-export the dependency
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package org.eclipse.pde.internal.ui.refactoring;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
Expand Down Expand Up @@ -69,8 +71,12 @@ public static Change createMoveToPackageChange(IFile file, MoveFromChange change
return null;
}

public static Change createEmptyPackageChange(IFile file, String packageName, IProgressMonitor monitor)
throws CoreException {
public static Change createDeletePackagesChange(IFile file, Collection<IPackageFragment> packages,
IProgressMonitor monitor) throws CoreException {
List<String> packageNames = packages.stream().map(IPackageFragment::getElementName).toList();
if (packageNames.isEmpty()) {
return null;
}
try {
Bundle bundle = getBundle(file, monitor);
if (bundle == null) {
Expand All @@ -82,8 +88,8 @@ public static Change createEmptyPackageChange(IFile file, String packageName, IP
bundle.getModel().addModelChangedListener(listener);

BasePackageHeader header = (BasePackageHeader) bundle.getManifestHeader(Constants.EXPORT_PACKAGE);
if (header != null && header.hasPackage(packageName)) {
removePackage(header, packageName);
if (header != null) {
packageNames.stream().filter(header::hasPackage).forEach(name -> removePackage(header, name));
}
TextEdit[] operations = listener.getTextOperations();
if (operations.length > 0) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*******************************************************************************
* Copyright (c) 2026 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.pde.internal.ui.refactoring;

import java.util.HashSet;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
import org.eclipse.pde.internal.core.WorkspaceModelManager;
import org.eclipse.pde.internal.core.project.PDEProject;
import org.eclipse.pde.internal.ui.PDEPlugin;
import org.eclipse.pde.internal.ui.PDEUIMessages;

/**
* Handles package deletion in PDE plugin projects. Updates the bundle's
* MANIFEST.MF after deleting packages.
*/
public class ManifestPackageDeleteParticipant extends PDEDeleteParticipant {

private IProject fProject;
private Set<IPackageFragment> fPackages = new HashSet<>();

@Override
protected boolean initialize(Object element) {
IPackageFragment fragment = (IPackageFragment) element;
try {
if (!fragment.containsJavaResources()) {
return false;
}
} catch (JavaModelException e) {
PDEPlugin.logException(e);
}
Comment thread
HannesWell marked this conversation as resolved.
fProject = fragment.getJavaProject().getProject();
if (WorkspaceModelManager.isPluginProject(fProject)) {
fPackages.add(fragment);
return true;
}
return false;
}

@Override
public void addElement(Object element, RefactoringArguments arguments) {
fPackages.add((IPackageFragment) element);
}

@Override
public String getName() {
return PDEUIMessages.ManifestPackageDeleteParticipant_packageDelete;
}

@Override
protected void addChanges(CompositeChange result, IProgressMonitor pm) throws CoreException {
IFile file = PDEProject.getManifest(fProject);
if (file.exists()) {
Change change = BundleManifestChange.createDeletePackagesChange(file, fPackages, pm);
if (change != null) {
result.add(change);
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*******************************************************************************
* Copyright (c) 2026 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.pde.internal.ui.refactoring;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
import org.eclipse.pde.internal.core.WorkspaceModelManager;
import org.eclipse.pde.internal.core.project.PDEProject;
import org.eclipse.pde.internal.ui.PDEUIMessages;

/**
* Handles class deletion in PDE plugin projects. Updates the bundle's MANIFEST.MF
* when a package becomes empty after deleting types.
*/
public class ManifestTypeDeleteParticipant extends PDEDeleteParticipant {
Comment thread
HannesWell marked this conversation as resolved.

private IProject fProject;
private Set<IType> fTypes = new LinkedHashSet<>();

@Override
protected boolean initialize(Object element) {
IType type = (IType) element;
IJavaProject javaProject = type.getJavaProject();
if (javaProject != null) {
fProject = javaProject.getProject();
if (WorkspaceModelManager.isPluginProject(fProject)) {
fTypes.add(type);
return true;
}
}
return false;
}

@Override
public void addElement(Object element, RefactoringArguments arguments) {
IType type = (IType) element;
fTypes.add(type);
}

@Override
public String getName() {
return PDEUIMessages.ManifestTypeDeleteParticipant_composite;
}

@Override
protected void addChanges(CompositeChange result, IProgressMonitor pm) throws CoreException {
IFile file = PDEProject.getManifest(fProject);
if (!file.exists()) {
return;
}
// Group deleted types by package and collect their compilation units
Map<IPackageFragment, Set<ICompilationUnit>> deletedCUsByPackage = new HashMap<>();
for (IType type : fTypes) {
IPackageFragment pkg = type.getPackageFragment();
ICompilationUnit cu = type.getCompilationUnit();
if (cu != null) {
deletedCUsByPackage.computeIfAbsent(pkg, k -> new HashSet<>()).add(cu);
}
}
// Check each package to see if it becomes empty after deletion
List<IPackageFragment> emptiedPackages = deletedCUsByPackage.entrySet().stream().filter(e -> {
IPackageFragment pkg = e.getKey();
Set<ICompilationUnit> deletedCUs = e.getValue();
try {
return willPackageBeEmpty(pkg, deletedCUs);
} catch (CoreException ex) {
return false;
}
}).map(Map.Entry::getKey).toList();

Change change = BundleManifestChange.createDeletePackagesChange(file, emptiedPackages, pm);
if (change != null) {
result.add(change);
}

}

/**
* Checks if a package will be empty after deleting the specified compilation units.
*
* @param pkg the package to check
* @param deletedCUs the compilation units being deleted
* @return true if the package will be empty after deletion
* @throws CoreException if an error occurs accessing package contents
*/
private boolean willPackageBeEmpty(IPackageFragment pkg, Set<ICompilationUnit> deletedCUs) throws CoreException {
// Check for non-Java resources (properties files, XML files, etc.)
Object[] nonJavaResources = pkg.getNonJavaResources();
if (nonJavaResources != null && nonJavaResources.length > 0) {
return false;
}
// Check if any compilation unit in the package is NOT being deleted
ICompilationUnit[] compilationUnits = pkg.getCompilationUnits();
for (ICompilationUnit cu : compilationUnits) {
if (!deletedCUs.contains(cu)) {
// This compilation unit is not being deleted, so package is not
// empty
return false;
}
}
return true;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ protected void addChange(CompositeChange result, IProgressMonitor pm) throws Cor
int totalFiles = children.length;
int movingCount = movingTypes.size();
if (totalFiles == movingCount) {
Change change = BundleManifestChange.createEmptyPackageChange(file, pkg.getElementName(), pm);
Change change = BundleManifestChange.createDeletePackagesChange(file, List.of(pkg), pm);
if (change != null) {
result.add(change);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright (c) 2026 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.pde.internal.ui.refactoring;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.DeleteParticipant;
import org.eclipse.ltk.core.refactoring.participants.ISharableParticipant;

public abstract class PDEDeleteParticipant extends DeleteParticipant implements ISharableParticipant {

@Override
public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context)
throws OperationCanceledException {
return new RefactoringStatus();
}

@Override
public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
CompositeChange result = new CompositeChange(getName());
addChanges(result, pm);
return result.getChildren().length == 0 ? null : result;
}

protected abstract void addChanges(CompositeChange result, IProgressMonitor pm) throws CoreException;

}
Loading