From b7885a3fa27e29efa99ac5b248fa0f7f8f1ab72c Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Wed, 25 Mar 2020 15:10:49 -0700 Subject: [PATCH] Address feedback from Neal --- .../Semantics/NullableReferenceTypesTests.cs | 101 ++++++++++++++++++ .../Core/Portable/MetadataReader/PEModule.cs | 8 +- .../Portable/Differencing/TreeComparer.cs | 2 +- 3 files changed, 106 insertions(+), 5 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index 2f25f78ab3eec..23382a8011ee7 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -20293,6 +20293,8 @@ public C() // 1, 2 } [MemberNotNull(null!, null!)] + [MemberNotNull(members: null!)] + [MemberNotNull(member: null!)] void Init() => throw null!; } ", MemberNotNullAttributeDefinition }, parseOptions: TestOptions.RegularPreview); @@ -21894,6 +21896,51 @@ public C() ); } + [Fact] + public void MemberNotNull_Multiple_ParamsConstructor() + { + var c = CreateNullableCompilation(new[] { @" +using System.Diagnostics.CodeAnalysis; +public class C +{ + public string field1; + public string field2; + public string field3; + public string field4; + + public C() + { + Init(); + field1.ToString(); + field2.ToString(); + field3.ToString(); + field4.ToString(); + } + + [MemberNotNull(nameof(field1), nameof(field2))] + [MemberNotNull(nameof(field3), nameof(field4))] + void Init() + { + } +} +", MemberNotNullAttributeDefinition }, parseOptions: TestOptions.RegularPreview); + + c.VerifyDiagnostics( + // (23,5): warning CS8774: Member 'field1' may not have a null value when exiting. + // } + Diagnostic(ErrorCode.WRN_MemberNotNull, "}").WithArguments("field1").WithLocation(23, 5), + // (23,5): warning CS8774: Member 'field2' may not have a null value when exiting. + // } + Diagnostic(ErrorCode.WRN_MemberNotNull, "}").WithArguments("field2").WithLocation(23, 5), + // (23,5): warning CS8774: Member 'field3' may not have a null value when exiting. + // } + Diagnostic(ErrorCode.WRN_MemberNotNull, "}").WithArguments("field3").WithLocation(23, 5), + // (23,5): warning CS8774: Member 'field4' may not have a null value when exiting. + // } + Diagnostic(ErrorCode.WRN_MemberNotNull, "}").WithArguments("field4").WithLocation(23, 5) + ); + } + [Fact] public void MemberNotNull_Multiple_Property() { @@ -22396,6 +22443,8 @@ public C() // 1, 2 } [MemberNotNullWhen(true, null!, null!)] + [MemberNotNullWhen(true, members: null!)] + [MemberNotNullWhen(true, member: null!)] bool Init() => throw null!; } ", MemberNotNullWhenAttributeDefinition }, parseOptions: TestOptions.RegularPreview); @@ -23442,6 +23491,58 @@ public C() ); } + [Fact] + public void MemberNotNullWhenTrue_Multiple_ParamsConstructor() + { + var c = CreateNullableCompilation(new[] { @" +using System.Diagnostics.CodeAnalysis; +public class C +{ + public string field1; + public string? field2; + public string field3; + public string? field4; + + public C() + { + if (Init()) + { + field1.ToString(); + field2.ToString(); + field3.ToString(); + field4.ToString(); + } + else + { + throw null!; + } + } + + [MemberNotNullWhen(true, nameof(field1), nameof(field2))] + [MemberNotNullWhen(true, nameof(field3), nameof(field4))] + bool Init() + { + return true; + } +} +", MemberNotNullWhenAttributeDefinition }, parseOptions: TestOptions.RegularPreview); + + c.VerifyDiagnostics( + // (29,9): warning CS8775: Member 'field1' may not have a null value when exiting with `True`. + // return true; + Diagnostic(ErrorCode.WRN_MemberNotNullWhen, "return true;").WithArguments("field1", "True").WithLocation(29, 9), + // (29,9): warning CS8775: Member 'field2' may not have a null value when exiting with `True`. + // return true; + Diagnostic(ErrorCode.WRN_MemberNotNullWhen, "return true;").WithArguments("field2", "True").WithLocation(29, 9), + // (29,9): warning CS8775: Member 'field3' may not have a null value when exiting with `True`. + // return true; + Diagnostic(ErrorCode.WRN_MemberNotNullWhen, "return true;").WithArguments("field3", "True").WithLocation(29, 9), + // (29,9): warning CS8775: Member 'field4' may not have a null value when exiting with `True`. + // return true; + Diagnostic(ErrorCode.WRN_MemberNotNullWhen, "return true;").WithArguments("field4", "True").WithLocation(29, 9) + ); + } + [Fact] public void MemberNotNullWhenTrue_Multiple_Property() { diff --git a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs index dc1fb0759ef69..f72afe3b17bc9 100644 --- a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs +++ b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs @@ -1244,7 +1244,7 @@ internal ImmutableArray GetMemberNotNullAttributeValues(EntityHandle tok { if (ai.SignatureIndex == 0) { - if (TryExtractStringValueFromAttribute(ai.Handle, out var extracted)) + if (TryExtractStringValueFromAttribute(ai.Handle, out string extracted)) { if (extracted is object) { @@ -1252,7 +1252,7 @@ internal ImmutableArray GetMemberNotNullAttributeValues(EntityHandle tok } } } - else if (TryExtractStringArrayValueFromAttribute(ai.Handle, out var extracted2)) + else if (TryExtractStringArrayValueFromAttribute(ai.Handle, out ImmutableArray extracted2)) { foreach (var value in extracted2) { @@ -1285,7 +1285,7 @@ internal ImmutableArray GetMemberNotNullAttributeValues(EntityHandle tok { if (ai.SignatureIndex == 0) { - if (TryExtractValueFromAttribute(ai.Handle, out var extracted, s_attributeBoolAndStringValueExtractor)) + if (TryExtractValueFromAttribute(ai.Handle, out BoolAndStringData extracted, s_attributeBoolAndStringValueExtractor)) { if (extracted.String is object) { @@ -1294,7 +1294,7 @@ internal ImmutableArray GetMemberNotNullAttributeValues(EntityHandle tok } } } - else if (TryExtractValueFromAttribute(ai.Handle, out var extracted2, s_attributeBoolAndStringArrayValueExtractor)) + else if (TryExtractValueFromAttribute(ai.Handle, out BoolAndStringArrayData extracted2, s_attributeBoolAndStringArrayValueExtractor)) { var whenResult = extracted2.Sense ? whenTrue : whenFalse; foreach (var value in extracted2.Strings) diff --git a/src/Workspaces/Core/Portable/Differencing/TreeComparer.cs b/src/Workspaces/Core/Portable/Differencing/TreeComparer.cs index 3325f169855e1..065c391651e7b 100644 --- a/src/Workspaces/Core/Portable/Differencing/TreeComparer.cs +++ b/src/Workspaces/Core/Portable/Differencing/TreeComparer.cs @@ -104,7 +104,7 @@ internal TNode GetParent(TNode node) { var hasParent = TryGetParent(node, out var parent); Debug.Assert(hasParent); - return parent; + return parent!; } internal TNode GetAncestor(TNode node, int level)