Bug 526011 - PDE should provide an abstraction above
annotation-configuration in .classpath
* introduce new manifest header Eclipse-ExportExternalAnnotations
* if set to true, resolved entries in Required-Plugins will define
their annotationPath equal to the plugin location
This suffices to help JDT/Core to use these annotations for null
analysis, if .eea files are shipped with the plug-in jar.
We even have content assist for the new header :)
Change-Id: I84643bc57d3da9f5a8f50d61da4ea82f8cd9cac9
Signed-off-by: Stephan Herrmann <stephan.herrmann@berlin.de>
Reviewed-on: https://git.eclipse.org/r/c/pde/eclipse.pde.ui/+/175466
Tested-by: Vikas Chandra <Vikas.Chandra@in.ibm.com>
Reviewed-by: Vikas Chandra <Vikas.Chandra@in.ibm.com>
diff --git a/ui/org.eclipse.pde.core/.settings/.api_filters b/ui/org.eclipse.pde.core/.settings/.api_filters
index 5d17ac3..686677b 100644
--- a/ui/org.eclipse.pde.core/.settings/.api_filters
+++ b/ui/org.eclipse.pde.core/.settings/.api_filters
@@ -1,5 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.pde.core" version="2">
+ <resource path="META-INF/MANIFEST.MF">
+ <filter comment="experimental addition of a manifest option" id="924844039">
+ <message_arguments>
+ <message_argument value="3.15.200"/>
+ <message_argument value="3.15.100"/>
+ </message_arguments>
+ </filter>
+ </resource>
<resource path="src/org/eclipse/pde/internal/core/project/BundleProjectService.java" type="org.eclipse.pde.internal.core.project.BundleProjectService">
<filter comment="Platform Team allows use of bundle importers for PDE import from source repository" id="640712815">
<message_arguments>
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/plugin/IPluginBase.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/plugin/IPluginBase.java
index 5f37e02..170f140 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/plugin/IPluginBase.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/plugin/IPluginBase.java
@@ -179,4 +179,16 @@
*/
void setSchemaVersion(String schemaVersion) throws CoreException;
+ /**
+ * Returns whether this plugin exports its external annotations (.eea files)
+ * to be considered by clients performing annotation based null analysis.
+ * This is read from the manifest header
+ * {@code Eclipse-ExportExternalAnnotations}.
+ *
+ * @since 3.15
+ */
+ default boolean exportsExternalAnnotations() {
+ return false;
+ }
+
}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/ICoreConstants.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/ICoreConstants.java
index e28d771..d61f5e3 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/ICoreConstants.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/ICoreConstants.java
@@ -285,6 +285,7 @@
String ECLIPSE_SOURCE_REFERENCES = "Eclipse-SourceReferences"; //$NON-NLS-1$
String SERVICE_COMPONENT = "Service-Component"; //$NON-NLS-1$
String AUTOMATIC_MODULE_NAME = "Automatic-Module-Name"; //$NON-NLS-1$
+ String ECLIPSE_EXPORT_EXTERNAL_ANNOTATIONS = "Eclipse-ExportExternalAnnotations"; //$NON-NLS-1$
// Equinox-specific system properties
String OSGI_SYSTEM_BUNDLE = "osgi.system.bundle"; //$NON-NLS-1$
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PDEAuxiliaryState.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PDEAuxiliaryState.java
index d668d56..41996da 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PDEAuxiliaryState.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PDEAuxiliaryState.java
@@ -95,6 +95,7 @@
String project;
String localization;
String bundleSourceEntry;
+ boolean exportsExternalAnnotations;
}
/**
@@ -188,6 +189,11 @@
return info == null ? null : info.bundleSourceEntry;
}
+ public boolean exportsExternalAnnotations(long bundleID) {
+ PluginInfo info = fPluginInfos.get(Long.toString(bundleID));
+ return info == null ? false : info.exportsExternalAnnotations;
+ }
+
/**
* Builds an xml document storing the auxiliary plugin info.
* @param dir directory location to create the file
@@ -375,6 +381,8 @@
info.localization = manifest.get(Constants.BUNDLE_LOCALIZATION);
info.hasBundleStructure = hasBundleStructure;
info.bundleSourceEntry = manifest.get(ICoreConstants.ECLIPSE_SOURCE_BUNDLE);
+ info.exportsExternalAnnotations = "true" //$NON-NLS-1$
+ .equals(manifest.get(ICoreConstants.ECLIPSE_EXPORT_EXTERNAL_ANNOTATIONS));
fPluginInfos.put(Long.toString(desc.getBundleId()), info);
}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PDEClasspathContainer.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PDEClasspathContainer.java
index a631457..1274af0 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PDEClasspathContainer.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PDEClasspathContainer.java
@@ -16,6 +16,7 @@
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
@@ -24,6 +25,7 @@
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.pde.core.plugin.IPluginLibrary;
import org.eclipse.pde.core.plugin.IPluginModelBase;
@@ -54,21 +56,28 @@
private static final IAccessRule EXCLUDE_ALL_RULE = JavaCore.newAccessRule(new Path("**/*"), IAccessRule.K_NON_ACCESSIBLE | IAccessRule.IGNORE_IF_BETTER); //$NON-NLS-1$
- protected void addProjectEntry(IProject project, Rule[] rules, ArrayList<IClasspathEntry> entries) throws CoreException {
+ protected void addProjectEntry(IProject project, Rule[] rules, boolean exportsExternalAnnotations,
+ ArrayList<IClasspathEntry> entries) throws CoreException {
if (project.hasNature(JavaCore.NATURE_ID)) {
- IClasspathEntry entry = null;
- if (rules != null) {
- IAccessRule[] accessRules = getAccessRules(rules);
- entry = JavaCore.newProjectEntry(project.getFullPath(), accessRules, true, new IClasspathAttribute[0], false);
- } else {
- entry = JavaCore.newProjectEntry(project.getFullPath());
- }
+ IAccessRule[] accessRules = rules != null ? getAccessRules(rules) : null;
+ IClasspathAttribute[] extraAttribs = getClasspathAttributesForProject(project, exportsExternalAnnotations);
+ IClasspathEntry entry = JavaCore.newProjectEntry(project.getFullPath(), accessRules, true, extraAttribs, false);
if (!entries.contains(entry)) {
entries.add(entry);
}
}
}
+ private IClasspathAttribute[] getClasspathAttributesForProject(IProject project, boolean exportsExternalAnnotations)
+ throws JavaModelException {
+ if (exportsExternalAnnotations) {
+ String annotationPath = JavaCore.create(project).getOutputLocation().toString();
+ return new IClasspathAttribute[] {
+ JavaCore.newClasspathAttribute(IClasspathAttribute.EXTERNAL_ANNOTATION_PATH, annotationPath) };
+ }
+ return new IClasspathAttribute[0];
+ }
+
public static IClasspathEntry[] getExternalEntries(IPluginModelBase model) {
ArrayList<IClasspathEntry> entries = new ArrayList<>();
addExternalPlugin(model, new Rule[0], entries);
@@ -153,12 +162,20 @@
}
private static IClasspathAttribute[] getClasspathAttributes(IPluginModelBase model) {
+ List<IClasspathAttribute> attributes = new ArrayList<>();
JavadocLocationManager manager = PDECore.getDefault().getJavadocLocationManager();
String location = manager.getJavadocLocation(model);
- if (location == null) {
- return new IClasspathAttribute[0];
+ if (location != null) {
+ attributes
+ .add(JavaCore.newClasspathAttribute(IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, location));
}
- return new IClasspathAttribute[] {JavaCore.newClasspathAttribute(IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, location)};
+ if (model.getPluginBase().exportsExternalAnnotations()) {
+ String installLocation = model.getInstallLocation();
+ attributes.add(
+ JavaCore.newClasspathAttribute(IClasspathAttribute.EXTERNAL_ANNOTATION_PATH,
+ installLocation));
+ }
+ return attributes.toArray(IClasspathAttribute[]::new);
}
private static synchronized IAccessRule getDiscouragedRule(IPath path) {
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PDEState.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PDEState.java
index 1a0cf66..c7ccc40 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PDEState.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/PDEState.java
@@ -306,4 +306,8 @@
return fAuxiliaryState.getBundleSourceEntry(bundleID);
}
+ public boolean exportsExternalAnnotations(long bundleID) {
+ return fAuxiliaryState.exportsExternalAnnotations(bundleID);
+ }
+
}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsClasspathContainer.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsClasspathContainer.java
index 310abc4..3999a40 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsClasspathContainer.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsClasspathContainer.java
@@ -347,7 +347,7 @@
}
if (resource != null) {
- addProjectEntry(resource.getProject(), rules, entries);
+ addProjectEntry(resource.getProject(), rules, model.getPluginBase().exportsExternalAnnotations(), entries);
} else {
addExternalPlugin(model, rules, entries);
}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/WorkspacePluginModelManager.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/WorkspacePluginModelManager.java
index a726211..30dd5e9 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/WorkspacePluginModelManager.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/WorkspacePluginModelManager.java
@@ -84,7 +84,8 @@
Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT, //
IPDEBuildConstants.ECLIPSE_PLATFORM_FILTER, //
ICoreConstants.ECLIPSE_SYSTEM_BUNDLE, //
- ICoreConstants.ECLIPSE_SOURCE_BUNDLE)));
+ ICoreConstants.ECLIPSE_SOURCE_BUNDLE, //
+ ICoreConstants.ECLIPSE_EXPORT_EXTERNAL_ANNOTATIONS)));
private final ArrayList<IExtensionDeltaListener> fExtensionListeners = new ArrayList<>();
private ArrayList<ModelChange> fChangedExtensions = null;
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/bundle/BundlePlugin.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/bundle/BundlePlugin.java
index 1b253ce..7965327 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/bundle/BundlePlugin.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/bundle/BundlePlugin.java
@@ -52,4 +52,9 @@
return "true".equals(getValue(ICoreConstants.EXTENSIBLE_API, false)); //$NON-NLS-1$
}
+ @Override
+ public boolean exportsExternalAnnotations() {
+ return "true".equals(getValue(ICoreConstants.ECLIPSE_EXPORT_EXTERNAL_ANNOTATIONS, false)); //$NON-NLS-1$
+ }
+
}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/plugin/PluginBase.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/plugin/PluginBase.java
index faf0a78..046b963 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/plugin/PluginBase.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/plugin/PluginBase.java
@@ -51,6 +51,7 @@
private String fVersion;
private boolean fHasBundleStructure;
private String fBundleSourceEntry;
+ private boolean fExportsExternalAnnotations;
public PluginBase(boolean readOnly) {
super(readOnly);
@@ -123,6 +124,7 @@
fProviderName = state.getProviderName(bundleDesc.getBundleId());
fHasBundleStructure = state.hasBundleStructure(bundleDesc.getBundleId());
fBundleSourceEntry = state.getBundleSourceEntry(bundleDesc.getBundleId());
+ fExportsExternalAnnotations = state.exportsExternalAnnotations(bundleDesc.getBundleId());
loadRuntime(bundleDesc, state);
loadImports(bundleDesc);
}
@@ -443,4 +445,8 @@
return fBundleSourceEntry;
}
+ public boolean exportsExternalAnnotations() {
+ return fExportsExternalAnnotations;
+ }
+
}
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/contentassist/ManifestContentAssistProcessor.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/contentassist/ManifestContentAssistProcessor.java
index 806cede..ee4af33 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/contentassist/ManifestContentAssistProcessor.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/contentassist/ManifestContentAssistProcessor.java
@@ -48,7 +48,7 @@
private IJavaProject fJP;
// if we order the headers alphabetically in the array, there is no need to sort and we can save time
- private static final String[] fHeader = { ICoreConstants.AUTOMATIC_MODULE_NAME, Constants.BUNDLE_ACTIVATIONPOLICY, Constants.BUNDLE_ACTIVATOR, Constants.BUNDLE_CATEGORY, Constants.BUNDLE_CLASSPATH, Constants.BUNDLE_CONTACTADDRESS, Constants.BUNDLE_COPYRIGHT, Constants.BUNDLE_DESCRIPTION, Constants.BUNDLE_DOCURL, Constants.BUNDLE_LOCALIZATION, Constants.BUNDLE_MANIFESTVERSION, Constants.BUNDLE_NAME, Constants.BUNDLE_NATIVECODE, Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT, Constants.BUNDLE_SYMBOLICNAME, Constants.BUNDLE_UPDATELOCATION, Constants.BUNDLE_VENDOR, Constants.BUNDLE_VERSION, Constants.DYNAMICIMPORT_PACKAGE, ICoreConstants.ECLIPSE_BUDDY_POLICY, ICoreConstants.ECLIPSE_BUNDLE_SHAPE, ICoreConstants.ECLIPSE_GENERIC_CAPABILITY, ICoreConstants.ECLIPSE_GENERIC_REQUIRED, ICoreConstants.ECLIPSE_LAZYSTART,
+ private static final String[] fHeader = { ICoreConstants.AUTOMATIC_MODULE_NAME, Constants.BUNDLE_ACTIVATIONPOLICY, Constants.BUNDLE_ACTIVATOR, Constants.BUNDLE_CATEGORY, Constants.BUNDLE_CLASSPATH, Constants.BUNDLE_CONTACTADDRESS, Constants.BUNDLE_COPYRIGHT, Constants.BUNDLE_DESCRIPTION, Constants.BUNDLE_DOCURL, Constants.BUNDLE_LOCALIZATION, Constants.BUNDLE_MANIFESTVERSION, Constants.BUNDLE_NAME, Constants.BUNDLE_NATIVECODE, Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT, Constants.BUNDLE_SYMBOLICNAME, Constants.BUNDLE_UPDATELOCATION, Constants.BUNDLE_VENDOR, Constants.BUNDLE_VERSION, Constants.DYNAMICIMPORT_PACKAGE, ICoreConstants.ECLIPSE_BUDDY_POLICY, ICoreConstants.ECLIPSE_BUNDLE_SHAPE, ICoreConstants.ECLIPSE_EXPORT_EXTERNAL_ANNOTATIONS, ICoreConstants.ECLIPSE_GENERIC_CAPABILITY, ICoreConstants.ECLIPSE_GENERIC_REQUIRED, ICoreConstants.ECLIPSE_LAZYSTART,
ICoreConstants.PLATFORM_FILTER, ICoreConstants.ECLIPSE_REGISTER_BUDDY, ICoreConstants.ECLIPSE_SOURCE_REFERENCES, Constants.EXPORT_PACKAGE, ICoreConstants.EXPORT_SERVICE, Constants.FRAGMENT_HOST, Constants.IMPORT_PACKAGE, ICoreConstants.IMPORT_SERVICE, Constants.PROVIDE_CAPABILITY, Constants.REQUIRE_BUNDLE, Constants.REQUIRE_CAPABILITY};
@@ -229,6 +229,10 @@
return handleBuddyPolicyCompletion(value.substring(ICoreConstants.ECLIPSE_BUDDY_POLICY.length() + 1), offset);
if (value.regionMatches(true, 0, ICoreConstants.ECLIPSE_BUNDLE_SHAPE, 0, Math.min(length, ICoreConstants.ECLIPSE_BUNDLE_SHAPE.length())))
return handleEclipseBundleShape(value.substring(ICoreConstants.ECLIPSE_BUNDLE_SHAPE.length() + 1), offset);
+ if (value.regionMatches(true, 0, ICoreConstants.ECLIPSE_EXPORT_EXTERNAL_ANNOTATIONS, 0,
+ Math.min(length, ICoreConstants.ECLIPSE_EXPORT_EXTERNAL_ANNOTATIONS.length())))
+ return handleTrueFalseValue(
+ value.substring(ICoreConstants.ECLIPSE_EXPORT_EXTERNAL_ANNOTATIONS.length() + 1), offset);
return new ICompletionProposal[0];
}