Annotate config.GetValue() with [NotNullIfNotNull] - #101336

Merged
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability
Apr 29, 2024
Merged

Annotate config.GetValue() with [NotNullIfNotNull]#101336
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability

Conversation

@dahlbyk

@dahlbykdahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
Contributor

This is annoying:

// CS8600: Converting possible null value to non-nullable type.stringfoo=config.GetValue("foo","bar");

Before the fix, the updated tests fail to compile:

ConfigurationBinderTests.cs(357,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(358,48): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(368,25): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(369,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(370,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(372,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(373,48): error CS8600: Converting null literal or possible null value to non-nullable type.

The source generator has been updated as well.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2024
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-configuration
See info in area-owners.md if you want to be subscribed.

@dahlbyk

dahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
ContributorAuthor

Hmm, tried adding System.Diagnostics.CodeAnalysis to the source generator:Update: Changed to fully-qualified reference instead of using.

privatereadonlySortedSet<string>_namespaces=new()
{
"System",
"System.CodeDom.Compiler",
"System.Globalization",
"System.Runtime.CompilerServices",
"Microsoft.Extensions.Configuration",
};

But build is failing with:

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Using the type defined in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs'. [src\libraries\Microsoft.Extensions.Configuration.Binder\tests\SourceGenerationTests\Microsoft.Extensions.Configura
tion.Binder.SourceGeneration.Tests.csproj::TargetFramework=net462]

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk thanks for submitting the PR. I converted this to a draft PR as there is more need to be done before we can accept this PR. Adding the attribute to these APIs make sense, there is more need to be done here if we want to proceed with that.

  • This is kind of breaking change. you can see the app compatibility failures:
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error : API compatibility errors between 'ref/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (left) and 'lib/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (right):
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue(Microsoft.Extensions.Configuration.IConfiguration, System.Type, string, object?)'.
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue<T>(Microsoft.Extensions.Configuration.IConfiguration, string, T)'.

We need to decide if we should go with the breaking change and file a breaking change doc for it. Also, we'll need to suppress the app compatibility failure:

error : API breaking changes found. If those are intentional, the APICompat suppression file can be updated by rebuilding with '/p:ApiCompatGenerateSuppressionFile=true' [D:\a\_work\1\s\src\libraries\Microsoft.Extensions.Configuration.Binder\src\Microsoft.Extensions.Configuration.Binder.csproj]

CC @stephentoub@ericstj if they have any suggestion or recommendation about his change.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Thanks for the initial feedback! I've conditionally included NullableAttributes.cs and suppressed the compatibility failure for Microsoft.Extensions.Configuration.Binder.dll.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

I took a stab at updating the source generator. Haven't figured out the CS0436 error mentioned above, but I did noticed it's specific to TargetFramework=net462.

@ericstj

Copy link
Copy Markdown
Member

I don't think making a nullable API less nullable should be actually breaking. I think the issue flagged by APICompat is just that the reference assembly needs to be updated. Please make sure to update reference source in the ref folder. We also don't have strongly typed rules for nullability attributes - so those are just going to get flagged no matter what. If we agree to the change we can suppress the diagnostic.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 860871c to d44f69dCompareApril 23, 2024 05:53
Comment on lines +21 to +23
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'netstandard2.0'">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs" Link="System.Private.CoreLib\System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

@dahlbykdahlbykApr 23, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It turns out this is redundant, as NullableAttributes.cs is already included in most libraries automatically:

<!-- Adds Nullable annotation attributes to C# non .NETCoreApp builds. -->
<ItemGroupCondition="'$(Nullable)' != '' and
'$(Nullable)' != 'disable' and
'$(MSBuildProjectExtension)' == '.csproj' and
'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<CompileInclude="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs"Link="System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

This explains #101336 (comment):

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, ...'.

Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj has its own NullableAttributes.cs that it has ignored, but when actually used it conflicts with internal one in Microsoft.Extensions.Configuration.Binder:

[assembly:InternalsVisibleTo("Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

There may be a cleaner way, but I was able to work around this by allowing projects to opt out of the import.

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk We shouldn't enforce the definition of the nullable attribute in the source generator as it could lead to complications and problems. The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly. If it's not defined, we should refrain from emitting any code that relies on this attribute. Users can choose to define the attribute in their code if they wish to support it, granting them flexibility in its usage.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly.

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

@tarekgh

Copy link
Copy Markdown
Member

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

You may look at the code

Half=compilation.GetBestTypeByMetadataName("System.Half");
as example to see how you can search for a type in the compilation. You may look at the docs Compilation.GetTypesByMetadataName and Compilation.GetTypeByMetadataName too for more info.

You search for NotNullIfNotNullAttribute type then if it is found, utilize it.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 001579c to 4ffdaa3CompareApril 27, 2024 05:34
@dahlbyk

dahlbyk commented Apr 27, 2024

Copy link
Copy Markdown
ContributorAuthor
  1. Updated to only emit [NotNullIfNotNull] if it exists
  2. Dropped all the churn from the branch
  3. Rebased onto latest main

Update: build is fine.

I'm curious if the build is going to reproduce local failures that seem related to #95830:

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

It does, in fact, have an implementation:

I might just need to do a full rebuild?

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Restored NoIncludeNullableAttributes and rebased onto main again.

Comment threadsrc/libraries/Directory.Build.targets Outdated

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @dahlbyk, I added a minor comments, otherwise LGTM .

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 8b8b2be to 92d4c26CompareApril 29, 2024 01:04
@tarekgh

Copy link
Copy Markdown
Member

Thanks @dahlbyk for your help getting this working and completing it.

@tarekgh
tarekgh merged commit 92ca5f3 into dotnet:mainApr 29, 2024
@dahlbyk
dahlbyk deleted the config-defaultValue-nullability branch April 29, 2024 19:34
matouskozak pushed a commit to matouskozak/runtime that referenced this pull request Apr 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
michaelgsharp pushed a commit to michaelgsharp/runtime that referenced this pull request May 9, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Configurationcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@dahlbyk@tarekgh@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Annotate config.GetValue() with [NotNullIfNotNull] - #101336

Merged
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability
Apr 29, 2024
Merged

Annotate config.GetValue() with [NotNullIfNotNull]#101336
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability

Conversation

@dahlbyk

@dahlbykdahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
Contributor

This is annoying:

// CS8600: Converting possible null value to non-nullable type.stringfoo=config.GetValue("foo","bar");

Before the fix, the updated tests fail to compile:

ConfigurationBinderTests.cs(357,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(358,48): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(368,25): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(369,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(370,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(372,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(373,48): error CS8600: Converting null literal or possible null value to non-nullable type.

The source generator has been updated as well.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2024
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-configuration
See info in area-owners.md if you want to be subscribed.

@dahlbyk

dahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
ContributorAuthor

Hmm, tried adding System.Diagnostics.CodeAnalysis to the source generator:Update: Changed to fully-qualified reference instead of using.

privatereadonlySortedSet<string>_namespaces=new()
{
"System",
"System.CodeDom.Compiler",
"System.Globalization",
"System.Runtime.CompilerServices",
"Microsoft.Extensions.Configuration",
};

But build is failing with:

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Using the type defined in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs'. [src\libraries\Microsoft.Extensions.Configuration.Binder\tests\SourceGenerationTests\Microsoft.Extensions.Configura
tion.Binder.SourceGeneration.Tests.csproj::TargetFramework=net462]

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk thanks for submitting the PR. I converted this to a draft PR as there is more need to be done before we can accept this PR. Adding the attribute to these APIs make sense, there is more need to be done here if we want to proceed with that.

  • This is kind of breaking change. you can see the app compatibility failures:
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error : API compatibility errors between 'ref/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (left) and 'lib/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (right):
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue(Microsoft.Extensions.Configuration.IConfiguration, System.Type, string, object?)'.
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue<T>(Microsoft.Extensions.Configuration.IConfiguration, string, T)'.

We need to decide if we should go with the breaking change and file a breaking change doc for it. Also, we'll need to suppress the app compatibility failure:

error : API breaking changes found. If those are intentional, the APICompat suppression file can be updated by rebuilding with '/p:ApiCompatGenerateSuppressionFile=true' [D:\a\_work\1\s\src\libraries\Microsoft.Extensions.Configuration.Binder\src\Microsoft.Extensions.Configuration.Binder.csproj]

CC @stephentoub@ericstj if they have any suggestion or recommendation about his change.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Thanks for the initial feedback! I've conditionally included NullableAttributes.cs and suppressed the compatibility failure for Microsoft.Extensions.Configuration.Binder.dll.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

I took a stab at updating the source generator. Haven't figured out the CS0436 error mentioned above, but I did noticed it's specific to TargetFramework=net462.

@ericstj

Copy link
Copy Markdown
Member

I don't think making a nullable API less nullable should be actually breaking. I think the issue flagged by APICompat is just that the reference assembly needs to be updated. Please make sure to update reference source in the ref folder. We also don't have strongly typed rules for nullability attributes - so those are just going to get flagged no matter what. If we agree to the change we can suppress the diagnostic.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 860871c to d44f69dCompareApril 23, 2024 05:53
Comment on lines +21 to +23
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'netstandard2.0'">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs" Link="System.Private.CoreLib\System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

@dahlbykdahlbykApr 23, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It turns out this is redundant, as NullableAttributes.cs is already included in most libraries automatically:

<!-- Adds Nullable annotation attributes to C# non .NETCoreApp builds. -->
<ItemGroupCondition="'$(Nullable)' != '' and
'$(Nullable)' != 'disable' and
'$(MSBuildProjectExtension)' == '.csproj' and
'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<CompileInclude="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs"Link="System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

This explains #101336 (comment):

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, ...'.

Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj has its own NullableAttributes.cs that it has ignored, but when actually used it conflicts with internal one in Microsoft.Extensions.Configuration.Binder:

[assembly:InternalsVisibleTo("Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

There may be a cleaner way, but I was able to work around this by allowing projects to opt out of the import.

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk We shouldn't enforce the definition of the nullable attribute in the source generator as it could lead to complications and problems. The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly. If it's not defined, we should refrain from emitting any code that relies on this attribute. Users can choose to define the attribute in their code if they wish to support it, granting them flexibility in its usage.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly.

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

@tarekgh

Copy link
Copy Markdown
Member

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

You may look at the code

Half=compilation.GetBestTypeByMetadataName("System.Half");
as example to see how you can search for a type in the compilation. You may look at the docs Compilation.GetTypesByMetadataName and Compilation.GetTypeByMetadataName too for more info.

You search for NotNullIfNotNullAttribute type then if it is found, utilize it.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 001579c to 4ffdaa3CompareApril 27, 2024 05:34
@dahlbyk

dahlbyk commented Apr 27, 2024

Copy link
Copy Markdown
ContributorAuthor
  1. Updated to only emit [NotNullIfNotNull] if it exists
  2. Dropped all the churn from the branch
  3. Rebased onto latest main

Update: build is fine.

I'm curious if the build is going to reproduce local failures that seem related to #95830:

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

It does, in fact, have an implementation:

I might just need to do a full rebuild?

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Restored NoIncludeNullableAttributes and rebased onto main again.

Comment threadsrc/libraries/Directory.Build.targets Outdated

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @dahlbyk, I added a minor comments, otherwise LGTM .

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 8b8b2be to 92d4c26CompareApril 29, 2024 01:04
@tarekgh

Copy link
Copy Markdown
Member

Thanks @dahlbyk for your help getting this working and completing it.

@tarekgh
tarekgh merged commit 92ca5f3 into dotnet:mainApr 29, 2024
@dahlbyk
dahlbyk deleted the config-defaultValue-nullability branch April 29, 2024 19:34
matouskozak pushed a commit to matouskozak/runtime that referenced this pull request Apr 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
michaelgsharp pushed a commit to michaelgsharp/runtime that referenced this pull request May 9, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Configurationcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@dahlbyk@tarekgh@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Annotate config.GetValue() with [NotNullIfNotNull] - #101336

Merged
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability
Apr 29, 2024
Merged

Annotate config.GetValue() with [NotNullIfNotNull]#101336
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability

Conversation

@dahlbyk

@dahlbykdahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
Contributor

This is annoying:

// CS8600: Converting possible null value to non-nullable type.stringfoo=config.GetValue("foo","bar");

Before the fix, the updated tests fail to compile:

ConfigurationBinderTests.cs(357,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(358,48): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(368,25): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(369,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(370,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(372,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(373,48): error CS8600: Converting null literal or possible null value to non-nullable type.

The source generator has been updated as well.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2024
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-configuration
See info in area-owners.md if you want to be subscribed.

@dahlbyk

dahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
ContributorAuthor

Hmm, tried adding System.Diagnostics.CodeAnalysis to the source generator:Update: Changed to fully-qualified reference instead of using.

privatereadonlySortedSet<string>_namespaces=new()
{
"System",
"System.CodeDom.Compiler",
"System.Globalization",
"System.Runtime.CompilerServices",
"Microsoft.Extensions.Configuration",
};

But build is failing with:

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Using the type defined in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs'. [src\libraries\Microsoft.Extensions.Configuration.Binder\tests\SourceGenerationTests\Microsoft.Extensions.Configura
tion.Binder.SourceGeneration.Tests.csproj::TargetFramework=net462]

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk thanks for submitting the PR. I converted this to a draft PR as there is more need to be done before we can accept this PR. Adding the attribute to these APIs make sense, there is more need to be done here if we want to proceed with that.

  • This is kind of breaking change. you can see the app compatibility failures:
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error : API compatibility errors between 'ref/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (left) and 'lib/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (right):
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue(Microsoft.Extensions.Configuration.IConfiguration, System.Type, string, object?)'.
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue<T>(Microsoft.Extensions.Configuration.IConfiguration, string, T)'.

We need to decide if we should go with the breaking change and file a breaking change doc for it. Also, we'll need to suppress the app compatibility failure:

error : API breaking changes found. If those are intentional, the APICompat suppression file can be updated by rebuilding with '/p:ApiCompatGenerateSuppressionFile=true' [D:\a\_work\1\s\src\libraries\Microsoft.Extensions.Configuration.Binder\src\Microsoft.Extensions.Configuration.Binder.csproj]

CC @stephentoub@ericstj if they have any suggestion or recommendation about his change.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Thanks for the initial feedback! I've conditionally included NullableAttributes.cs and suppressed the compatibility failure for Microsoft.Extensions.Configuration.Binder.dll.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

I took a stab at updating the source generator. Haven't figured out the CS0436 error mentioned above, but I did noticed it's specific to TargetFramework=net462.

@ericstj

Copy link
Copy Markdown
Member

I don't think making a nullable API less nullable should be actually breaking. I think the issue flagged by APICompat is just that the reference assembly needs to be updated. Please make sure to update reference source in the ref folder. We also don't have strongly typed rules for nullability attributes - so those are just going to get flagged no matter what. If we agree to the change we can suppress the diagnostic.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 860871c to d44f69dCompareApril 23, 2024 05:53
Comment on lines +21 to +23
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'netstandard2.0'">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs" Link="System.Private.CoreLib\System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

@dahlbykdahlbykApr 23, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It turns out this is redundant, as NullableAttributes.cs is already included in most libraries automatically:

<!-- Adds Nullable annotation attributes to C# non .NETCoreApp builds. -->
<ItemGroupCondition="'$(Nullable)' != '' and
'$(Nullable)' != 'disable' and
'$(MSBuildProjectExtension)' == '.csproj' and
'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<CompileInclude="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs"Link="System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

This explains #101336 (comment):

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, ...'.

Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj has its own NullableAttributes.cs that it has ignored, but when actually used it conflicts with internal one in Microsoft.Extensions.Configuration.Binder:

[assembly:InternalsVisibleTo("Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

There may be a cleaner way, but I was able to work around this by allowing projects to opt out of the import.

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk We shouldn't enforce the definition of the nullable attribute in the source generator as it could lead to complications and problems. The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly. If it's not defined, we should refrain from emitting any code that relies on this attribute. Users can choose to define the attribute in their code if they wish to support it, granting them flexibility in its usage.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly.

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

@tarekgh

Copy link
Copy Markdown
Member

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

You may look at the code

Half=compilation.GetBestTypeByMetadataName("System.Half");
as example to see how you can search for a type in the compilation. You may look at the docs Compilation.GetTypesByMetadataName and Compilation.GetTypeByMetadataName too for more info.

You search for NotNullIfNotNullAttribute type then if it is found, utilize it.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 001579c to 4ffdaa3CompareApril 27, 2024 05:34
@dahlbyk

dahlbyk commented Apr 27, 2024

Copy link
Copy Markdown
ContributorAuthor
  1. Updated to only emit [NotNullIfNotNull] if it exists
  2. Dropped all the churn from the branch
  3. Rebased onto latest main

Update: build is fine.

I'm curious if the build is going to reproduce local failures that seem related to #95830:

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

It does, in fact, have an implementation:

I might just need to do a full rebuild?

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Restored NoIncludeNullableAttributes and rebased onto main again.

Comment threadsrc/libraries/Directory.Build.targets Outdated

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @dahlbyk, I added a minor comments, otherwise LGTM .

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 8b8b2be to 92d4c26CompareApril 29, 2024 01:04
@tarekgh

Copy link
Copy Markdown
Member

Thanks @dahlbyk for your help getting this working and completing it.

@tarekgh
tarekgh merged commit 92ca5f3 into dotnet:mainApr 29, 2024
@dahlbyk
dahlbyk deleted the config-defaultValue-nullability branch April 29, 2024 19:34
matouskozak pushed a commit to matouskozak/runtime that referenced this pull request Apr 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
michaelgsharp pushed a commit to michaelgsharp/runtime that referenced this pull request May 9, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Configurationcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@dahlbyk@tarekgh@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Annotate config.GetValue() with [NotNullIfNotNull] - #101336

Merged
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability
Apr 29, 2024
Merged

Annotate config.GetValue() with [NotNullIfNotNull]#101336
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability

Conversation

@dahlbyk

@dahlbykdahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
Contributor

This is annoying:

// CS8600: Converting possible null value to non-nullable type.stringfoo=config.GetValue("foo","bar");

Before the fix, the updated tests fail to compile:

ConfigurationBinderTests.cs(357,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(358,48): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(368,25): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(369,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(370,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(372,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(373,48): error CS8600: Converting null literal or possible null value to non-nullable type.

The source generator has been updated as well.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2024
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-configuration
See info in area-owners.md if you want to be subscribed.

@dahlbyk

dahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
ContributorAuthor

Hmm, tried adding System.Diagnostics.CodeAnalysis to the source generator:Update: Changed to fully-qualified reference instead of using.

privatereadonlySortedSet<string>_namespaces=new()
{
"System",
"System.CodeDom.Compiler",
"System.Globalization",
"System.Runtime.CompilerServices",
"Microsoft.Extensions.Configuration",
};

But build is failing with:

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Using the type defined in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs'. [src\libraries\Microsoft.Extensions.Configuration.Binder\tests\SourceGenerationTests\Microsoft.Extensions.Configura
tion.Binder.SourceGeneration.Tests.csproj::TargetFramework=net462]

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk thanks for submitting the PR. I converted this to a draft PR as there is more need to be done before we can accept this PR. Adding the attribute to these APIs make sense, there is more need to be done here if we want to proceed with that.

  • This is kind of breaking change. you can see the app compatibility failures:
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error : API compatibility errors between 'ref/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (left) and 'lib/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (right):
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue(Microsoft.Extensions.Configuration.IConfiguration, System.Type, string, object?)'.
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue<T>(Microsoft.Extensions.Configuration.IConfiguration, string, T)'.

We need to decide if we should go with the breaking change and file a breaking change doc for it. Also, we'll need to suppress the app compatibility failure:

error : API breaking changes found. If those are intentional, the APICompat suppression file can be updated by rebuilding with '/p:ApiCompatGenerateSuppressionFile=true' [D:\a\_work\1\s\src\libraries\Microsoft.Extensions.Configuration.Binder\src\Microsoft.Extensions.Configuration.Binder.csproj]

CC @stephentoub@ericstj if they have any suggestion or recommendation about his change.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Thanks for the initial feedback! I've conditionally included NullableAttributes.cs and suppressed the compatibility failure for Microsoft.Extensions.Configuration.Binder.dll.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

I took a stab at updating the source generator. Haven't figured out the CS0436 error mentioned above, but I did noticed it's specific to TargetFramework=net462.

@ericstj

Copy link
Copy Markdown
Member

I don't think making a nullable API less nullable should be actually breaking. I think the issue flagged by APICompat is just that the reference assembly needs to be updated. Please make sure to update reference source in the ref folder. We also don't have strongly typed rules for nullability attributes - so those are just going to get flagged no matter what. If we agree to the change we can suppress the diagnostic.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 860871c to d44f69dCompareApril 23, 2024 05:53
Comment on lines +21 to +23
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'netstandard2.0'">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs" Link="System.Private.CoreLib\System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

@dahlbykdahlbykApr 23, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It turns out this is redundant, as NullableAttributes.cs is already included in most libraries automatically:

<!-- Adds Nullable annotation attributes to C# non .NETCoreApp builds. -->
<ItemGroupCondition="'$(Nullable)' != '' and
'$(Nullable)' != 'disable' and
'$(MSBuildProjectExtension)' == '.csproj' and
'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<CompileInclude="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs"Link="System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

This explains #101336 (comment):

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, ...'.

Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj has its own NullableAttributes.cs that it has ignored, but when actually used it conflicts with internal one in Microsoft.Extensions.Configuration.Binder:

[assembly:InternalsVisibleTo("Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

There may be a cleaner way, but I was able to work around this by allowing projects to opt out of the import.

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk We shouldn't enforce the definition of the nullable attribute in the source generator as it could lead to complications and problems. The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly. If it's not defined, we should refrain from emitting any code that relies on this attribute. Users can choose to define the attribute in their code if they wish to support it, granting them flexibility in its usage.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly.

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

@tarekgh

Copy link
Copy Markdown
Member

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

You may look at the code

Half=compilation.GetBestTypeByMetadataName("System.Half");
as example to see how you can search for a type in the compilation. You may look at the docs Compilation.GetTypesByMetadataName and Compilation.GetTypeByMetadataName too for more info.

You search for NotNullIfNotNullAttribute type then if it is found, utilize it.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 001579c to 4ffdaa3CompareApril 27, 2024 05:34
@dahlbyk

dahlbyk commented Apr 27, 2024

Copy link
Copy Markdown
ContributorAuthor
  1. Updated to only emit [NotNullIfNotNull] if it exists
  2. Dropped all the churn from the branch
  3. Rebased onto latest main

Update: build is fine.

I'm curious if the build is going to reproduce local failures that seem related to #95830:

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

It does, in fact, have an implementation:

I might just need to do a full rebuild?

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Restored NoIncludeNullableAttributes and rebased onto main again.

Comment threadsrc/libraries/Directory.Build.targets Outdated

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @dahlbyk, I added a minor comments, otherwise LGTM .

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 8b8b2be to 92d4c26CompareApril 29, 2024 01:04
@tarekgh

Copy link
Copy Markdown
Member

Thanks @dahlbyk for your help getting this working and completing it.

@tarekgh
tarekgh merged commit 92ca5f3 into dotnet:mainApr 29, 2024
@dahlbyk
dahlbyk deleted the config-defaultValue-nullability branch April 29, 2024 19:34
matouskozak pushed a commit to matouskozak/runtime that referenced this pull request Apr 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
michaelgsharp pushed a commit to michaelgsharp/runtime that referenced this pull request May 9, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Configurationcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@dahlbyk@tarekgh@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Annotate config.GetValue() with [NotNullIfNotNull] - #101336

Merged
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability
Apr 29, 2024
Merged

Annotate config.GetValue() with [NotNullIfNotNull]#101336
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability

Conversation

@dahlbyk

@dahlbykdahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
Contributor

This is annoying:

// CS8600: Converting possible null value to non-nullable type.stringfoo=config.GetValue("foo","bar");

Before the fix, the updated tests fail to compile:

ConfigurationBinderTests.cs(357,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(358,48): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(368,25): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(369,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(370,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(372,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(373,48): error CS8600: Converting null literal or possible null value to non-nullable type.

The source generator has been updated as well.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2024
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-configuration
See info in area-owners.md if you want to be subscribed.

@dahlbyk

dahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
ContributorAuthor

Hmm, tried adding System.Diagnostics.CodeAnalysis to the source generator:Update: Changed to fully-qualified reference instead of using.

privatereadonlySortedSet<string>_namespaces=new()
{
"System",
"System.CodeDom.Compiler",
"System.Globalization",
"System.Runtime.CompilerServices",
"Microsoft.Extensions.Configuration",
};

But build is failing with:

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Using the type defined in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs'. [src\libraries\Microsoft.Extensions.Configuration.Binder\tests\SourceGenerationTests\Microsoft.Extensions.Configura
tion.Binder.SourceGeneration.Tests.csproj::TargetFramework=net462]

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk thanks for submitting the PR. I converted this to a draft PR as there is more need to be done before we can accept this PR. Adding the attribute to these APIs make sense, there is more need to be done here if we want to proceed with that.

  • This is kind of breaking change. you can see the app compatibility failures:
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error : API compatibility errors between 'ref/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (left) and 'lib/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (right):
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue(Microsoft.Extensions.Configuration.IConfiguration, System.Type, string, object?)'.
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue<T>(Microsoft.Extensions.Configuration.IConfiguration, string, T)'.

We need to decide if we should go with the breaking change and file a breaking change doc for it. Also, we'll need to suppress the app compatibility failure:

error : API breaking changes found. If those are intentional, the APICompat suppression file can be updated by rebuilding with '/p:ApiCompatGenerateSuppressionFile=true' [D:\a\_work\1\s\src\libraries\Microsoft.Extensions.Configuration.Binder\src\Microsoft.Extensions.Configuration.Binder.csproj]

CC @stephentoub@ericstj if they have any suggestion or recommendation about his change.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Thanks for the initial feedback! I've conditionally included NullableAttributes.cs and suppressed the compatibility failure for Microsoft.Extensions.Configuration.Binder.dll.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

I took a stab at updating the source generator. Haven't figured out the CS0436 error mentioned above, but I did noticed it's specific to TargetFramework=net462.

@ericstj

Copy link
Copy Markdown
Member

I don't think making a nullable API less nullable should be actually breaking. I think the issue flagged by APICompat is just that the reference assembly needs to be updated. Please make sure to update reference source in the ref folder. We also don't have strongly typed rules for nullability attributes - so those are just going to get flagged no matter what. If we agree to the change we can suppress the diagnostic.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 860871c to d44f69dCompareApril 23, 2024 05:53
Comment on lines +21 to +23
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'netstandard2.0'">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs" Link="System.Private.CoreLib\System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

@dahlbykdahlbykApr 23, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It turns out this is redundant, as NullableAttributes.cs is already included in most libraries automatically:

<!-- Adds Nullable annotation attributes to C# non .NETCoreApp builds. -->
<ItemGroupCondition="'$(Nullable)' != '' and
'$(Nullable)' != 'disable' and
'$(MSBuildProjectExtension)' == '.csproj' and
'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<CompileInclude="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs"Link="System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

This explains #101336 (comment):

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, ...'.

Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj has its own NullableAttributes.cs that it has ignored, but when actually used it conflicts with internal one in Microsoft.Extensions.Configuration.Binder:

[assembly:InternalsVisibleTo("Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

There may be a cleaner way, but I was able to work around this by allowing projects to opt out of the import.

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk We shouldn't enforce the definition of the nullable attribute in the source generator as it could lead to complications and problems. The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly. If it's not defined, we should refrain from emitting any code that relies on this attribute. Users can choose to define the attribute in their code if they wish to support it, granting them flexibility in its usage.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly.

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

@tarekgh

Copy link
Copy Markdown
Member

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

You may look at the code

Half=compilation.GetBestTypeByMetadataName("System.Half");
as example to see how you can search for a type in the compilation. You may look at the docs Compilation.GetTypesByMetadataName and Compilation.GetTypeByMetadataName too for more info.

You search for NotNullIfNotNullAttribute type then if it is found, utilize it.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 001579c to 4ffdaa3CompareApril 27, 2024 05:34
@dahlbyk

dahlbyk commented Apr 27, 2024

Copy link
Copy Markdown
ContributorAuthor
  1. Updated to only emit [NotNullIfNotNull] if it exists
  2. Dropped all the churn from the branch
  3. Rebased onto latest main

Update: build is fine.

I'm curious if the build is going to reproduce local failures that seem related to #95830:

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

It does, in fact, have an implementation:

I might just need to do a full rebuild?

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Restored NoIncludeNullableAttributes and rebased onto main again.

Comment threadsrc/libraries/Directory.Build.targets Outdated

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @dahlbyk, I added a minor comments, otherwise LGTM .

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 8b8b2be to 92d4c26CompareApril 29, 2024 01:04
@tarekgh

Copy link
Copy Markdown
Member

Thanks @dahlbyk for your help getting this working and completing it.

@tarekgh
tarekgh merged commit 92ca5f3 into dotnet:mainApr 29, 2024
@dahlbyk
dahlbyk deleted the config-defaultValue-nullability branch April 29, 2024 19:34
matouskozak pushed a commit to matouskozak/runtime that referenced this pull request Apr 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
michaelgsharp pushed a commit to michaelgsharp/runtime that referenced this pull request May 9, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Configurationcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@dahlbyk@tarekgh@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Annotate config.GetValue() with [NotNullIfNotNull] - #101336

Merged
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability
Apr 29, 2024
Merged

Annotate config.GetValue() with [NotNullIfNotNull]#101336
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability

Conversation

@dahlbyk

@dahlbykdahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
Contributor

This is annoying:

// CS8600: Converting possible null value to non-nullable type.stringfoo=config.GetValue("foo","bar");

Before the fix, the updated tests fail to compile:

ConfigurationBinderTests.cs(357,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(358,48): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(368,25): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(369,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(370,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(372,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(373,48): error CS8600: Converting null literal or possible null value to non-nullable type.

The source generator has been updated as well.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2024
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-configuration
See info in area-owners.md if you want to be subscribed.

@dahlbyk

dahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
ContributorAuthor

Hmm, tried adding System.Diagnostics.CodeAnalysis to the source generator:Update: Changed to fully-qualified reference instead of using.

privatereadonlySortedSet<string>_namespaces=new()
{
"System",
"System.CodeDom.Compiler",
"System.Globalization",
"System.Runtime.CompilerServices",
"Microsoft.Extensions.Configuration",
};

But build is failing with:

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Using the type defined in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs'. [src\libraries\Microsoft.Extensions.Configuration.Binder\tests\SourceGenerationTests\Microsoft.Extensions.Configura
tion.Binder.SourceGeneration.Tests.csproj::TargetFramework=net462]

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk thanks for submitting the PR. I converted this to a draft PR as there is more need to be done before we can accept this PR. Adding the attribute to these APIs make sense, there is more need to be done here if we want to proceed with that.

  • This is kind of breaking change. you can see the app compatibility failures:
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error : API compatibility errors between 'ref/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (left) and 'lib/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (right):
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue(Microsoft.Extensions.Configuration.IConfiguration, System.Type, string, object?)'.
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue<T>(Microsoft.Extensions.Configuration.IConfiguration, string, T)'.

We need to decide if we should go with the breaking change and file a breaking change doc for it. Also, we'll need to suppress the app compatibility failure:

error : API breaking changes found. If those are intentional, the APICompat suppression file can be updated by rebuilding with '/p:ApiCompatGenerateSuppressionFile=true' [D:\a\_work\1\s\src\libraries\Microsoft.Extensions.Configuration.Binder\src\Microsoft.Extensions.Configuration.Binder.csproj]

CC @stephentoub@ericstj if they have any suggestion or recommendation about his change.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Thanks for the initial feedback! I've conditionally included NullableAttributes.cs and suppressed the compatibility failure for Microsoft.Extensions.Configuration.Binder.dll.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

I took a stab at updating the source generator. Haven't figured out the CS0436 error mentioned above, but I did noticed it's specific to TargetFramework=net462.

@ericstj

Copy link
Copy Markdown
Member

I don't think making a nullable API less nullable should be actually breaking. I think the issue flagged by APICompat is just that the reference assembly needs to be updated. Please make sure to update reference source in the ref folder. We also don't have strongly typed rules for nullability attributes - so those are just going to get flagged no matter what. If we agree to the change we can suppress the diagnostic.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 860871c to d44f69dCompareApril 23, 2024 05:53
Comment on lines +21 to +23
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'netstandard2.0'">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs" Link="System.Private.CoreLib\System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

@dahlbykdahlbykApr 23, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It turns out this is redundant, as NullableAttributes.cs is already included in most libraries automatically:

<!-- Adds Nullable annotation attributes to C# non .NETCoreApp builds. -->
<ItemGroupCondition="'$(Nullable)' != '' and
'$(Nullable)' != 'disable' and
'$(MSBuildProjectExtension)' == '.csproj' and
'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<CompileInclude="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs"Link="System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

This explains #101336 (comment):

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, ...'.

Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj has its own NullableAttributes.cs that it has ignored, but when actually used it conflicts with internal one in Microsoft.Extensions.Configuration.Binder:

[assembly:InternalsVisibleTo("Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

There may be a cleaner way, but I was able to work around this by allowing projects to opt out of the import.

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk We shouldn't enforce the definition of the nullable attribute in the source generator as it could lead to complications and problems. The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly. If it's not defined, we should refrain from emitting any code that relies on this attribute. Users can choose to define the attribute in their code if they wish to support it, granting them flexibility in its usage.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly.

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

@tarekgh

Copy link
Copy Markdown
Member

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

You may look at the code

Half=compilation.GetBestTypeByMetadataName("System.Half");
as example to see how you can search for a type in the compilation. You may look at the docs Compilation.GetTypesByMetadataName and Compilation.GetTypeByMetadataName too for more info.

You search for NotNullIfNotNullAttribute type then if it is found, utilize it.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 001579c to 4ffdaa3CompareApril 27, 2024 05:34
@dahlbyk

dahlbyk commented Apr 27, 2024

Copy link
Copy Markdown
ContributorAuthor
  1. Updated to only emit [NotNullIfNotNull] if it exists
  2. Dropped all the churn from the branch
  3. Rebased onto latest main

Update: build is fine.

I'm curious if the build is going to reproduce local failures that seem related to #95830:

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

It does, in fact, have an implementation:

I might just need to do a full rebuild?

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Restored NoIncludeNullableAttributes and rebased onto main again.

Comment threadsrc/libraries/Directory.Build.targets Outdated

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @dahlbyk, I added a minor comments, otherwise LGTM .

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 8b8b2be to 92d4c26CompareApril 29, 2024 01:04
@tarekgh

Copy link
Copy Markdown
Member

Thanks @dahlbyk for your help getting this working and completing it.

@tarekgh
tarekgh merged commit 92ca5f3 into dotnet:mainApr 29, 2024
@dahlbyk
dahlbyk deleted the config-defaultValue-nullability branch April 29, 2024 19:34
matouskozak pushed a commit to matouskozak/runtime that referenced this pull request Apr 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
michaelgsharp pushed a commit to michaelgsharp/runtime that referenced this pull request May 9, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Configurationcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@dahlbyk@tarekgh@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Annotate config.GetValue() with [NotNullIfNotNull] - #101336

Merged
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability
Apr 29, 2024
Merged

Annotate config.GetValue() with [NotNullIfNotNull]#101336
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability

Conversation

@dahlbyk

@dahlbykdahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
Contributor

This is annoying:

// CS8600: Converting possible null value to non-nullable type.stringfoo=config.GetValue("foo","bar");

Before the fix, the updated tests fail to compile:

ConfigurationBinderTests.cs(357,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(358,48): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(368,25): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(369,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(370,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(372,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(373,48): error CS8600: Converting null literal or possible null value to non-nullable type.

The source generator has been updated as well.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2024
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-configuration
See info in area-owners.md if you want to be subscribed.

@dahlbyk

dahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
ContributorAuthor

Hmm, tried adding System.Diagnostics.CodeAnalysis to the source generator:Update: Changed to fully-qualified reference instead of using.

privatereadonlySortedSet<string>_namespaces=new()
{
"System",
"System.CodeDom.Compiler",
"System.Globalization",
"System.Runtime.CompilerServices",
"Microsoft.Extensions.Configuration",
};

But build is failing with:

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Using the type defined in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs'. [src\libraries\Microsoft.Extensions.Configuration.Binder\tests\SourceGenerationTests\Microsoft.Extensions.Configura
tion.Binder.SourceGeneration.Tests.csproj::TargetFramework=net462]

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk thanks for submitting the PR. I converted this to a draft PR as there is more need to be done before we can accept this PR. Adding the attribute to these APIs make sense, there is more need to be done here if we want to proceed with that.

  • This is kind of breaking change. you can see the app compatibility failures:
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error : API compatibility errors between 'ref/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (left) and 'lib/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (right):
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue(Microsoft.Extensions.Configuration.IConfiguration, System.Type, string, object?)'.
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue<T>(Microsoft.Extensions.Configuration.IConfiguration, string, T)'.

We need to decide if we should go with the breaking change and file a breaking change doc for it. Also, we'll need to suppress the app compatibility failure:

error : API breaking changes found. If those are intentional, the APICompat suppression file can be updated by rebuilding with '/p:ApiCompatGenerateSuppressionFile=true' [D:\a\_work\1\s\src\libraries\Microsoft.Extensions.Configuration.Binder\src\Microsoft.Extensions.Configuration.Binder.csproj]

CC @stephentoub@ericstj if they have any suggestion or recommendation about his change.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Thanks for the initial feedback! I've conditionally included NullableAttributes.cs and suppressed the compatibility failure for Microsoft.Extensions.Configuration.Binder.dll.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

I took a stab at updating the source generator. Haven't figured out the CS0436 error mentioned above, but I did noticed it's specific to TargetFramework=net462.

@ericstj

Copy link
Copy Markdown
Member

I don't think making a nullable API less nullable should be actually breaking. I think the issue flagged by APICompat is just that the reference assembly needs to be updated. Please make sure to update reference source in the ref folder. We also don't have strongly typed rules for nullability attributes - so those are just going to get flagged no matter what. If we agree to the change we can suppress the diagnostic.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 860871c to d44f69dCompareApril 23, 2024 05:53
Comment on lines +21 to +23
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'netstandard2.0'">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs" Link="System.Private.CoreLib\System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

@dahlbykdahlbykApr 23, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It turns out this is redundant, as NullableAttributes.cs is already included in most libraries automatically:

<!-- Adds Nullable annotation attributes to C# non .NETCoreApp builds. -->
<ItemGroupCondition="'$(Nullable)' != '' and
'$(Nullable)' != 'disable' and
'$(MSBuildProjectExtension)' == '.csproj' and
'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<CompileInclude="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs"Link="System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

This explains #101336 (comment):

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, ...'.

Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj has its own NullableAttributes.cs that it has ignored, but when actually used it conflicts with internal one in Microsoft.Extensions.Configuration.Binder:

[assembly:InternalsVisibleTo("Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

There may be a cleaner way, but I was able to work around this by allowing projects to opt out of the import.

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk We shouldn't enforce the definition of the nullable attribute in the source generator as it could lead to complications and problems. The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly. If it's not defined, we should refrain from emitting any code that relies on this attribute. Users can choose to define the attribute in their code if they wish to support it, granting them flexibility in its usage.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly.

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

@tarekgh

Copy link
Copy Markdown
Member

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

You may look at the code

Half=compilation.GetBestTypeByMetadataName("System.Half");
as example to see how you can search for a type in the compilation. You may look at the docs Compilation.GetTypesByMetadataName and Compilation.GetTypeByMetadataName too for more info.

You search for NotNullIfNotNullAttribute type then if it is found, utilize it.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 001579c to 4ffdaa3CompareApril 27, 2024 05:34
@dahlbyk

dahlbyk commented Apr 27, 2024

Copy link
Copy Markdown
ContributorAuthor
  1. Updated to only emit [NotNullIfNotNull] if it exists
  2. Dropped all the churn from the branch
  3. Rebased onto latest main

Update: build is fine.

I'm curious if the build is going to reproduce local failures that seem related to #95830:

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

It does, in fact, have an implementation:

I might just need to do a full rebuild?

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Restored NoIncludeNullableAttributes and rebased onto main again.

Comment threadsrc/libraries/Directory.Build.targets Outdated

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @dahlbyk, I added a minor comments, otherwise LGTM .

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 8b8b2be to 92d4c26CompareApril 29, 2024 01:04
@tarekgh

Copy link
Copy Markdown
Member

Thanks @dahlbyk for your help getting this working and completing it.

@tarekgh
tarekgh merged commit 92ca5f3 into dotnet:mainApr 29, 2024
@dahlbyk
dahlbyk deleted the config-defaultValue-nullability branch April 29, 2024 19:34
matouskozak pushed a commit to matouskozak/runtime that referenced this pull request Apr 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
michaelgsharp pushed a commit to michaelgsharp/runtime that referenced this pull request May 9, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Configurationcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@dahlbyk@tarekgh@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Annotate config.GetValue() with [NotNullIfNotNull] - #101336

Merged
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability
Apr 29, 2024
Merged

Annotate config.GetValue() with [NotNullIfNotNull]#101336
tarekgh merged 3 commits into
dotnet:mainfrom
dahlbyk:config-defaultValue-nullability

Conversation

@dahlbyk

@dahlbykdahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
Contributor

This is annoying:

// CS8600: Converting possible null value to non-nullable type.stringfoo=config.GetValue("foo","bar");

Before the fix, the updated tests fail to compile:

ConfigurationBinderTests.cs(357,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(358,48): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(368,25): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(369,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(370,29): error CS8605: Unboxing a possibly null value.
ConfigurationBinderTests.cs(372,31): error CS8600: Converting null literal or possible null value to non-nullable type.
ConfigurationBinderTests.cs(373,48): error CS8600: Converting null literal or possible null value to non-nullable type.

The source generator has been updated as well.

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 20, 2024
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-configuration
See info in area-owners.md if you want to be subscribed.

@dahlbyk

dahlbyk commented Apr 20, 2024

Copy link
Copy Markdown
ContributorAuthor

Hmm, tried adding System.Diagnostics.CodeAnalysis to the source generator:Update: Changed to fully-qualified reference instead of using.

privatereadonlySortedSet<string>_namespaces=new()
{
"System",
"System.CodeDom.Compiler",
"System.Globalization",
"System.Runtime.CompilerServices",
"Microsoft.Extensions.Configuration",
};

But build is failing with:

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Using the type defined in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs'. [src\libraries\Microsoft.Extensions.Configuration.Binder\tests\SourceGenerationTests\Microsoft.Extensions.Configura
tion.Binder.SourceGeneration.Tests.csproj::TargetFramework=net462]

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk thanks for submitting the PR. I converted this to a draft PR as there is more need to be done before we can accept this PR. Adding the attribute to these APIs make sense, there is more need to be done here if we want to proceed with that.

  • This is kind of breaking change. you can see the app compatibility failures:
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error : API compatibility errors between 'ref/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (left) and 'lib/net9.0/Microsoft.Extensions.Configuration.Binder.dll' (right):
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue(Microsoft.Extensions.Configuration.IConfiguration, System.Type, string, object?)'.
❌.packages\microsoft.dotnet.apicompat.task\9.0.100-preview.4.24215.1\build\Microsoft.DotNet.ApiCompat.ValidateAssemblies.Common.targets(16,5): error CP0016: Cannot add attribute 'System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("defaultValue")' to 'Microsoft.Extensions.Configuration.ConfigurationBinder.GetValue<T>(Microsoft.Extensions.Configuration.IConfiguration, string, T)'.

We need to decide if we should go with the breaking change and file a breaking change doc for it. Also, we'll need to suppress the app compatibility failure:

error : API breaking changes found. If those are intentional, the APICompat suppression file can be updated by rebuilding with '/p:ApiCompatGenerateSuppressionFile=true' [D:\a\_work\1\s\src\libraries\Microsoft.Extensions.Configuration.Binder\src\Microsoft.Extensions.Configuration.Binder.csproj]

CC @stephentoub@ericstj if they have any suggestion or recommendation about his change.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Thanks for the initial feedback! I've conditionally included NullableAttributes.cs and suppressed the compatibility failure for Microsoft.Extensions.Configuration.Binder.dll.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

I took a stab at updating the source generator. Haven't figured out the CS0436 error mentioned above, but I did noticed it's specific to TargetFramework=net462.

@ericstj

Copy link
Copy Markdown
Member

I don't think making a nullable API less nullable should be actually breaking. I think the issue flagged by APICompat is just that the reference assembly needs to be updated. Please make sure to update reference source in the ref folder. We also don't have strongly typed rules for nullability attributes - so those are just going to get flagged no matter what. If we agree to the change we can suppress the diagnostic.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 860871c to d44f69dCompareApril 23, 2024 05:53
Comment on lines +21 to +23
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'netstandard2.0'">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs" Link="System.Private.CoreLib\System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

@dahlbykdahlbykApr 23, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

It turns out this is redundant, as NullableAttributes.cs is already included in most libraries automatically:

<!-- Adds Nullable annotation attributes to C# non .NETCoreApp builds. -->
<ItemGroupCondition="'$(Nullable)' != '' and
'$(Nullable)' != 'disable' and
'$(MSBuildProjectExtension)' == '.csproj' and
'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<CompileInclude="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\NullableAttributes.cs"Link="System\Diagnostics\CodeAnalysis\NullableAttributes.cs" />
</ItemGroup>

This explains #101336 (comment):

error CS0436: The type 'NotNullIfNotNullAttribute' in 'src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs' conflicts with the imported type 'NotNullIfNotNullAttribute' in 'Microsoft.Extensions.Configuration.Binder, ...'.

Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj has its own NullableAttributes.cs that it has ignored, but when actually used it conflicts with internal one in Microsoft.Extensions.Configuration.Binder:

[assembly:InternalsVisibleTo("Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

There may be a cleaner way, but I was able to work around this by allowing projects to opt out of the import.

@tarekgh

Copy link
Copy Markdown
Member

@dahlbyk We shouldn't enforce the definition of the nullable attribute in the source generator as it could lead to complications and problems. The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly. If it's not defined, we should refrain from emitting any code that relies on this attribute. Users can choose to define the attribute in their code if they wish to support it, granting them flexibility in its usage.

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

The source generator only needs to verify if the attribute is defined during compilation and utilize it accordingly.

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

@tarekgh

Copy link
Copy Markdown
Member

This seems reasonable but I'm new to SG so not sure what this looks like. Any examples/docs?

You may look at the code

Half=compilation.GetBestTypeByMetadataName("System.Half");
as example to see how you can search for a type in the compilation. You may look at the docs Compilation.GetTypesByMetadataName and Compilation.GetTypeByMetadataName too for more info.

You search for NotNullIfNotNullAttribute type then if it is found, utilize it.

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 001579c to 4ffdaa3CompareApril 27, 2024 05:34
@dahlbyk

dahlbyk commented Apr 27, 2024

Copy link
Copy Markdown
ContributorAuthor
  1. Updated to only emit [NotNullIfNotNull] if it exists
  2. Dropped all the churn from the branch
  3. Rebased onto latest main

Update: build is fine.

I'm curious if the build is going to reproduce local failures that seem related to #95830:

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

System.TypeLoadException: Method 'get_Keys' in type 'ImplementerOfIDictionaryClass`2' from assembly 'Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' does not have an implementation.

It does, in fact, have an implementation:

I might just need to do a full rebuild?

@dahlbyk

Copy link
Copy Markdown
ContributorAuthor

Restored NoIncludeNullableAttributes and rebased onto main again.

Comment threadsrc/libraries/Directory.Build.targets Outdated

@tarekghtarekgh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @dahlbyk, I added a minor comments, otherwise LGTM .

@dahlbyk
dahlbykforce-pushed the config-defaultValue-nullability branch from 8b8b2be to 92d4c26CompareApril 29, 2024 01:04
@tarekgh

Copy link
Copy Markdown
Member

Thanks @dahlbyk for your help getting this working and completing it.

@tarekgh
tarekgh merged commit 92ca5f3 into dotnet:mainApr 29, 2024
@dahlbyk
dahlbyk deleted the config-defaultValue-nullability branch April 29, 2024 19:34
matouskozak pushed a commit to matouskozak/runtime that referenced this pull request Apr 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
michaelgsharp pushed a commit to michaelgsharp/runtime that referenced this pull request May 9, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* Annotate GetValue() with [NotNullIfNotNull]
* Avoid duplicate NullableAttributes.cs
* Annotate generated GetValue() with [NotNullIfNotNull]
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 31, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Configurationcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@dahlbyk@tarekgh@ericstj