未验证 提交 0a54c5ad 编写于 作者: A Andy Gocke 提交者: GitHub

Use correct type parameter binder for local functions (#24108)

This looks like simple oversight. The binder being used for type
parameters was retrieved from the binder factory since we didn't
explicitly pass one. For members this is correct since the binder
factory can be queried for top-level binders. This is not correct for
local functions because they use method body binders, which are not
accessible from the binder factory.

Mostly, this doesn't matter. The exception is when you try to
speculatively bind an attribute on a type parameter. Here, you need an
in-method binder and VS will crash if it's the wrong binder. This was
uncommon since attributes on type parameters are not permitted in local
functions, but VS should not crash.

Fixes #17814 
上级 c7983cf2
......@@ -179,7 +179,8 @@ internal virtual CustomAttributesBag<CSharpAttributeData> GetAttributesBag()
{
lazyAttributesStored = LoadAndValidateAttributes(
OneOrMany.Create(this.MergedAttributeDeclarationSyntaxLists),
ref _lazyCustomAttributesBag);
ref _lazyCustomAttributesBag,
binderOpt: (ContainingSymbol as LocalFunctionSymbol)?.SignatureBinder);
}
else
{
......
......@@ -30,6 +30,90 @@ internal void VerifyDiagnostics(string source, CSharpCompilationOptions options,
[CompilerTrait(CompilerFeature.LocalFunctions)]
public class LocalFunctionTests : LocalFunctionsTestBase
{
[Fact]
public void LocalFunctionTypeParametersUseCorrectBinder()
{
var text = @"
class C
{
static void M()
{
void local<[X]T>() {}
}
}";
var tree = SyntaxFactory.ParseSyntaxTree(text);
var comp = CreateStandardCompilation(tree);
var model = comp.GetSemanticModel(tree, ignoreAccessibility: true);
var newTree = SyntaxFactory.ParseSyntaxTree(text + " ");
var m = newTree.GetRoot()
.DescendantNodes().OfType<MethodDeclarationSyntax>().Single();
Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(m.Body.SpanStart, m, out model));
var x = newTree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Single();
Assert.Equal("X", x.Identifier.Text);
// If we aren't using the right binder here, the compiler crashes going through the binder factory
var info = model.GetSymbolInfo(x);
Assert.Null(info.Symbol);
comp.VerifyDiagnostics(
// (6,20): error CS8205: Attributes are not allowed on local function parameters or type parameters
// void local<[X]T>() {}
Diagnostic(ErrorCode.ERR_AttributesInLocalFuncDecl, "[X]").WithLocation(6, 20),
// (6,21): error CS0246: The type or namespace name 'XAttribute' could not be found (are you missing a using directive or an assembly reference?)
// void local<[X]T>() {}
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "X").WithArguments("XAttribute").WithLocation(6, 21),
// (6,21): error CS0246: The type or namespace name 'X' could not be found (are you missing a using directive or an assembly reference?)
// void local<[X]T>() {}
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "X").WithArguments("X").WithLocation(6, 21),
// (6,14): warning CS8321: The local function 'local' is declared but never used
// void local<[X]T>() {}
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(6, 14));
}
[Fact]
public void LocalFunctionAttribute()
{
const string text = @"
using System;
class A : Attribute {}
class C
{
static void M()
{
void local<[A]T>() {}
}
}";
var tree = SyntaxFactory.ParseSyntaxTree(text);
var comp = CreateStandardCompilation(tree);
var model = comp.GetSemanticModel(tree);
var a = tree.GetRoot().DescendantNodes()
.OfType<IdentifierNameSyntax>().ElementAt(2);
Assert.Equal("A", a.Identifier.Text);
var attrInfo = model.GetSymbolInfo(a);
var attrType = comp.GlobalNamespace.GetTypeMember("A");
var attrCtor = attrType.GetMember(".ctor");
Assert.Equal(attrCtor, attrInfo.Symbol);
// Assert that this is also true for the speculative semantic model
var newTree = SyntaxFactory.ParseSyntaxTree(text + " ");
var m = newTree.GetRoot()
.DescendantNodes().OfType<MethodDeclarationSyntax>().Single();
Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(m.Body.SpanStart, m, out model));
a = newTree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().ElementAt(2);
Assert.Equal("A", a.Identifier.Text);
// If we aren't using the right binder here, the compiler crashes going through the binder factory
var info = model.GetSymbolInfo(a);
// This behavior is wrong. See https://github.com/dotnet/roslyn/issues/24135
Assert.Equal(attrType, info.Symbol);
}
[Fact]
public void UnsafeLocal()
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册