Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Add nullable annotations to NuGet.LibraryModel - #5417

#5417
Merged
zivkan merged 4 commits into
devNuGet/NuGet.Client:devfrom
dev-zivkan-nullable-NuGet.LibraryModelNuGet/NuGet.Client:dev-zivkan-nullable-NuGet.LibraryModelCopy head branch name to clipboard
Sep 29, 2023
Merged

Add nullable annotations to NuGet.LibraryModel#5417
zivkan merged 4 commits into
devNuGet/NuGet.Client:devfrom
dev-zivkan-nullable-NuGet.LibraryModelNuGet/NuGet.Client:dev-zivkan-nullable-NuGet.LibraryModelCopy head branch name to clipboard

Conversation

@zivkan

@zivkan zivkan commented Sep 21, 2023

Copy link
Copy Markdown
Member

Note: this will not be merged until the dev branch targets V6.9

Bug

Fixes: NuGet/Home#12889

Regression? No

Description

Enable nullable in NuGet.LibraryModel, and its test project.

This PR uses the required keyword for the first time in our code. This is a C#11 feature, and the compiler needs attributes that are only available in .NET 7's BCL. Therefore, I had to copy these attributes from the .NET runtime repo into this repo. For more info on the impact on customers, please see the linked issue. I wrote a long description in there. Note that this does create an API breaking change, but there's little reason for other repos to create instances of these classes, except maybe for tests.

Since I needed to add a new file in build\Shared, I noticed that a bunch of other files in that directory were not listed in the solution's virtual directory, so I added all of them, not just the one new file I added.

Otherwise, this was the easiest project to enable nullable on so far, but the project is mostly models, not business logic, and has a lot less code than other projects. From memory, the nullable checks didn't find any bugs, and other than the required keyword, I don't remember any other breaking changes.

PR Checklist

  • PR has a meaningful title

  • PR has a linked issue.

  • Described changes

  • Tests

    • Automated tests added
    • OR
    • Test exception
    • OR
    • N/A
  • Documentation

    • Documentation PR or issue filled
    • OR
    • N/A

@zivkan
zivkan requested a review from a team as a code owner September 21, 2023 17:21
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

#if NETFRAMEWORK || NETSTANDARD
#if !NET5_0_OR_GREATER

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the test projects targeting netcoreapp3.1 started failing once I added the RequiredModiferAttributes file, hence I needed to fix this, as this IsExernalInit attribute was added in .NET 5.

public int CompareTo(DownloadDependency other)
public int CompareTo(DownloadDependency? other)
{
if (other == null) return 1;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code would previously throw if other was null. But, the interface for IComparable<T> shows an expectation of handling nulls, and the docs explain that nulls should be sorted after non null values. We can change this to throw an ArgumentNullException if we want, but to avoid a compiler warning/error, we have to keep the ? in the method signature, since IComparable<T> does.

if (!string.IsNullOrEmpty(flags))
{
var splitFlags = flags.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
var splitFlags = flags!.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two lines up, !string.ISNullOrEmpty prevents flags being null here. In case you didn't review my other PRs enabling nullable in other projects, only the .NET 5 BCL has annotated string.IsNullOrEmpty, hence on .NET Standard and .NET Framework (and theoretically .NET Core 3.1 and earlier, for our tests), the compiler doesn't know, hence we have to tell it with the !

Comment thread src/NuGet.Core/NuGet.LibraryModel/Library.cs
public bool Equals(Library? x, Library? y)
{
if (x is null && y is null) return true;
if (x is null || y is null) return false;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also a change in behaviour. Previously it would throw a null reference exception. But I think this is better.

public int CompareTo(LibraryIdentity other)
public int CompareTo(LibraryIdentity? other)
{
if (other is null) return 1;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another example of code that previously threw NullReferenceException, violating the IComparable<T> contract.

jeffkl
jeffkl previously approved these changes Sep 21, 2023
}

[SetsRequiredMembers]
public LibraryDependency(LibraryRange libraryRange) : this()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add XML doc comments indicating that specifying a null libraryRange will throw an ArgumentNullException? Or is that overkill here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not seeing the text within any exception docs, including in other XMLDoc that already exists, in VS 2022 Int Preview, public preview, or GA versions 😕
image

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, I expected the tooltip of the Exception to show the text but yeah I can't figure out how the text is displayed in the IDE. It must only be for docs? 🤷

Comment thread src/NuGet.Core/NuGet.LibraryModel/LibraryExtensions.cs
Comment thread src/NuGet.Core/NuGet.LibraryModel/PublicAPI.Shipped.txt
@jeffkl jeffkl added the Merge next release PRs that should not be merged until the dev branch targets the next release label Sep 26, 2023
}

[SetsRequiredMembers]
public LibraryDependency(LibraryRange libraryRange) : this()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, I expected the tooltip of the Exception to show the text but yeah I can't figure out how the text is displayed in the IDE. It must only be for docs? 🤷

@zivkan
zivkan merged commit 59a83ca into dev Sep 29, 2023
@zivkan
zivkan deleted the dev-zivkan-nullable-NuGet.LibraryModel branch September 29, 2023 08:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Merge next release PRs that should not be merged until the dev branch targets the next release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add nullable annotations to NuGet.LibraryModel

4 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.