// 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.
#nullable disable
using System;
using System.Globalization;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting;
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.Semantics;
[CompilerTrait(CompilerFeature.Extensions)]
public partial class ExtensionTests : CompilingTestBase
{
[Fact]
public void Deconstruct_01()
{
var src = """
var (x, y) = "";
static class E
{
extension(object o)
{
public void Deconstruct(out int i, out int j, params int[] k) => throw null;
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (1,6): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x'.
// var (x, y) = "";
Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x").WithArguments("x").WithLocation(1, 6),
// (1,9): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'y'.
// var (x, y) = "";
Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y").WithArguments("y").WithLocation(1, 9),
// (1,14): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'string', with 2 out parameters and a void return type.
// var (x, y) = "";
Diagnostic(ErrorCode.ERR_MissingDeconstruct, @"""""").WithArguments("string", "2").WithLocation(1, 14));
}
[Fact]
public void Deconstruct_02()
{
var src = """
var (x, y) = "";
static class E
{
extension(object o)
{
public void Deconstruct(out int i, out int j, int k = 0) => throw null;
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (1,6): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x'.
// var (x, y) = "";
Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x").WithArguments("x").WithLocation(1, 6),
// (1,9): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'y'.
// var (x, y) = "";
Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y").WithArguments("y").WithLocation(1, 9),
// (1,14): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'string', with 2 out parameters and a void return type.
// var (x, y) = "";
Diagnostic(ErrorCode.ERR_MissingDeconstruct, @"""""").WithArguments("string", "2").WithLocation(1, 14));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80217")]
public void Deconstruct_Nested_01()
{
var source = """
var (a, b, c) = 42;
var ((d, _, _), (_, e, _), (_, _, f)) = 42;
System.Console.WriteLine($"{a} {b} {c} {d} {e} {f}");
static class E
{
extension(int instance)
{
public void Deconstruct(out int a, out int b, out int c)
=> (a, b, c) = (1, 2, 3);
}
}
""";
CompileAndVerify(source, expectedOutput: "1 2 3 1 2 3").VerifyDiagnostics();
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80217")]
public void Deconstruct_Nested_02()
{
var source = """
((int a, int b, int c), (int d, int e), (int f, int g, int h, int i)) = 42;
static class E
{
extension(int instance)
{
public void Deconstruct(out int a, out int b, out int c)
=> (a, b, c) = (1, 2, 3);
}
}
""";
CreateCompilation(source).VerifyEmitDiagnostics(
// (1,73): error CS7036: There is no argument given that corresponds to the required parameter 'c' of 'E.extension(int).Deconstruct(out int, out int, out int)'
// ((int a, int b, int c), (int d, int e), (int f, int g, int h, int i)) = 42;
Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "42").WithArguments("c", "E.extension(int).Deconstruct(out int, out int, out int)").WithLocation(1, 73),
// (1,73): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'int', with 2 out parameters and a void return type.
// ((int a, int b, int c), (int d, int e), (int f, int g, int h, int i)) = 42;
Diagnostic(ErrorCode.ERR_MissingDeconstruct, "42").WithArguments("int", "2").WithLocation(1, 73),
// (1,73): error CS1501: No overload for method 'Deconstruct' takes 4 arguments
// ((int a, int b, int c), (int d, int e), (int f, int g, int h, int i)) = 42;
Diagnostic(ErrorCode.ERR_BadArgCount, "42").WithArguments("Deconstruct", "4").WithLocation(1, 73),
// (1,73): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'int', with 4 out parameters and a void return type.
// ((int a, int b, int c), (int d, int e), (int f, int g, int h, int i)) = 42;
Diagnostic(ErrorCode.ERR_MissingDeconstruct, "42").WithArguments("int", "4").WithLocation(1, 73));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80217")]
public void Deconstruct_Nested_03()
{
var source = """
((int d, int _, int _), (int _, int e, int _), (int _, int _, int f), (int _, int _, int _)) = 42;
static class E
{
extension(int instance)
{
public void Deconstruct(out int a, out int b, out int c)
=> (a, b, c) = (1, 2, 3);
}
}
""";
CreateCompilation(source).VerifyEmitDiagnostics(
// (1,96): error CS1501: No overload for method 'Deconstruct' takes 4 arguments
// ((int d, int _, int _), (int _, int e, int _), (int _, int _, int f), (int _, int _, int _)) = 42;
Diagnostic(ErrorCode.ERR_BadArgCount, "42").WithArguments("Deconstruct", "4").WithLocation(1, 96),
// (1,96): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'int', with 4 out parameters and a void return type.
// ((int d, int _, int _), (int _, int e, int _), (int _, int _, int f), (int _, int _, int _)) = 42;
Diagnostic(ErrorCode.ERR_MissingDeconstruct, "42").WithArguments("int", "4").WithLocation(1, 96));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80217")]
public void Deconstruct_Nested_04()
{
var source = """
var ((a, b, c), (d, e), (f, g)) = 42;
System.Console.WriteLine($"{a} {b} {c} {d} {e} {f} {g}");
static class E
{
extension(int instance)
{
public void Deconstruct(out int a, out int b, out int c)
=> (a, b, c) = (1, 2, 3);
public void Deconstruct(out int a, out int b)
=> (a, b) = (4, 5);
}
}
""";
CompileAndVerify(source, expectedOutput: "1 2 3 4 5 4 5").VerifyDiagnostics();
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75484")]
public void Deconstruction_UnscopedRef_ExtensionMethod()
{
var source = """
class C
{
R M1()
{
new S().Deconstruct(out var x, out _);
return x; // 1
}
R M2()
{
(var x, _) = new S();
return x; // 2
}
R M3()
{
if (new S() is (var x, _))
return x; // 3
return default;
}
}
struct S;
ref struct R;
static class E
{
extension(in S s)
{
public void Deconstruct(out R x, out int y) => throw null;
}
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (6,16): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope
// return x; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(6, 16),
// (11,16): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope
// return x; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(11, 16),
// (16,20): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope
// return x; // 3
Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(16, 20));
}
[Fact]
public void Deconstruction_ScopedRef_ExtensionMethod()
{
var source = """
class C
{
R M1()
{
new S().Deconstruct(out var x, out _);
return x;
}
R M2()
{
(var x, _) = new S();
return x;
}
R M3()
{
if (new S() is (var x, _))
return x;
return default;
}
}
struct S;
ref struct R;
static class E
{
extension(scoped in S s)
{
public void Deconstruct(out R x, out int y) => throw null;
}
}
""";
CreateCompilation(source).VerifyDiagnostics();
}
[Fact]
public void ForeachDeconstruct_Conversion()
{
var src = """
C[] c = new C[] { new C() };
foreach (var (x1, x2) in c)
{
System.Console.Write(x1.ToString());
}
class C { }
static class E
{
extension(object o)
{
public void Deconstruct(out int i1, out int i2) { i1 = i2 = 42; }
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics();
CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics();
}
[Fact]
public void PositionalPattern_01()
{
var src = """
_ = "" is (i: 42, other: 43);
static class E
{
extension(object o)
{
public void Deconstruct(out int i, out int j) => throw null;
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (1,19): error CS8517: The name 'other' does not match the corresponding 'Deconstruct' parameter 'j'.
// _ = "" is (i: 42, other: 43);
Diagnostic(ErrorCode.ERR_DeconstructParameterNameMismatch, "other").WithArguments("other", "j").WithLocation(1, 19));
}
[Fact]
public void PositionalPattern_02()
{
var src = """
_ = new C() is var (x, y);
class C { }
static class E
{
extension(object o)
{
public void Deconstruct(out int i, out int j) => throw null;
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void PositionalPattern_03()
{
// implicit span conversion
var src = """
int[] i = new int[] { 1, 2 };
if (i is var (x, y))
System.Console.Write((x, y));
static class E
{
extension(System.Span<int> s)
{
public void Deconstruct(out int i, out int j) { i = 42; j = 43; }
}
}
""";
var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
CompileAndVerify(comp, expectedOutput: ExpectedOutput("(42, 43)"), verify: Verification.Skipped).VerifyDiagnostics();
}
[Fact]
public void PositionalPattern_04()
{
// implicit tuple conversion
var src = """
var t = (42, "ran");
if (t is var (x, y))
System.Console.Write((x, y));
static class E
{
extension((object, object) t)
{
public void Deconstruct(out int i, out int j) { i = 42; j = 43; }
}
}
""";
var comp = CreateCompilation(src);
CompileAndVerify(comp, expectedOutput: ExpectedOutput("(42, ran)")).VerifyDiagnostics();
}
[Fact]
public void PositionalPattern_05()
{
// We check conversion during initial binding
var src = """
int[] i = [];
_ = i is var (x, y);
static class E
{
extension(System.ReadOnlySpan<int> r)
{
public void Deconstruct(out int i, out int j) => throw null;
}
}
namespace System
{
public ref struct ReadOnlySpan<T>
{
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (2,14): error CS0656: Missing compiler required member 'ReadOnlySpan<T>.op_Implicit'
// _ = i is var (x, y);
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "(x, y)").WithArguments("System.ReadOnlySpan<T>", "op_Implicit").WithLocation(2, 14));
}
[Fact]
public void InvocationOnNull()
{
var src = """
null.M1("");
null.M2("");
static class E
{
extension<T>(T t1)
{
public void M1(T t2) => throw null!;
}
public static void M2<T>(this T t1, T t2) => throw null!;
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (1,1): error CS0023: Operator '.' cannot be applied to operand of type '<null>'
// null.M1("");
Diagnostic(ErrorCode.ERR_BadUnaryOp, "null.M1").WithArguments(".", "<null>").WithLocation(1, 1),
// (2,1): error CS0023: Operator '.' cannot be applied to operand of type '<null>'
// null.M2("");
Diagnostic(ErrorCode.ERR_BadUnaryOp, "null.M2").WithArguments(".", "<null>").WithLocation(2, 1));
}
[Fact]
public void RemoveLowerPriorityMembers_Deconstruct()
{
var src = """
var (x, y) = "";
public static class E
{
extension(object o)
{
[System.Runtime.CompilerServices.OverloadResolutionPriority(1)]
public void Deconstruct(out int i2, out int i3) { System.Console.Write("ran"); i2 = i3 = 43; }
}
extension(string s)
{
public void Deconstruct(out int i2, out int i3) => throw null;
}
}
""";
var comp = CreateCompilation([src, OverloadResolutionPriorityAttributeDefinition]);
CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics();
src = """
var (x, y) = "";
public static class E
{
extension(object o)
{
public void Deconstruct(out int i2, out int i3) => throw null;
}
extension(string s)
{
public void Deconstruct(out int i2, out int i3) { System.Console.Write("ran"); i2 = i3 = 43; }
}
}
""";
comp = CreateCompilation([src, OverloadResolutionPriorityAttributeDefinition]);
CompileAndVerify(comp, expectedOutput: "ran").VerifyDiagnostics();
}
[Fact]
public void RemoveLowerPriorityMembers_Foreach_GetEnumerator()
{
var src = """
using System.Collections.Generic;
foreach (var x in new C()) { System.Console.Write(x); }
public class C { }
public static class E
{
extension(object o)
{
[System.Runtime.CompilerServices.OverloadResolutionPriority(1)]
public IEnumerator<int> GetEnumerator() { yield return 42; }
}
extension(C c)
{
public IEnumerator<int> GetEnumerator() => throw null;
}
}
""";
var comp = CreateCompilation([src, OverloadResolutionPriorityAttributeDefinition]);
CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics();
}
[Fact]
public void RemoveLowerPriorityMembers_CollectionInitializer()
{
var src = """
using System.Collections;
using System.Collections.Generic;
_ = new C() { 42 };
public class C : IEnumerable<int>, IEnumerable
{
IEnumerator<int> IEnumerable<int>.GetEnumerator() => throw null;
IEnumerator IEnumerable.GetEnumerator() => throw null;
}
public static class E
{
extension(object o)
{
[System.Runtime.CompilerServices.OverloadResolutionPriority(1)]
public void Add(int i) { System.Console.Write("add"); }
}
extension(C c)
{
public void Add(int i) => throw null;
}
}
""";
var comp = CreateCompilation([src, OverloadResolutionPriorityAttributeDefinition]);
CompileAndVerify(comp, expectedOutput: "add").VerifyDiagnostics();
}
[Fact]
public void RemoveLowerPriorityMembers_Fixed()
{
var src = """
unsafe class C
{
public static void Main()
{
fixed (int* p = new Fixable()) { }
}
}
public class Fixable { }
public static class E
{
extension(object o)
{
[System.Runtime.CompilerServices.OverloadResolutionPriority(1)]
public ref int GetPinnableReference() { System.Console.Write("ran"); return ref (new int[] { 1, 2, 3 })[0]; }
}
extension(Fixable f)
{
public ref int GetPinnableReference() => throw null;
}
}
""";
var comp = CreateCompilation([src, OverloadResolutionPriorityAttributeDefinition], options: TestOptions.UnsafeDebugExe);
CompileAndVerify(comp, expectedOutput: "ran", verify: Verification.Skipped).VerifyDiagnostics();
}
[Fact]
public void RemoveLowerPriorityMembers_Await()
{
var src = """
using System;
using System.Runtime.CompilerServices;
int i = await new C();
System.Console.Write(i);
public class C { }
public class D : INotifyCompletion
{
public int GetResult() => 42;
public void OnCompleted(Action continuation) => throw null;
public bool IsCompleted => true;
}
public static class E
{
extension(object o)
{
[System.Runtime.CompilerServices.OverloadResolutionPriority(1)]
public D GetAwaiter() => new D();
}
extension(C c)
{
public D GetAwaiter() => throw null;
}
}
""";
var comp = CreateCompilation([src, OverloadResolutionPriorityAttributeDefinition]);
CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics();
}
[Fact]
public void RemoveLowerPriorityMembers_ObjectInitializer()
{
var src = """
_ = new C() { Property = 42 };
public class C { }
public static class E
{
extension(object o)
{
[System.Runtime.CompilerServices.OverloadResolutionPriority(1)]
public int Property { set { System.Console.Write("property"); } }
}
extension(C c)
{
public int Property => throw null;
}
}
""";
var comp = CreateCompilation([src, OverloadResolutionPriorityAttributeDefinition]);
CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics();
}
[Fact]
public void RemoveLowerPriorityMembers_With()
{
var src = """
_ = new S() with { Property = 42 };
public struct S { }
public static class E
{
extension(object o)
{
[System.Runtime.CompilerServices.OverloadResolutionPriority(1)]
public int Property { set { System.Console.Write("property"); } }
}
extension(S s)
{
public int Property { set => throw null; }
}
}
""";
var comp = CreateCompilation([src, OverloadResolutionPriorityAttributeDefinition]);
CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics();
}
[Fact]
public void RemoveLowerPriorityMembers_PropertyPattern()
{
var src = """
_ = new C() is { Property: 42 };
public class C{ }
public static class E
{
extension(object o)
{
[System.Runtime.CompilerServices.OverloadResolutionPriority(1)]
public int Property { get { System.Console.Write("property"); return 42; } }
}
extension(C c)
{
public int Property => throw null;
}
}
""";
var comp = CreateCompilation([src, OverloadResolutionPriorityAttributeDefinition]);
CompileAndVerify(comp, expectedOutput: "property").VerifyDiagnostics();
}
[Fact]
public void AnonymousType_01()
{
var src = """
var person = new { Name = "John", Age = 30 };
person.M();
person.M2();
_ = person.Property;
public static class E
{
extension<T>(T t)
{
public void M() { System.Console.Write("method "); }
public int Property { get { System.Console.Write("property"); return 42; } }
}
public static void M2<T>(this T t) { System.Console.Write("method2 "); }
}
""";
var comp = CreateCompilation(src);
CompileAndVerify(comp, expectedOutput: "method method2 property").VerifyDiagnostics();
}
[Fact]
public void AnonymousType_02()
{
// instance members come first
var src = """
System.Action a = () => { System.Console.Write("method "); };
var person = new { DoStuff = a, Property = 42 };
person.DoStuff();
System.Console.Write(person.Property);
public static class E
{
extension<T>(T t)
{
public void DoStuff() => throw null;
public int Property => throw null;
}
}
""";
var comp = CreateCompilation(src);
CompileAndVerify(comp, expectedOutput: "method 42").VerifyDiagnostics();
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78968")]
public void AnonymousType_03()
{
var src = """
42.M();
public static class E
{
extension(int i)
{
public void M()
{
var x = new { A = 1 };
local(x, x => new { x.A });
void local<U>(U u, System.Linq.Expressions.Expression<System.Func<U, object>> f)
{
System.Console.Write(f.Compile()(u));
}
}
}
}
""";
var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
CompileAndVerify(comp, expectedOutput: ExpectedOutput("{ A = 1 }"), verify: Verification.Skipped).VerifyDiagnostics();
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78968")]
public void AnonymousType_04()
{
var src = """
42.M(43);
public static class E
{
extension(int i)
{
public void M<T>(T t)
{
var x = new { A = t };
local(x, x => new { x.A });
static void local<U>(U u, System.Linq.Expressions.Expression<System.Func<U, object>> f)
{
System.Console.Write(f.Compile()(u));
}
}
}
}
""";
var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
CompileAndVerify(comp, expectedOutput: ExpectedOutput("{ A = 43 }"), verify: Verification.Skipped).VerifyDiagnostics();
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/80250")]
public void Cls()
{
var src = """
[assembly: System.CLSCompliant(true)]
public static class Extensions
{
extension(object) { }
}
""";
CreateCompilation(src).VerifyEmitDiagnostics();
}
[Fact]
public void Attribute_01()
{
var src = """
[My(Property = 42)]
class C { }
public class MyAttribute : System.Attribute { }
public static class E
{
extension(MyAttribute a)
{
public int Property { get => throw null; set => throw null; }
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0246: The type or namespace name 'Property' could not be found (are you missing a using directive or an assembly reference?)
// [My(Property = 42)]
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Property").WithArguments("Property").WithLocation(1, 5));
}
[Fact]
public void Lock_01()
{
var src = """
System.Threading.Lock x = new System.Threading.Lock();
lock (x) { }
namespace System.Threading
{
public sealed class Lock
{
public Scope EnterScope() { System.Console.Write("ran "); return new Scope(); }
public ref struct Scope
{
public void Dispose() { System.Console.Write("disposed"); }
}
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics();
CompileAndVerify(comp, expectedOutput: "ran disposed", verify: Verification.Skipped).VerifyDiagnostics();
src = """
System.Threading.Lock x = new System.Threading.Lock();
lock (x) { }
namespace System.Threading
{
public sealed class Lock
{
public ref struct Scope
{
public void Dispose() => throw null;
}
}
}
public static class E
{
extension(System.Threading.Lock x)
{
public System.Threading.Lock.Scope EnterScope() => throw null;
}
}
""";
comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
// lock (x) { }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7));
src = """
System.Threading.Lock x = new System.Threading.Lock();
lock (x) { }
namespace System.Threading
{
public sealed class Lock
{
public Scope EnterScope() => throw null;
public ref struct Scope
{
}
}
}
public static class E
{
extension(System.Threading.Lock.Scope x)
{
public void Dispose() => throw null;
}
}
""";
comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock+Scope.Dispose'
// lock (x) { }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x").WithArguments("System.Threading.Lock+Scope", "Dispose").WithLocation(2, 7));
}
[Fact]
public void Nullability_PropertyAccess_01()
{
// nullability check on the receiver, annotated extension parameter
var src = """
#nullable enable
object? oNull = null;
_ = oNull.P;
object? oNull2 = null;
E.get_P(oNull2);
object? oNotNull = new object();
_ = oNotNull.P;
E.get_P(oNotNull);
""";
var libSrc = """
#nullable enable
public static class E
{
extension(object? o)
{
public int P { get => throw null!; }
}
}
""";
var comp = CreateCompilation([src, libSrc]);
comp.VerifyEmitDiagnostics();
var libComp = CreateCompilation(libSrc);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]);
comp2.VerifyEmitDiagnostics();
}
[Fact]
public void SynthesizedAttributeOnParameters_Params_01()
{
var src = """
new object().M(1, 2, 3);
E.M(new object(), 1, 2, 3);
""";
var libSrc = """
public static class E
{
extension(object o)
{
public void M(params int[] i) { System.Console.Write((i[0], i[1], i[2])); }
}
}
""";
var comp = CreateCompilation([src, libSrc]);
CompileAndVerify(comp, expectedOutput: "(1, 2, 3)(1, 2, 3)").VerifyDiagnostics();
var libComp = CreateCompilation(libSrc);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]);
CompileAndVerify(comp2, expectedOutput: "(1, 2, 3)(1, 2, 3)").VerifyDiagnostics();
}
[Fact]
public void SynthesizedAttributeOnParameters_Params_02()
{
var src = """
new object().M(1, 2, 3);
E.M(new object(), 1, 2, 3);
""";
var libSrc = """
using System.Linq;
public static class E
{
extension(object o)
{
public void M(params System.Collections.Generic.IEnumerable<int> i) { int[] i2 = i.ToArray(); System.Console.Write((i2[0], i2[1], i2[2])); }
}
}
""";
var comp = CreateCompilation([src, libSrc]);
CompileAndVerify(comp, expectedOutput: "(1, 2, 3)(1, 2, 3)", symbolValidator: validate).VerifyDiagnostics();
var libComp = CreateCompilation(libSrc);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]);
CompileAndVerify(comp, expectedOutput: "(1, 2, 3)(1, 2, 3)").VerifyDiagnostics();
static void validate(ModuleSymbol m)
{
var module = (PEModuleSymbol)m;
var parameterSymbol = (PEParameterSymbol)m.GlobalNamespace.GetMember<MethodSymbol>("E.M").Parameters[1];
Assert.True(module.Module.HasParamCollectionAttribute(parameterSymbol.Handle));
}
}
[Fact]
public void SynthesizedAttributeOnParameters_Dynamic_01()
{
var src = """
public static class E
{
extension(object o)
{
public void M(dynamic d) { }
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics();
CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate, verify: Verification.Skipped);
static void validate(ModuleSymbol m)
{
AssertEx.SetEqual(m is SourceModuleSymbol ? new string[] { } : ["System.Runtime.CompilerServices.DynamicAttribute"],
m.GlobalNamespace.GetMember<MethodSymbol>("E.M").Parameters[1].GetAttributes().ToStrings());
}
}
[Fact]
public void SynthesizedAttributeOnParameters_Dynamic_02()
{
var src = """
public class C<T> { }
public static class E
{
extension(C<dynamic> d)
{
public void M() { }
public int Property => 42;
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics();
CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate);
static void validate(ModuleSymbol m)
{
AssertEx.SetEqual(m is SourceModuleSymbol ? new string[] { } : ["System.Runtime.CompilerServices.DynamicAttribute({false, true})"],
m.GlobalNamespace.GetMember<MethodSymbol>("E.M").Parameters[0].GetAttributes().ToStrings());
AssertEx.SetEqual(m is SourceModuleSymbol ? new string[] { } : ["System.Runtime.CompilerServices.DynamicAttribute({false, true})"],
m.GlobalNamespace.GetMember<MethodSymbol>("E.get_Property").Parameters[0].GetAttributes().ToStrings());
}
}
[Fact]
public void SynthesizedAttributeOnParameters_In_01()
{
var src = """
class C
{
void M(in int i)
{
_ = i.P;
_ = E.get_P(i);
_ = i.P2;
_ = E.get_P2(ref i);
}
}
""";
var libSrc = """
public static class E
{
extension(in int i)
{
public int P => throw null!;
}
extension(ref int i)
{
public int P2 => throw null!;
}
}
""";
DiagnosticDescription[] expected = [
// (8,13): error CS8329: Cannot use variable 'i' as a ref or out value because it is a readonly variable
// _ = i.P2;
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "i").WithArguments("variable", "i").WithLocation(8, 13),
// (9,26): error CS8329: Cannot use variable 'i' as a ref or out value because it is a readonly variable
// _ = E.get_P2(ref i);
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "i").WithArguments("variable", "i").WithLocation(9, 26)
];
var comp = CreateCompilation([src, libSrc]);
comp.VerifyEmitDiagnostics(expected);
var libComp = CreateCompilation(libSrc);
CompileAndVerify(libComp, symbolValidator: validate);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]);
comp2.VerifyEmitDiagnostics(expected);
static void validate(ModuleSymbol m)
{
var module = (PEModuleSymbol)m;
var parameterSymbol = (PEParameterSymbol)m.GlobalNamespace.GetMember<MethodSymbol>("E.get_P").Parameters[0];
Assert.True(module.Module.HasIsReadOnlyAttribute(parameterSymbol.Handle));
parameterSymbol = (PEParameterSymbol)m.GlobalNamespace.GetMember<MethodSymbol>("E.get_P2").Parameters[0];
Assert.False(module.Module.HasIsReadOnlyAttribute(parameterSymbol.Handle));
}
}
[Fact]
public void SynthesizedAttributeOnParameters_In_02()
{
var src = """
class C
{
void M(in int i)
{
i.M();
E.M(i);
i.M2();
E.M2(ref i);
}
}
""";
var libSrc = """
public static class E
{
extension(in int i)
{
public void M() => throw null!;
}
extension(ref int i)
{
public void M2() => throw null!;
}
}
""";
DiagnosticDescription[] expected = [
// (8,9): error CS8329: Cannot use variable 'i' as a ref or out value because it is a readonly variable
// i.M2();
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "i").WithArguments("variable", "i").WithLocation(8, 9),
// (9,18): error CS8329: Cannot use variable 'i' as a ref or out value because it is a readonly variable
// E.M2(ref i);
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "i").WithArguments("variable", "i").WithLocation(9, 18)
];
var comp = CreateCompilation([src, libSrc]);
comp.VerifyEmitDiagnostics(expected);
var libComp = CreateCompilation(libSrc);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]);
comp2.VerifyEmitDiagnostics(expected);
}
[Fact]
public void SynthesizedAttributeOnReturn_Dynamic_01()
{
var src = """
new object().P.Dynamic();
E.get_P(new object()).Dynamic();
""";
var libSrc = """
public static class E
{
extension(object o)
{
public dynamic P => throw null!;
}
}
""";
var comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics();
CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate, verify: Verification.Skipped);
static void validate(ModuleSymbol m)
{
AssertEx.SetEqual(m is SourceModuleSymbol ? new string[] { } : ["System.Runtime.CompilerServices.DynamicAttribute"],
m.GlobalNamespace.GetMember<MethodSymbol>("E.get_P").GetReturnTypeAttributes().ToStrings());
}
var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net90);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()], targetFramework: TargetFramework.Net90);
comp2.VerifyEmitDiagnostics();
}
[Fact]
public void Nullability_PropertyAccess_02()
{
// nullability check on the receiver, un-annotated extension parameter
var src = """
#nullable enable
object? oNull = null;
_ = oNull.P;
object? oNull2 = null;
E.get_P(oNull2);
object? oNotNull = new object();
_ = oNotNull.P;
E.get_P(oNotNull);
""";
var libSrc = """
#nullable enable
public static class E
{
extension(object o)
{
public int P { get => throw null!; }
}
public static void M(object here) { }
}
""";
DiagnosticDescription[] expected = [
// (4,5): warning CS8604: Possible null reference argument for parameter 'o' in 'E.extension(object)'.
// _ = oNull.P;
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "oNull").WithArguments("o", "E.extension(object)").WithLocation(4, 5),
// (7,9): warning CS8604: Possible null reference argument for parameter 'o' in 'int E.get_P(object o)'.
// E.get_P(oNull2);
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "oNull2").WithArguments("o", "int E.get_P(object o)").WithLocation(7, 9)
];
var comp = CreateCompilation([src, libSrc]);
comp.VerifyEmitDiagnostics(expected);
var libComp = CreateCompilation(libSrc);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]);
comp2.VerifyEmitDiagnostics(expected);
}
[Fact]
public void Nullability_PropertyAccess_03()
{
// nullability check on the return value
var src = """
#nullable enable
object o1 = object.P; // 1
object? o2 = object.P;
object o3 = E.get_P(); // 2
object? o4 = E.get_P();
object o5 = object.P2;
object? o6 = object.P2;
object o7 = E.get_P2();
object? o8 = E.get_P2();
""";
var libSrc = """
#nullable enable
public static class E
{
extension(object)
{
public static object? P { get => throw null!; }
public static object P2 { get => throw null!; }
}
}
""";
DiagnosticDescription[] expected = [
// (3,13): warning CS8600: Converting null literal or possible null value to non-nullable type.
// object o1 = object.P; // 1
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "object.P").WithLocation(3, 13),
// (6,13): warning CS8600: Converting null literal or possible null value to non-nullable type.
// object o3 = E.get_P(); // 2
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "E.get_P()").WithLocation(6, 13)
];
var comp = CreateCompilation([src, libSrc]);
comp.VerifyEmitDiagnostics(expected);
var libComp = CreateCompilation(libSrc);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]);
comp2.VerifyEmitDiagnostics(expected);
}
[Fact]
public void Nullability_PropertyAccess_04()
{
// nullability check on the set value
var src = """
#nullable enable
object.P = null;
object.P = new object();
E.set_P(null);
E.set_P(new object());
object.P2 = null; // 1
object.P2 = new object();
E.set_P2(null); // 2
E.set_P2(new object());
""";
var libSrc = """
#nullable enable
public static class E
{
extension(object)
{
public static object? P { set => throw null!; }
public static object P2 { set => throw null!; }
}
}
""";
DiagnosticDescription[] expected = [
// (9,13): warning CS8625: Cannot convert null literal to non-nullable reference type.
// object.P2 = null; // 1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(9, 13),
// (12,10): warning CS8625: Cannot convert null literal to non-nullable reference type.
// E.set_P2(null); // 2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(12, 10)
];
var comp = CreateCompilation([src, libSrc]);
comp.VerifyEmitDiagnostics(expected);
var libComp = CreateCompilation(libSrc);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]);
comp2.VerifyEmitDiagnostics(expected);
}
[Fact]
public void Nullability_PropertyAccess_05()
{
// nullability check on compound assignment
var src = """
#nullable enable
object.P ??= null;
object.P ??= new object();
object.P2 ??= null; // 1
object.P2 ??= new object();
static class E
{
extension(object)
{
public static object? P { get => throw null!; set => throw null!; }
public static object P2 { get => throw null!; set => throw null!; }
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (6,15): warning CS8625: Cannot convert null literal to non-nullable reference type.
// object.P2 ??= null; // 1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(6, 15));
}
[Fact]
public void Nullability_PropertyAccess_06()
{
// generic extension parameter, property read access
var src = """
#nullable enable
object? oNull = null;
oNull.P.ToString();
object? oNotNull = new object();
oNotNull.P.ToString();
static class E
{
extension<T>(T t)
{
public T P { get => throw null!; }
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (4,1): warning CS8602: Dereference of a possibly null reference.
// oNull.P.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "oNull.P").WithLocation(4, 1));
var tree = comp.SyntaxTrees.First();
var model = comp.GetSemanticModel(tree);
var propertyAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "oNull.P");
AssertEx.Equal("System.Object? E.extension<System.Object?>(System.Object?).P { get; }", model.GetSymbolInfo(propertyAccess1).Symbol.ToTestDisplayString(includeNonNullable: true));
var propertyAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "oNotNull.P");
AssertEx.Equal("System.Object! E.extension<System.Object!>(System.Object!).P { get; }", model.GetSymbolInfo(propertyAccess2).Symbol.ToTestDisplayString(includeNonNullable: true));
}
[Fact]
public void Nullability_PropertyAccess_07()
{
// generic extension parameter, instance member, property write access
var src = """
#nullable enable
object? oNull = null;
oNull.P = null;
object? oNull2 = null;
oNull2.P = new object();
object? oNotNull = new object();
oNotNull.P = null; // 1
oNotNull.P = new object();
oNotNull?.P = null; // 2
static class E
{
extension<T>(T t)
{
public T P { set => throw null!; }
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (10,14): warning CS8625: Cannot convert null literal to non-nullable reference type.
// oNotNull.P = null; // 1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 14),
// (14,15): warning CS8625: Cannot convert null literal to non-nullable reference type.
// oNotNull?.P = null; // 2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(14, 15));
}
[Fact]
public void Nullability_PropertyAccess_08()
{
// generic extension parameter, static member
var src = """
#nullable enable
C<object>.P = new C<object?>(); // 1
C<object>.P = new C<object>();
C<object?>.P = new C<object?>();
C<object?>.P = new C<object>(); // 2
class C<T> { }
static class E
{
extension<T>(T)
{
public static T P { set => throw null!; }
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (3,15): warning CS8619: Nullability of reference types in value of type 'C<object?>' doesn't match target type 'C<object>'.
// C<object>.P = new C<object?>(); // 1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new C<object?>()").WithArguments("C<object?>", "C<object>").WithLocation(3, 15),
// (7,16): warning CS8619: Nullability of reference types in value of type 'C<object>' doesn't match target type 'C<object?>'.
// C<object?>.P = new C<object>(); // 2
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new C<object>()").WithArguments("C<object>", "C<object?>").WithLocation(7, 16));
var tree = comp.SyntaxTrees.First();
var model = comp.GetSemanticModel(tree);
var propertyAccess = GetSyntaxes<MemberAccessExpressionSyntax>(tree, "C<object?>.P").First();
AssertEx.Equal("C<System.Object?>! E.extension<C<System.Object?>!>(C<System.Object?>!).P { set; }", model.GetSymbolInfo(propertyAccess).Symbol.ToTestDisplayString(includeNonNullable: true));
}
[Fact]
public void Nullability_PropertyAccess_09()
{
// notnull constraint
var src = """
#nullable enable
object? oNull = null;
_ = oNull.P;
object? oNull2 = null;
_ = oNull2?.P;
object? oNotNull = new object();
_ = oNotNull.P;
static class E
{
extension<T>(T t) where T : notnull
{
public T P { get => throw null!; }
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (4,5): warning CS8714: The type 'object?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(T)'. Nullability of type argument 'object?' doesn't match 'notnull' constraint.
// _ = oNull.P;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "oNull.P").WithArguments("E.extension<T>(T)", "T", "object?").WithLocation(4, 5));
var tree = comp.SyntaxTrees.First();
var model = comp.GetSemanticModel(tree);
var propertyAccess1 = GetSyntax<MemberAccessExpressionSyntax>(tree, "oNull.P");
AssertEx.Equal("System.Object? E.extension<System.Object?>(System.Object?).P { get; }", model.GetSymbolInfo(propertyAccess1).Symbol.ToTestDisplayString(includeNonNullable: true));
var propertyAccess2 = GetSyntax<MemberAccessExpressionSyntax>(tree, "oNotNull.P");
AssertEx.Equal("System.Object! E.extension<System.Object!>(System.Object!).P { get; }", model.GetSymbolInfo(propertyAccess2).Symbol.ToTestDisplayString(includeNonNullable: true));
}
[Fact]
public void Nullability_PropertyAccess_10()
{
// notnull constraint, in tuple
var src = """
#nullable enable
object? oNull = null;
_ = (1, oNull.P);
static class E
{
extension<T>(T t) where T : notnull
{
public T P { get => throw null!; }
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (4,9): warning CS8714: The type 'object?' cannot be used as type parameter 'T' in the generic type or method 'E.extension<T>(T)'. Nullability of type argument 'object?' doesn't match 'notnull' constraint.
// _ = (1, oNull.P);
Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterNotNullConstraint, "oNull.P").WithArguments("E.extension<T>(T)", "T", "object?").WithLocation(4, 9));
}
[Fact]
public void Nullability_PropertyAccess_11()
{
// implicit reference conversion on the receiver
var src = """
#nullable enable
string? sNull = null;
_ = sNull.P;
string? sNotNull = "";
_ = sNotNull.P;
static class E
{
extension(object? o)
{
public int P { get => throw null!; }
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void Nullability_PropertyAccess_12()
{
// implicit reference conversion on the receiver
var src = """
#nullable enable
string? sNull = null;
_ = sNull.P;
string? sNotNull = "";
_ = sNotNull.P;
static class E
{
extension(object o)
{
public int P { get => throw null!; }
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (4,5): warning CS8604: Possible null reference argument for parameter 'o' in 'E.extension(object)'.
// _ = sNull.P;
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "sNull").WithArguments("o", "E.extension(object)").WithLocation(4, 5));
}
[Fact]
public void Nullability_PropertyAccess_13()
{
// `ref` extension parameter
var src = """
#nullable enable
S<object?> s1 = default;
_ = s1.P;
S<object> s2 = default;
_ = s2.P; // 1
S<object?> s3 = default;
_ = s3.P2; // 2
S<object> s4 = default;
_ = s4.P2;
struct S<T> { }
static class E
{
extension(ref S<object?> o)
{
public int P { get => throw null!; }
}
extension(ref S<object> o)
{
public int P2 { get => throw null!; }
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (7,5): warning CS8620: Argument of type 'S<object>' cannot be used for parameter 'o' of type 'S<object?>' in 'E.extension(ref S<object?>)' due to differences in the nullability of reference types.
// _ = s2.P; // 1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "s2").WithArguments("S<object>", "S<object?>", "o", "E.extension(ref S<object?>)").WithLocation(7, 5),
// (10,5): warning CS8620: Argument of type 'S<object?>' cannot be used for parameter 'o' of type 'S<object>' in 'E.extension(ref S<object>)' due to differences in the nullability of reference types.
// _ = s3.P2; // 2
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "s3").WithArguments("S<object?>", "S<object>", "o", "E.extension(ref S<object>)").WithLocation(10, 5));
}
[Fact]
public void Nullability_PropertyAccess_14()
{
// `in` extension parameter
var src = """
#nullable enable
S<object?> s1 = default;
_ = s1.P;
S<object> s2 = default;
_ = s2.P; // 1
S<object?> s3 = default;
_ = s3.P2; // 2
S<object> s4 = default;
_ = s4.P2;
""";
var libSrc = """
#nullable enable
public struct S<T> { }
public static class E
{
extension(in S<object?> o)
{
public int P { get => throw null!; }
}
extension(in S<object> o)
{
public int P2 { get => throw null!; }
}
}
""";
DiagnosticDescription[] expected = [
// (7,5): warning CS8620: Argument of type 'S<object>' cannot be used for parameter 'o' of type 'S<object?>' in 'E.extension(in S<object?>)' due to differences in the nullability of reference types.
// _ = s2.P; // 1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "s2").WithArguments("S<object>", "S<object?>", "o", "E.extension(in S<object?>)").WithLocation(7, 5),
// (10,5): warning CS8620: Argument of type 'S<object?>' cannot be used for parameter 'o' of type 'S<object>' in 'E.extension(in S<object>)' due to differences in the nullability of reference types.
// _ = s3.P2; // 2
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "s3").WithArguments("S<object?>", "S<object>", "o", "E.extension(in S<object>)").WithLocation(10, 5)
];
var comp = CreateCompilation([src, libSrc]);
comp.VerifyEmitDiagnostics(expected);
var libComp = CreateCompilation(libSrc);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]);
comp2.VerifyEmitDiagnostics(expected);
}
[Fact]
public void Nullability_PropertyAccess_15()
{
// NotNullIfNotNull
var src = """
#nullable enable
object? oNull = null;
oNull.P.ToString(); // 1
object? oNull2 = null;
E.get_P(oNull2).ToString(); // 2
object oNotNull = new object();
oNotNull.P.ToString();
E.get_P(oNotNull).ToString();
""";
var libSrc = """
#nullable enable
public static class E
{
extension(object? o)
{
[property: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o))]
public object? P { get => throw null!; }
}
}
""";
DiagnosticDescription[] expected = [
// (4,1): warning CS8602: Dereference of a possibly null reference.
// oNull.P.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "oNull.P").WithLocation(4, 1),
// (7,1): warning CS8602: Dereference of a possibly null reference.
// E.get_P(oNull2).ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "E.get_P(oNull2)").WithLocation(7, 1),
// Tracked by https://github.com/dotnet/roslyn/issues/37238 : NotNullIfNotNull not yet supported on indexers. The last two warnings are spurious
// (10,1): warning CS8602: Dereference of a possibly null reference.
// oNotNull.P.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "oNotNull.P").WithLocation(10, 1),
// (12,1): warning CS8602: Dereference of a possibly null reference.
// E.get_P(oNotNull).ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "E.get_P(oNotNull)").WithLocation(12, 1)
];
var comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics(expected);
var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net90);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()], targetFramework: TargetFramework.Net90);
comp2.VerifyEmitDiagnostics(expected);
src = """
#nullable enable
object? oNull = null;
new C()[oNull].ToString();
object oNotNull = new object();
new C()[oNotNull].ToString();
class C
{
[property: System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o))]
public object? this[object? o] { get => throw null!; }
}
""";
comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
// Tracked by https://github.com/dotnet/roslyn/issues/37238 : NotNullIfNotNull not yet supported on indexers.
comp.VerifyEmitDiagnostics(
// (4,1): warning CS8602: Dereference of a possibly null reference.
// new C()[oNull].ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "new C()[oNull]").WithLocation(4, 1),
// (7,1): warning CS8602: Dereference of a possibly null reference.
// new C()[oNotNull].ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "new C()[oNotNull]").WithLocation(7, 1));
}
[Fact]
public void Nullability_PropertyAccess_16()
{
// NotNull
var src = """
#nullable enable
object.P.ToString();
object.P = null;
E.get_P().ToString();
E.set_P(null);
""";
var libSrc = """
#nullable enable
public static class E
{
extension(object)
{
[property: System.Diagnostics.CodeAnalysis.NotNull]
public static object? P { get => throw null!; set => throw null!; }
public static object? P2 { get => throw null!; set => throw null!; }
}
}
""";
var comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics();
var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net90);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()], targetFramework: TargetFramework.Net90);
comp2.VerifyEmitDiagnostics();
CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate, verify: Verification.Skipped);
static void validate(ModuleSymbol m)
{
AssertEx.SetEqual(m is SourceModuleSymbol ? new string[] { } : ["System.Diagnostics.CodeAnalysis.NotNullAttribute"],
m.GlobalNamespace.GetMember<MethodSymbol>("E.get_P").GetReturnTypeAttributes().ToStrings());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P").GetReturnTypeAttributes());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P").Parameters[0].GetAttributes());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.get_P2").GetReturnTypeAttributes());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P2").GetReturnTypeAttributes());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P2").Parameters[0].GetAttributes());
}
}
[Fact]
public void Nullability_PropertyAccess_17()
{
// MaybeNull
var src = """
#nullable enable
object.P.ToString(); // 1
object.P = null; // 2
object.P = "";
E.get_P().ToString(); // 3
E.set_P(null); // 4
""";
var libSrc = """
#nullable enable
public static class E
{
extension(object)
{
[property: System.Diagnostics.CodeAnalysis.MaybeNull]
public static object P { get => throw null!; set => throw null!; }
public static object P2 { get => throw null!; set => throw null!; }
}
}
""";
DiagnosticDescription[] expected = [
// (3,1): warning CS8602: Dereference of a possibly null reference.
// object.P.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "object.P").WithLocation(3, 1),
// (4,12): warning CS8625: Cannot convert null literal to non-nullable reference type.
// object.P = null; // 2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(4, 12),
// (7,1): warning CS8602: Dereference of a possibly null reference.
// E.get_P().ToString(); // 3
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "E.get_P()").WithLocation(7, 1),
// (8,9): warning CS8625: Cannot convert null literal to non-nullable reference type.
// E.set_P(null); // 4
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 9)
];
var comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics(expected);
var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net90);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()], targetFramework: TargetFramework.Net90);
comp2.VerifyEmitDiagnostics(expected);
CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate, verify: Verification.Skipped);
static void validate(ModuleSymbol m)
{
AssertEx.SetEqual(m is SourceModuleSymbol ? new string[] { } : ["System.Diagnostics.CodeAnalysis.MaybeNullAttribute"],
m.GlobalNamespace.GetMember<MethodSymbol>("E.get_P").GetReturnTypeAttributes().ToStrings());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P").GetReturnTypeAttributes());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P").Parameters[0].GetAttributes());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.get_P2").GetReturnTypeAttributes());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P2").GetReturnTypeAttributes());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P2").Parameters[0].GetAttributes());
}
}
[Fact]
public void Nullability_PropertyAccess_18()
{
// AllowNull
var src = """
#nullable enable
object.P.ToString();
object.P = null;
E.get_P().ToString();
E.set_P(null);
""";
var libSrc = """
public static class E
{
extension(object)
{
[property: System.Diagnostics.CodeAnalysis.AllowNull]
public static object P { get => throw null!; set => throw null!; }
public static object P2 { get => throw null!; set => throw null!; }
}
}
""";
var comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics();
var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net90);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()], targetFramework: TargetFramework.Net90);
comp2.VerifyEmitDiagnostics();
CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate, verify: Verification.Skipped);
static void validate(ModuleSymbol m)
{
AssertEx.SetEqual(m is SourceModuleSymbol ? new string[] { } : ["System.Diagnostics.CodeAnalysis.AllowNullAttribute"],
m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P").Parameters[0].GetAttributes().ToStrings());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P").GetReturnTypeAttributes());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P2").Parameters[0].GetAttributes());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P2").GetReturnTypeAttributes());
}
}
[Fact]
public void Nullability_PropertyAccess_19()
{
// DisallowNull
var src = """
#nullable enable
object.P.ToString();
object.P = null;
E.get_P().ToString();
E.set_P(null);
""";
var libSrc = """
#nullable enable
public static class E
{
extension(object)
{
[property: System.Diagnostics.CodeAnalysis.DisallowNull]
public static object? P { get => throw null!; set => throw null!; }
public static object? P2 { get => throw null!; set => throw null!; }
}
}
""";
DiagnosticDescription[] expected = [
// (3,1): warning CS8602: Dereference of a possibly null reference.
// object.P.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "object.P").WithLocation(3, 1),
// (4,12): warning CS8625: Cannot convert null literal to non-nullable reference type.
// object.P = null;
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(4, 12),
// (6,1): warning CS8602: Dereference of a possibly null reference.
// E.get_P().ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "E.get_P()").WithLocation(6, 1),
// (7,9): warning CS8625: Cannot convert null literal to non-nullable reference type.
// E.set_P(null);
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 9)
];
var comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics(expected);
var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net90);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()], targetFramework: TargetFramework.Net90);
comp2.VerifyEmitDiagnostics(expected);
CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate, verify: Verification.Skipped);
static void validate(ModuleSymbol m)
{
AssertEx.SetEqual(m is SourceModuleSymbol ? new string[] { } : ["System.Diagnostics.CodeAnalysis.DisallowNullAttribute"],
m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P").Parameters[0].GetAttributes().ToStrings());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P").GetReturnTypeAttributes());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P2").Parameters[0].GetAttributes());
Assert.Empty(m.GlobalNamespace.GetMember<MethodSymbol>("E.set_P2").GetReturnTypeAttributes());
}
}
[Fact]
public void Nullability_PropertyAccess_20()
{
// DoesNotReturn
var src = """
#nullable enable
bool b = false;
object? o = null;
if (b)
{
_ = object.P;
o.ToString(); // incorrect
}
if (b)
{
object.P = 0;
o.ToString(); // incorrect
}
if (b)
{
E.get_P();
o.ToString();
}
if (b)
{
E.set_P(0);
o.ToString();
}
""";
var libSrc = """
#nullable enable
public static class E
{
extension(object)
{
public static int P
{
[System.Diagnostics.CodeAnalysis.DoesNotReturn]
get => throw null!;
[System.Diagnostics.CodeAnalysis.DoesNotReturn]
set => throw null!;
}
}
}
""";
// Tracked by https://github.com/dotnet/roslyn/issues/50018 : DoesNotReturn not yet supported on indexers.
var comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics(
// (9,5): warning CS8602: Dereference of a possibly null reference.
// o.ToString(); // incorrect
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(9, 5),
// (15,5): warning CS8602: Dereference of a possibly null reference.
// o.ToString(); // incorrect
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(15, 5));
var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net90);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()], targetFramework: TargetFramework.Net90);
comp2.VerifyEmitDiagnostics(
// (9,5): warning CS8602: Dereference of a possibly null reference.
// o.ToString(); // incorrect
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(9, 5),
// (15,5): warning CS8602: Dereference of a possibly null reference.
// o.ToString(); // incorrect
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(15, 5));
src = """
#nullable enable
bool b = false;
object? o = null;
if (b)
{
_ = object.P;
o.ToString(); // incorrect
}
if (b)
{
object.P = 0;
o.ToString(); // incorrect
}
public static class E
{
extension(object)
{
public static int P
{
[System.Diagnostics.CodeAnalysis.DoesNotReturn]
get => throw null!;
[System.Diagnostics.CodeAnalysis.DoesNotReturn]
set => throw null!;
}
}
}
""";
comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics(
// (9,5): warning CS8602: Dereference of a possibly null reference.
// o.ToString(); // incorrect
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(9, 5),
// (15,5): warning CS8602: Dereference of a possibly null reference.
// o.ToString(); // incorrect
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(15, 5));
}
[Fact]
public void Nullability_PropertyAccess_21()
{
// NotNullWhen
var src = """
#nullable enable
object? o = null;
if (o.P)
o.ToString();
else
o.ToString(); // 1
object? o2 = null;
if (E.get_P(o2))
o2.ToString();
else
o2.ToString(); // 2
""";
var libSrc = """
#nullable enable
public static class E
{
extension([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] object? o)
{
public bool P => throw null!;
}
}
""";
DiagnosticDescription[] expected = [
// (7,5): warning CS8602: Dereference of a possibly null reference.
// o.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(7, 5),
// (13,5): warning CS8602: Dereference of a possibly null reference.
// o2.ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o2").WithLocation(13, 5)
];
var comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics(expected);
var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net90);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()], targetFramework: TargetFramework.Net90);
comp2.VerifyEmitDiagnostics(expected);
}
[Fact]
public void Nullability_PropertyAccess_22()
{
// MaybeNullWhen
var src = """
#nullable enable
object o = new object();
if (o.P)
o.ToString(); // 1
else
o.ToString();
object o2 = new object();
if (E.get_P(o2))
o2.ToString(); // 2
else
o2.ToString();
""";
var libSrc = """
#nullable enable
public static class E
{
extension([System.Diagnostics.CodeAnalysis.MaybeNullWhen(true)] object? o)
{
public bool P => throw null!;
}
}
""";
DiagnosticDescription[] expected = [
// (5,5): warning CS8602: Dereference of a possibly null reference.
// o.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o").WithLocation(5, 5),
// (11,5): warning CS8602: Dereference of a possibly null reference.
// o2.ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "o2").WithLocation(11, 5)
];
var comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics(expected);
var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net90);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()], targetFramework: TargetFramework.Net90);
comp2.VerifyEmitDiagnostics(expected);
}
[Fact]
public void Nullability_PropertyAccess_23()
{
// MemberNotNull
var src = """
#nullable enable
if (object.P)
object.P2.ToString(); // 1
else
object.P2.ToString();
if (E.get_P())
E.get_P2().ToString(); // 2
else
E.get_P2().ToString();
""";
var libSrc = """
#nullable enable
public static class E
{
extension(object)
{
[System.Diagnostics.CodeAnalysis.MemberNotNull("P2")]
public static bool P => throw null!;
public static object? P2 => throw null!;
}
}
""";
// Tracked by https://github.com/dotnet/roslyn/issues/78828 : nullability, should we extend member post-conditions to work with extension members?
DiagnosticDescription[] expected = [
// (4,5): warning CS8602: Dereference of a possibly null reference.
// object.P2.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "object.P2").WithLocation(4, 5),
// (6,5): warning CS8602: Dereference of a possibly null reference.
// object.P2.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "object.P2").WithLocation(6, 5),
// (9,5): warning CS8602: Dereference of a possibly null reference.
// E.get_P2().ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "E.get_P2()").WithLocation(9, 5),
// (11,5): warning CS8602: Dereference of a possibly null reference.
// E.get_P2().ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "E.get_P2()").WithLocation(11, 5)
];
var comp = CreateCompilation([src, libSrc], targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics(expected);
var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Net90);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()], targetFramework: TargetFramework.Net90);
comp2.VerifyEmitDiagnostics(expected);
}
[Fact]
public void Nullability_PropertyAccess_24()
{
var src = """
#nullable enable
public static class E
{
extension<T>(T t)
{
public int P { get { _ = t.P; return 42; } }
public static int P2 { get { _ = T.P2; return 42; } }
}
}
""";
var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics(
// (8,42): error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter
// public static int P2 { get { _ = T.P2; return 42; } }
Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(8, 42));
}
[Fact]
public void Nullability_NullableContext_01()
{
var src = """
#nullable enable
public static class E
{
extension(object x)
{
public static void M1(object o) { }
public static void M2(object o) { }
public static void M3(object o) { }
public static void M4(object o) { }
public static void M5(object o) { }
public static void M6(object o) { }
}
public static void N1(object? o) { }
public static void N2(object? o) { }
public static void N3(object? o) { }
}
""";
var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate, verify: Verification.Skipped).VerifyDiagnostics();
static void validate(ModuleSymbol m)
{
AssertEx.SetEqual(m is SourceModuleSymbol ? new string[] { } : ["System.Runtime.CompilerServices.NullableContextAttribute(1)", "System.Runtime.CompilerServices.NullableAttribute(0)"],
m.GlobalNamespace.GetTypeMember("E").GetAttributes().ToStrings());
}
}
[Fact]
public void Nullability_NullableContext_02()
{
var src = """
#nullable enable
public static class E
{
extension(object? x)
{
public static void M1(object? o) { }
public static void M2(object? o) { }
public static void M3(object? o) { }
public static void M4(object? o) { }
public static void M5(object? o) { }
public static void M6(object? o) { }
}
public static void N1(object o) { }
public static void N2(object o) { }
public static void N3(object o) { }
}
""";
var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate, verify: Verification.Skipped).VerifyDiagnostics();
static void validate(ModuleSymbol m)
{
AssertEx.SetEqual(m is SourceModuleSymbol ? new string[] { } : ["System.Runtime.CompilerServices.NullableContextAttribute(2)", "System.Runtime.CompilerServices.NullableAttribute(0)"],
m.GlobalNamespace.GetTypeMember("E").GetAttributes().ToStrings());
}
}
[Fact]
public void Nullability_PropertyPattern_01()
{
// return type of property
var src = """
#nullable enable
if (new object() is { P: var x })
x.ToString(); // 1
if (new object() is { P2: var x2 })
x2.ToString();
#nullable enable
public static class E
{
extension(object o)
{
public object? P => throw null!;
public object P2 => throw null!;
}
}
""";
var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics(
// (4,5): warning CS8602: Dereference of a possibly null reference.
// x.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(4, 5));
}
[Fact]
public void Nullability_PropertyPattern_02()
{
// nullability of extension parameter
var src = """
#nullable enable
object? oNull = null;
_ = oNull is { P: 0 };
object? oNull2 = null;
_ = oNull2 is { P2: 0 };
#nullable enable
public static class E
{
extension(object o)
{
public int P => throw null!;
}
extension(object? o)
{
public int P2 => throw null!;
}
}
""";
var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics();
}
[Fact]
public void Nullability_PropertyPattern_03()
{
// NotNull
var src = """
#nullable enable
if (new object() is { P: var x })
x.ToString();
if (new object() is { P2: var x2 })
x2.ToString(); // 1
if (new C() is { P3: var x3 })
x3.ToString();
public static class E
{
extension(object o)
{
[property: System.Diagnostics.CodeAnalysis.NotNull]
public object? P => throw null!;
public object? P2 => throw null!;
}
}
class C
{
[property: System.Diagnostics.CodeAnalysis.NotNull]
public object? P3 => throw null!;
}
""";
// Tracked by https://github.com/dotnet/roslyn/issues/78828 : incorrect nullability analysis for property pattern with extension property (unexpected warning)
var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics(
// (4,5): warning CS8602: Dereference of a possibly null reference.
// x.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(4, 5),
// (7,5): warning CS8602: Dereference of a possibly null reference.
// x2.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x2").WithLocation(7, 5));
}
[Fact]
public void Nullability_PropertyPattern_Reinference_01()
{
var source = """
#nullable enable
using System.Collections.Generic;
class Program
{
void M1(bool b)
{
var item = "a";
if (b)
{
item = null;
}
var list = M2(item)/*T:System.Collections.Generic.List<string?>!*/;
if (list is { First: var first })
{
first.ToString(); // 1
}
}
List<T> M2<T>(T item) => [item];
}
static class ListExtensions
{
extension<T>(List<T> list)
{
public T First => list[0];
}
}
""";
var comp = CreateCompilation(source);
comp.VerifyTypes();
comp.VerifyEmitDiagnostics(
// (17,13): warning CS8602: Dereference of a possibly null reference.
// first.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "first").WithLocation(17, 13));
}
[Fact]
public void Nullability_PropertyPattern_Reinference_02()
{
var source = """
#nullable enable
using System.Collections.Generic;
class Program
{
void M1(bool b)
{
var item = "a";
if (b)
{
item = null;
}
var list = M2(item)/*T:System.Collections.Generic.List<string?>!*/;
if (list is { First: var first }) // 1
{
first.ToString();
}
}
List<T> M2<T>(T item) => [item];
}
static class ListExtensions
{
extension(List<string> list)
{
public string First => list[0];
}
}
""";
var comp = CreateCompilation(source);
comp.VerifyTypes();
comp.VerifyEmitDiagnostics(
// (15,23): warning CS8620: Argument of type 'List<string?>' cannot be used for parameter 'list' of type 'List<string>' in 'ListExtensions.extension(List<string>)' due to differences in the nullability of reference types.
// if (list is { First: var first }) // 1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "First").WithArguments("System.Collections.Generic.List<string?>", "System.Collections.Generic.List<string>", "list", "ListExtensions.extension(List<string>)").WithLocation(15, 23));
}
[Fact]
public void Nullability_PropertyPattern_Reinference_03()
{
var source = """
#nullable enable
using System.Collections.Generic;
class Program
{
void M1(bool b)
{
var item = "a";
if (b)
{
item = null;
}
var list = M2(item)/*T:System.Collections.Generic.List<string?>!*/;
if (list is { First: var first }) // 1
{
first.ToString(); // 2
}
}
List<T> M2<T>(T item) => [item];
}
static class ListExtensions
{
extension<T>(List<T> list) where T : class
{
public T First => list[0];
}
}
""";
var comp = CreateCompilation(source);
comp.VerifyTypes();
comp.VerifyEmitDiagnostics(
// (15,23): warning CS8634: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'ListExtensions.extension<T>(List<T>)'. Nullability of type argument 'string?' doesn't match 'class' constraint.
// if (list is { First: var first }) // 1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterReferenceTypeConstraint, "First").WithArguments("ListExtensions.extension<T>(System.Collections.Generic.List<T>)", "T", "string?").WithLocation(15, 23),
// (17,13): warning CS8602: Dereference of a possibly null reference.
// first.ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "first").WithLocation(17, 13));
}
[Fact]
public void Nullability_PropertyPattern_Postcondition_01()
{
var source = """
#nullable enable
using System.Diagnostics.CodeAnalysis;
class Program
{
void M(object? obj)
{
if (obj is { AsNotNull: var notNull })
notNull.ToString();
}
}
static class Extensions
{
extension(object? obj)
{
[NotNull]
public object? AsNotNull => obj!;
}
}
""";
var comp = CreateCompilation([source, NotNullAttributeDefinition]);
// Tracked by https://github.com/dotnet/roslyn/issues/78828 : should we extend member post-conditions to work with extension members?
comp.VerifyEmitDiagnostics(
// (9,13): warning CS8602: Dereference of a possibly null reference.
// notNull.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "notNull").WithLocation(9, 13));
}
[Fact]
public void WellKnownAttribute_Conditional()
{
var src = """
object.M();
E.M();
""";
var libSrc = """
public static class E
{
extension(object)
{
[System.Diagnostics.Conditional("CONDITION")]
public static void M() { System.Console.Write("ran "); }
}
}
""";
var comp = CreateCompilation([src, libSrc]);
CompileAndVerify(comp, expectedOutput: "").VerifyDiagnostics();
var libComp = CreateCompilation(libSrc);
var comp2 = CreateCompilation(src, references: [libComp.EmitToImageReference()]);
CompileAndVerify(comp2, expectedOutput: "").VerifyDiagnostics();
var src2 = """
#define CONDITION
object.M();
E.M();
""";
comp = CreateCompilation([src2, libSrc]);
CompileAndVerify(comp, expectedOutput: "ran ran").VerifyDiagnostics();
libComp = CreateCompilation(libSrc);
comp2 = CreateCompilation(src2, references: [libComp.EmitToImageReference()]);
CompileAndVerify(comp2, expectedOutput: "ran ran").VerifyDiagnostics();
}
[Fact]
public void WellKnownAttribute_ModuleInitializer()
{
var src = """
System.Console.Write("");
public static class E
{
extension(object)
{
[System.Runtime.CompilerServices.ModuleInitializer] // 1
public static void M() => throw null;
public static int P
{
[System.Runtime.CompilerServices.ModuleInitializer] // 2
get => throw null;
}
}
}
""";
var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics(
// (7,10): error CS8813: A module initializer must be an ordinary member method
// [System.Runtime.CompilerServices.ModuleInitializer] // 1
Diagnostic(ErrorCode.ERR_ModuleInitializerMethodMustBeOrdinary, "System.Runtime.CompilerServices.ModuleInitializer").WithLocation(7, 10),
// (12,14): error CS8813: A module initializer must be an ordinary member method
// [System.Runtime.CompilerServices.ModuleInitializer] // 2
Diagnostic(ErrorCode.ERR_ModuleInitializerMethodMustBeOrdinary, "System.Runtime.CompilerServices.ModuleInitializer").WithLocation(12, 14));
}
[Fact]
public void WellKnownAttribute_UnscopedRef_01()
{
var src = """
public static class E
{
extension<T>(System.Span<T> span)
{
[System.Diagnostics.CodeAnalysis.UnscopedRef]
public ref T GetFirst() => throw null;
[System.Diagnostics.CodeAnalysis.UnscopedRef]
public ref T First => throw null;
}
}
""";
var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
comp.VerifyEmitDiagnostics(
// (5,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members.
// [System.Diagnostics.CodeAnalysis.UnscopedRef]
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "System.Diagnostics.CodeAnalysis.UnscopedRef").WithLocation(5, 10),
// (8,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members.
// [System.Diagnostics.CodeAnalysis.UnscopedRef]
Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "System.Diagnostics.CodeAnalysis.UnscopedRef").WithLocation(8, 10));
}
[Fact]
public void Ambiguity_01()
{
var src = """
var x = object.M; // 1
x();
System.Action y = object.M; // 2
static class E1
{
extension(object)
{
public static void M() { }
}
}
static class E2
{
extension(object)
{
public static int M => 0;
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (1,9): error CS9339: The extension resolution is ambiguous between the following members: 'E1.extension(object).M()' and 'E2.extension(object).M'
// var x = object.M; // 1
Diagnostic(ErrorCode.ERR_AmbigExtension, "object.M").WithArguments("E1.extension(object).M()", "E2.extension(object).M").WithLocation(1, 9),
// (4,19): error CS9339: The extension resolution is ambiguous between the following members: 'E1.extension(object).M()' and 'E2.extension(object).M'
// System.Action y = object.M; // 2
Diagnostic(ErrorCode.ERR_AmbigExtension, "object.M").WithArguments("E1.extension(object).M()", "E2.extension(object).M").WithLocation(4, 19));
src = """
var x = I.M; // binds to I1.M (method)
x();
System.Action y = I.M; // binds to I1.M (method)
y();
interface I1 { static void M() { System.Console.Write("I1.M() "); } }
interface I2 { static int M => 0; }
interface I3 { static int M = 0; }
interface I : I1, I2, I3 { }
""";
comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
CompileAndVerify(comp, expectedOutput: ExpectedOutput("I1.M() I1.M()"), verify: Verification.Skipped).VerifyDiagnostics();
src = """
I i = new C();
var x = i.M; // binds to I1.M (method)
x();
System.Action y = i.M; // binds to I1.M (method)
y();
interface I1 { void M() { System.Console.Write("I1.M() "); } }
interface I2 { int M => 0; }
interface I : I1, I2 { }
class C : I { }
""";
comp = CreateCompilation(src, targetFramework: TargetFramework.Net90);
CompileAndVerify(comp, expectedOutput: ExpectedOutput("I1.M() I1.M()"), verify: Verification.Skipped).VerifyDiagnostics();
}
[Fact]
public void CS1943ERR_QueryTypeInferenceFailedSelectMany()
{
// ReportQueryInferenceFailedSelectMany
var comp = CreateCompilation("""
using System;
using System.Collections.Generic;
class Test
{
class TestClass
{ }
static void Main()
{
int[] nums = { 0, 1, 2, 3, 4, 5 };
TestClass tc = new TestClass();
var x = from n in nums
from s in tc // CS1943
select n + s;
}
}
static class E
{
extension<TSource>(IEnumerable<TSource> source)
{
public IEnumerable<TResult> SelectMany<TCollection, TResult>(
Func<TSource, IEnumerable<TCollection>> collectionSelector,
Func<TSource, TCollection,TResult> resultSelector)
=> throw null;
}
}
""");
comp.VerifyEmitDiagnostics(
// (13,27): error CS1943: An expression of type 'Test.TestClass' is not allowed in a subsequent from clause in a query expression with source type 'int[]'. Type inference failed in the call to 'SelectMany'.
// tc
Diagnostic(ErrorCode.ERR_QueryTypeInferenceFailedSelectMany, "tc").WithArguments("Test.TestClass", "int[]", "SelectMany"));
}
[Fact]
public void Foreach_Extension_01()
{
var src = """
class Program
{
public static void M(Buffer4<int> x)
{
foreach(var s in x)
{
}
}
}
namespace System
{
public readonly ref struct Span<T>
{
}
}
static class Ext
{
extension<T>(System.Span<T> f)
{
public Enumerator<T> GetEnumerator() => default;
}
public ref struct Enumerator<T>
{
public ref T Current => throw null;
public bool MoveNext() => false;
}
}
[System.Runtime.CompilerServices.InlineArray(4)]
public struct Buffer4<T>
{
private T _element0;
}
""";
var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseDll);
comp.VerifyEmitDiagnostics(
// (5,26): error CS9189: foreach statement on an inline array of type 'Buffer4<int>' is not supported
// foreach(var s in x)
Diagnostic(ErrorCode.ERR_InlineArrayForEachNotSupported, "x").WithArguments("Buffer4<int>").WithLocation(5, 26),
// (20,25): warning CS0436: The type 'Span<T>' in '' conflicts with the imported type 'Span<T>' in 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Using the type defined in ''.
// extension<T>(System.Span<T> f)
Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "Span<T>").WithArguments("", "System.Span<T>", "System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Span<T>").WithLocation(20, 25)
);
}
[Fact]
public void DelegateCreation_01()
{
var src = """
string s;
_ = new System.Action(s.M);
string s2;
_ = new System.Action(s2.M2);
_ = new System.Action(string.M2);
static class E
{
extension(string s)
{
public void M() { }
public static void M2() { }
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (2,23): error CS0165: Use of unassigned local variable 's'
// _ = new System.Action(s.M);
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(2, 23),
// (4,8): warning CS0168: The variable 's2' is declared but never used
// string s2;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "s2").WithArguments("s2").WithLocation(4, 8),
// (5,23): error CS0176: Member 'E.extension(string).M2()' cannot be accessed with an instance reference; qualify it with a type name instead
// _ = new System.Action(s2.M2);
Diagnostic(ErrorCode.ERR_ObjectProhibited, "s2.M2").WithArguments("E.extension(string).M2()").WithLocation(5, 23));
}
[Fact]
public void AsyncMethodBuilder_01()
{
var src = """
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
Console.Write(await object.M());
static class C
{
extension(object)
{
[AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))]
public static async MyTask<int> M() { await Task.Yield(); Console.Write("M "); return 3; }
}
}
public class MyTask<T>
{
private Action _continuation;
private bool _isCompleted;
internal T _result;
public Awaiter GetAwaiter() => new Awaiter(this);
public T Result => _result;
internal void Complete(T result)
{
_result = result;
_isCompleted = true;
_continuation?.Invoke();
}
public readonly struct Awaiter : ICriticalNotifyCompletion
{
private readonly MyTask<T> _task;
internal Awaiter(MyTask<T> task) => _task = task;
public bool IsCompleted => _task._isCompleted;
public T GetResult() => _task._result;
public void OnCompleted(Action cont) => HandleCompletion(cont);
public void UnsafeOnCompleted(Action cont) => HandleCompletion(cont);
private void HandleCompletion(Action cont)
{
if (_task._isCompleted) { cont(); return; }
_task._continuation = cont;
}
}
}
public struct MyTaskMethodBuilder<T>
{
private readonly MyTask<T> _task;
private MyTaskMethodBuilder(MyTask<T> task) => _task = task;
public static MyTaskMethodBuilder<T> Create() => new MyTaskMethodBuilder<T>(new MyTask<T>());
public MyTask<T> Task => _task;
public void Start<TSM>(ref TSM sm) where TSM : IAsyncStateMachine => sm.MoveNext();
public void SetStateMachine(IAsyncStateMachine _) { }
public void SetResult(T result) => _task.Complete(result);
public void SetException(Exception e) => throw null;
public void AwaitOnCompleted<TA, TSM>(ref TA a, ref TSM sm) where TA : INotifyCompletion where TSM: IAsyncStateMachine => a.OnCompleted(sm.MoveNext);
public void AwaitUnsafeOnCompleted<TA, TSM>(ref TA a, ref TSM sm) where TA : ICriticalNotifyCompletion where TSM: IAsyncStateMachine => a.UnsafeOnCompleted(sm.MoveNext);
}
namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } }
""";
var comp = CreateCompilation(src);
CompileAndVerify(comp, expectedOutput: "M 3").VerifyDiagnostics();
}
[Fact]
public void PEMethodSymbol_GetUseSiteInfo()
{
// missing implementation method for M
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$F4B4FFE41AB49E80A4ECF390CF6EB372'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34
46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43
46 33 39 30 43 46 36 45 42 33 37 32 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0570: 'E.extension(int).M()' is not supported by the language
// int.M();
Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension(int).M()").WithLocation(1, 5));
}
[Fact]
public void Retargeting_01()
{
var libSrc = """
public static class E
{
extension(object)
{
public static void M() { }
}
}
namespace System.Runtime.CompilerServices
{
public class ExtensionAttribute : System.Attribute {}
}
""";
var libComp = CreateCompilation(libSrc, targetFramework: TargetFramework.Mscorlib40);
var src = """
object.M();
""";
var comp = CreateCompilation(src, targetFramework: TargetFramework.Mscorlib46, references: [libComp.ToMetadataReference()]);
comp.VerifyEmitDiagnostics();
var extension = comp.GlobalNamespace.GetTypeMember("E").GetTypeMembers().Single();
Assert.IsType<RetargetingNamedTypeSymbol>(extension);
AssertExtensionDeclaration(extension.GetPublicSymbol());
}
[Theory]
[InlineData("public")]
[InlineData("assembly")]
[InlineData("family")]
public void PENamedTypeSymbol_01(string accessibility)
{
// Accessibility of extension marker is not private
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = $$"""
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method {{accessibility}} hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics();
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var invocation = GetSyntax<InvocationExpressionSyntax>(tree, "int.M()");
Assert.Equal("void E.<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M()", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
}
[Fact]
public void PENamedTypeSymbol_03()
{
// Extension marker method is generic
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$F4B4FFE41AB49E80A4ECF390CF6EB372'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$'<T> ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 46 34 42 34
46 46 45 34 31 41 42 34 39 45 38 30 41 34 45 43
46 33 39 30 43 46 36 45 42 33 37 32 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0117: 'int' does not contain a definition for 'M'
// int.M();
Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5));
}
[Fact]
public void PENamedTypeSymbol_04()
{
// Extension marker method is not static
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0117: 'int' does not contain a definition for 'M'
// int.M();
Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5));
}
[Fact]
public void PENamedTypeSymbol_05()
{
// Extension marker doesn't return void
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static int32 '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ldc.i4.0
IL_0001: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0117: 'int' does not contain a definition for 'M'
// int.M();
Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5));
}
[Fact]
public void PENamedTypeSymbol_06()
{
// Extension marker lacks its parameter
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' () cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0117: 'int' does not contain a definition for 'M'
// int.M();
Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5));
}
[Fact]
public void PENamedTypeSymbol_07()
{
// Extension marker has an extra parameter
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '', string s ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0117: 'int' does not contain a definition for 'M'
// int.M();
Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5));
}
[Fact]
public void PENamedTypeSymbol_08()
{
// No containing type
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0117: 'int' does not contain a definition for 'M'
// int.M();
Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5));
var extension = comp.GlobalNamespace.GetTypeMember("<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69");
Assert.False(extension.IsExtension);
}
[Fact]
public void PENamedTypeSymbol_09()
{
// Two extension marker methods
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
.method public hidebysig specialname static void '<Extension>$' ( string s ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0117: 'int' does not contain a definition for 'M'
// int.M();
Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5));
}
[Fact]
public void PENamedTypeSymbol_10()
{
// Arity mismatch between extension member and implementation
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M<T> () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0570: 'E.extension(int).M()' is not supported by the language
// int.M();
Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension(int).M()").WithLocation(1, 5));
}
[Fact]
public void PENamedTypeSymbol_11()
{
// Accessibility mismatch between extension and implementation members
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method assembly hidebysig static void M () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0570: 'E.extension(int).M()' is not supported by the language
// int.M();
Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension(int).M()").WithLocation(1, 5));
}
[Fact]
public void PENamedTypeSymbol_12()
{
// parameter count mismatch between extension and implementation members
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M ( string s ) cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0570: 'E.extension(int).M()' is not supported by the language
// int.M();
Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension(int).M()").WithLocation(1, 5));
}
[Fact]
public void PENamedTypeSymbol_13()
{
// return type mismatch between extension and implementation members
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static int32 M () cil managed
{
IL_0000: ldnull
IL_0001: throw
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0570: 'E.extension(int).M()' is not supported by the language
// int.M();
Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension(int).M()").WithLocation(1, 5));
}
[Fact]
public void PENamedTypeSymbol_14()
{
// parameter type mismatch, instance method
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 i ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig instance void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M ( object i ) cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
42.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,4): error CS0570: 'E.extension(int).M()' is not supported by the language
// 42.M();
Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension(int).M()").WithLocation(1, 4));
}
[Fact]
public void PENamedTypeSymbol_15()
{
// parameter type mismatch, instance method
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig instance void M ( string s ) cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M ( int32 i, object s ) cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
42.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,4): error CS0570: 'E.extension(int).M(string)' is not supported by the language
// 42.M();
Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension(int).M(string)").WithLocation(1, 4));
}
[Fact]
public void PENamedTypeSymbol_16()
{
// constraint mismatch between extension and implementation members
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M<T> () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M<class T> () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0570: 'E.extension(int).M<T>()' is not supported by the language
// int.M();
Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension(int).M<T>()").WithLocation(1, 5));
var method = comp.GlobalNamespace.GetTypeMember("E").GetTypeMembers().Single().GetMember<MethodSymbol>("M").GetPublicSymbol();
Assert.Null(method.AssociatedExtensionImplementation);
}
[Fact]
public void PENamedTypeSymbol_17()
{
// implementation is not static
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig instance void M () cil managed
{
IL_0000: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0570: 'E.extension(int).M()' is not supported by the language
// int.M();
Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension(int).M()").WithLocation(1, 5));
}
[Fact]
public void PENamedTypeSymbol_18()
{
// grouping type is not sealed
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0117: 'int' does not contain a definition for 'M'
// int.M();
Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5));
Assert.False(comp.GetTypeByMetadataName("E").GetTypeMembers().Single().IsExtension);
}
[Theory]
[InlineData("assembly")]
[InlineData("family")]
public void PENamedTypeSymbol_19(string accessibility)
{
// grouping type is not public
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = $$"""
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested {{accessibility}} auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0117: 'int' does not contain a definition for 'M'
// int.M();
Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5));
Assert.False(comp.GetTypeByMetadataName("E").GetTypeMembers().Single().IsExtension);
}
[Fact]
public void PENamedTypeSymbol_21()
{
// grouping type has a base that's not object
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.String
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0117: 'int' does not contain a definition for 'M'
// int.M();
Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5));
Assert.False(comp.GetTypeByMetadataName("E").GetTypeMembers().Single().IsExtension);
}
[Fact]
public void PENamedTypeSymbol_22()
{
// grouping type implements an interface
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
implements I
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
.class interface private auto ansi abstract beforefieldinit I
{
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0117: 'int' does not contain a definition for 'M'
// int.M();
Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5));
Assert.False(comp.GetTypeByMetadataName("E").GetTypeMembers().Single().IsExtension);
}
[Fact]
public void PENamedTypeSymbol_23()
{
// parameter type mismatch, static method
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M ( string s ) cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M ( object s ) cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0570: 'E.extension(int).M(string)' is not supported by the language
// int.M();
Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension(int).M(string)").WithLocation(1, 5));
}
[Fact]
public void PENamedTypeSymbol_24()
{
// attributes on grouping and marker types or marker method are not loaded
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void MyAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends [mscorlib]System.Object
{
.custom instance void MyAttribute::.ctor() = ( 01 00 00 00 )
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void MyAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: ret
}
}
.class public auto ansi beforefieldinit MyAttribute
extends [mscorlib]System.Attribute
{
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
IL_0000: ldnull
IL_0001: throw
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics();
var extension = (PENamedTypeSymbol)comp.GetMember<NamedTypeSymbol>("E").GetTypeMembers().Single();
AssertEx.Equal("E.<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69", extension.ToTestDisplayString());
AssertEx.SetEqual([], extension.GetAttributes().Select(a => a.ToString()));
Assert.Equal("", extension.Name);
AssertEx.Equal("<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69", extension.MetadataName);
}
[Fact]
public void PENamedTypeSymbol_25()
{
var libSrc = """
public static class E
{
extension<T>(T)
{
public static void M() { }
}
}
""";
var libComp = CreateCompilation(libSrc);
var src = """
int.M();
""";
var comp = CreateCompilation(src, references: [libComp.EmitToImageReference()]);
comp.VerifyEmitDiagnostics();
var extension = (PENamedTypeSymbol)comp.GetMember<NamedTypeSymbol>("E").GetTypeMembers().Single();
Assert.True(extension.IsExtension);
Assert.Equal("<G>$8048A6C8BE30A622530249B904B537EB", extension.ExtensionGroupingName);
Assert.Equal("<M>$01CE3801593377B4E240F33E20D30D50", extension.ExtensionMarkerName);
AssertEx.Equal("E.<G>$8048A6C8BE30A622530249B904B537EB<T>.<M>$01CE3801593377B4E240F33E20D30D50", extension.ToTestDisplayString());
Assert.Equal("", extension.Name);
AssertEx.Equal("<M>$01CE3801593377B4E240F33E20D30D50", extension.MetadataName);
Assert.False(extension.MangleName);
}
[Fact]
public void PENamedTypeSymbol_26()
{
// marker type has different arity than grouping type
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$8048A6C8BE30A622530249B904B537EB'<$T0>
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$2789E59A55056F0AD9E820EBD5BCDFBF'<T, U>
extends System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( !T '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 32 37 38 39
45 35 39 41 35 35 30 35 36 46 30 41 44 39 45 38
32 30 45 42 44 35 42 43 44 46 42 46 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M<T> () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0117: 'int' does not contain a definition for 'M'
// int.M();
Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("int", "M").WithLocation(1, 5));
Assert.Empty(comp.GetMember<NamedTypeSymbol>("E").GetTypeMembers());
}
[Fact]
public void PENamedTypeSymbol_27()
{
// marker type has different type constraints than grouping type
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$8048A6C8BE30A622530249B904B537EB'<$T0>
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$2789E59A55056F0AD9E820EBD5BCDFBF'<class T>
extends System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( !T '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 32 37 38 39
45 35 39 41 35 35 30 35 36 46 30 41 44 39 45 38
32 30 45 42 44 35 42 43 44 46 42 46 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M<T> () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0570: 'E.extension<T>(T).M()' is not supported by the language
// int.M();
Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension<T>(T).M()").WithLocation(1, 5));
var extension = (PENamedTypeSymbol)comp.GetMember<NamedTypeSymbol>("E").GetTypeMembers().Single();
Assert.True(extension.IsExtension);
}
[Fact]
public void PENamedTypeSymbol_28()
{
// implementation method has different type constraints than grouping and marker type
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$8048A6C8BE30A622530249B904B537EB'<$T0>
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$2789E59A55056F0AD9E820EBD5BCDFBF'<T>
extends System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( !T '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 32 37 38 39
45 35 39 41 35 35 30 35 36 46 30 41 44 39 45 38
32 30 45 42 44 35 42 43 44 46 42 46 00 00
)
IL_0000: ldnull
IL_0001: throw
}
}
.method public hidebysig static void M<class T> () cil managed
{
IL_0000: nop
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (1,5): error CS0570: 'E.extension<T>(T).M()' is not supported by the language
// int.M();
Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("E.extension<T>(T).M()").WithLocation(1, 5));
var extension = (PENamedTypeSymbol)comp.GetMember<NamedTypeSymbol>("E").GetTypeMembers().Single();
Assert.True(extension.IsExtension);
}
[Fact]
public void PENamedTypeSymbol_29()
{
// nested types in grouping and marker types not loaded
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
.class nested public auto ansi beforefieldinit Nested1
extends System.Object
{
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
IL_0000: ldnull
IL_0001: throw
}
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
.class nested public auto ansi beforefieldinit Nested2
extends System.Object
{
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
IL_0000: ldnull
IL_0001: throw
}
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics();
var extension = (PENamedTypeSymbol)comp.GetMember<NamedTypeSymbol>("E").GetTypeMembers().Single();
Assert.True(extension.IsExtension);
Assert.Empty(extension.GetTypeMembers());
}
[Fact]
public void PENamedTypeSymbol_30()
{
// fields in grouping and marker types not loaded
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
.field public static int32 'field'
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
.field public static int32 'field'
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
}
.method public hidebysig static void M () cil managed
{
IL_0000: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics();
var extension = (PENamedTypeSymbol)comp.GetMember<NamedTypeSymbol>("E").GetTypeMembers().Single();
Assert.True(extension.IsExtension);
AssertEx.Equal(["void E.<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M()"], extension.GetMembers().ToTestDisplayStrings());
}
[Fact]
public void PENamedTypeSymbol_31()
{
// method from grouping or marker type not loaded
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
.method public hidebysig static void Method1 () cil managed
{
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
.method public hidebysig static void Method2 () cil managed
{
IL_0000: ret
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: ret
}
.method public hidebysig static void Method1 () cil managed
{
IL_0000: ret
}
.method public hidebysig static void Method2 () cil managed
{
IL_0000: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
int.Method1();
int.Method2();
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (2,5): error CS0117: 'int' does not contain a definition for 'Method1'
// int.Method1();
Diagnostic(ErrorCode.ERR_NoSuchMember, "Method1").WithArguments("int", "Method1").WithLocation(2, 5),
// (3,5): error CS0117: 'int' does not contain a definition for 'Method2'
// int.Method2();
Diagnostic(ErrorCode.ERR_NoSuchMember, "Method2").WithArguments("int", "Method2").WithLocation(3, 5));
var extension = (PENamedTypeSymbol)comp.GetMember<NamedTypeSymbol>("E").GetTypeMembers().Single();
Assert.True(extension.IsExtension);
AssertEx.Equal(["void E.<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M()"], extension.GetMembers().ToTestDisplayStrings());
}
[Fact]
public void PENamedTypeSymbol_32()
{
// property in grouping or marker type not loaded
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
IL_0000: ret
}
.method public hidebysig specialname static int32 get_P1 () cil managed
{
IL_0000: ldc.i4.0
IL_0001: ret
}
.property int32 P1()
{
.get int32 E/'<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'/'<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P1()
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
IL_0000: ldnull
IL_0001: throw
}
.method public hidebysig specialname static int32 get_P2 () cil managed
{
IL_0000: ldc.i4.0
IL_0001: ret
}
.property int32 P2()
{
.get int32 E/'<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::get_P2()
}
}
.method public hidebysig static void M () cil managed
{
IL_0000: ret
}
.method public hidebysig static int32 get_P1 () cil managed
{
IL_0000: ldc.i4.0
IL_0001: ret
}
.method public hidebysig static int32 get_P2 () cil managed
{
IL_0000: ldc.i4.0
IL_0001: ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
_ = int.P1;
_ = int.P2;
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (2,9): error CS0117: 'int' does not contain a definition for 'P1'
// _ = int.P1;
Diagnostic(ErrorCode.ERR_NoSuchMember, "P1").WithArguments("int", "P1").WithLocation(2, 9),
// (3,9): error CS0117: 'int' does not contain a definition for 'P2'
// _ = int.P2;
Diagnostic(ErrorCode.ERR_NoSuchMember, "P2").WithArguments("int", "P2").WithLocation(3, 9));
var extension = (PENamedTypeSymbol)comp.GetMember<NamedTypeSymbol>("E").GetTypeMembers().Single();
Assert.True(extension.IsExtension);
AssertEx.Equal(["void E.<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M()"], extension.GetMembers().ToTestDisplayStrings());
}
[Fact]
public void PENamedTypeSymbol_33()
{
// event from grouping or marker type not loaded
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
ret
}
.method public hidebysig specialname static void add_Event1 ( class [mscorlib]System.Action 'value' ) cil managed
{
ret
}
.method public hidebysig specialname static void remove_Event1 ( class [mscorlib]System.Action 'value' ) cil managed
{
ret
}
.event [mscorlib]System.Action Event1
{
.addon void E/'<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'/'<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::add_Event1(class [mscorlib]System.Action)
.removeon void E/'<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'/'<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::remove_Event1(class [mscorlib]System.Action)
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
ldnull
throw
}
.method public hidebysig specialname static void add_Event2 ( class [mscorlib]System.Action 'value' ) cil managed
{
ret
}
.method public hidebysig specialname static void remove_Event2 ( class [mscorlib]System.Action 'value' ) cil managed
{
ret
}
.event [mscorlib]System.Action Event2
{
.addon void E/'<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::add_Event2(class [mscorlib]System.Action)
.removeon void E/'<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::remove_Event2(class [mscorlib]System.Action)
}
}
.method public hidebysig static void M () cil managed
{
ret
}
.method public hidebysig specialname static void add_Event1 ( class [mscorlib]System.Action 'value' ) cil managed
{
ret
}
.method public hidebysig specialname static void remove_Event1 ( class [mscorlib]System.Action 'value' ) cil managed
{
ret
}
.method public hidebysig specialname static void add_Event2 ( class [mscorlib]System.Action 'value' ) cil managed
{
ret
}
.method public hidebysig specialname static void remove_Event2 ( class [mscorlib]System.Action 'value' ) cil managed
{
ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
int.Event1 += (System.Action)null;
int.Event2 += (System.Action)null;
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (2,5): error CS0117: 'int' does not contain a definition for 'Event1'
// int.Event1 += (System.Action)null;
Diagnostic(ErrorCode.ERR_NoSuchMember, "Event1").WithArguments("int", "Event1").WithLocation(2, 5),
// (3,5): error CS0117: 'int' does not contain a definition for 'Event2'
// int.Event2 += (System.Action)null;
Diagnostic(ErrorCode.ERR_NoSuchMember, "Event2").WithArguments("int", "Event2").WithLocation(3, 5));
var extension = (PENamedTypeSymbol)comp.GetMember<NamedTypeSymbol>("E").GetTypeMembers().Single();
Assert.True(extension.IsExtension);
AssertEx.Equal(["void E.<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M()"], extension.GetMembers().ToTestDisplayStrings());
}
[Fact]
public void PENamedTypeSymbol_34()
{
// event from grouping type not loaded, even with ExtensionMarkerAttribute
// Note: the grouping and marker types and attributes use a previous naming convention (which doesn't affect metadata loading)
var ilSrc = """
.class public auto ansi abstract sealed beforefieldinit E
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi sealed specialname '<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
.class nested public auto ansi abstract sealed specialname '<Marker>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'
extends System.Object
{
.method public hidebysig specialname static void '<Extension>$' ( int32 '' ) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
ret
}
}
.method public hidebysig static void M () cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
ldnull
throw
}
.method public hidebysig specialname static void add_Event2 ( class [mscorlib]System.Action 'value' ) cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
ret
}
.method public hidebysig specialname static void remove_Event2 ( class [mscorlib]System.Action 'value' ) cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
ret
}
.event [mscorlib]System.Action Event2
{
.custom instance void System.Runtime.CompilerServices.ExtensionMarkerAttribute::.ctor(string) = (
01 00 29 3c 4d 61 72 6b 65 72 3e 24 42 41 34 31
43 46 45 32 42 35 45 44 41 45 42 38 43 31 42 39
30 36 32 46 35 39 45 44 34 44 36 39 00 00
)
.addon void E/'<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::add_Event2(class [mscorlib]System.Action)
.removeon void E/'<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69'::remove_Event2(class [mscorlib]System.Action)
}
}
.method public hidebysig static void M () cil managed
{
ret
}
.method public hidebysig specialname static void add_Event2 ( class [mscorlib]System.Action 'value' ) cil managed
{
ret
}
.method public hidebysig specialname static void remove_Event2 ( class [mscorlib]System.Action 'value' ) cil managed
{
ret
}
}
""" + ExtensionMarkerAttributeIL;
var src = """
int.M();
int.Event2 += (System.Action)null;
""";
var comp = CreateCompilationWithIL(src, ilSrc);
comp.VerifyEmitDiagnostics(
// (2,5): error CS0117: 'int' does not contain a definition for 'Event2'
// int.Event2 += (System.Action)null;
Diagnostic(ErrorCode.ERR_NoSuchMember, "Event2").WithArguments("int", "Event2").WithLocation(2, 5));
var extension = (PENamedTypeSymbol)comp.GetMember<NamedTypeSymbol>("E").GetTypeMembers().Single();
Assert.True(extension.IsExtension);
AssertEx.Equal([
"void E.<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M()",
"void E.<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.add_Event2(System.Action value)",
"void E.<Extension>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.remove_Event2(System.Action value)"
], extension.GetMembers().ToTestDisplayStrings());
}
[Fact]
public void RefReadonlyExtensionParameterWithOneExplicitRefArgument()
{
var src = """
int i = 0;
42.Copy(ref i);
System.Console.Write(i);
static class E
{
extension(ref readonly int i)
{
public void Copy(ref int j) { j = i; }
}
}
""";
var comp = CreateCompilation(src);
CompileAndVerify(comp, expectedOutput: "42");
}
[Fact]
public void Cref_01()
{
var src = """
/// <see cref="E.extension(int).M(string)"/>
/// <see cref="E.M(int, string)"/>
/// <see cref="E.extension(int).M"/>
/// <see cref="E.M"/>
static class E
{
extension(int i)
{
/// <see cref="M(int, string)"/>
/// <see cref="M(string)"/>
/// <see cref="M"/>
public void M(string s) => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (10,24): warning CS1574: XML comment has cref attribute 'M(string)' that could not be resolved
// /// <see cref="M(string)"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "M(string)").WithArguments("M(string)").WithLocation(10, 24));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M(System.String)"/>
<see cref="M:E.M(System.Int32,System.String)"/>
<see cref="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M(System.String)"/>
<see cref="M:E.M(System.Int32,System.String)"/>
</member>
""", e.GetDocumentationCommentXml());
AssertEx.Equal("T:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.<M>$F4B4FFE41AB49E80A4ECF390CF6EB372",
e.GetTypeMembers().Single().GetDocumentationCommentId());
var mSkeleton = comp.GetMember<NamedTypeSymbol>("E").GetTypeMembers().Single().GetMember("M");
AssertEx.Equal("""
<member name="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M(System.String)">
<see cref="M:E.M(System.Int32,System.String)"/>
<see cref="!:M(string)"/>
<see cref="M:E.M(System.Int32,System.String)"/>
</member>
""", mSkeleton.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.Equal([
"(E.extension(int).M(string), void E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M(System.String s))",
"(E.M(int, string), void E.M(this System.Int32 i, System.String s))",
"(E.extension(int).M, void E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M(System.String s))",
"(E.M, void E.M(this System.Int32 i, System.String s))",
"(M(int, string), void E.M(this System.Int32 i, System.String s))",
"(M(string), null)",
"(M, void E.M(this System.Int32 i, System.String s))"],
PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_02()
{
var src = """
/// <see cref="E.extension{T}(T).M{U}(U)"/>
static class E
{
extension<T>(T t)
{
public void M<U>(U u) => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M``1(``0)"/>
</member>
""", e.GetDocumentationCommentXml());
AssertEx.Equal("T:E.<G>$8048A6C8BE30A622530249B904B537EB`1.<M>$D1693D81A12E8DED4ED68FE22D9E856F",
e.GetTypeMembers().Single().GetDocumentationCommentId());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension{T}(T).M{U}(U), void E.<G>$8048A6C8BE30A622530249B904B537EB<T>.M<U>(U u))"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_03()
{
var src = """
/// <see cref="E.extension(ref int).M()"/>
static class E
{
extension(int i)
{
public void M() => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1574: XML comment has cref attribute 'extension(ref int).M()' that could not be resolved
// /// <see cref="E.extension(ref int).M()"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension(ref int).M()").WithArguments("extension(ref int).M()").WithLocation(1, 16));
}
[Fact]
public void Cref_04()
{
var src = """
/// <see cref="E.extension(ref int).M()"/>
/// <see cref="E.extension(int).M()"/>
static class E
{
extension(ref int i)
{
public void M() => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (2,16): warning CS1574: XML comment has cref attribute 'extension(int).M()' that could not be resolved
// /// <see cref="E.extension(int).M()"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension(int).M()").WithArguments("extension(int).M()").WithLocation(2, 16));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M"/>
<see cref="!:E.extension(int).M()"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.Equal([
"(E.extension(ref int).M(), void E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M())",
"(E.extension(int).M(), null)"],
PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_05()
{
var src = """
/// <see cref="E.extension(int).M()"/>
static class E
{
extension(int i)
{
public void M() => throw null!;
}
extension(string s)
{
public void M() => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(int).M(), void E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M())"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_06()
{
var src = """
/// <see cref="E.extension(int).M()"/>
/// <see cref="E.extension(int).M"/>
static class E
{
extension(int i)
{
public void M() => throw null!;
}
extension(int)
{
public static void M() => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS0419: Ambiguous reference in cref attribute: 'E.extension(int).M()'. Assuming 'E.extension(int).M()', but could have also matched other overloads including 'E.extension(int).M()'.
// /// <see cref="E.extension(int).M()"/>
Diagnostic(ErrorCode.WRN_AmbiguousXMLReference, "E.extension(int).M()").WithArguments("E.extension(int).M()", "E.extension(int).M()", "E.extension(int).M()").WithLocation(1, 16),
// (2,16): warning CS0419: Ambiguous reference in cref attribute: 'E.extension(int).M'. Assuming 'E.extension(int).M()', but could have also matched other overloads including 'E.extension(int).M()'.
// /// <see cref="E.extension(int).M"/>
Diagnostic(ErrorCode.WRN_AmbiguousXMLReference, "E.extension(int).M").WithArguments("E.extension(int).M", "E.extension(int).M()", "E.extension(int).M()").WithLocation(2, 16),
// (11,28): error CS0111: Type 'E' already defines a member called 'M' with the same parameter types
// public static void M() => throw null!;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "E").WithLocation(11, 28));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M"/>
<see cref="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.Equal([
"(E.extension(int).M(), null)",
"(E.extension(int).M, null)"],
PrintXmlCrefSymbols(tree, model));
var docComments = tree.GetCompilationUnitRoot().DescendantTrivia().Select(trivia => trivia.GetStructure()).OfType<DocumentationCommentTriviaSyntax>();
var crefs = docComments.SelectMany(doc => doc.DescendantNodes().OfType<XmlCrefAttributeSyntax>()).ToArray();
Assert.Equal(CandidateReason.OverloadResolutionFailure, model.GetSymbolInfo(crefs[0].Cref).CandidateReason);
Assert.Equal(CandidateReason.Ambiguous, model.GetSymbolInfo(crefs[1].Cref).CandidateReason);
}
[Fact]
public void Cref_08()
{
var src = """
/// <see cref="E.extension(int).M()"/>
static class E
{
extension(int i, int j)
{
public void M() => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (4,22): error CS9285: An extension container can have only one receiver parameter
// extension(int i, int j)
Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "int j").WithLocation(4, 22));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(int).M(), void E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M())"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_09()
{
var src = """
/// <see cref="E.extension(int, int).M()"/>
static class E
{
extension(int i, int j)
{
public void M() => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1574: XML comment has cref attribute 'extension(int, int).M()' that could not be resolved
// /// <see cref="E.extension(int, int).M()"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension(int, int).M()").WithArguments("extension(int, int).M()").WithLocation(1, 16),
// (4,22): error CS9285: An extension container can have only one receiver parameter
// extension(int i, int j)
Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "int j").WithLocation(4, 22));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="!:E.extension(int, int).M()"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(int, int).M(), null)"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_10()
{
// Missing closing parens
var src = """
/// <see cref="E.extension(.M()"/>
static class E
{
extension(int i)
{
public void M() => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1584: XML comment has syntactically incorrect cref attribute 'E.extension(.M()'
// /// <see cref="E.extension(.M()"/>
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "E.extension(.M()").WithArguments("E.extension(.M()").WithLocation(1, 16),
// (1,28): warning CS1658: ) expected. See also error CS1026.
// /// <see cref="E.extension(.M()"/>
Diagnostic(ErrorCode.WRN_ErrorOverride, ".").WithArguments(") expected", "1026").WithLocation(1, 28));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="!:E.extension(.M()"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(.M(), null)"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_11()
{
// Missing extension parameter
var src = """
/// <see cref="E.extension().M()"/>
static class E
{
extension(int i)
{
public void M() => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1574: XML comment has cref attribute 'extension().M()' that could not be resolved
// /// <see cref="E.extension().M()"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension().M()").WithArguments("extension().M()").WithLocation(1, 16));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="!:E.extension().M()"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension().M(), null)"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_12()
{
// Two extension parameters
var src = """
/// <see cref="E.extension(int, int).M()"/>
static class E
{
extension(int i, int j)
{
public void M() => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1574: XML comment has cref attribute 'extension(int, int).M()' that could not be resolved
// /// <see cref="E.extension(int, int).M()"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension(int, int).M()").WithArguments("extension(int, int).M()").WithLocation(1, 16),
// (4,22): error CS9285: An extension container can have only one receiver parameter
// extension(int i, int j)
Diagnostic(ErrorCode.ERR_ReceiverParameterOnlyOne, "int j").WithLocation(4, 22));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="!:E.extension(int, int).M()"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(int, int).M(), null)"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_13()
{
var src = """
/// <see cref="E.extension(int).P"/>
static class E
{
extension(int i)
{
public int P => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="P:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.P"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(int).P, System.Int32 E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.P { get; })"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_14()
{
var src = """
/// <see cref="E.extension(int).P"/>
static class E
{
extension(int i)
{
public int P => throw null!;
}
extension(string s)
{
public string P => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="P:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.P"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(int).P, System.Int32 E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.P { get; })"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_15()
{
var src = """
/// <see cref="E.extension(string).P"/>
static class E
{
extension(int i)
{
public int P => throw null!;
}
extension(string s)
{
public string P => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="P:E.<G>$34505F560D9EACF86A87F3ED1F85E448.P"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(string).P, System.String E.<G>$34505F560D9EACF86A87F3ED1F85E448.P { get; })"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_16()
{
var src = """
/// <see cref="E.extension(int).M"/>
static class E
{
extension(int i)
{
public void M() => throw null;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(int).M, void E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M())"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_17()
{
var src = """
/// <see cref="E.extension(string).M"/>
static class E
{
extension(int i)
{
public void M() => throw null;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1574: XML comment has cref attribute 'extension(string).M' that could not be resolved
// /// <see cref="E.extension(string).M"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension(string).M").WithArguments("extension(string).M").WithLocation(1, 16));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="!:E.extension(string).M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(string).M, null)"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_18()
{
var src = """
/// <see cref="E.extension(int).M"/>
static class E
{
extension(int i)
{
public void M<T>() => throw null;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M``1"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(int).M, void E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M<T>())"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_19()
{
var src = """
/// <see cref="E.extension(int).M"/>
static class E
{
extension(int i)
{
public void M<T>() => throw null;
public void M() => throw null;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(int).M, void E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M())"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_20()
{
var src = """
/// <see cref="E.extension(int).M{U}"/>
/// <see cref="E.M{U}"/>
static class E
{
extension(int i)
{
public void M<T>() => throw null;
public void M() => throw null;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="M:E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M``1"/>
<see cref="M:E.M``1(System.Int32)"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.Equal([
"(E.extension(int).M{U}, void E.<G>$BA41CFE2B5EDAEB8C1B9062F59ED4D69.M<U>())",
"(E.M{U}, void E.M<U>(this System.Int32 i))"],
PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_21()
{
// Arity for extension in cref differs from that in declaration
var src = """
/// <see cref="E.extension(int).M"/>
static class E
{
extension<T>(int i)
{
public void M() => throw null;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1574: XML comment has cref attribute 'extension(int).M' that could not be resolved
// /// <see cref="E.extension(int).M"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension(int).M").WithArguments("extension(int).M").WithLocation(1, 16));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="!:E.extension(int).M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(int).M, null)"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_22()
{
// Arity for extension in cref differs from that in declaration
var src = """
/// <see cref="E.extension{T}(int).M"/>
static class E
{
extension(int i)
{
public void M() => throw null;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1574: XML comment has cref attribute 'extension{T}(int).M' that could not be resolved
// /// <see cref="E.extension{T}(int).M"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension{T}(int).M").WithArguments("extension{T}(int).M").WithLocation(1, 16));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="!:E.extension<T>(int).M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension{T}(int).M, null)"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_23()
{
var src = """
/// <see cref="E.extension{T}(int).M"/>
static class E
{
extension<T>(int i)
{
public void M() => throw null;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="M:E.<G>$B8D310208B4544F25EEBACB9990FC73B`1.M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension{T}(int).M, void E.<G>$B8D310208B4544F25EEBACB9990FC73B<T>.M())"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_24()
{
var src = """
/// <see cref="E.M"/>
static class E<T>
{
public static void M() => throw null;
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1574: XML comment has cref attribute 'M' that could not be resolved
// /// <see cref="E.M"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.M").WithArguments("M").WithLocation(1, 16));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E`1">
<see cref="!:E.M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.M, null)"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_25()
{
// Type argument name differs from type parameter name
var src = """
/// <see cref="E.extension{U}(U).M"/>
static class E
{
extension<T>(T t)
{
public void M() => throw null;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="M:E.<G>$8048A6C8BE30A622530249B904B537EB`1.M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension{U}(U).M, void E.<G>$8048A6C8BE30A622530249B904B537EB<U>.M())"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_26()
{
// __arglist
var src = """
/// <see cref="E.extension(string).P"/>
static class E
{
extension(__arglist)
{
public int P => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1574: XML comment has cref attribute 'extension(string).P' that could not be resolved
// /// <see cref="E.extension(string).P"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension(string).P").WithArguments("extension(string).P").WithLocation(1, 16),
// (4,15): error CS1669: __arglist is not valid in this context
// extension(__arglist)
Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(4, 15));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="!:E.extension(string).P"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(string).P, null)"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_27()
{
// member named "extension"
var src = """
/// <see cref="E.extension(string)"/>
static class E
{
public static void extension(string s) => throw null!;
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="M:E.extension(System.String)"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(string), void E.extension(System.String s))"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_28()
{
var src = """
/// <see cref="E.extension(int)."/>
static class E
{
extension(int i)
{
public int P => throw null!;
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1584: XML comment has syntactically incorrect cref attribute 'E.extension(int).'
// /// <see cref="E.extension(int)."/>
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "E.extension(int).").WithArguments("E.extension(int).").WithLocation(1, 16),
// (1,33): warning CS1658: Identifier expected. See also error CS1001.
// /// <see cref="E.extension(int)."/>
Diagnostic(ErrorCode.WRN_ErrorOverride, @"""").WithArguments("Identifier expected", "1001").WithLocation(1, 33));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="!:E.extension(int)."/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(int)., null)"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_29()
{
var src = """
/// <see cref="E.extension(int).Nested"/>
static class E
{
extension(int i)
{
public class Nested { }
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1574: XML comment has cref attribute 'extension(int).Nested' that could not be resolved
// /// <see cref="E.extension(int).Nested"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension(int).Nested").WithArguments("extension(int).Nested").WithLocation(1, 16),
// (6,22): error CS9282: This member is not allowed in an extension block
// public class Nested { }
Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "Nested").WithLocation(6, 22));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="!:E.extension(int).Nested"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(int).Nested, null)"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_30()
{
var src = """
/// <see cref="E.extension(int).M"/>
static class E
{
extension(int i)
{
void I.M() { }
}
}
interface I
{
void M();
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1574: XML comment has cref attribute 'extension(int).M' that could not be resolved
// /// <see cref="E.extension(int).M"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension(int).M").WithArguments("extension(int).M").WithLocation(1, 16),
// (6,16): error CS0541: 'E.extension(int).M()': explicit interface declaration can only be declared in a class, record, struct or interface
// void I.M() { }
Diagnostic(ErrorCode.ERR_ExplicitInterfaceImplementationInNonClassOrStruct, "M").WithArguments("E.extension(int).M()").WithLocation(6, 16),
// (6,16): error CS9282: This member is not allowed in an extension block
// void I.M() { }
Diagnostic(ErrorCode.ERR_ExtensionDisallowsMember, "M").WithLocation(6, 16));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="!:E.extension(int).M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(int).M, null)"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_31()
{
var src = """
/// <see cref="E.extension(missing).M"/>
static class E
{
extension(object)
{
public static void M() { }
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1574: XML comment has cref attribute 'extension(missing).M' that could not be resolved
// /// <see cref="E.extension(missing).M"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension(missing).M").WithArguments("extension(missing).M").WithLocation(1, 16),
// (1,28): warning CS1580: Invalid type for parameter missing in XML comment cref attribute: 'E.extension(missing).M'
// /// <see cref="E.extension(missing).M"/>
Diagnostic(ErrorCode.WRN_BadXMLRefParamType, "missing").WithArguments("missing", "E.extension(missing).M").WithLocation(1, 28));
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="!:E.extension(missing).M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.SequenceEqual(["(E.extension(missing).M, null)"], PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_32()
{
// nested type named "extension"
var src = """
/// <see cref="E.extension"/>
/// <see cref="E.extension.M"/>
/// <see cref="E.extension.M()"/>
static class E
{
class @extension
{
public static void M() { }
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="T:E.extension"/>
<see cref="M:E.extension.M"/>
<see cref="M:E.extension.M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.Equal([
"(E.extension, E.extension)",
"(E.extension.M, void E.extension.M())",
"(E.extension.M(), void E.extension.M())"],
PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_33()
{
// nested type named "extension", error cases
var src = """
/// <see cref="E.extension()"/>
/// <see cref="E.extension().M"/>
/// <see cref="E.extension(int).M"/>
static class E
{
class @extension
{
public static void M() { }
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (2,16): warning CS1574: XML comment has cref attribute 'extension().M' that could not be resolved
// /// <see cref="E.extension().M"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension().M").WithArguments("extension().M").WithLocation(2, 16),
// (3,16): warning CS1574: XML comment has cref attribute 'extension(int).M' that could not be resolved
// /// <see cref="E.extension(int).M"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension(int).M").WithArguments("extension(int).M").WithLocation(3, 16));
}
[Fact]
public void Cref_34()
{
// generic nested type named "extension"
var src = """
/// <see cref="E.extension{T}"/>
/// <see cref="E.extension{T}.M"/>
static class E
{
class @extension<T>
{
public static void M() { }
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics();
var e = comp.GetMember<NamedTypeSymbol>("E");
AssertEx.Equal("""
<member name="T:E">
<see cref="T:E.extension`1"/>
<see cref="M:E.extension`1.M"/>
</member>
""", e.GetDocumentationCommentXml());
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
AssertEx.Equal([
"(E.extension{T}, E.extension<T>)",
"(E.extension{T}.M, void E.extension<T>.M())"],
PrintXmlCrefSymbols(tree, model));
}
[Fact]
public void Cref_35()
{
// generic nested type named "extension", error cases
var src = """
/// <see cref="E.extension{T}(int).M"/>
static class E
{
class @extension<T>
{
public static void M() { }
}
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (1,16): warning CS1574: XML comment has cref attribute 'extension{T}(int).M' that could not be resolved
// /// <see cref="E.extension{T}(int).M"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E.extension{T}(int).M").WithArguments("extension{T}(int).M").WithLocation(1, 16));
}
[Fact]
public void Cref_36()
{
// can refer to method named "extension", but cannot refer to extension block
var src = """
/// <see cref="E.extension()"/>
/// <see cref="E.extension(int)"/>
static class E
{
public static void extension() { }
public static void extension(int i) { }
}
/// <see cref="E2.extension()"/>
/// <see cref="E2.extension(int)"/>
static class E2
{
extension(int)
{
}
/// <see cref="extension()"/>
/// <see cref="extension(int)"/>
static void M() { }
}
""";
var comp = CreateCompilation(src, parseOptions: TestOptions.RegularPreviewWithDocumentationComments);
comp.VerifyEmitDiagnostics(
// (9,16): warning CS1574: XML comment has cref attribute 'extension()' that could not be resolved
// /// <see cref="E2.extension()"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E2.extension()").WithArguments("extension()").WithLocation(9, 16),
// (10,16): warning CS1574: XML comment has cref attribute 'extension(int)' that could not be resolved
// /// <see cref="E2.extension(int)"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "E2.extension(int)").WithArguments("extension(int)").WithLocation(10, 16),
// (17,20): warning CS1574: XML comment has cref attribute 'extension()' that could not be resolved
// /// <see cref="extension()"/>
Diagnostic(ErrorCode.WRN_BadXMLRef, "extension()").WithArguments("extension()").WithLocation(17, 20),
// (18,20): warning CS1574: XML comment has cref attribute 'extension(int)' that could not be resolved
// /// <see cref="extension(int)"/>
|