Skip to content

Commit 836bba5

Browse files
Copilotlaeubi
andcommitted
Fix API tools to persist nested classes with @noreference in
.api_description The issue was that TypeNode.persistXML and PackageNode.persistXML only persisted nodes with API visibility, filtering out non-API types even if they had restrictions like @noreference. Added shouldPersist() method to check if a node or its descendants should be persisted based on API visibility OR restrictions, ensuring nested types with @noreference are included in .api_description file. Fix #1949 Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com>
1 parent 7caca2d commit 836bba5

File tree

3 files changed

+64
-2
lines changed

3 files changed

+64
-2
lines changed

apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/model/tests/ApiDescriptionTests.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,4 +800,41 @@ public void testBinaryHasApiDescription() throws CoreException {
800800
IApiComponent componentA = profile.getApiComponent("component.a"); //$NON-NLS-1$
801801
assertTrue("Should have an .api_description file", componentA.hasApiDescription()); //$NON-NLS-1$
802802
}
803+
804+
/**
805+
* Tests that nested types with restrictions are persisted in XML.
806+
* This is a regression test for issue #1949 where nested classes marked
807+
* with @noreference were not being included in the .api_description file.
808+
*/
809+
@Test
810+
public void testNestedTypesWithRestrictionsPersisted() throws CoreException {
811+
// Create an API description with an outer class and a nested class with restrictions
812+
IApiDescription description = newDescription();
813+
814+
// Set package visibility to API
815+
description.setVisibility(Factory.packageDescriptor("test.pkg"), VisibilityModifiers.API); //$NON-NLS-1$
816+
817+
// Outer class has API visibility (default)
818+
IReferenceTypeDescriptor outerType = Factory.typeDescriptor("test.pkg.OuterClass"); //$NON-NLS-1$
819+
820+
// Nested class with @noreference restriction
821+
IReferenceTypeDescriptor nestedType = Factory.typeDescriptor("test.pkg.OuterClass$NestedClass"); //$NON-NLS-1$
822+
description.setRestrictions(nestedType, RestrictionModifiers.NO_REFERENCE);
823+
824+
// Create component and generate XML
825+
IApiComponent component = TestSuiteHelper.createTestingApiComponent("test", "test", description); //$NON-NLS-1$ //$NON-NLS-2$
826+
Document xml = getApiDescriptionXML(component);
827+
String xmlString = Util.serializeDocument(xml);
828+
829+
// Verify the XML contains the nested type
830+
assertTrue("XML should contain nested type", xmlString.contains("OuterClass$NestedClass")); //$NON-NLS-1$
831+
832+
// Restore from XML and verify the restriction is preserved
833+
IApiDescription restored = new ApiDescription(null);
834+
ApiDescriptionProcessor.annotateApiSettings(null, restored, xmlString);
835+
836+
IApiAnnotations annotations = restored.resolveAnnotations(nestedType);
837+
assertEquals("Nested type should have NO_REFERENCE restriction", //$NON-NLS-1$
838+
RestrictionModifiers.NO_REFERENCE, annotations.getRestrictions());
839+
}
803840
}

apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiDescription.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,31 @@ protected boolean hasApiVisibility(ManifestNode node) {
179179
return false;
180180
}
181181

182+
/**
183+
* Returns whether this node or any of its descendants should be persisted
184+
* in the API description. A node should be persisted if it has API visibility
185+
* or if it (or any descendant) has restrictions.
186+
*
187+
* @return true if this node or any descendant should be persisted, false otherwise
188+
*/
189+
protected boolean shouldPersist() {
190+
// Persist if the node has API visibility
191+
if (hasApiVisibility(this)) {
192+
return true;
193+
}
194+
// Persist if the node has restrictions
195+
if (!RestrictionModifiers.isUnrestricted(this.restrictions)) {
196+
return true;
197+
}
198+
// Persist if any descendant has restrictions
199+
for (ManifestNode child : children.values()) {
200+
if (child.shouldPersist()) {
201+
return true;
202+
}
203+
}
204+
return false;
205+
}
206+
182207
/**
183208
* Ensure this node is up to date. Default implementation does nothing.
184209
* Subclasses should override as required.

apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ProjectApiDescription.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ protected ManifestNode refresh() {
121121

122122
@Override
123123
void persistXML(Document document, Element parentElement) {
124-
if (hasApiVisibility(this)) {
124+
if (shouldPersist()) {
125125
Element pkg = document.createElement(IApiXmlConstants.ELEMENT_PACKAGE);
126126
for (IPackageFragment fFragment : fFragments) {
127127
Element fragment = document.createElement(IApiXmlConstants.ELEMENT_PACKAGE_FRAGMENT);
@@ -302,7 +302,7 @@ private void logRefreshing() {
302302

303303
@Override
304304
void persistXML(Document document, Element parentElement) {
305-
if (hasApiVisibility(this)) {
305+
if (shouldPersist()) {
306306
Element type = document.createElement(IApiXmlConstants.ELEMENT_TYPE);
307307
type.setAttribute(IApiXmlConstants.ATTR_HANDLE, fType.getHandleIdentifier());
308308
persistAnnotations(type);

0 commit comments

Comments
 (0)