|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests;
[CompilerTrait(CompilerFeature.CollectionExpressions)]
public sealed class CollectionExpressionTests_WithElement_Nullable : CSharpTestBase
{
private static string? IncludeExpectedOutput(string expectedOutput) => ExecutionConditionUtil.IsMonoOrCoreClr ? expectedOutput : null;
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72142")]
public void ConstructorTestNullElementAdd()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
List<string> list = [null];
Console.WriteLine(list.Count);
""";
CompileAndVerify(source, expectedOutput: IncludeExpectedOutput("1")).VerifyDiagnostics(
// (4,22): warning CS8625: Cannot convert null literal to non-nullable reference type.
// List<string> list = [null];
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(5, 22));
}
private void AssertExpectedWithElementSymbol(Compilation compilation, string expected)
{
var syntaxTree = compilation.SyntaxTrees.Last();
var root = syntaxTree.GetRoot();
var withElement = root.DescendantNodes().OfType<WithElementSyntax>().Single();
var semanticModel = compilation.GetSemanticModel(syntaxTree);
var symbolInfo = semanticModel.GetSymbolInfo(withElement);
AssertEx.Equal(expected, symbolInfo.Symbol.ToTestDisplayString(includeNonNullable: true));
}
[Fact]
public void ConstructorNonNullParameterPassedNull()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
class MyList<T> : List<T>
{
public MyList(string arg)
{
}
}
class C
{
static void Main()
{
MyList<int> list = [with(null), 1, 2];
Console.WriteLine($"{list.Count}");
}
}
""";
var verifier = CompileAndVerify(source, expectedOutput: IncludeExpectedOutput("2")).VerifyDiagnostics(
// (16,34): warning CS8625: Cannot convert null literal to non-nullable reference type.
// MyList<int> list = [with(null), 1, 2];
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(16, 34));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String! arg)");
}
[Fact]
public void ConstructorNonNullParameterPassedPossibleNull()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
class MyList<T> : List<T>
{
public MyList(string arg)
{
}
}
class C
{
static void Main()
{
string? s = null;
MyList<int> list = [with(s), 1, 2];
Console.WriteLine($"{list.Count}");
}
}
""";
var verifier = CompileAndVerify(source, expectedOutput: IncludeExpectedOutput("2")).VerifyDiagnostics(
// (17,34): warning CS8604: Possible null reference argument for parameter 'arg' in 'MyList<int>.MyList(string arg)'.
// MyList<int> list = [with(s), 1, 2];
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("arg", "MyList<int>.MyList(string arg)").WithLocation(17, 34));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String! arg)");
}
[Fact]
public void ConstructorNonNullParameterPassedSuppressedValue()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
class MyList<T> : List<T>
{
public MyList(string arg)
{
}
}
class C
{
static void Main()
{
string? s = null;
MyList<int> list = [with(s!), 1, 2];
Console.WriteLine($"{list.Count}");
}
}
""";
var verifier = CompileAndVerify(source, expectedOutput: IncludeExpectedOutput("2")).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String! arg)");
}
[Fact]
public void ConstructorNonNullParameterPassedAssignedValue()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
class MyList<T> : List<T>
{
public MyList(string arg)
{
}
}
class C
{
static void Main()
{
string? s = null;
MyList<int> list = [with(s = ""), 1, 2];
Console.WriteLine($"{list.Count}");
}
}
""";
var verifier = CompileAndVerify(source, expectedOutput: IncludeExpectedOutput("2")).VerifyDiagnostics(
// (16,17): warning CS0219: The variable 's' is assigned but its value is never used
// string? s = null;
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "s").WithArguments("s").WithLocation(16, 17));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String! arg)");
}
[Fact]
public void ConstructorNonNullParameterPassedNull_Inference1()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
class MyList<T> : List<T>
{
public MyList(T arg)
{
}
}
class C
{
static void Main()
{
Goo([with(null), ""]);
}
static void Goo<T>(MyList<T> list)
{
Console.WriteLine(list.Count);
}
}
""";
var verifier = CompileAndVerify(source, expectedOutput: IncludeExpectedOutput("1")).VerifyDiagnostics(
// (16,19): warning CS8625: Cannot convert null literal to non-nullable reference type.
// Goo([with(null), ""]);
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(16, 19));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.String!>.MyList(System.String! arg)");
}
[Fact]
public void ConstructorNonNullParameterPassedNull_Inference2()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
class MyList<T> : List<T>
{
public MyList(T? arg)
{
}
}
class C
{
static void Main()
{
var val = Goo([with(null), ""]);
Bar(val);
}
static void Bar(string s) { }
static T Goo<T>(MyList<T> list)
{
Console.WriteLine(list.Count);
return default!;
}
}
""";
var verifier = CompileAndVerify(source, expectedOutput: IncludeExpectedOutput("1")).VerifyDiagnostics();
var compilation = verifier.Compilation;
var semanticModel = compilation.GetSemanticModel(compilation.SyntaxTrees.Last());
var invocation = compilation.SyntaxTrees.Last().GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().First();
var symbolInfo = semanticModel.GetSymbolInfo(invocation);
AssertEx.Equal("System.String! C.Goo<System.String!>(MyList<System.String!>! list)", symbolInfo.Symbol.ToTestDisplayString(true));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.String!>.MyList(System.String? arg)");
}
[Fact]
public void CollectionBuilderNonNullParameterPassedNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : IEnumerable<T>
{
private readonly List<T> _items;
public MyCollection(string value, ReadOnlySpan<T> items)
{
_items = new();
_items.AddRange(items.ToArray());
}
public IEnumerator<T> GetEnumerator() => _items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
class MyBuilder
{
public static MyCollection<T> Create<T>(string value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
using System;
class Program
{
static void Main()
{
MyCollection<int> c = [with(null), 1, 2];
Console.WriteLine(string.Join(", ", c));
}
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
expectedOutput: IncludeExpectedOutput("1, 2"),
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (7,37): warning CS8625: Cannot convert null literal to non-nullable reference type.
// MyCollection<int> c = [with(null), 1, 2];
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 37));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String! value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNonNullParameterPassedPossibleNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : IEnumerable<T>
{
private readonly List<T> _items;
public MyCollection(string value, ReadOnlySpan<T> items)
{
_items = new();
_items.AddRange(items.ToArray());
}
public IEnumerator<T> GetEnumerator() => _items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
class MyBuilder
{
public static MyCollection<T> Create<T>(string value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
using System;
class Program
{
static void Main()
{
string? s = null;
MyCollection<int> c = [with(s), 1, 2];
Console.WriteLine(string.Join(", ", c));
}
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
expectedOutput: IncludeExpectedOutput("1, 2"),
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (8,37): warning CS8604: Possible null reference argument for parameter 'value' in 'MyCollection<int> MyBuilder.Create<int>(string value, ReadOnlySpan<int> items)'.
// MyCollection<int> c = [with(s), 1, 2];
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("value", "MyCollection<int> MyBuilder.Create<int>(string value, ReadOnlySpan<int> items)").WithLocation(8, 37));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String! value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNonNullParameterPassedSuppressedValue()
{
string sourceA = """
#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : IEnumerable<T>
{
private readonly List<T> _items;
public MyCollection(string value, ReadOnlySpan<T> items)
{
_items = new();
_items.AddRange(items.ToArray());
}
public IEnumerator<T> GetEnumerator() => _items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
class MyBuilder
{
public static MyCollection<T> Create<T>(string value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
using System;
class Program
{
static void Main()
{
string? s = null;
MyCollection<int> c = [with(s!), 1, 2];
Console.WriteLine(string.Join(", ", c));
}
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
expectedOutput: IncludeExpectedOutput("1, 2"),
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String! value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNonNullParameterPassedAssignedValue()
{
string sourceA = """
#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : IEnumerable<T>
{
private readonly List<T> _items;
public MyCollection(string value, ReadOnlySpan<T> items)
{
_items = new();
_items.AddRange(items.ToArray());
}
public IEnumerator<T> GetEnumerator() => _items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
class MyBuilder
{
public static MyCollection<T> Create<T>(string value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
using System;
class Program
{
static void Main()
{
string? s = null;
MyCollection<int> c = [with(s = ""), 1, 2];
Console.WriteLine(string.Join(", ", c));
}
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
expectedOutput: IncludeExpectedOutput("1, 2"),
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (7,17): warning CS0219: The variable 's' is assigned but its value is never used
// string? s = null;
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "s").WithArguments("s").WithLocation(7, 17));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String! value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNonNullParameterPassedNull_Inference1()
{
string sourceA = """
#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : IEnumerable<T>
{
private readonly List<T> _items;
public MyCollection(T value, ReadOnlySpan<T> items)
{
_items = new();
_items.AddRange(items.ToArray());
}
public IEnumerator<T> GetEnumerator() => _items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
class MyBuilder
{
public static MyCollection<T> Create<T>(T value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
using System;
class Program
{
static void Main()
{
Goo([with(null), "goo"]);
}
static void Goo<T>(MyCollection<T> list)
{
Console.WriteLine(string.Join(", ", list));
}
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
expectedOutput: IncludeExpectedOutput("goo"),
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (7,19): warning CS8625: Cannot convert null literal to non-nullable reference type.
// Goo([with(null), "goo"]);
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 19));
var compilation = verifier.Compilation;
var semanticModel = compilation.GetSemanticModel(compilation.SyntaxTrees.Last());
var invocation = compilation.SyntaxTrees.Last().GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().First();
var symbolInfo = semanticModel.GetSymbolInfo(invocation);
AssertEx.Equal("void Program.Goo<System.String!>(MyCollection<System.String!>! list)", symbolInfo.Symbol.ToTestDisplayString(true));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.String!>! MyBuilder.Create<System.String!>(System.String! value, System.ReadOnlySpan<System.String!> items)");
}
[Fact]
public void CollectionBuilderNonNullParameterPassedNull_Inference2()
{
string sourceA = """
#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : IEnumerable<T>
{
private readonly List<T> _items;
public MyCollection(T? value, ReadOnlySpan<T> items)
{
_items = new();
_items.AddRange(items.ToArray());
}
public IEnumerator<T> GetEnumerator() => _items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
class MyBuilder
{
public static MyCollection<T> Create<T>(T? value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
using System;
class Program
{
static void Main()
{
Goo([with(null), "goo"]);
}
static void Goo<T>(MyCollection<T> list)
{
Console.WriteLine(string.Join(", ", list));
}
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
expectedOutput: IncludeExpectedOutput("goo"),
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics();
var compilation = verifier.Compilation;
var semanticModel = compilation.GetSemanticModel(compilation.SyntaxTrees.Last());
var invocation = compilation.SyntaxTrees.Last().GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().First();
var symbolInfo = semanticModel.GetSymbolInfo(invocation);
AssertEx.Equal("void Program.Goo<System.String!>(MyCollection<System.String!>! list)", symbolInfo.Symbol.ToTestDisplayString(true));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.String!>! MyBuilder.Create<System.String!>(System.String? value, System.ReadOnlySpan<System.String!> items)");
}
[Fact]
public void TestInferTypeFromOtherBranch1()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
var v = true
? [with(null), "a", "b"]
: new MyCollection<string>("");
Console.WriteLine(string.Join(", ", v));
class MyCollection<T> : List<T>
{
public MyCollection(T arg)
{
}
}
""";
var verifier = CompileAndVerify(source, expectedOutput: IncludeExpectedOutput("a, b")).VerifyDiagnostics(
// (6,13): warning CS8625: Cannot convert null literal to non-nullable reference type.
// ? [with(null), "a", "b"]
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(6, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.String!>.MyCollection(System.String! arg)");
}
[Fact]
public void TestInferTypeFromOtherBranch2()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
var v = true
? [with(""), null]
: new MyCollection<string>("");
Console.WriteLine(string.Join(", ", v));
class MyCollection<T> : List<T>
{
public MyCollection(T arg)
{
}
}
""";
var verifier = CompileAndVerify(source, expectedOutput: IncludeExpectedOutput("")).VerifyDiagnostics(
// (6,18): warning CS8625: Cannot convert null literal to non-nullable reference type.
// ? [with(""), null]
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(6, 18));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.String!>.MyCollection(System.String! arg)");
}
[Fact]
public void TestTernaryInference1()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
var v = true
? Goo([with(""), null])
: Goo([with(""), ""]);
Console.WriteLine(string.Join(", ", v));
MyCollection<T> Goo<T>(MyCollection<T> c) { return c; }
class MyCollection<T> : List<T>
{
public MyCollection(T arg)
{
}
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (6,7): error CS0411: The type arguments for method 'Goo<T>(MyCollection<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
// ? Goo([with(""), null])
Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Goo").WithArguments("Goo<T>(MyCollection<T>)").WithLocation(6, 7));
}
[Fact]
public void TestTernaryInference2()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
var v = true
? Goo([with(""), null])
: Goo([with(null), ""]);
Console.WriteLine(string.Join(", ", v));
MyCollection<T> Goo<T>(MyCollection<T> c) { return c; }
class MyCollection<T> : List<T>
{
public MyCollection(T arg)
{
}
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (6,7): error CS0411: The type arguments for method 'Goo<T>(MyCollection<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
// ? Goo([with(""), null])
Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Goo").WithArguments("Goo<T>(MyCollection<T>)").WithLocation(6, 7));
}
[Fact]
public void TestTernaryInference3()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
var v = true
? Goo([with(null), null, ""])
: Goo([with(null), ""]);
Console.WriteLine(string.Join(", ", v));
MyCollection<T> Goo<T>(MyCollection<T> c) { return c; }
class MyCollection<T> : List<T>
{
public MyCollection(T arg)
{
}
}
""";
CompileAndVerify(source, expectedOutput: IncludeExpectedOutput(",")).VerifyDiagnostics(
// (6,7): warning CS8619: Nullability of reference types in value of type 'MyCollection<string?>' doesn't match target type 'MyCollection<string>'.
// ? Goo([with(null), null, ""])
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, @"Goo([with(null), null, """"])").WithArguments("MyCollection<string?>", "MyCollection<string>").WithLocation(6, 7));
}
[Fact]
public void TestTernaryInference4()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
var v = true
? Goo([with(null), null, ""])
: Goo([with(null), "", null]);
Console.WriteLine(string.Join(", ", v));
MyCollection<T> Goo<T>(MyCollection<T> c) { return c; }
class MyCollection<T> : List<T>
{
public MyCollection(T arg)
{
}
}
""";
CompileAndVerify(source, expectedOutput: IncludeExpectedOutput(",")).VerifyDiagnostics(
// (6,7): warning CS8619: Nullability of reference types in value of type 'MyCollection<string?>' doesn't match target type 'MyCollection<string>'.
// ? Goo([with(null), null, ""])
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, @"Goo([with(null), null, """"])").WithArguments("MyCollection<string?>", "MyCollection<string>").WithLocation(6, 7));
}
[Fact]
public void CollectionBuilderInferenceIncorrectArity()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
}
class MyBuilder
{
// This is incorrect as the arity doesn't match MyCollection<T>
public static MyCollection<TElement> Create<TElement, TOther>(TOther arg, ReadOnlySpan<TElement> elements) => default!;
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
MyCollection<string> x = [with(""), "goo"];
}
}
""";
CreateCompilation([sourceA, sourceB], targetFramework: TargetFramework.Net80).VerifyDiagnostics(
// (6,34): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'.
// MyCollection<string> x = [with(""), "goo"];
Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, @"[with(""""), ""goo""]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(6, 34));
}
#region AllowNull
[Fact]
public void ConstructorNonNullableParameterWithAllowNull_Null()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([AllowNull] string arg)
{
}
}
class C
{
static void Main()
{
string? s = null;
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (18,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void C.Goo(string s)").WithLocation(18, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String! arg)");
}
[Fact]
public void ConstructorNonNullableParameterWithAllowNull_NotNull()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([AllowNull] string arg)
{
}
}
class C
{
static void Main()
{
string? s = "";
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String! arg)");
}
[Fact]
public void ConstructorNullableParameterWithAllowNull_Null()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([AllowNull] string? arg)
{
}
}
class C
{
static void Main()
{
string? s = null;
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (18,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void C.Goo(string s)").WithLocation(18, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String? arg)");
}
[Fact]
public void ConstructorNullableParameterWithAllowNull_NotNull()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([AllowNull] string? arg)
{
}
}
class C
{
static void Main()
{
string? s = "";
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String? arg)");
}
[Fact]
public void CollectionBuilderNonNullableParameterWithAllowNull_Null()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([AllowNull] string value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = null;
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (8,13): warning CS8604: Possible null reference argument for parameter 's' in 'void Program.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void Program.Goo(string s)").WithLocation(8, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String! value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNonNullableParameterWithAllowNull_NotNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([AllowNull] string value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = "";
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String! value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNullableParameterWithAllowNull_Null()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([AllowNull] string? value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = null;
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (9,13): warning CS8604: Possible null reference argument for parameter 's' in 'void Program.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void Program.Goo(string s)").WithLocation(9, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String? value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNullableParameterWithAllowNull_NotNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([AllowNull] string? value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = "";
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String? value, System.ReadOnlySpan<System.Int32> items)");
}
#endregion
#region DisallowNull
[Fact]
public void ConstructorNonNullableParameterWithDisallowNull_Null()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([DisallowNull] string arg)
{
}
}
class C
{
static void Main()
{
string? s = null;
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (18,34): warning CS8604: Possible null reference argument for parameter 'arg' in 'MyList<int>.MyList(string arg)'.
// MyList<int> list = [with(s), 1, 2];
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("arg", "MyList<int>.MyList(string arg)").WithLocation(18, 34));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String! arg)");
}
[Fact]
public void ConstructorNonNullableParameterWithDisallowNull_NotNull()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([DisallowNull] string arg)
{
}
}
class C
{
static void Main()
{
string? s = "";
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String! arg)");
}
[Fact]
public void ConstructorNullableParameterWithDisallowNull_Null()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([DisallowNull] string? arg)
{
}
}
class C
{
static void Main()
{
string? s = null;
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (18,34): warning CS8604: Possible null reference argument for parameter 'arg' in 'MyList<int>.MyList(string? arg)'.
// MyList<int> list = [with(s), 1, 2];
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("arg", "MyList<int>.MyList(string? arg)").WithLocation(18, 34));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String? arg)");
}
[Fact]
public void ConstructorNullableParameterWithDisallowNull_NotNull()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([DisallowNull] string? arg)
{
}
}
class C
{
static void Main()
{
string? s = "";
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String? arg)");
}
[Fact]
public void CollectionBuilderNonNullableParameterWithDisallowNull_Null()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([DisallowNull] string value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = null;
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (8,37): warning CS8604: Possible null reference argument for parameter 'value' in 'MyCollection<int> MyBuilder.Create<int>(string value, ReadOnlySpan<int> items)'.
// MyCollection<int> c = [with(s), 1, 2];
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("value", "MyCollection<int> MyBuilder.Create<int>(string value, ReadOnlySpan<int> items)").WithLocation(8, 37));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String! value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNonNullableParameterWithDisallowNull_NotNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([DisallowNull] string value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = "";
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String! value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNullableParameterWithDisallowNull_Null()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([DisallowNull] string? value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = null;
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (8,37): warning CS8604: Possible null reference argument for parameter 'value' in 'MyCollection<int> MyBuilder.Create<int>(string? value, ReadOnlySpan<int> items)'.
// MyCollection<int> c = [with(s), 1, 2];
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("value", "MyCollection<int> MyBuilder.Create<int>(string? value, ReadOnlySpan<int> items)").WithLocation(8, 37));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String? value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNullableParameterWithDisallowNull_NotNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([DisallowNull] string? value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = "";
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String? value, System.ReadOnlySpan<System.Int32> items)");
}
#endregion
#region MaybeNull
[Fact]
public void ConstructorNonNullableParameterWithMaybeNull_Null()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([MaybeNull] string arg)
{
}
}
class C
{
static void Main()
{
string? s = null;
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (17,34): warning CS8604: Possible null reference argument for parameter 'arg' in 'MyList<int>.MyList(string arg)'.
// MyList<int> list = [with(s), 1, 2];
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("arg", "MyList<int>.MyList(string arg)").WithLocation(17, 34),
// (18,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void C.Goo(string s)").WithLocation(18, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String! arg)");
}
[Fact]
public void ConstructorNonNullableParameterWithMaybeNull_NotNull()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([MaybeNull] string arg)
{
}
}
class C
{
static void Main()
{
string? s = "";
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (18,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void C.Goo(string s)").WithLocation(18, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String! arg)");
}
[Fact]
public void ConstructorNullableParameterWithMaybeNull_Null()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([MaybeNull] string? arg)
{
}
}
class C
{
static void Main()
{
string? s = null;
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (18,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void C.Goo(string s)").WithLocation(18, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String? arg)");
}
[Fact]
public void ConstructorNullableParameterWithMaybeNull_NotNull()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([MaybeNull] string? arg)
{
}
}
class C
{
static void Main()
{
string? s = "";
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (18,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void C.Goo(string s)").WithLocation(18, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String? arg)");
}
[Fact]
public void CollectionBuilderNonNullableParameterWithMaybeNull_Null()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([MaybeNull] string value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = null;
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (7,37): warning CS8604: Possible null reference argument for parameter 'value' in 'MyCollection<int> MyBuilder.Create<int>(string value, ReadOnlySpan<int> items)'.
// MyCollection<int> c = [with(s), 1, 2];
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("value", "MyCollection<int> MyBuilder.Create<int>(string value, ReadOnlySpan<int> items)").WithLocation(7, 37),
// (8,13): warning CS8604: Possible null reference argument for parameter 's' in 'void Program.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void Program.Goo(string s)").WithLocation(8, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String! value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNonNullableParameterWithMaybeNull_NotNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([MaybeNull] string value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = "";
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (8,13): warning CS8604: Possible null reference argument for parameter 's' in 'void Program.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void Program.Goo(string s)").WithLocation(8, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String! value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNullableParameterWithMaybeNull_Null()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([MaybeNull] string? value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = null;
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (8,13): warning CS8604: Possible null reference argument for parameter 's' in 'void Program.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void Program.Goo(string s)").WithLocation(8, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String? value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNullableParameterWithMaybeNull_NotNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([MaybeNull] string? value, ReadOnlySpan<T> items) => new(value, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = "";
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (8,13): warning CS8604: Possible null reference argument for parameter 's' in 'void Program.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void Program.Goo(string s)").WithLocation(8, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String? value, System.ReadOnlySpan<System.Int32> items)");
}
#endregion
#region NotNull
[Fact]
public void ConstructorNullableParameterWithNotNull_Null()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([NotNull] string? arg)
{
arg = "";
}
}
class C
{
static void Main()
{
string? s = null;
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String? arg)");
}
[Fact]
public void ConstructorNullableParameterWithNotNull_NotNull()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([NotNull] string? arg)
{
arg = "";
}
}
class C
{
static void Main()
{
string? s = "";
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String? arg)");
}
[Fact]
public void ConstructorNonNullableParameterWithNotNull_Null()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([NotNull] string arg)
{
arg = "";
}
}
class C
{
static void Main()
{
string? s = null;
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (18,34): warning CS8604: Possible null reference argument for parameter 'arg' in 'MyList<int>.MyList(string arg)'.
// MyList<int> list = [with(s), 1, 2];
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("arg", "MyList<int>.MyList(string arg)").WithLocation(18, 34));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String! arg)");
}
[Fact]
public void ConstructorNonNullableParameterWithNotNull_NotNull()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([NotNull] string arg)
{
arg = "";
}
}
class C
{
static void Main()
{
string? s = "";
MyList<int> list = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String! arg)");
}
[Fact]
public void CollectionBuilderNullableParameterWithNotNull_Null()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([NotNull] string? value, ReadOnlySpan<T> items)
{
value = "";
return new(value, items);
}
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = null;
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String? value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNullableParameterWithNotNull_NotNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([NotNull] string? value, ReadOnlySpan<T> items)
{
value = "";
return new(value, items);
}
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = "";
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String? value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNonNullableParameterWithNotNull_Null()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([NotNull] string value, ReadOnlySpan<T> items)
{
value = "";
return new(value, items);
}
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = null;
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (7,37): warning CS8604: Possible null reference argument for parameter 'value' in 'MyCollection<int> MyBuilder.Create<int>(string value, ReadOnlySpan<int> items)'.
// MyCollection<int> c = [with(s), 1, 2];
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("value", "MyCollection<int> MyBuilder.Create<int>(string value, ReadOnlySpan<int> items)").WithLocation(7, 37));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String! value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderNonNullableParameterWithNotNull_NotNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([NotNull] string value, ReadOnlySpan<T> items)
{
value = "";
return new(value, items);
}
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = "";
MyCollection<int> c = [with(s), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String! value, System.ReadOnlySpan<System.Int32> items)");
}
#endregion
#region NotNullIfNotNull
[Fact]
public void ConstructorParameterWithNotNullIfNotNull_BothNull()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([NotNullIfNotNull(nameof(other))] string? arg, string? other)
{
}
}
class C
{
static void Main()
{
string? arg = null;
string? other = null;
MyList<int> list = [with(arg, other), 1, 2];
Goo(arg);
Goo(other);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (19,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(arg);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "arg").WithArguments("s", "void C.Goo(string s)").WithLocation(19, 13),
// (20,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(other);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "other").WithArguments("s", "void C.Goo(string s)").WithLocation(20, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String? arg, System.String? other)");
}
[Fact]
public void ConstructorParameterWithNotNullIfNotNull_ArgNull_OtherNotNull()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([NotNullIfNotNull(nameof(other))] string? arg, string? other)
{
}
}
class C
{
static void Main()
{
string? arg = null;
string other = "";
MyList<int> list = [with(arg, other), 1, 2];
Goo(arg);
Goo(other);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (19,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(arg);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "arg").WithArguments("s", "void C.Goo(string s)").WithLocation(19, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String? arg, System.String? other)");
}
[Fact]
public void ConstructorParameterWithNotNullIfNotNull_ArgNotNull_OtherNull()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([NotNullIfNotNull(nameof(other))] string? arg, string? other)
{
}
}
class C
{
static void Main()
{
string? arg = "";
string? other = null;
MyList<int> list = [with(arg, other), 1, 2];
Goo(arg);
Goo(other);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (20,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(other);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "other").WithArguments("s", "void C.Goo(string s)").WithLocation(20, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String? arg, System.String? other)");
}
[Fact]
public void ConstructorParameterWithNotNullIfNotNull_BothNotNull()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([NotNullIfNotNull(nameof(other))] string? arg, string? other)
{
}
}
class C
{
static void Main()
{
string? arg = "";
string? other = "";
MyList<int> list = [with(arg, other), 1, 2];
Goo(arg);
Goo(other);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.String? arg, System.String? other)");
}
[Fact]
public void CollectionBuilderParameterWithNotNullIfNotNull_BothNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, string? other, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([NotNullIfNotNull(nameof(other))] string? value, string? other, ReadOnlySpan<T> items)
=> new(value, other, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? arg = null;
string? other = null;
MyCollection<int> c = [with(arg, other), 1, 2];
Goo(arg);
Goo(other);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (9,13): warning CS8604: Possible null reference argument for parameter 's' in 'void Program.Goo(string s)'.
// Goo(arg);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "arg").WithArguments("s", "void Program.Goo(string s)").WithLocation(9, 13),
// (10,13): warning CS8604: Possible null reference argument for parameter 's' in 'void Program.Goo(string s)'.
// Goo(other);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "other").WithArguments("s", "void Program.Goo(string s)").WithLocation(10, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String? value, System.String? other, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderParameterWithNotNullIfNotNull_ArgNull_OtherNotNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, string? other, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([NotNullIfNotNull(nameof(other))] string? value, string? other, ReadOnlySpan<T> items)
=> new(value, other, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? arg = null;
string? other = "";
MyCollection<int> c = [with(arg, other), 1, 2];
Goo(arg);
Goo(other);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (9,13): warning CS8604: Possible null reference argument for parameter 's' in 'void Program.Goo(string s)'.
// Goo(arg);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "arg").WithArguments("s", "void Program.Goo(string s)").WithLocation(9, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String? value, System.String? other, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderParameterWithNotNullIfNotNull_ArgNotNull_OtherNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, string? other, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([NotNullIfNotNull(nameof(other))] string? value, string? other, ReadOnlySpan<T> items)
=> new(value, other, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? arg = "";
string? other = null;
MyCollection<int> c = [with(arg, other), 1, 2];
Goo(arg);
Goo(other);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (10,13): warning CS8604: Possible null reference argument for parameter 's' in 'void Program.Goo(string s)'.
// Goo(other);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "other").WithArguments("s", "void Program.Goo(string s)").WithLocation(10, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String? value, System.String? other, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderParameterWithNotNullIfNotNull_BothNotNull()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
public MyCollection(string? value, string? other, ReadOnlySpan<T> items)
{
}
}
class MyBuilder
{
public static MyCollection<T> Create<T>([NotNullIfNotNull(nameof(other))] string? value, string? other, ReadOnlySpan<T> items)
=> new(value, other, items);
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? arg = "";
string? other = "";
MyCollection<int> c = [with(arg, other), 1, 2];
Goo(arg);
Goo(other);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.String? value, System.String? other, System.ReadOnlySpan<System.Int32> items)");
}
#endregion
#region DoesNotReturnIf
[Fact]
public void ConstructorWithDoesNotReturnIf_Null_NullCheck()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([DoesNotReturnIf(true)] bool b)
{
}
}
class C
{
static void Main()
{
string? s = null;
MyList<int> list = [with(s == null), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.Boolean b)");
}
[Fact]
public void ConstructorWithDoesNotReturnIf_Null_NotNullCheck()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([DoesNotReturnIf(true)] bool b)
{
}
}
class C
{
static void Main()
{
string? s = null;
MyList<int> list = [with(s != null), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (18,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void C.Goo(string s)").WithLocation(18, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.Boolean b)");
}
[Fact]
public void ConstructorWithDoesNotReturnIf_NotNull_NullCheck()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([DoesNotReturnIf(true)] bool b)
{
}
}
class C
{
static void Main()
{
string? s = "";
MyList<int> list = [with(s == null), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.Boolean b)");
}
[Fact]
public void ConstructorWithDoesNotReturnIf_NotNull_NotNullCheck()
{
var source = """
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
class MyList<T> : List<T>
{
public MyList([DoesNotReturnIf(true)] bool b)
{
}
}
class C
{
static void Main()
{
string? s = "";
MyList<int> list = [with(s != null), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (18,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void C.Goo(string s)").WithLocation(18, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyList<System.Int32>.MyList(System.Boolean b)");
}
[Fact]
public void CollectionBuilderWithDoesNotReturnIf_Null_NullCheck()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
}
class MyBuilder
{
public static MyCollection<T> Create<T>([DoesNotReturnIf(true)] bool value, ReadOnlySpan<T> items) => null!;
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = null;
MyCollection<int> c = [with(s == null), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.Boolean value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderWithDoesNotReturnIf_Null_NotNullCheck()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
}
class MyBuilder
{
public static MyCollection<T> Create<T>([DoesNotReturnIf(true)] bool value, ReadOnlySpan<T> items) => null!;
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = null;
MyCollection<int> c = [with(s != null), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (8,13): warning CS8604: Possible null reference argument for parameter 's' in 'void Program.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void Program.Goo(string s)").WithLocation(8, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.Boolean value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderWithDoesNotReturnIf_NotNull_NullCheck()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
}
class MyBuilder
{
public static MyCollection<T> Create<T>([DoesNotReturnIf(true)] bool value, ReadOnlySpan<T> items) => null!;
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = "";
MyCollection<int> c = [with(s == null), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.Boolean value, System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderWithDoesNotReturnIf_NotNull_NotNullCheck()
{
string sourceA = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
}
class MyBuilder
{
public static MyCollection<T> Create<T>([DoesNotReturnIf(true)] bool value, ReadOnlySpan<T> items) => null!;
}
""";
string sourceB = """
#nullable enable
class Program
{
static void Main()
{
string? s = "";
MyCollection<int> c = [with(s != null), 1, 2];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(
[sourceA, sourceB],
targetFramework: TargetFramework.Net80,
verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (8,13): warning CS8604: Possible null reference argument for parameter 's' in 'void Program.Goo(string s)'.
// Goo(s);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void Program.Goo(string s)").WithLocation(8, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.Boolean value, System.ReadOnlySpan<System.Int32> items)");
}
#endregion
#region DoesNotReturn
[Fact]
public void CollectionBuilderWithDoesNotReturn_NoArgs_NoWithElement()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
}
class MyBuilder
{
[DoesNotReturn]
public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => throw null!;
}
class C
{
static void Main()
{
string? s = null;
MyCollection<int> list = [];
Goo(s);
}
static void Goo(string s) { }
}
""";
CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics();
}
[Fact]
public void CollectionBuilderWithDoesNotReturn_NoArgs_WithElement()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
}
class MyBuilder
{
[DoesNotReturn]
public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => throw null!;
}
class C
{
static void Main()
{
string? s = null;
MyCollection<int> list = [with()];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.ReadOnlySpan<System.Int32> items)");
}
[Fact]
public void CollectionBuilderWithDoesNotReturn_Args_WithElement()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
}
class MyBuilder
{
[DoesNotReturn]
public static MyCollection<T> Create<T>(bool b, ReadOnlySpan<T> items) => throw null!;
}
class C
{
static void Main()
{
string? s = null;
MyCollection<int> list = [with(true)];
Goo(s);
}
static void Goo(string s) { }
}
""";
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics();
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.Boolean b, System.ReadOnlySpan<System.Int32> items)");
}
#endregion
#region MemberNotNull
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/82029")]
public void CollectionBuilderWithMemberNotNull()
{
var source = """
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection<T> : List<T>
{
}
static class MyBuilder
{
public static string? Singleton;
[MemberNotNull(nameof(Singleton))]
public static MyCollection<T> Create<T>(bool b, ReadOnlySpan<T> items) => throw null!;
}
static class Other
{
public static string? Singleton;
[MemberNotNull(nameof(Singleton))]
public static void EnsureNotNull() => throw null!;
}
class C
{
static void Main()
{
Other.EnsureNotNull();
Goo(Other.Singleton);
MyCollection<int> list = [with(true)];
Goo(MyBuilder.Singleton);
}
static void Goo(string s) { }
}
""";
// MemberNotNull analysis does not flow across calls to collection builders yet. This is probably
// because we lack a way to track that the collection builder affects 'MyBuilder' state, and thus the member
// access to MyBuilder.Singleton. This is unlike the normal static call case on 'Other' where both the method
// call and the member access are off of the same 'Other' type in the code directly.
//
// https://github.com/dotnet/roslyn/issues/82029 tracks determining if this is even a bug, or is the
// expected behavior.
var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyDiagnostics(
// (14,27): warning CS0649: Field 'MyBuilder.Singleton' is never assigned to, and will always have its default value null
// public static string? Singleton;
Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Singleton").WithArguments("MyBuilder.Singleton", "null").WithLocation(14, 27),
// (22,27): warning CS0649: Field 'Other.Singleton' is never assigned to, and will always have its default value null
// public static string? Singleton;
Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Singleton").WithArguments("Other.Singleton", "null").WithLocation(22, 27),
// (36,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(MyBuilder.Singleton);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "MyBuilder.Singleton").WithArguments("s", "void C.Goo(string s)").WithLocation(36, 13));
AssertExpectedWithElementSymbol(verifier.Compilation, "MyCollection<System.Int32>! MyBuilder.Create<System.Int32>(System.Boolean b, System.ReadOnlySpan<System.Int32> items)");
}
#endregion
}
|