Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ private Binder SkipSemanticModelBinder()
private static BoundAttribute BindAttributeCore(Binder binder, AttributeSyntax node, NamedTypeSymbol attributeType, Symbol? attributedMember, BindingDiagnosticBag diagnostics)
{
Debug.Assert(binder.SkipSemanticModelBinder() == binder.GetRequiredBinder(node).SkipSemanticModelBinder());
binder = binder.WithAdditionalFlags(BinderFlags.AttributeArgument);
Debug.Assert(binder.InAttributeArgument);

// If attribute name bound to an error type with a single named type
// candidate symbol, we want to bind the attribute constructor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2717,7 +2717,7 @@ private bool MemberGroupFinalValidationAccessibilityChecks(BoundExpression? rece
diagnostics.Add(ErrorCode.ERR_ObjectRequired, node.Location, memberSymbol);
return true;
}
else if (WasImplicitReceiver(receiverOpt))
else if (WasImplicitReceiver(receiverOpt) && !(IsInsideNameof && Compilation.IsFeatureEnabled(MessageID.IDS_FeatureInstanceMemberInNameof)))
{
if (InFieldInitializer && !ContainingType!.IsScriptClass || InConstructorInitializer || InAttributeArgument)
{
Expand Down
6 changes: 6 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ internal partial class Binder
/// <returns>True if a reference to "this" is available.</returns>
internal bool HasThis(bool isExplicit, out bool inStaticContext)
{
if (!isExplicit && IsInsideNameof && Compilation.IsFeatureEnabled(MessageID.IDS_FeatureInstanceMemberInNameof))
Copy link
Member

Choose a reason for hiding this comment

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

I didn't follow why !isExplicit is needed in this check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't follow why !isExplicit is needed in this check.

There are no tests indicating that it must not be present. If you have a scenario in mind, please suggest an example.

Copy link
Contributor Author

@AlekseyTs AlekseyTs Dec 10, 2025

Choose a reason for hiding this comment

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

My goal was to use most conservative conditions to fix failing tests.

{
inStaticContext = false;
return true;
}

var memberOpt = this.ContainingMemberOrLambda?.ContainingNonLambdaMember();
if (memberOpt?.IsStatic == true)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2351,6 +2351,7 @@ private bool TryBindNameofOperator(InvocationExpressionSyntax node, BindingDiagn
if (node.MayBeNameofOperator())
{
var binder = this.GetBinder(node);
Debug.Assert(binder.Flags == this.Flags);
if (binder.EnclosingNameofArgument == node.ArgumentList.Arguments[0].Expression)
{
result = binder.BindNameofOperatorInternal(node, diagnostics);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ public override void VisitEqualsValueClause(EqualsValueClauseSyntax node)

public override void VisitAttribute(AttributeSyntax node)
{
var attrBinder = new ExpressionVariableBinder(node, _enclosing);
var attrBinder = new ExpressionVariableBinder(node, _enclosing.WithAdditionalFlags(BinderFlags.AttributeArgument));
AddToMap(node, attrBinder);

if (node.ArgumentList?.Arguments.Count > 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ protected AttributeSemanticModel CreateModelForAttribute(Binder enclosingBinder,
attributeType,
aliasOpt,
attributeTarget,
enclosingBinder.WithAdditionalFlags(BinderFlags.AttributeArgument),
enclosingBinder,
containingModel?.GetRemappedSymbols());

Symbol? getAttributeTarget(SyntaxNode? targetSyntax)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47359,5 +47359,112 @@ class D

CompileAndVerify(CreateCompilationWithSpan([source, CollectionBuilderAttributeDefinition]), expectedOutput: "").VerifyDiagnostics();
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/81576")]
public void Issue81576_01()
{
var source = """
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

[CollectionBuilder(typeof(MyFancyCollection), nameof(MyFancyCollection.))]
public class MyFancyCollection : IEnumerable<int>
{
public MyFancyCollection Create(ReadOnlySpan<int> ints)
{
return null;
}

public IEnumerator<int> GetEnumerator()
{
throw new NotImplementedException();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
""";

CreateCompilationWithSpan([source, CollectionBuilderAttributeDefinition]).VerifyEmitDiagnostics(
// (6,72): error CS1001: Identifier expected
// [CollectionBuilder(typeof(MyFancyCollection), nameof(MyFancyCollection.))]
Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(6, 72)
);
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/81576")]
public void Issue81576_02()
{
var source = """
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

[CollectionBuilder(typeof(MyFancyCollection), nameof(MyFancyCollection.Missing))]
public class MyFancyCollection : IEnumerable<int>
{
public MyFancyCollection Create(ReadOnlySpan<int> ints)
{
return null;
}

public IEnumerator<int> GetEnumerator()
{
throw new NotImplementedException();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
""";

CreateCompilationWithSpan([source, CollectionBuilderAttributeDefinition]).VerifyEmitDiagnostics(
// (6,72): error CS0117: 'MyFancyCollection' does not contain a definition for 'Missing'
// [CollectionBuilder(typeof(MyFancyCollection), nameof(MyFancyCollection.Missing))]
Diagnostic(ErrorCode.ERR_NoSuchMember, "Missing").WithArguments("MyFancyCollection", "Missing").WithLocation(6, 72)
);
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/81576")]
public void Issue81576_03()
{
var source = """
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

[CollectionBuilder(typeof(MyFancyCollection), nameof(MyFancyCollection.Create))]
public class MyFancyCollection : IEnumerable<int>
{
public MyFancyCollection Create(ReadOnlySpan<int> ints)
{
return null;
}

public IEnumerator<int> GetEnumerator()
{
throw new NotImplementedException();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
""";

CreateCompilationWithSpan([source, CollectionBuilderAttributeDefinition]).VerifyEmitDiagnostics();
}
}
}
46 changes: 45 additions & 1 deletion src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2348,7 +2348,7 @@ class Attr : System.Attribute { public Attr(string s) {} }";
}

[Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler2()
public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler2_01()
{
var source = @"
class C
Expand All @@ -2365,6 +2365,50 @@ class Attr : System.Attribute { public Attr(string s) {} }";
};
CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
// (4,18): error CS0120: An object reference is required for the non-static field, method, or property 'C.Method<C>()'
// [Attr(nameof(Method<C>().Method))]
Diagnostic(ErrorCode.ERR_ObjectRequired, "Method<C>").WithArguments("C.Method<C>()").WithLocation(4, 18)
);
}

[Fact]
public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler2_02()
{
var source = @"
class C
{
[Attr(nameof(P.P))]
C P => default;
}
class Attr : System.Attribute { public Attr(string s) {} }";
CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics();
CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics();
CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
// (4,18): error CS9058: Feature 'instance member in 'nameof'' is not available in C# 11.0. Please use language version 12.0 or greater.
// [Attr(nameof(P.P))]
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion11, "P").WithArguments("instance member in 'nameof'", "12.0").WithLocation(4, 18)
);
}

[Fact]
public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler2_03()
{
var source = @"
class C
{
[Attr(nameof(this.P.P))]
C P => default;
}
class Attr : System.Attribute { public Attr(string s) {} }";
var expectedDiagnostics = new[]
{
// (4,18): error CS0027: Keyword 'this' is not available in the current context
// [Attr(nameof(this.P.P))]
Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(4, 18)
};
CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics);
CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics);
}

Expand Down