Merge remote-tracking branch 'origin/master' into BETA_JAVA17
diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml
index cc23d13..cfc4f26 100644
--- a/.mvn/extensions.xml
+++ b/.mvn/extensions.xml
@@ -3,6 +3,6 @@
   <extension>
     <groupId>org.eclipse.tycho.extras</groupId>
     <artifactId>tycho-pomless</artifactId>
-    <version>2.3.0</version>
+    <version>2.4.0</version>
   </extension>
 </extensions>
\ No newline at end of file
diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/completion/APIToolsJavadocCompletionProposalComputer.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/completion/APIToolsJavadocCompletionProposalComputer.java
index 3ae967d..7302b2c 100644
--- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/completion/APIToolsJavadocCompletionProposalComputer.java
+++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/completion/APIToolsJavadocCompletionProposalComputer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2020 IBM Corporation and others.
+ * Copyright (c) 2007, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -400,7 +400,7 @@
 
 	@Override
 	public void sessionStarted() {
-		fParser = ASTParser.newParser(AST.JLS15);
+		fParser = ASTParser.newParser(AST.getJLSLatest());
 		fErrorMessage = null;
 	}
 
diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/JavadocTagOperation.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/JavadocTagOperation.java
index bd012b5..ef11bb2 100644
--- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/JavadocTagOperation.java
+++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/JavadocTagOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2020 IBM Corporation and others.
+ * Copyright (c) 2008, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -90,7 +90,7 @@
 	 * @return a new {@link AST}
 	 */
 	protected CompilationUnit createAST(final ICompilationUnit unit, int focalposition, boolean resolvebindings) {
-		ASTParser parser = ASTParser.newParser(AST.JLS15);
+		ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
 		parser.setSource(unit);
 		parser.setFocalPosition(focalposition);
 		parser.setResolveBindings(resolvebindings);
diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/RemoveUnsupportedAnnotationOperation.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/RemoveUnsupportedAnnotationOperation.java
index 4181957..157974f 100644
--- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/RemoveUnsupportedAnnotationOperation.java
+++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/RemoveUnsupportedAnnotationOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) Sep 12, 2018, 2020 IBM Corporation and others.
+ * Copyright (c) Sep 12, 2018, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -141,7 +141,7 @@
 						localMonitor.split(1);
 					}
 					localMonitor.split(1);
-					ASTParser parser = ASTParser.newParser(AST.JLS15);
+					ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
 					parser.setSource(compilationUnit);
 					Integer charStartAttribute = null;
 					charStartAttribute = (Integer) fMarker.getAttribute(IMarker.CHAR_START);
diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/RemoveUnsupportedTagOperation.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/RemoveUnsupportedTagOperation.java
index f1b3575..7a4b375 100644
--- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/RemoveUnsupportedTagOperation.java
+++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/RemoveUnsupportedTagOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2020 IBM Corporation and others.
+ * Copyright (c) 2008, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -90,7 +90,7 @@
 						localMonitor.split(1);
 					}
 					localMonitor.split(1);
-					ASTParser parser = ASTParser.newParser(AST.JLS15);
+					ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
 					parser.setSource(compilationUnit);
 					Integer charStartAttribute = null;
 					charStartAttribute = (Integer) this.markers[i].getAttribute(IMarker.CHAR_START);
diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/UpdateSinceTagOperation.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/UpdateSinceTagOperation.java
index a9d6870..1a1a20d 100644
--- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/UpdateSinceTagOperation.java
+++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/markers/UpdateSinceTagOperation.java
@@ -93,7 +93,7 @@
 					// quickfix change
 					JavaUI.openInEditor(compilationUnit);
 				}
-				ASTParser parser = ASTParser.newParser(AST.JLS15);
+				ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
 				parser.setSource(compilationUnit);
 				if (intValue <= 0) {
 					// try to use the name range of the corresponding element
diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/preferences/ApiBaselinesConfigurationBlock.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/preferences/ApiBaselinesConfigurationBlock.java
index 5103188..b0f24b2 100644
--- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/preferences/ApiBaselinesConfigurationBlock.java
+++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/preferences/ApiBaselinesConfigurationBlock.java
@@ -429,8 +429,8 @@
 			}
 			if (changes.size() == 2) {
 				Key k2 = changes.get(1);
-				String original2 = k2.getStoredValue(fLookupOrder[1], null);
-				String newval2 = k2.getStoredValue(fLookupOrder[1], fManager);
+				String original2 = k2.getStoredValue(fLookupOrder[0], null);
+				String newval2 = k2.getStoredValue(fLookupOrder[0], fManager);
 				if (original2 == null && newval2 == null) {
 					changes.remove(1);
 				}
diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/use/ApiUseScanTab.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/use/ApiUseScanTab.java
index 1eb1896..2f08b85 100644
--- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/use/ApiUseScanTab.java
+++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/use/ApiUseScanTab.java
@@ -22,6 +22,7 @@
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
@@ -39,6 +40,7 @@
 import org.eclipse.pde.core.target.ITargetHandle;
 import org.eclipse.pde.core.target.ITargetPlatformService;
 import org.eclipse.pde.internal.core.PDECore;
+import org.eclipse.pde.internal.core.TargetPlatformHelper;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.ModifyListener;
 import org.eclipse.swt.events.SelectionListener;
@@ -553,6 +555,8 @@
 				} else {
 					radioBaseline.setSelection(false);
 					radioTarget.setSelection(true);
+					TargetPlatformHelper.getWorkspaceTargetResolved(new NullProgressMonitor());
+					updateAvailableTargets();
 				}
 				radioInstall.setSelection(false);
 				radioReportOnly.setSelection(false);
diff --git a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/JavadocConversionRefactoring.java b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/JavadocConversionRefactoring.java
index f4a65d8..05b24f0 100644
--- a/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/JavadocConversionRefactoring.java
+++ b/apitools/org.eclipse.pde.api.tools.ui/src/org/eclipse/pde/api/tools/ui/internal/wizards/JavadocConversionRefactoring.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013, 2020 IBM Corporation and others.
+ * Copyright (c) 2013, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -324,7 +324,7 @@
 		 * @throws CoreException
 		 */
 		void collectUpdates(IType type, IElementDescriptor element, IApiDescription description) throws CoreException {
-			ASTParser parser = ASTParser.newParser(AST.JLS15);
+			ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
 			ICompilationUnit cunit = type.getCompilationUnit();
 			if (cunit != null) {
 				if (this.monitor.isCanceled()) {
diff --git a/apitools/org.eclipse.pde.api.tools/.settings/.api_filters b/apitools/org.eclipse.pde.api.tools/.settings/.api_filters
deleted file mode 100644
index 11f36c7..0000000
--- a/apitools/org.eclipse.pde.api.tools/.settings/.api_filters
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<component id="org.eclipse.pde.api.tools" version="2">
-    <resource path="META-INF/MANIFEST.MF">
-        <filter id="931135546">
-            <message_arguments>
-                <message_argument value="1.2.500"/>
-                <message_argument value="1.2.300"/>
-            </message_arguments>
-        </filter>
-    </resource>
-</component>
diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiBaselineManager.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiBaselineManager.java
index 957c41b..3cd1088 100644
--- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiBaselineManager.java
+++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiBaselineManager.java
@@ -40,7 +40,6 @@
 import org.eclipse.core.resources.ISaveParticipant;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
@@ -402,7 +401,7 @@
 	 * @throws CoreException
 	 */
 	private static void abort(String message, Throwable e) throws CoreException {
-		throw new CoreException(new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, message, e));
+		throw new CoreException(Status.error(message, e));
 	}
 
 	/**
diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiDescriptionManager.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiDescriptionManager.java
index 68e51ab..5202d22 100644
--- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiDescriptionManager.java
+++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiDescriptionManager.java
@@ -443,7 +443,7 @@
 	 * @throws CoreException
 	 */
 	private static void abort(String message, Throwable exception) throws CoreException {
-		IStatus status = new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, message, exception);
+		IStatus status = Status.error(message, exception);
 		throw new CoreException(status);
 	}
 }
diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiDescriptionProcessor.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiDescriptionProcessor.java
index e72c6b2..a82bdfe 100644
--- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiDescriptionProcessor.java
+++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiDescriptionProcessor.java
@@ -171,7 +171,7 @@
 				} catch (CoreException e) {
 					addStatus(e.getStatus());
 				} catch (BadLocationException e) {
-					addStatus(new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, ScannerMessages.ComponentXMLScanner_0 + element.toString(), e));
+					addStatus(Status.error(ScannerMessages.ComponentXMLScanner_0 + element.toString(), e));
 				}
 				members.clear();
 			}
@@ -592,7 +592,7 @@
 	 * @throws CoreException
 	 */
 	private static void abort(String message, Throwable exception) throws CoreException {
-		IStatus status = new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, message, exception);
+		IStatus status = Status.error(message, exception);
 		throw new CoreException(status);
 	}
 
diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/SystemApiDescriptionProcessor.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/SystemApiDescriptionProcessor.java
index 11e0f7f..af62846 100644
--- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/SystemApiDescriptionProcessor.java
+++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/SystemApiDescriptionProcessor.java
@@ -118,7 +118,7 @@
 	 * @throws CoreException
 	 */
 	private static void abort(String message, Throwable exception) throws CoreException {
-		IStatus status = new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, message, exception);
+		IStatus status = Status.error(message, exception);
 		throw new CoreException(status);
 	}
 
diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/AbstractIllegalTypeReference.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/AbstractIllegalTypeReference.java
index 2e41ef2..c126ea1 100644
--- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/AbstractIllegalTypeReference.java
+++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/AbstractIllegalTypeReference.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2020 IBM Corporation and others.
+ * Copyright (c) 2008, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -119,7 +119,7 @@
 				String name = ltype.getSimpleName();
 				ICompilationUnit cunit = type.getCompilationUnit();
 				if (cunit.isWorkingCopy()) {
-					cunit.reconcile(AST.JLS15, false, null, null);
+					cunit.reconcile(AST.getJLSLatest(), false, null, null);
 				}
 				IType localtype = type;
 				method = getEnclosingMethod(type, reference, doc);
diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/AbstractProblemDetector.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/AbstractProblemDetector.java
index 0e86905..b470445 100644
--- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/AbstractProblemDetector.java
+++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/AbstractProblemDetector.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2020 IBM Corporation and others.
+ * Copyright (c) 2008, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -677,7 +677,7 @@
 			String name = apitype.getSimpleName();
 			ICompilationUnit cunit = type.getCompilationUnit();
 			if (cunit.isWorkingCopy()) {
-				cunit.reconcile(AST.JLS15, false, null, null);
+				cunit.reconcile(AST.getJLSLatest(), false, null, null);
 			}
 			IMethod method = getEnclosingMethod(type, reference, doc);
 			if (method != null) {
diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java
index d457368..95b4511 100644
--- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java
+++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java
@@ -486,7 +486,8 @@
 						try {
 							this.buildstate.setManifestState(ManifestElement.parseBundleManifest(manifest.getContents(), null));
 						} catch (Exception e) {
-							ApiPlugin.log(new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, "Error parsing the manifest of: " + currentproject.getName(), e));//$NON-NLS-1$
+							ApiPlugin
+									.log(Status.error("Error parsing the manifest of: " + currentproject.getName(), e));//$NON-NLS-1$
 						}
 					}
 					IPluginModelBase base = PluginRegistry.findModel(currentproject);
diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/ApiElement.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/ApiElement.java
index d9bb817..1964c6c 100644
--- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/ApiElement.java
+++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/ApiElement.java
@@ -14,9 +14,7 @@
 package org.eclipse.pde.api.tools.internal.model;
 
 import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
-import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
 import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent;
 import org.eclipse.pde.api.tools.internal.provisional.model.IApiElement;
 
@@ -103,7 +101,7 @@
 	 * @throws CoreException
 	 */
 	protected void abort(String message, Throwable e) throws CoreException {
-		throw new CoreException(new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, message, e));
+		throw new CoreException(Status.error(message, e));
 	}
 
 	@Override
diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/util/Util.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/util/Util.java
index 5d8a7c0..6d5e9c0 100644
--- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/util/Util.java
+++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/util/Util.java
@@ -325,7 +325,7 @@
 	 * @throws CoreException
 	 */
 	private static void abort(String message, Throwable exception) throws CoreException {
-		IStatus status = new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, message, exception);
+		IStatus status = Status.error(message, exception);
 		throw new CoreException(status);
 	}
 
diff --git a/ds/org.eclipse.pde.ds.annotations/src/org/eclipse/pde/ds/internal/annotations/DSAnnotationCompilationParticipant.java b/ds/org.eclipse.pde.ds.annotations/src/org/eclipse/pde/ds/internal/annotations/DSAnnotationCompilationParticipant.java
index 818e5c7..18a2904 100644
--- a/ds/org.eclipse.pde.ds.annotations/src/org/eclipse/pde/ds/internal/annotations/DSAnnotationCompilationParticipant.java
+++ b/ds/org.eclipse.pde.ds.annotations/src/org/eclipse/pde/ds/internal/annotations/DSAnnotationCompilationParticipant.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2017 Ecliptical Software Inc. and others.
+ * Copyright (c) 2012, 2021 Ecliptical Software Inc. and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -11,6 +11,7 @@
  * Contributors:
  *     Ecliptical Software Inc. - initial API and implementation
  *     Dirk Fauth <dirk.fauth@googlemail.com> - Bug 490062
+ *     Christoph Läubrich - Bug 573557 - [ds] use deterministic order in component descriptors
  *******************************************************************************/
 package org.eclipse.pde.ds.internal.annotations;
 
@@ -26,10 +27,12 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IMarker;
@@ -377,7 +380,7 @@
 				try {
 					saveState(project.getProject(), state);
 				} catch (IOException e) {
-					Activator.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Error saving file mappings.", e)); //$NON-NLS-1$
+					Activator.log(Status.error("Error saving file mappings.", e)); //$NON-NLS-1$
 				}
 			}
 
@@ -493,17 +496,8 @@
 			return;
 		}
 
-		StringBuilder buf = new StringBuilder();
-		for (IPath entry : entries) {
-			if (buf.length() > 0) {
-				buf.append("," + TextUtil.getDefaultLineDelimiter() + " "); //$NON-NLS-1$ //$NON-NLS-2$
-			}
-
-			buf.append(entry.toString());
-		}
-
-		String value = buf.toString();
-
+		String value = entries.stream().map(IPath::toString).sorted()
+				.collect(Collectors.joining("," + TextUtil.getDefaultLineDelimiter() + " "));//$NON-NLS-1$ //$NON-NLS-2$
 		if (debug.isDebugging()) {
 			debug.trace(String.format("Setting manifest header in %s to %s: %s", model.getUnderlyingResource().getFullPath(), DS_MANIFEST_KEY, value)); //$NON-NLS-1$
 		}
@@ -588,7 +582,9 @@
 			LinkedHashSet<IPath> entries = new LinkedHashSet<>();
 			collectBuildEntries(includes, entries);
 
-			for (String dsKey : retained) {
+			Iterator<String> iterator = retained.stream().sorted().iterator();
+			while (iterator.hasNext()) {
+				String dsKey = iterator.next();
 				IPath path = Path.fromPortableString(dsKey);
 				if (!isBuildEntryIncluded(entries, path)) {
 					includes.addToken(path.toString());
diff --git a/pom.xml b/pom.xml
index cb74e94..33c61d4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,7 +26,7 @@
   <packaging>pom</packaging>
 
   <properties>
-    <tycho.scmUrl>scm:git:git://git.eclipse.org/gitroot/pde/eclipse.pde.ui.git</tycho.scmUrl>
+    <tycho.scmUrl>scm:git:https://git.eclipse.org/r/pde/eclipse.pde.ui.git</tycho.scmUrl>
   </properties>
 
   <!--
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/plugin/PluginRegistry.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/plugin/PluginRegistry.java
index f4b4cfe..e847358 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/plugin/PluginRegistry.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/plugin/PluginRegistry.java
@@ -222,29 +222,6 @@
 	}
 
 	/**
-	 * Returns whether the given model matches the given id, version, and match rule.
-	 *
-	 * @param base match candidate
-	 * @param id id to match
-	 * @param version version to match or <code>null</code>
-	 * @param match version match rule
-	 * @return whether the model is a match
-	 */
-	private static boolean isMatch(IPluginBase base, String id, String version, int match) {
-		// if version is null, then match any version with same ID
-		if (base == null) {
-			return false; // guard against invalid plug-ins
-		}
-		if (base.getId() == null) {
-			return false; // guard against invalid plug-ins
-		}
-		if (version == null) {
-			return base.getId().equals(id);
-		}
-		return VersionUtil.compare(base.getId(), base.getVersion(), id, version, match);
-	}
-
-	/**
 	 * Returns a model matching the given id, version, match rule, and optional
 	 * filter, or <code>null</code> if none.
 	 * <p>
@@ -304,14 +281,19 @@
 	 * @since 3.6
 	 */
 	public static IPluginModelBase[] findModels(String id, String version, int match, PluginFilter filter) {
-		IPluginModelBase[] models = PluginRegistry.getAllModels();
+		IPluginModelBase[] models = findModels(id);
 		List<IPluginModelBase> results = new ArrayList<>();
 		for (IPluginModelBase model : models) {
-			if ((filter == null || filter.accept(model)) && isMatch(model.getPluginBase(), id, version, match)) {
+			IPluginBase base = model.getPluginBase();
+			if (base == null || base.getId() == null) {
+				continue; // guard against invalid plug-ins
+			}
+			if ((filter == null || filter.accept(model))
+					&& (version == null || VersionUtil.compare(base.getVersion(), version, match))) {
 				results.add(model);
 			}
 		}
-		return results.toArray(new IPluginModelBase[results.size()]);
+		return results.toArray(IPluginModelBase[]::new);
 	}
 
 	/**
@@ -390,10 +372,10 @@
 	 * @since 3.6
 	 */
 	public static IPluginModelBase[] findModels(String id, VersionRange range, PluginFilter filter) {
-		IPluginModelBase[] models = PluginRegistry.getAllModels();
+		IPluginModelBase[] models = findModels(id);
 		List<IPluginModelBase> results = new ArrayList<>();
 		for (IPluginModelBase model : models) {
-			if ((filter == null || filter.accept(model)) && id.equals(model.getPluginBase().getId())) {
+			if (filter == null || filter.accept(model)) {
 				String versionStr = model.getPluginBase().getVersion();
 				Version version = VersionUtil.validateVersion(versionStr).isOK() ? new Version(versionStr) : Version.emptyVersion;
 				if (range == null || range.isIncluded(version)) {
@@ -401,7 +383,15 @@
 				}
 			}
 		}
-		return results.toArray(new IPluginModelBase[results.size()]);
+		return results.toArray(IPluginModelBase[]::new);
+	}
+
+	private static IPluginModelBase[] findModels(String id) {
+		ModelEntry entry = PluginRegistry.findEntry(id);
+		if (entry != null) {
+			return entry.hasWorkspaceModels() ? entry.getWorkspaceModels() : entry.getExternalModels();
+		}
+		return new IPluginModelBase[0];
 	}
 
 	/**
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/DependencyManager.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/DependencyManager.java
index df74354..3c8560a 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/DependencyManager.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/DependencyManager.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *  Copyright (c) 2005, 2018 IBM Corporation and others.
+ *  Copyright (c) 2005, 2021 IBM Corporation and others.
  *
  *  This program and the accompanying materials
  *  are made available under the terms of the Eclipse Public License 2.0
@@ -34,7 +34,6 @@
 import org.eclipse.osgi.service.resolver.ResolverError;
 import org.eclipse.osgi.service.resolver.State;
 import org.eclipse.osgi.service.resolver.VersionConstraint;
-import org.eclipse.pde.core.plugin.IPluginExtension;
 import org.eclipse.pde.core.plugin.IPluginModelBase;
 import org.eclipse.pde.core.plugin.ModelEntry;
 import org.eclipse.pde.core.plugin.PluginRegistry;
@@ -160,7 +159,7 @@
 	 *            from the dependency resolution
 	 * @return a set of bundle IDs
 	 */
-	private static Set<String> getDependencies(Set<IPluginModelBase> selected, String[] implicit, State state,
+	public static Set<String> getDependencies(Set<IPluginModelBase> selected, String[] implicit, State state,
 			boolean removeSelf,
 			boolean includeOptional, Set<String> excludeFragments) {
 		Set<String> bundleIds = new TreeSet<>();
@@ -170,17 +169,6 @@
 		// Also consider plugin extensions and their dependencies.
 		for (IPluginModelBase model : selected) {
 			addBundleAndDependencies(model.getBundleDescription(), bundleIds, includeOptional, excludeFragments);
-			IPluginExtension[] extensions = model.getPluginBase().getExtensions();
-			for (IPluginExtension extension : extensions) {
-				String point = extension.getPoint();
-				if (point != null) {
-					int dot = point.lastIndexOf('.');
-					if (dot != -1) {
-						String id = point.substring(0, dot);
-						addBundleAndDependencies(state.getBundle(id, null), bundleIds, includeOptional, excludeFragments);
-					}
-				}
-			}
 		}
 
 		for (String element : implicit) {
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/pderesources.properties b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/pderesources.properties
index baeda3c..7d97216 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/pderesources.properties
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/pderesources.properties
@@ -210,7 +210,7 @@
 ManifestConsistencyChecker_buildDoesNotExist=build.properties does not exist
 ManifestConsistencyChecker_builderTaskName=Validating project
 ManifestConsistencyChecker_manifestDoesNotExist=META-INF/MANIFEST.MF does not exist
-ManifestConsistencyChecker_manifestMisspelled=Manifest file name misspelled. It must be spelled 'MANIFEST.MF'
+ManifestConsistencyChecker_manifestMisspelled=Manifest file name has incorrect casing. It must be written as 'MANIFEST.MF'
 SchemaElementReference_refElementMissing=No DTD available
 
 ExportWizard_badDirectory = Specified directory could not be created.
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinition.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinition.java
index 1715a50..99cb470 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinition.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetDefinition.java
@@ -832,7 +832,7 @@
 	 * @throws CoreException
 	 */
 	private void abort(String message, Exception e) throws CoreException {
-		throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, message, e));
+		throw new CoreException(Status.error(message, e));
 	}
 
 	@Override
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/util/VersionUtil.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/util/VersionUtil.java
index 1a0e019..14ea45a 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/util/VersionUtil.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/util/VersionUtil.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *  Copyright (c) 2006, 2013 IBM Corporation and others.
+ *  Copyright (c) 2006, 2021 IBM Corporation and others.
  *
  *  This program and the accompanying materials
  *  are made available under the terms of the Eclipse Public License 2.0
@@ -22,6 +22,9 @@
 
 public class VersionUtil {
 
+	private VersionUtil() { // static use only
+	}
+
 	public static IStatus validateVersion(String versionString) {
 		try {
 			if (versionString != null) {
@@ -46,22 +49,27 @@
 		if (!(id1.equals(id2))) {
 			return false;
 		}
+		return compare(version1, version2, match);
+	}
+
+	public static boolean compare(String version1, String version2, int match) {
 		try {
 			Version v1 = Version.parseVersion(version1);
 			Version v2 = Version.parseVersion(version2);
 
-			switch (match) {
-				case IMatchRules.NONE :
-				case IMatchRules.COMPATIBLE :
+			switch (match)
+				{
+				case IMatchRules.NONE:
+				case IMatchRules.COMPATIBLE:
 					return isCompatibleWith(v1, v2);
-				case IMatchRules.EQUIVALENT :
+				case IMatchRules.EQUIVALENT:
 					return isEquivalentTo(v1, v2);
-				case IMatchRules.PERFECT :
+				case IMatchRules.PERFECT:
 					return v1.equals(v2);
-				case IMatchRules.GREATER_OR_EQUAL :
+				case IMatchRules.GREATER_OR_EQUAL:
 					return isGreaterOrEqualTo(v1, v2);
-			}
-		} catch (RuntimeException e) {
+				}
+		} catch (RuntimeException e) { // ignore
 		}
 		return version1.equals(version2);
 	}
diff --git a/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF
index 05eb5eb..a224ce5 100644
--- a/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF
+++ b/ui/org.eclipse.pde.ui.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: PDE JUnit Tests
 Bundle-SymbolicName: org.eclipse.pde.ui.tests; singleton:=true
-Bundle-Version: 3.11.300.qualifier
+Bundle-Version: 3.11.400.qualifier
 Bundle-ClassPath: tests.jar
 Bundle-Activator: org.eclipse.pde.ui.tests.PDETestsPlugin
 Bundle-Vendor: Eclipse.org
diff --git a/ui/org.eclipse.pde.ui.tests/forceQualifierUpdate.txt b/ui/org.eclipse.pde.ui.tests/forceQualifierUpdate.txt
index c32e425..5a46dea 100644
--- a/ui/org.eclipse.pde.ui.tests/forceQualifierUpdate.txt
+++ b/ui/org.eclipse.pde.ui.tests/forceQualifierUpdate.txt
@@ -1,3 +1,4 @@
 Bug 534597 - Unanticipated comparator errors in I20180511-2000
 Bug 566115 - Comparator error in I build (I20200816-1800)
-Bug 566147 - Comparator errors in I20200817-1800
\ No newline at end of file
+Bug 566147 - Comparator errors in I20200817-1800
+Bug 575106 - Comparator error in 20210729-0050
\ No newline at end of file
diff --git a/ui/org.eclipse.pde.ui.tests/pom.xml b/ui/org.eclipse.pde.ui.tests/pom.xml
index e799d27..c60c71d 100644
--- a/ui/org.eclipse.pde.ui.tests/pom.xml
+++ b/ui/org.eclipse.pde.ui.tests/pom.xml
@@ -19,7 +19,7 @@
   </parent>
   <groupId>org.eclipse.pde</groupId>
   <artifactId>org.eclipse.pde.ui.tests</artifactId>
-  <version>3.11.300-SNAPSHOT</version>
+  <version>3.11.400-SNAPSHOT</version>
   <packaging>eclipse-test-plugin</packaging>
 
   <properties>
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java
index 96994eb..3bd660f 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java
@@ -14,22 +14,57 @@
  *******************************************************************************/
 package org.eclipse.pde.ui.tests.launcher;
 
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsEqual.equalTo;
+import static org.assertj.core.api.Assertions.assertThat;
 
+import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Stream;
+import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
 import org.eclipse.debug.core.ILaunchConfiguration;
-import org.eclipse.pde.core.plugin.IPluginModelBase;
+import org.eclipse.pde.core.plugin.*;
 import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper;
-import org.junit.Before;
-import org.junit.Test;
+import org.eclipse.pde.internal.ui.wizards.feature.CreateFeatureProjectOperation;
+import org.eclipse.pde.internal.ui.wizards.feature.FeatureData;
+import org.junit.*;
 
 public class FeatureBasedLaunchTest extends AbstractLaunchTest {
 
+	private static IProject featureProject;
+
 	private ILaunchConfiguration fFeatureBasedWithStartLevels;
 
+	@BeforeClass
+	public static void createTestFeature() throws Exception {
+
+		FeatureData featureData = new FeatureData();
+		featureData.id = FeatureBasedLaunchTest.class.getName() + "-feature";
+		featureData.version = "1.0.0";
+
+		IPluginBase[] contents = Stream.of("javax.inject", "org.eclipse.core.runtime", "org.eclipse.ui") //
+				.map(id -> PluginRegistry.findModel(id).getPluginBase()) //
+				.toArray(IPluginBase[]::new);
+
+		IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
+		featureProject = workspaceRoot.getProject(featureData.id);
+		IPath location = workspaceRoot.getLocation().append(featureProject.getName());
+		CreateFeatureProjectOperation operation = new CreateFeatureProjectOperation(featureProject, location,
+				featureData, contents, null) {
+			@Override
+			protected void openFeatureEditor(IFile manifestFile) {
+				// don't open in headless tests
+			}
+		};
+		operation.run(null);
+	}
+
+	@AfterClass
+	public static void cleanup() throws Exception {
+		featureProject.delete(true, null);
+	}
+
 	@Before
 	public void setupLaunchConfig() throws Exception {
 		fFeatureBasedWithStartLevels = getLaunchConfiguration("feature-based-with-startlevels.launch");
@@ -53,11 +88,12 @@
 	private void checkStartLevels(String pluginId, String expectedStartLevels) throws CoreException {
 		Map<IPluginModelBase, String> bundleMap = BundleLauncherHelper.getMergedBundleMap(fFeatureBasedWithStartLevels,
 				false);
-		String actualLevels = bundleMap.entrySet().stream()
-				.filter(e -> pluginId.equals(e.getKey().getPluginBase().getId())).map(e -> e.getValue()).findFirst()
-				.orElseThrow(() -> new AssertionError("no entry found for " + pluginId));
 
-		assertThat("start levels of " + pluginId, actualLevels, is(equalTo(expectedStartLevels)));
+		Map<String, String> byId = new LinkedHashMap<>();
+		for (Entry<IPluginModelBase, String> entry : bundleMap.entrySet()) {
+			byId.put(entry.getKey().getPluginBase().getId(), entry.getValue());
+		}
 
+		assertThat(byId).containsEntry(pluginId, expectedStartLevels);
 	}
 }
diff --git a/ui/org.eclipse.pde.ui.tests/tests/launch/feature-based-with-startlevels.launch b/ui/org.eclipse.pde.ui.tests/tests/launch/feature-based-with-startlevels.launch
index f8fad59..3c4cc56 100644
--- a/ui/org.eclipse.pde.ui.tests/tests/launch/feature-based-with-startlevels.launch
+++ b/ui/org.eclipse.pde.ui.tests/tests/launch/feature-based-with-startlevels.launch
@@ -28,7 +28,7 @@
     <stringAttribute key="pde.version" value="3.3"/>
     <stringAttribute key="product" value="org.eclipse.sdk.ide"/>
     <setAttribute key="selected_features">
-        <setEntry value="org.eclipse.rcp:default"/>
+        <setEntry value="org.eclipse.pde.ui.tests.launcher.FeatureBasedLaunchTest-feature:default"/>
     </setAttribute>
     <booleanAttribute key="show_selected_only" value="false"/>
     <stringAttribute key="templateConfig" value="${target_home}\configuration\config.ini"/>
diff --git a/ui/org.eclipse.pde.ui/.settings/.api_filters b/ui/org.eclipse.pde.ui/.settings/.api_filters
index b2e6330..36c32e7 100644
--- a/ui/org.eclipse.pde.ui/.settings/.api_filters
+++ b/ui/org.eclipse.pde.ui/.settings/.api_filters
@@ -1,13 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <component id="org.eclipse.pde.ui" version="2">
-    <resource path="META-INF/MANIFEST.MF" type="org.eclipse.pde.ui.IProvisionerWizard">
-        <filter comment="API was marked for removal" id="305324134">
-            <message_arguments>
-                <message_argument value="org.eclipse.pde.ui.IProvisionerWizard"/>
-                <message_argument value="org.eclipse.pde.ui_3.13.100"/>
-            </message_arguments>
-        </filter>
-    </resource>
     <resource path="src/org/eclipse/pde/internal/ui/editor/category/SiteBundleAdapter.java" type="org.eclipse.pde.internal.ui.editor.category.SiteBundleAdapter">
         <filter comment="PDE UI may use restricted code from PDE Core" id="574619656">
             <message_arguments>
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java
index 96c9d78..c72d191 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java
@@ -3186,8 +3186,10 @@
 	public static String OpenManifestsAction_cannotFind;
 
 	public static String OpenManifestsAction_cannotOpen;
+	public static String OpenManifestsAction_cannotOpenThisFile;
 
 	public static String OpenManifestsAction_title;
+	public static String OpenPluginManifestsAction_title;
 
 	public static String NewProjectCreationPage_invalidProjectName;
 	public static String NewProjectCreationPage_invalidLocationPath;
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/ManifestEditor.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/ManifestEditor.java
index 73fbcc1..46ef04c 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/ManifestEditor.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/plugin/ManifestEditor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *  Copyright (c) 2000, 2015 IBM Corporation and others.
+ *  Copyright (c) 2000, 2021 IBM Corporation and others.
  *
  *  This program and the accompanying materials
  *  are made available under the terms of the Eclipse Public License 2.0
@@ -23,9 +23,11 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
 import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.osgi.service.resolver.BaseDescription;
 import org.eclipse.osgi.service.resolver.BundleDescription;
+import org.eclipse.osgi.util.NLS;
 import org.eclipse.pde.core.IBaseModel;
 import org.eclipse.pde.core.IIdentifiable;
 import org.eclipse.pde.core.build.*;
@@ -180,12 +182,18 @@
 			manifestFile = file;
 			buildFile = container.getFile(ICoreConstants.BUILD_PROPERTIES_PATH);
 			pluginFile = createPluginFile(container);
-		} else if (name.equals(ICoreConstants.PLUGIN_FILENAME_DESCRIPTOR) || name.equals(ICoreConstants.FRAGMENT_FILENAME_DESCRIPTOR)) {
+		} else if (name.equals(ICoreConstants.PLUGIN_FILENAME_DESCRIPTOR)
+				|| name.equals(ICoreConstants.FRAGMENT_FILENAME_DESCRIPTOR)) {
 			pluginFile = file;
 			fragment = name.equals(ICoreConstants.FRAGMENT_FILENAME_DESCRIPTOR);
 			buildFile = container.getFile(ICoreConstants.BUILD_PROPERTIES_PATH);
 			manifestFile = container.getFile(ICoreConstants.MANIFEST_PATH);
 		}
+		if (manifestFile == null) {
+			MessageDialog.openError(PDEPlugin.getActiveWorkbenchShell(), PDEUIMessages.OpenPluginManifestsAction_title,
+					NLS.bind(PDEUIMessages.OpenManifestsAction_cannotOpenThisFile, name));
+			return;
+		}
 		if (manifestFile.exists()) {
 			IEditorInput in = new FileEditorInput(manifestFile);
 			manager.putContext(in, new BundleInputContext(this, in, file == manifestFile));
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/product/PluginSection.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/product/PluginSection.java
index 7b75cab..14c71e6 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/product/PluginSection.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/product/PluginSection.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2017 IBM Corporation and others.
+ * Copyright (c) 2005, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -22,6 +22,7 @@
 
 import java.util.*;
 import java.util.List;
+import java.util.stream.Collectors;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.*;
@@ -31,18 +32,17 @@
 import org.eclipse.jface.window.Window;
 import org.eclipse.jface.wizard.WizardDialog;
 import org.eclipse.osgi.service.resolver.BundleDescription;
-import org.eclipse.osgi.service.resolver.HostSpecification;
 import org.eclipse.pde.core.IModelChangedEvent;
 import org.eclipse.pde.core.plugin.*;
 import org.eclipse.pde.internal.core.*;
 import org.eclipse.pde.internal.core.iproduct.*;
 import org.eclipse.pde.internal.core.iproduct.IProduct;
+import org.eclipse.pde.internal.core.util.VersionUtil;
 import org.eclipse.pde.internal.ui.*;
 import org.eclipse.pde.internal.ui.dialogs.PluginSelectionDialog;
 import org.eclipse.pde.internal.ui.editor.*;
 import org.eclipse.pde.internal.ui.editor.plugin.ManifestEditor;
 import org.eclipse.pde.internal.ui.parts.TablePart;
-import org.eclipse.pde.internal.ui.search.dependencies.DependencyCalculator;
 import org.eclipse.pde.internal.ui.util.PersistablePluginObject;
 import org.eclipse.pde.internal.ui.util.SWTUtil;
 import org.eclipse.pde.internal.ui.wizards.plugin.NewFragmentProjectWizard;
@@ -349,34 +349,21 @@
 		if (plugins.length == 0)
 			return;
 
-		ArrayList<BundleDescription> list = new ArrayList<>(plugins.length);
-		for (IProductPlugin plugin : plugins) {
-			list.add(TargetPlatformHelper.getState().getBundle(plugin.getId(), null));
-		}
-		DependencyCalculator calculator = new DependencyCalculator(includeOptional);
-		calculator.findDependencies(list.toArray());
+		Set<IPluginModelBase> list = Arrays.stream(plugins).map(plugin -> {
+			String version = VersionUtil.isEmptyVersion(plugin.getVersion()) ? null : plugin.getVersion();
+			return PluginRegistry.findModel(plugin.getId(), version, IMatchRules.PERFECT, null);
+		}).filter(Objects::nonNull).collect(Collectors.toSet());
 
-		BundleDescription[] bundles = TargetPlatformHelper.getState().getBundles();
-		for (BundleDescription bundle : bundles) {
-			HostSpecification host = bundle.getHost();
-			if (host != null && calculator.containsPluginId(host.getName())) {
-				calculator.findDependency(bundle);
-			}
-		}
-
-		Collection<?> dependencies = calculator.getBundleIDs();
+		Set<String> dependencies = DependencyManager.getDependencies(list, new String[0],
+				TargetPlatformHelper.getState(), true, includeOptional, Collections.emptySet());
 
 		IProduct product = plugins[0].getProduct();
 		IProductModelFactory factory = product.getModel().getFactory();
-		IProductPlugin[] requiredPlugins = new IProductPlugin[dependencies.size()];
-		int i = 0;
-		Iterator<?> iter = dependencies.iterator();
-		while (iter.hasNext()) {
-			String id = iter.next().toString();
+		IProductPlugin[] requiredPlugins = dependencies.stream().map(id -> {
 			IProductPlugin plugin = factory.createPlugin();
 			plugin.setId(id);
-			requiredPlugins[i++] = plugin;
-		}
+			return plugin;
+		}).toArray(IProductPlugin[]::new);
 		product.addPlugins(requiredPlugins);
 	}
 
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/FeatureBlock.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/FeatureBlock.java
index 2cb79c0..d3ab3f6 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/FeatureBlock.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/FeatureBlock.java
@@ -183,6 +183,12 @@
 			}
 			return getColumnText(element, 0);
 		}
+
+		@Override
+		public void dispose() {
+			pdeLabelProvider.dispose();
+			super.dispose();
+		}
 	}
 
 	class ButtonSelectionListener extends SelectionAdapter {
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/nls/NLSFragmentGenerator.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/nls/NLSFragmentGenerator.java
index 1f03f5d..244d793 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/nls/NLSFragmentGenerator.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/nls/NLSFragmentGenerator.java
@@ -446,7 +446,7 @@
 			File file = folder.getFullPath().toFile();
 			String canonicalFilePath = file.getCanonicalPath();
 			if (!canonicalFilePath.startsWith(destCanonicalPath + File.separator)) {
-				throw new CoreException(new Status(IStatus.ERROR, PDEPlugin.getPluginId(),
+				throw new CoreException(Status.error(
 						MessageFormat.format("Entry is outside of the target dir: : {0}", file.getName()), null)); //$NON-NLS-1$
 			}
 			if (!folder.exists()) {
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties
index 146e0c4..a55dd36 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties
@@ -2345,8 +2345,10 @@
 NoLineTerminationResolutionRemove_description=Removes all whitespace characters from the last line of the manifest
 NoLineTerminationResolutionRemove_label=Remove excess whitespace from the end of the manifest
 OpenManifestsAction_title=Open Manifest
+OpenPluginManifestsAction_title=Plug-in Manifest Editor Error
 OpenManifestsAction_cannotFind=Cannot find manifest for {0}.
 OpenManifestsAction_cannotOpen=Cannot open manifest for {0}.
+OpenManifestsAction_cannotOpenThisFile=Cannot open Plug-in Manifest Editor for {0} as only MANIFEST.MF, feature.xml and plugin.xml allowed.
 OpenManifestAction_noManifest=Cannot find manifest for the current selection.
 SyntaxColorTab_elements=Elements:
 SyntaxColorTab_color=&Color:
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/search/dependencies/DependencyCalculator.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/search/dependencies/DependencyCalculator.java
deleted file mode 100644
index 33b05e1..0000000
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/search/dependencies/DependencyCalculator.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*******************************************************************************
- *  Copyright (c) 2007, 2012 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.search.dependencies;
-
-import java.util.HashMap;
-import java.util.Set;
-import org.eclipse.osgi.service.resolver.*;
-import org.eclipse.pde.core.plugin.IPluginModelBase;
-import org.eclipse.pde.core.plugin.PluginRegistry;
-import org.osgi.framework.Constants;
-
-public class DependencyCalculator {
-
-	boolean fIncludeOptional;
-	protected HashMap<String, IPluginModelBase> fDependencies;
-
-	/*
-	 * Object[] can be IPluginModelBases, BundleDescriptions, or Strings (id's of bundles)
-	 */
-	public DependencyCalculator(boolean includeOptional) {
-		super();
-		fIncludeOptional = includeOptional;
-	}
-
-	public void findDependencies(Object[] includedBundles) {
-		if (fDependencies == null)
-			fDependencies = new HashMap<>();
-		for (Object bundle : includedBundles) {
-			findObjectDependencies(bundle);
-		}
-	}
-
-	public void findDependency(Object bundle) {
-		if (fDependencies == null)
-			fDependencies = new HashMap<>();
-		findObjectDependencies(bundle);
-	}
-
-	private void findObjectDependencies(Object obj) {
-		if (obj instanceof IPluginModelBase) {
-			IPluginModelBase base = ((IPluginModelBase) obj);
-			BundleDescription desc = base.getBundleDescription();
-			if (desc != null)
-				obj = desc;
-		}
-		if (obj instanceof BundleDescription)
-			findDependencies((BundleDescription) obj);
-	}
-
-	/*
-	 * Returns a Set of Bundle Ids
-	 */
-	public Set<String> getBundleIDs() {
-		Set<String> temp = fDependencies.keySet();
-		fDependencies = null;
-		return temp;
-	}
-
-	protected void findDependencies(BundleDescription desc) {
-		if (desc == null)
-			return;
-		String id = desc.getSymbolicName();
-		if (fDependencies.containsKey(id))
-			return;
-		IPluginModelBase model = PluginRegistry.findModel(desc);
-		if (model == null)
-			return;
-		fDependencies.put(id, model);
-
-		addRequiredBundles(desc.getRequiredBundles());
-		addImportedPackages(desc.getImportPackages());
-
-		HostSpecification host = desc.getHost();
-		if (host != null) {
-			// if current BundleDescription is a fragment, include host bundle
-			BaseDescription bd = host.getSupplier();
-			if (bd != null && bd instanceof BundleDescription)
-				findDependencies((BundleDescription) bd);
-		} else {
-			// otherwise, include applicable fragments for bundle
-			addFragments(desc);
-		}
-	}
-
-	protected void addRequiredBundles(BundleSpecification[] requiredBundles) {
-		for (BundleSpecification bundle : requiredBundles) {
-			if (bundle.isOptional() && !fIncludeOptional)
-				continue;
-			BaseDescription bd = bundle.getSupplier();
-			// only recursively search statisfied require-bundles
-			if (bd != null && bd instanceof BundleDescription)
-				findDependencies((BundleDescription) bd);
-		}
-	}
-
-	protected void addImportedPackages(ImportPackageSpecification[] packages) {
-		for (ImportPackageSpecification pkg : packages) {
-			if (!fIncludeOptional)
-				if (Constants.RESOLUTION_OPTIONAL.equals(pkg.getDirective(Constants.RESOLUTION_DIRECTIVE))) {
-					continue;
-				}
-			BaseDescription bd = pkg.getSupplier();
-			// only recursively search statisfied import-packages
-			if (bd != null && bd instanceof ExportPackageDescription) {
-				BundleDescription exporter = ((ExportPackageDescription) bd).getExporter();
-				if (exporter != null)
-					findDependencies(exporter);
-			}
-		}
-	}
-
-	protected void addFragments(BundleDescription desc) {
-		BundleDescription[] fragments = desc.getFragments();
-		for (BundleDescription fragment : fragments)
-			if (fragment.isResolved()) {
-				findDependencies(fragment);
-			}
-	}
-
-	public boolean containsPluginId(String id) {
-		return fDependencies.containsKey(id);
-	}
-
-}
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/views/imagebrowser/repositories/AbstractRepository.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/views/imagebrowser/repositories/AbstractRepository.java
index 37cd16e..ed6c44b 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/views/imagebrowser/repositories/AbstractRepository.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/views/imagebrowser/repositories/AbstractRepository.java
@@ -72,7 +72,7 @@
 		try (InputStream s = new BufferedInputStream(file.getContents())) {
 			return new ImageData(s);
 		} catch (IOException e) {
-			throw new CoreException(new Status(IStatus.ERROR, PDEPlugin.getPluginId(),
+			throw new CoreException(Status.error(
 					"Failed to close stream on: " + file.getLocation(), e)); //$NON-NLS-1$
 		}
 	}
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/product/ProductFromExtensionOperation.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/product/ProductFromExtensionOperation.java
index 682e9d9..f38e773 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/product/ProductFromExtensionOperation.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/product/ProductFromExtensionOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *  Copyright (c) 2005, 2015 IBM Corporation and others.
+ *  Copyright (c) 2005, 2021 IBM Corporation and others.
  *
  *  This program and the accompanying materials
  *  are made available under the terms of the Eclipse Public License 2.0
@@ -13,12 +13,13 @@
  *******************************************************************************/
 package org.eclipse.pde.internal.ui.wizards.product;
 
-import java.util.Set;
+import java.util.*;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.pde.core.plugin.*;
+import org.eclipse.pde.internal.core.DependencyManager;
+import org.eclipse.pde.internal.core.TargetPlatformHelper;
 import org.eclipse.pde.internal.core.iproduct.IProduct;
 import org.eclipse.pde.internal.core.iproduct.IProductModelFactory;
-import org.eclipse.pde.internal.ui.search.dependencies.DependencyCalculator;
 
 public class ProductFromExtensionOperation extends BaseProductCreationOperation {
 
@@ -44,11 +45,12 @@
 		if (lastDot == -1)
 			return new String[0];
 
-		DependencyCalculator calculator = new DependencyCalculator(false);
+		Set<IPluginModelBase> plugins = new HashSet<>();
 		// add plugin declaring product and its pre-reqs
 		IPluginModelBase model = PluginRegistry.findModel(fId.substring(0, lastDot));
-		if (model != null)
-			calculator.findDependency(model);
+		if (model != null) {
+			plugins.add(model);
+		}
 
 		// add plugin declaring product application and its pre-reqs
 		IPluginElement element = getProductExtension(fId);
@@ -60,13 +62,14 @@
 				if (lastDot != -1) {
 					model = PluginRegistry.findModel(appId.substring(0, lastDot));
 					if (model != null) {
-						calculator.findDependency(model);
+						plugins.add(model);
 					}
 				}
 			}
 		}
-		Set<?> ids = calculator.getBundleIDs();
-		return ids.toArray(new String[ids.size()]);
+		Set<String> bundles = DependencyManager.getDependencies(plugins, new String[0],
+				TargetPlatformHelper.getState(), false, false, Collections.emptySet());
+		return bundles.toArray(String[]::new);
 	}
 
 }
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/product/UpdateSplashProgressOperation.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/product/UpdateSplashProgressOperation.java
index b5f151b..9b1c23f 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/product/UpdateSplashProgressOperation.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/wizards/product/UpdateSplashProgressOperation.java
@@ -211,7 +211,7 @@
 	}
 
 	private CoreException createCoreException(String message, Throwable exception) {
-		IStatus status = new Status(IStatus.ERROR, IPDEUIConstants.PLUGIN_ID, message, exception);
+		IStatus status = Status.error(message, exception);
 		return new CoreException(status);
 	}
 
diff --git a/ui/org.eclipse.pde.ui/src_samples/org/eclipse/pde/internal/ui/samples/ShowSampleAction.java b/ui/org.eclipse.pde.ui/src_samples/org/eclipse/pde/internal/ui/samples/ShowSampleAction.java
index 0bb6a36..1ddb9d5 100644
--- a/ui/org.eclipse.pde.ui/src_samples/org/eclipse/pde/internal/ui/samples/ShowSampleAction.java
+++ b/ui/org.eclipse.pde.ui/src_samples/org/eclipse/pde/internal/ui/samples/ShowSampleAction.java
@@ -36,15 +36,14 @@
 import org.eclipse.jface.window.Window;
 import org.eclipse.jface.wizard.WizardDialog;
 import org.eclipse.osgi.util.NLS;
-import org.eclipse.pde.internal.ui.*;
+import org.eclipse.pde.internal.ui.PDEPlugin;
+import org.eclipse.pde.internal.ui.PDEUIMessages;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.WorkbenchException;
 import org.eclipse.ui.intro.IIntroSite;
 import org.eclipse.ui.intro.config.*;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
+import org.osgi.framework.*;
 
 public class ShowSampleAction extends Action implements IIntroAction {
 	private static final String SAMPLE_FEATURE_ID = "org.eclipse.sdk.samples"; //$NON-NLS-1$
@@ -247,7 +246,7 @@
 		try {
 			configurator.applyConfiguration();
 		} catch (IOException e) {
-			throw new CoreException(new Status(IStatus.ERROR, IPDEUIConstants.PLUGIN_ID, "Unexpected failure applying configuration", e)); //$NON-NLS-1$
+			throw new CoreException(Status.error("Unexpected failure applying configuration", e)); //$NON-NLS-1$
 		} finally {
 			context.ungetService(reference);
 		}