Skip to content

Commit

Permalink
Disallow declaration of indexers in absence of proper DefaultMemberAt…
Browse files Browse the repository at this point in the history
…tribute. (#75099)

Fixes #75032.
  • Loading branch information
AlekseyTs authored Sep 30, 2024
1 parent 3c1810f commit ba7fe35
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 17 deletions.
12 changes: 12 additions & 0 deletions docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,15 @@ class C
}
}
```


## Declaration of indexers in absence of proper declaration of DefaultMemberAttribute is no longer allowed.

***Introduced in Visual Studio 2022 version 17.13***

```cs
public interface I1
{
public I1 this[I1 args] { get; } // error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor'
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -1796,27 +1796,30 @@ protected override void AfterMembersCompletedChecks(BindingDiagnosticBag diagnos
Debug.Assert(ObsoleteKind != ObsoleteAttributeKind.Uninitialized);
Debug.Assert(GetMembers().All(m => m.ObsoleteKind != ObsoleteAttributeKind.Uninitialized));

if (ObsoleteKind != ObsoleteAttributeKind.None
|| GetMembers().All(m => m is not MethodSymbol { MethodKind: MethodKind.Constructor, ObsoleteKind: ObsoleteAttributeKind.None } method
if (ObsoleteKind == ObsoleteAttributeKind.None
&& !GetMembers().All(m => m is not MethodSymbol { MethodKind: MethodKind.Constructor, ObsoleteKind: ObsoleteAttributeKind.None } method
|| !method.ShouldCheckRequiredMembers()))
{
return;
}

foreach (var member in GetMembers())
{
if (!member.IsRequired())
foreach (var member in GetMembers())
{
continue;
}
if (!member.IsRequired())
{
continue;
}

if (member.ObsoleteKind != ObsoleteAttributeKind.None)
{
// Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete.
diagnostics.Add(ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired, member.GetFirstLocation(), member);
if (member.ObsoleteKind != ObsoleteAttributeKind.None)
{
// Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete.
diagnostics.Add(ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired, member.GetFirstLocation(), member);
}
}
}

if (Indexers.FirstOrDefault() is PropertySymbol indexerSymbol)
{
Binder.GetWellKnownTypeMember(DeclaringCompilation, WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor, diagnostics, indexerSymbol.TryGetFirstLocation() ?? GetFirstLocation());
}

if (TypeKind == TypeKind.Struct && !IsRecordStruct && HasInlineArrayAttribute(out _))
{
if (Layout.Kind == LayoutKind.Explicit)
Expand Down
76 changes: 76 additions & 0 deletions src/Compilers/CSharp/Test/Emit/CodeGen/IndexerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.CSharp.UnitTests.Emit;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
Expand Down Expand Up @@ -1185,5 +1186,80 @@ static void Main()
}

#endregion Lowering

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/75032")]
public void MissingDefaultMemberAttribute_01()
{
var text1 = @"
public interface I1
{
public I1 this[I1 args] { get; }
}
";
var comp1 = CreateCompilation(text1);
comp1.MakeMemberMissing(WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor);

comp1.VerifyDiagnostics(
// (4,15): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor'
// public I1 this[I1 args] { get; }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(4, 15)
);

comp1 = CreateCompilation(text1);
comp1.MakeTypeMissing(WellKnownType.System_Reflection_DefaultMemberAttribute);

comp1.VerifyDiagnostics(
// (4,15): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor'
// public I1 this[I1 args] { get; }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(4, 15)
);

comp1 = CreateCompilation(text1);
comp1.VerifyEmitDiagnostics();
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/75032")]
public void MissingDefaultMemberAttribute_02()
{
var text1 = @"
public interface I1
{
public I1 this[I1 args] { get; }
}
";
var comp1 = CreateCompilation(text1);

var text2 = @"
class C : I1
{
I1 I1.this[I1 args] => throw null;
}
";
var comp2 = CreateCompilation(text2, references: [comp1.ToMetadataReference()]);
comp2.MakeMemberMissing(WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor);
comp2.VerifyEmitDiagnostics();
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/75032")]
public void MissingDefaultMemberAttribute_03()
{
var text1 = @"
using System.Collections.Generic;
class Program
{
static IEnumerable<int> Test()
{
return [123];
}
}
";
var comp1 = CreateCompilation(text1);
comp1.MakeMemberMissing(WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor);
CompileAndVerify(comp1).VerifyDiagnostics();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1565,6 +1565,9 @@ class Test
}";

CreateEmptyCompilation(code).VerifyDiagnostics(
// (9,27): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor'
// public virtual object this[in object p] => null;
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(9, 27),
// (9,32): error CS0518: Predefined type 'System.Runtime.InteropServices.InAttribute' is not defined or imported
// public virtual object this[in object p] => null;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "in object p").WithArguments("System.Runtime.InteropServices.InAttribute").WithLocation(9, 32));
Expand All @@ -1588,7 +1591,11 @@ class Test
CreateEmptyCompilation(code).VerifyDiagnostics(
// (10,20): error CS0518: Predefined type 'System.Runtime.InteropServices.InAttribute' is not defined or imported
// public virtual ref readonly object this[object p] => ref value;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "ref readonly object").WithArguments("System.Runtime.InteropServices.InAttribute").WithLocation(10, 20));
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "ref readonly object").WithArguments("System.Runtime.InteropServices.InAttribute").WithLocation(10, 20),
// (10,40): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor'
// public virtual ref readonly object this[object p] => ref value;
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(10, 40)
);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2588,6 +2588,9 @@ void M1()
// (6,37): error CS0518: Predefined type 'System.Int32' is not defined or imported
// public int this[int x, int? y = 5]
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "5").WithArguments("System.Int32").WithLocation(6, 37),
// (6,16): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor'
// public int this[int x, int? y = 5]
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(6, 16),
// (5,27): error CS0518: Predefined type 'System.Int32' is not defined or imported
// private int _number = 0;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "0").WithArguments("System.Int32").WithLocation(5, 27),
Expand Down Expand Up @@ -2766,6 +2769,9 @@ void M1()
// (5,12): error CS0518: Predefined type 'System.Int32' is not defined or imported
// public int this[int x, int? y = null]
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "int").WithArguments("System.Int32").WithLocation(5, 12),
// (5,16): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor'
// public int this[int x, int? y = null]
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(5, 16),
// (5,21): error CS0518: Predefined type 'System.Int32' is not defined or imported
// public int this[int x, int? y = null]
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "int").WithArguments("System.Int32").WithLocation(5, 21),
Expand Down Expand Up @@ -3829,6 +3835,9 @@ P M1()
// (5,37): error CS0518: Predefined type 'System.Int32' is not defined or imported
// public int this[int x, int? y = 0]
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "0").WithArguments("System.Int32").WithLocation(5, 37),
// (5,16): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor'
// public int this[int x, int? y = 0]
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(5, 16),
// (4,27): error CS0518: Predefined type 'System.Int32' is not defined or imported
// private int _number = 0;
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "0").WithArguments("System.Int32").WithLocation(4, 27),
Expand Down Expand Up @@ -3903,6 +3912,9 @@ P M1()
// (5,12): error CS0518: Predefined type 'System.Int32' is not defined or imported
// public int this[int x, int? y = null]
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "int").WithArguments("System.Int32").WithLocation(5, 12),
// (5,16): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor'
// public int this[int x, int? y = null]
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(5, 16),
// (5,21): error CS0518: Predefined type 'System.Int32' is not defined or imported
// public int this[int x, int? y = null]
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "int").WithArguments("System.Int32").WithLocation(5, 21),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#nullable disable

using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
Expand Down Expand Up @@ -3462,7 +3463,10 @@ void M(C c)
";

var reference = CreateMetadataReferenceFromIlSource(il);
var comp = CreateCompilation(source, references: new[] { reference }, parseOptions: TestOptions.Regular9);
var comp = CreateCompilation(source, references: new[] { reference }, parseOptions: TestOptions.Regular9,
options: TestOptions.ReleaseDll.WithSpecificDiagnosticOptions(
// warning CS1685: The predefined type 'DefaultMemberAttribute' is defined in multiple assemblies
ImmutableDictionary<string, ReportDiagnostic>.Empty.Add("CS1685", ReportDiagnostic.Suppress)));
comp.VerifyEmitDiagnostics(
// (4,25): error CS0569: 'Derived.this[int]': cannot override 'C.this[int]' because it is not supported by the language
// public override int this[int i] { set { throw null; } }
Expand Down Expand Up @@ -3558,7 +3562,10 @@ public class Derived2 : C
";

var reference = CreateMetadataReferenceFromIlSource(il);
var comp = CreateCompilation(source, references: new[] { reference }, parseOptions: TestOptions.Regular9);
var comp = CreateCompilation(source, references: new[] { reference }, parseOptions: TestOptions.Regular9,
options: TestOptions.ReleaseDll.WithSpecificDiagnosticOptions(
// warning CS1685: The predefined type 'DefaultMemberAttribute' is defined in multiple assemblies
ImmutableDictionary<string, ReportDiagnostic>.Empty.Add("CS1685", ReportDiagnostic.Suppress)));
comp.VerifyEmitDiagnostics(
// (4,39): error CS0570: 'C.this[int].set' is not supported by the language
// public override int this[int i] { set { throw null; } }
Expand Down

0 comments on commit ba7fe35

Please sign in to comment.