Skip to content

Commit

Permalink
Adjust semantic model for method group conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
jcouv committed Nov 6, 2024
1 parent 6217b5c commit 146f4ac
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4294,11 +4294,15 @@ private OneOrMany<Symbol> GetMethodGroupSemanticSymbols(
// we want to get the symbol that overload resolution chose for M, not the whole method group M.
var conversion = (BoundConversion)boundNodeForSyntacticParent;

while (conversion.ConversionKind is not ConversionKind.MethodGroup && conversion.Operand is BoundConversion nestedConversion)
{
Debug.Assert(conversion.ConversionKind is ConversionKind.NoConversion || conversion.ExplicitCastInCode);
conversion = nestedConversion;
}

var method = conversion.SymbolOpt;
if ((object)method != null)
{
Debug.Assert(conversion.ConversionKind == ConversionKind.MethodGroup);

if (conversion.IsExtensionMethod)
{
method = ReducedExtensionMethodSymbol.Create(method);
Expand Down
107 changes: 107 additions & 0 deletions src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Roslyn.Test.Utilities;
using Xunit;
using Basic.Reference.Assemblies;
using Microsoft.CodeAnalysis.Test.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols
{
Expand Down Expand Up @@ -425,6 +426,112 @@ static void Main()
Assert.True(conversion.IsNumeric);
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36377")]
public void GetSymbolInfo_ExplicitCastOnMethodGroup()
{
var src = """
public sealed class C
{
public static void M()
{
C x = (C)C.Test;
}
public static int Test() => 1;
public static explicit operator C(System.Func<int> intDelegate)
{
return new C();
}
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics();

var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.Test");
Assert.Equal("System.Int32 C.Test()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString());
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36377")]
public void GetSymbolInfo_TwoExplicitCastsOnMethodGroup()
{
var src = """
public sealed class C
{
public static void M()
{
D x = (D)(C)C.Test;
}
public static int Test() => 1;
public static explicit operator C(System.Func<int> intDelegate) => throw null;
}
public sealed class D
{
public static explicit operator D(C c) => throw null;
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics();

var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.Test");
Assert.Equal("System.Int32 C.Test()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString());
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36377")]
public void GetSymbolInfo_NoConversion()
{
var src = """
public sealed class C
{
public static void M()
{
int x = C.Test;
}
public static int Test() => 1;
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (5,19): error CS0428: Cannot convert method group 'Test' to non-delegate type 'int'. Did you intend to invoke the method?
// int x = C.Test;
Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "Test").WithArguments("Test", "int").WithLocation(5, 19));

var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.Test");
Assert.Null(model.GetSymbolInfo(memberAccess).Symbol);
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36377")]
public void GetSymbolInfo_MethodGroupConversion()
{
var src = """
public sealed class C
{
public static void M()
{
System.Func<int> x = C.Test;
}
public static int Test() => 1;
}
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics();

var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var memberAccess = GetSyntax<MemberAccessExpressionSyntax>(tree, "C.Test");
Assert.Equal("System.Int32 C.Test()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString());
}

#region "Diagnostics"
[Fact]
public void VarianceRelationFail()
Expand Down

0 comments on commit 146f4ac

Please sign in to comment.