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
Original file line number Diff line number Diff line change
Expand Up @@ -800,4 +800,38 @@ public void testBinaryHasApiDescription() throws CoreException {
IApiComponent componentA = profile.getApiComponent("component.a"); //$NON-NLS-1$
assertTrue("Should have an .api_description file", componentA.hasApiDescription()); //$NON-NLS-1$
}

/**
* Tests that nested types with restrictions are persisted in XML.
* This is a regression test for issue #1949 where nested classes marked
* with @noreference were not being included in the .api_description file.
*/
@Test
public void testNestedTypesWithRestrictionsPersisted() throws CoreException {
// Create an API description with an outer class and a nested class with restrictions
IApiDescription description = newDescription();

// Set package visibility to API
description.setVisibility(Factory.packageDescriptor("test.pkg"), VisibilityModifiers.API); //$NON-NLS-1$

// Nested class with @noreference restriction
IReferenceTypeDescriptor nestedType = Factory.typeDescriptor("test.pkg.OuterClass$NestedClass"); //$NON-NLS-1$
description.setRestrictions(nestedType, RestrictionModifiers.NO_REFERENCE);

// Create component and generate XML
IApiComponent component = TestSuiteHelper.createTestingApiComponent("test", "test", description); //$NON-NLS-1$ //$NON-NLS-2$
Document xml = getApiDescriptionXML(component);
String xmlString = Util.serializeDocument(xml);

// Verify the XML contains the nested type
assertTrue("XML should contain nested type", xmlString.contains("OuterClass$NestedClass")); //$NON-NLS-1$ //$NON-NLS-2$

// Restore from XML and verify the restriction is preserved
IApiDescription restored = new ApiDescription(null);
ApiDescriptionProcessor.annotateApiSettings(null, restored, xmlString);

IApiAnnotations annotations = restored.resolveAnnotations(nestedType);
assertEquals("Nested type should have NO_REFERENCE restriction", //$NON-NLS-1$
RestrictionModifiers.NO_REFERENCE, annotations.getRestrictions());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,31 @@ protected boolean hasApiVisibility(ManifestNode node) {
return false;
}

/**
* Returns whether this node or any of its descendants should be persisted
* in the API description. A node should be persisted if it has API visibility
* or if it (or any descendant) has restrictions.
*
* @return true if this node or any descendant should be persisted, false otherwise
*/
protected boolean shouldPersist() {
// Persist if the node has API visibility
if (hasApiVisibility(this)) {
return true;
}
// Persist if the node has restrictions
if (!RestrictionModifiers.isUnrestricted(this.restrictions)) {
return true;
}
// Persist if any descendant has restrictions
for (ManifestNode child : children.values()) {
if (child.shouldPersist()) {
return true;
}
}
return false;
}

/**
* Ensure this node is up to date. Default implementation does nothing.
* Subclasses should override as required.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ protected ManifestNode refresh() {

@Override
void persistXML(Document document, Element parentElement) {
if (hasApiVisibility(this)) {
if (shouldPersist()) {
Element pkg = document.createElement(IApiXmlConstants.ELEMENT_PACKAGE);
for (IPackageFragment fFragment : fFragments) {
Element fragment = document.createElement(IApiXmlConstants.ELEMENT_PACKAGE_FRAGMENT);
Expand Down Expand Up @@ -302,7 +302,7 @@ private void logRefreshing() {

@Override
void persistXML(Document document, Element parentElement) {
if (hasApiVisibility(this)) {
if (shouldPersist()) {
Element type = document.createElement(IApiXmlConstants.ELEMENT_TYPE);
type.setAttribute(IApiXmlConstants.ATTR_HANDLE, fType.getHandleIdentifier());
persistAnnotations(type);
Expand Down
Loading