Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annotate remainder of .NET Core assemblies for nullable reference types #2339

Closed
stephentoub opened this issue Aug 27, 2019 · 17 comments
Closed
Assignees
Labels
area-Meta tracking This issue is tracking the completion of other related issues.
Milestone

Comments

@stephentoub
Copy link
Member

stephentoub commented Aug 27, 2019

In .NET Core 3.0, we annotated System.Private.CoreLib for nullable reference types, along with the reference assemblies that surface those types, and the implementations for all of the partial facades behind those reference assemblies. That represents something around 20% of the surface area. Post-.NET Core 3.0, we plan to annotate the rest.

Our desired approach to annotating an assembly is to only do so once all of its dependencies are annotated. That way, the assembly can be annotated as a unit, and barring any bugs that need to be fixed in a dependency, we won't need to spend time fixing up new warnings in higher-level assemblies as lower-level assemblies are annotated. This leads to a semi-ordering of how assemblies should be annotated, from the "bottom up". Here is a rough grouping. We can annotate everything in group 1 (in parallel if desired), then everything in group 2 (in parallel if desired), etc. There is of course more parallelism than this available, as not every assembly in group N has a dependency on every assembly in group N - 1, but the graph is complicated and this is easier to visualize and reason about.

We will:

  • Submit individual PRs, one for each assembly. Each PR should include changes to both the src and the ref. Each PR should contain only changes related to the nullable annotations/attributes, no other changes.
  • PRs can be merged once the annotations have been appropriately reviewed in PR.
  • API reviews will happen subsequently, after PRs have been merged, in batch based on everything in master.

cc: @dotnet/nullablefc, @cartermp

0 (Completed in .NET Core 3.0)

  • System.Buffers
  • System.Collections
  • System.Collections.Concurrent
  • System.Diagnostics.Contracts
  • System.Diagnostics.Debug
  • System.Diagnostics.StackTrace
  • System.Diagnostics.Tools
  • System.Diagnostics.Tracing
  • System.Memory
  • System.Numerics.Vectors
  • System.Reflection.Emit
  • System.Reflection.Emit.ILGenerator
  • System.Reflection.Emit.Lightweight
  • System.Reflection.Primitives
  • System.Resources.ResourceManager
  • System.Runtime
  • System.Runtime.Extensions
  • System.Runtime.InteropServices
  • System.Runtime.Intrinsics
  • System.Runtime.Loader
  • System.Security.Principal
  • System.Text.Encoding.Extensions
  • System.Threading
  • System.Threading.Overlapped
  • System.Threading.Tasks
  • System.Threading.Thread
  • System.Threading.ThreadPool
  • System.Threading.Timer

1

  • Microsoft.Win32.Primitives
  • System.Collections.NonGeneric
  • System.Collections.Specialized
  • System.ComponentModel
  • System.ComponentModel.Primitives
  • System.Console
  • System.Diagnostics.DiagnosticSource
  • System.Drawing.Primitives
  • System.IO.Compression
  • System.IO.Pipelines
  • System.Linq
  • System.Linq.Parallel
  • System.Net.WebHeaderCollection
  • System.ObjectModel
  • System.Reflection.DispatchProxy
  • System.Reflection.TypeExtensions
  • System.Resources.Writer
  • System.Runtime.CompilerServices.Unsafe
  • System.Runtime.CompilerServices.VisualC
  • System.Runtime.InteropServices.RuntimeInformation
  • System.Runtime.Numerics
  • System.Runtime.Serialization.Formatters
  • System.Runtime.Serialization.Primitives
  • System.Security.Cryptography.Primitives
  • System.Security.Principal
  • System.Text.Encoding.CodePages
  • System.Text.Encodings.Web
  • System.Text.Json
  • System.Text.RegularExpressions
  • System.Threading.Channels
  • System.Threading.Tasks.Parallel
  • System.Transactions.Local
  • System.Web.HttpUtility

2

  • System.Collections.Immutable
  • System.ComponentModel.EventBasedAsync
  • System.IO.Compression.Brotli
  • System.IO.FileSystem
  • System.IO.FileSystem.DriveInfo
  • System.IO.FileSystem.Watcher
  • System.IO.MemoryMappedFiles
  • System.Linq.Expressions
  • System.Reflection.Metadata
  • System.Security.Claims
  • System.Security.Cryptography.Encoding

3

  • Microsoft.Win32.SystemEvents
  • System.ComponentModel.Composition
  • System.Diagnostics.FileVersionInfo
  • System.Dynamic.Runtime
  • System.IO.Compression.ZipFile
  • System.Linq.Queryable
  • System.Reflection.MetadataLoadContext
  • System.Security.AccessControl
  • System.Security.Cryptography.Algorithms
  • System.Security.Principal.Windows

4

  • Microsoft.Win32.Registry
  • System.Diagnostics.Process
  • System.Diagnostics.TraceSource
  • System.Drawing.Common
  • System.IO.FileSystem.AccessControl
  • System.IO.IsolatedStorage
  • System.IO.Pipes
  • System.Net.Primitives
  • System.Net.WebSockets
  • System.Security.Cryptography.Cng
  • System.Security.Cryptography.Csp
  • System.Security.Cryptography.OpenSsl
  • System.Security.Cryptography.X509Certificates

5

  • Microsoft.VisualBasic.Core
  • System.IO.Pipes.AccessControl
  • System.Net.NameResolution
  • System.Net.Ping
  • System.Net.Security
  • System.Net.ServicePoint
  • System.Net.Sockets
  • System.Security.Cryptography.Pkcs

6

  • System.Net.NetworkInformation
  • System.Net.WebProxy

7

  • System.Net.Http

8

  • System.Net.Requests
  • System.Net.WebSockets.Client
  • System.Utf8String.Experimental
  • System.Runtime.WindowsRuntime
  • System.Runtime.WindowsRuntime.UI.Xaml
  • Microsoft.CSharp
  • System.Private.Xml (this and the below System.Xml.* contracts should all be done together)
  • System.Xml.ReaderWriter
  • System.Xml.XPath
  • System.Xml.XPath.XDocument
  • System.Xml.XDocument
  • System.Xml.XmlDocument
  • System.Xml.XmlSerializer

9

  • System.ComponentModel.TypeConverter (will be annotated in 6.0; in progress by @safern)
  • System.Data.Common
  • System.Data.DataSetExtensions
  • System.Diagnostics.TextWriterTraceListener
  • System.Net.HttpListener
  • System.Net.Mail
  • System.Net.WebClient
  • System.Private.DataContractSerialization
  • System.Private.Xml.Linq
  • System.Runtime.Serialization.Json
  • System.Runtime.Serialization.Xml

10 (part of netcoreapp but reference netstandard)

With netstandard not annotated, we will need to be cognizant of the fact that all dependencies will be viewed as oblivious.

  • System.ComponentModel.Annotations
  • System.Threading.Tasks.Dataflow

11 (not part of netcoreapp but reference netcoreapp)

  • System.DirectoryServices
  • System.Data.Odbc
  • System.Diagnostics.EventLog
  • System.DirectoryServices.Protocols
  • System.Security.Permissions
  • System.ServiceProcess.ServiceController
  • System.Windows.Extensions

12 (built from dotnet/runtime but not in netcoreapp and reference netstandard)

With netstandard not annotated, we will need to be cognizant of the fact that all dependencies will be viewed as oblivious:

  • Microsoft.Win32.Registry.AccessControl => netstandard
  • System.CodeDom => netstandard
  • System.ComponentModel.Composition.Registration => netstandard, System.Reflection.Context
  • System.Composition.AttributedModel => netstandard
  • System.Composition.Convention => netstandard, System.Composition.AttributedModel
  • System.Composition.Hosting => netstandard, System.Composition.Runtime
  • System.Composition.Runtime => netstandard
  • System.Composition.TypedParts => netstandard, System.Composition.Runtime, System.Composition.AttributedModel, System.Composition.Hosting
  • System.Configuration.ConfigurationManager => netstandard, System.Security.Cryptography.ProtectedData
  • System.Data.OleDb => netstandard, System.Diagnostics.PerformanceCounter, System.Configuration.ConfigurationManager
  • System.Diagnostics.PerformanceCounter => System.Configuration.ConfigurationManager
  • System.DirectoryServices.AccountManagement => System.Configuration.ConfigurationManager
  • System.IO.Packaging => netstandard
  • System.IO.Ports => netstandard
  • System.Management => System.CodeDom
  • System.Net.Http.WinHttpHandler => netstandard
  • System.Numerics.Tensors => netstandard
  • System.Reflection.Context => netstandard
  • System.Resources.Extensions => netstandard
  • System.Runtime.Caching => netstandard, System.Configuration.ConfigurationManager
  • System.Security.Cryptography.ProtectedData => netstandard
  • System.Security.Cryptography.Xml => netstandard
  • System.ServiceModel.Syndication => netstandard
  • System.Threading.AccessControl => netstandard

13

  • Remove #nullable enable from individual files after all dependent projects annotated
maryamariyan referenced this issue in maryamariyan/corefx Sep 17, 2019
maryamariyan referenced this issue in maryamariyan/corefx Sep 17, 2019
maryamariyan referenced this issue in maryamariyan/corefx Sep 18, 2019
maryamariyan referenced this issue in dotnet/corefx Sep 19, 2019
@eiriktsarpalis
Copy link
Member

Do you think we should take the effort to annotate our test projects as well? It seems that it might be a good way to catch annotations bugs, particularly in the public API surface.

@stephentoub
Copy link
Member Author

stephentoub commented Dec 20, 2019

Do you think we should take the effort to annotate our test projects as well? It seems that it might be a good way to catch annotations bugs, particularly in the public API surface.

No.

  1. Even if we did, we wouldn't want to do it until all of our surface area was annotated, as tests use a lot more than just their associated library.

  2. They also use unannotated 3rd-party libs, too, like xunit itself.

  3. A lot of our tests are about validating behavior upon misuse, including null behaviors. There will be tons upon tons of suppressions.

  4. The vast majority of tests do not compose calls the way apps do. It is extremely unlikely in my opinion that they would find meaningful annotation mistakes, even more so because we'll be in the habit with (3) of adding suppressions everywhere.

  5. Lots of tests implicitly use reflection, e.g. inputs passed to theories, where the nullability of the inputs won't be transferred to the callee, making it useless.

I don't see the ROI.

@eiriktsarpalis eiriktsarpalis transferred this issue from dotnet/corefx Jan 29, 2020
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-Meta untriaged New issue has not been triaged by the area owner labels Jan 29, 2020
@eiriktsarpalis eiriktsarpalis removed the untriaged New issue has not been triaged by the area owner label Jan 29, 2020
@eiriktsarpalis eiriktsarpalis added this to the 5.0 milestone Jan 29, 2020
@iSazonov
Copy link
Contributor

I looked System.DirectoryServices and found many inconsistencies there. Which option does MSFT team prefer - ref-only annotation or full src review with code fixes?
The second option may require a lot of effort since there are a lot of files and a lot of comments from owners of the code since the design is not always clear (it seems there is a lot of confidence in ADDS).

@stephentoub
Copy link
Member Author

I looked System.DirectoryServices and found many inconsistencies there

Inconsistencies?

Which option does MSFT team prefer - ref-only annotation or full src review with code fixes?

In general we strongly prefer to do a full source annotation (details at https://github.com/dotnet/runtime/blob/master/docs/coding-guidelines/api-guidelines/nullability.md). This isn't always possible or fruitful, though. For example, we have some libraries that build against netstandard2.0, and the benefit of doing full source annotation there is significantly diminished because the targeted surface area isn't annotated; as such, we actually disable all nullable warnings for such builds. As another example, Microsoft.VisualBasic.Core is ref only because we can't annotate the VB source, and Microsoft.CSharp is ref only because the code is mostly a direct port of an old C++ codebase that's also generally only consumed directly by compiler-generated code, and there'd be little value in exerting the effort to null annotate the implementation.

System.DirectoryServices, though, references netcoreapp, so we would want to fully annotate its implementation.

@iSazonov
Copy link
Contributor

Inconsistencies

return new Guid(_schemaGuidBinaryForm) can throw ArgumentNullException that is weird for reading operation:

public Guid SchemaGuid
{
get
{
CheckIfDisposed();
if (isBound)
{
if (_schemaGuidBinaryForm == null)
{
// get the property from the server
_schemaGuidBinaryForm = (byte[])GetValueFromCache(PropertyManager.SchemaIDGuid, true);
}
}
// we cache the byte array and create a new guid each time
return new Guid(_schemaGuidBinaryForm);
}
set
{
CheckIfDisposed();
if (isBound)
{
// set the value on the directory entry
SetProperty(PropertyManager.SchemaIDGuid, (value.Equals(Guid.Empty)) ? null : value.ToByteArray());
}
_schemaGuidBinaryForm = (value.Equals(Guid.Empty)) ? null : value.ToByteArray();
}
}

It seems it should be return _schemaGuidBinaryForm is null ? Guid.Empty : new Guid(_schemaGuidBinaryForm)

I found some points with such inconsistencies.

System.DirectoryServices, though, references netcoreapp, so we would want to fully annotate its implementation.

There are over 120 files. Makes sense to split the work to some PRs?

@stephentoub
Copy link
Member Author

There are over 120 files. Makes sense to split the work to some PRs?

Personally I think it'd be better to do it all in one. I expect you'll find that updates to annotations in one file cause new warnings in other files that have already been annotated.

@richlander
Copy link
Member

That represents something around 20% of the surface area. Post-.NET Core 3.0, we plan to annotate the rest.

Could you add absolute numbers to the issues, alone the lines of:

Annotated APIs (inclusive counts):

  • .NET Core 3.1: x
  • .NET 5.0: y

@terrajobst
Copy link
Member

Could you add absolute numbers to the issues, alone the lines of:

Annotated APIs (inclusive counts):

  • .NET Core 3.1: x
  • .NET 5.0: y

Will do

@terrajobst
Copy link
Member

terrajobst commented Aug 20, 2020

Only looking at Microsoft.NetCoreApp (because that's all we we were shooting for):

Framework #AnnotatableAPIs #AnnotatedAPIs %
netcoreapp2.1 15,487 0 0%
netcoreapp3.0 16,582 5,142 31%
netcoreapp3.1 16,582 5,142 31%
net5.0 17,043 13,680 80%

Currently missing in .NET 5:

  • System.ComponentModel.TypeConverter
  • System.Net.HttpListener
  • System.Runtime.Serialization.Json
  • System.Runtime.Serialization.Xml
  • System.Xml.ReaderWriter
  • System.Xml.XDocument
  • System.Xml.XmlSerializer
  • System.Xml.XPath.XDocument

Picture1

eerhardt added a commit to eerhardt/runtime that referenced this issue Aug 27, 2020
krwq pushed a commit that referenced this issue Aug 28, 2020
…Runtime.Serialization.Json (#41476)

* Initial nullable annotations of System.Private.DataContractSerialization

Contributes to #2339

* Mark DataMember.Name as non-nullable.

* Fix a few simple nullable compile errors.

* Assert attributes is non-null in XmlObjectSerializerReadContext

* Ensure XmlObjectSerializerContext.serializer is never null

* Fix a few simple nullable errors

* Remove any checks that DataMember.MemberInfo can be null.

* Mark EnumDataContract.Members as non-nullable.

Fix nullable errors in SchemaExporter.

* Correctly annotate CollectionDataContract.IsCollectionOrTryCreate.

* Assert DataContractResolver is non-null.

* Suppress #41465

* Update System.Runtime.Serialization.Json ref source for nullable annotations.

* Update System.Runtime.Serializaiton.Xml ref source for nullable annotations.

* Update for Xml.ReaderWriter nullable annotations

* Work around compiler issue.

* Fix test failure.

Reference compiler issue in TODO comment.

* Revert nullable suppression now that XmlSchemaAppInfo.Markup is annotated correctly.

* Fix build for latest annotations in master.

* PR feedback round 1

* Address PR feedback round 2
carlossanlop pushed a commit to carlossanlop/runtime that referenced this issue Aug 28, 2020
…Runtime.Serialization.Json (dotnet#41476)

* Initial nullable annotations of System.Private.DataContractSerialization

Contributes to dotnet#2339

* Mark DataMember.Name as non-nullable.

* Fix a few simple nullable compile errors.

* Assert attributes is non-null in XmlObjectSerializerReadContext

* Ensure XmlObjectSerializerContext.serializer is never null

* Fix a few simple nullable errors

* Remove any checks that DataMember.MemberInfo can be null.

* Mark EnumDataContract.Members as non-nullable.

Fix nullable errors in SchemaExporter.

* Correctly annotate CollectionDataContract.IsCollectionOrTryCreate.

* Assert DataContractResolver is non-null.

* Suppress dotnet#41465

* Update System.Runtime.Serialization.Json ref source for nullable annotations.

* Update System.Runtime.Serializaiton.Xml ref source for nullable annotations.

* Update for Xml.ReaderWriter nullable annotations

* Work around compiler issue.

* Fix test failure.

Reference compiler issue in TODO comment.

* Revert nullable suppression now that XmlSchemaAppInfo.Markup is annotated correctly.

* Fix build for latest annotations in master.

* PR feedback round 1

* Address PR feedback round 2
@jeffhandley
Copy link
Member

Closing this 5.0.0 issue; the remaining annotations will be covered in 6.0 with #41720.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-Meta tracking This issue is tracking the completion of other related issues.
Projects
None yet
Development

No branches or pull requests