未验证 提交 8b78d492 编写于 作者: M msftbot[bot] 提交者: GitHub

Merge pull request #42214 from CyrusNajmabadi/nameofGeneration

Properly generate 'nameof' expressions that bind correctly in the compiler
// 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.
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeGeneration;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeGeneration
{
[UseExportProvider]
public class SyntaxGeneratorTests
{
[Fact]
public async Task TestNameOfBindsWithoutErrors()
{
var g = CSharpSyntaxGenerator.Instance;
using var workspace = TestWorkspace.CreateCSharp(@"
class C
{
string M()
{
return ""a"";
}
}");
var solution = workspace.CurrentSolution;
var document = solution.Projects.Single().Documents.Single();
var root = await document.GetSyntaxRootAsync();
// validate that if we change `return "a";` to `return nameof(M);` that this binds
// without a problem. We need to do special work in SyntaxGenerator.NameOfExpression to
// make this happen.
var statement = root.DescendantNodes().Single(n => n is ReturnStatementSyntax);
var replacement = g.ReturnStatement(g.NameOfExpression(g.IdentifierName("M")));
var newRoot = root.ReplaceNode(statement, replacement);
var newDocument = document.WithSyntaxRoot(newRoot);
var semanticModel = await newDocument.GetSemanticModelAsync();
var diagnostics = semanticModel.GetDiagnostics();
Assert.Empty(diagnostics);
}
[Fact]
public async Task TestNameOfBindsWithoutErrors_SpeculativeModel()
{
var g = CSharpSyntaxGenerator.Instance;
using var workspace = TestWorkspace.CreateCSharp(@"
class C
{
string M()
{
return ""a"";
}
}");
var solution = workspace.CurrentSolution;
var document = solution.Projects.Single().Documents.Single();
var root = await document.GetSyntaxRootAsync();
// validate that if we change `return "a";` to `return nameof(M);` that this binds
// without a problem. We need to do special work in SyntaxGenerator.NameOfExpression to
// make this happen.
var statement = root.DescendantNodes().Single(n => n is ReturnStatementSyntax);
var semanticModel = await document.GetSemanticModelAsync();
var diagnostics = semanticModel.GetDiagnostics();
Assert.Empty(diagnostics);
var replacement = (ReturnStatementSyntax)g.ReturnStatement(g.NameOfExpression(g.IdentifierName("M")));
Assert.True(semanticModel.TryGetSpeculativeSemanticModel(
statement.SpanStart, replacement,
out var speculativeModel));
// Make sure even in the speculative model that the compiler understands that this is a
// the special `nameof` construct.
var typeInfo = speculativeModel.GetTypeInfo(replacement.Expression);
Assert.Equal(SpecialType.System_String, typeInfo.Type.SpecialType);
Assert.Equal(SpecialType.System_String, typeInfo.ConvertedType.SpecialType);
var constantValue = speculativeModel.GetConstantValue(replacement.Expression);
Assert.True(constantValue.HasValue);
Assert.Equal("M", constantValue.Value);
}
}
}
......@@ -25,6 +25,12 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration
[ExportLanguageService(typeof(SyntaxGenerator), LanguageNames.CSharp), Shared]
internal class CSharpSyntaxGenerator : SyntaxGenerator
{
// A bit hacky, but we need to actually run ParseToken on the "nameof" text as there's no
// other way to get a token back that has the appropriate internal bit set that indicates
// this has the .ContextualKind of SyntaxKind.NameOfKeyword.
private static readonly IdentifierNameSyntax s_nameOfIdentifier =
SyntaxFactory.IdentifierName(SyntaxFactory.ParseToken("nameof"));
[ImportingConstructor]
public CSharpSyntaxGenerator()
{
......@@ -3200,11 +3206,7 @@ public override SyntaxNode AwaitExpression(SyntaxNode expression)
}
public override SyntaxNode NameOfExpression(SyntaxNode expression)
{
return this.InvocationExpression(
this.IdentifierName(CSharp.SyntaxFacts.GetText(SyntaxKind.NameOfKeyword)),
expression);
}
=> this.InvocationExpression(s_nameOfIdentifier, expression);
public override SyntaxNode ReturnStatement(SyntaxNode expressionOpt = null)
=> SyntaxFactory.ReturnStatement((ExpressionSyntax)expressionOpt);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册