File: CodeGeneration\SyntaxGeneratorTests.cs
Web Access
Project: src\src\EditorFeatures\CSharpTest\Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests)
// 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.
 
#nullable disable
 
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeGeneration;
using Microsoft.CodeAnalysis.CSharp.Syntax;
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 = EditorTestWorkspace.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 = EditorTestWorkspace.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);
    }
}