Root element for generated parts should be nullable#1922
Root element for generated parts should be nullable#1922tomjebo merged 8 commits intodotnet:mainfrom
Conversation
There was a problem hiding this comment.
Pull Request Overview
This pull request makes root elements for generated parts nullable and updates related tests and generator code accordingly. Key changes include:
- Updating test files to use null‐forgiving operators where necessary.
- Adding explicit null checks in sample utility and presentation helper methods.
- Adjusting generator code with nullable annotations and a new [DisallowNull] attribute.
Reviewed Changes
Copilot reviewed 135 out of 135 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/DocumentFormat.OpenXml.Linq.Tests/OpenXmlPartRootXElementExtensionsTests.cs | Removed "#nullable enable" directive and added null-forgiving operators on Document accesses. |
| test/DocumentFormat.OpenXml.Framework.Features.Tests/RandomParagraphIdGeneratorTests.cs | Updated null-forgiving operators on Document and Body accesses. |
| src/DocumentFormat.OpenXml/Packaging/WordprocessingDocument.cs | Added null-forgiving operator for Settings when appending the AttachedTemplate element. |
| samples/common/PowerPointUtils.cs | Introduced an explicit null check for Presentation in CreatePresentationParts. |
| samples/common/ExampleUtilities.cs | Added and adjusted null-checks and null-forgiving operators around core worksheet and workbook operations. |
| samples/Linq/SvgExample/StronglyTypedTools.cs | Added null checks for Presentation and Slide elements in SVG addition methods. |
| gen/DocumentFormat.OpenXml.Generator.Models/Generators/Parts/PartWriter.cs | Inserted a [DisallowNull] attribute and made the generated property return type nullable. |
Comments suppressed due to low confidence (1)
test/DocumentFormat.OpenXml.Linq.Tests/OpenXmlPartRootXElementExtensionsTests.cs:11
- Removal of '#nullable enable' may inadvertently disable nullable reference type checking in this file; consider reintroducing it if nullability enforcement is desired.
#nullable enable
|
|
||
| // Save the new worksheet. | ||
| worksheetPart.Worksheet.Save(); | ||
| worksheetPart.Worksheet?.Save(); |
There was a problem hiding this comment.
Using the null-conditional operator here may silently skip the Save() call if Worksheet is null; consider throwing an exception instead to maintain consistent failure behavior.
| worksheetPart.Worksheet?.Save(); | |
| if (worksheetPart.Worksheet == null) | |
| { | |
| throw new InvalidOperationException("Worksheet is null. Unable to save changes."); | |
| } | |
| worksheetPart.Worksheet.Save(); |
| writer.Write("public "); | ||
| writer.Write(apiName); | ||
| writer.Write(" "); | ||
| writer.Write("? "); |
There was a problem hiding this comment.
Applying [DisallowNull] on a property whose type is rendered as nullable (using '?') is contradictory; please ensure that the nullability annotations and attributes are consistent.
| writer.Write("? "); | |
| writer.Write(" "); |
There was a problem hiding this comment.
It's not contradictory (there are times you may want this), but @tomjebo why do have both? This means it may be null, but a user can't set it to that. Do we want that?
There was a problem hiding this comment.
@twsouthwick This was my misreading of your comment here in 959. I read that as [DisallowNull] and set the type to nullable with ?. I think you must have meant or but I was guessing there was a reason for wanting both. I'll take out the attribute [DisallowNull] as I think the root element property will have to be null at some point.
There was a problem hiding this comment.
It also may have been early on in nullables and I misunderstood the point of it :) for now, just setting it to be nullable is good enough
There was a problem hiding this comment.
so if the point is only to prevent assignment to null via static code analysis then I'm thinking we shouldn't use this as a way to enforce part root element minOccurs conformance. we should allow code to set to null (assuming eventually it will be set to a valid root element as required by the schemas) and then rely on our validation metadata to correctly catch the minOccurs constraint. that's my feeling. do you agree?
There was a problem hiding this comment.
that sounds reasonable for now (that's the current behavior, right?)
|
|
||
| if (presentationPart.Presentation is null) | ||
| { | ||
| throw new ArgumentNullException(@"Presentation root element is missing!"); |
There was a problem hiding this comment.
Nit, but you don't need the @ symbol when there are no characters to be escaped in a string.
There was a problem hiding this comment.
I'll change both lines. I just copied that from above and didn't remove the superfluous @.
|
|
||
| if (slidePart.Slide is null) | ||
| { | ||
| throw new ArgumentNullException(@"Slide root element is missing!"); |
| { | ||
| if (part.Presentation is null) | ||
| { | ||
| throw new ArgumentNullException(@"Presentation root element is missing!"); |
|
@twsouthwick @mikeebowen one more review if you have time. there was one more thing that I needed to add here and that was to enable nullability for projects that had any tests of the part root elements. Therefore, I turned it on for I initially turned it on for |
| .Elements<Presentation.SlideId>() | ||
| .Select(slideId => (string)slideId.RelationshipId!) | ||
| .FirstOrDefault() ?? throw new InvalidOperationException(@"Presentation has no slides."); | ||
| .FirstOrDefault() ?? throw new InvalidOperationException("Presentation has no slides."); |
There was a problem hiding this comment.
if you want to ensure it's there, you can just call .First() and it will throw if it's not available
Changes root elements for generated parts to be nullable.
Fixes #959 and #995