File: CodeGeneration\AbstractCodeGenerationTests.cs
Web Access
Project: ..\..\..\src\EditorFeatures\Test\Microsoft.CodeAnalysis.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.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.
 
using System;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.VisualBasic.Syntax;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.UnitTests.CodeGeneration
{
    [UseExportProvider]
    public abstract class AbstractCodeGenerationTests
    {
        private static SyntaxNode Simplify(
            AdhocWorkspace workspace,
            SyntaxNode syntaxNode,
            string languageName)
        {
            var projectId = ProjectId.CreateNewId();
 
            var project = workspace.CurrentSolution
                .AddProject(projectId, languageName, $"{languageName}.dll", languageName).GetRequiredProject(projectId);
 
            var normalizedSyntax = syntaxNode.NormalizeWhitespace().ToFullString();
            var document = project.AddMetadataReference(TestMetadata.Net451.mscorlib)
                .AddDocument("Fake Document", SourceText.From(normalizedSyntax));
 
            var root = document.GetRequiredSyntaxRootAsync(default).AsTask().Result;
            var annotatedDocument = document.WithSyntaxRoot(
                    root.WithAdditionalAnnotations(Simplifier.Annotation));
 
            var options = document.Project.Services.GetRequiredService<ISimplificationService>().DefaultOptions;
            var simplifiedDocument = Simplifier.ReduceAsync(annotatedDocument, options, CancellationToken.None).Result;
 
            var rootNode = simplifiedDocument.GetRequiredSyntaxRootAsync(default).AsTask().Result;
 
            return rootNode;
        }
 
        private static SyntaxNode WrapExpressionInBoilerplate(SyntaxNode expression, SyntaxGenerator codeDefFactory)
        {
            return codeDefFactory.CompilationUnit(
                codeDefFactory.NamespaceImportDeclaration(codeDefFactory.IdentifierName("System")),
                codeDefFactory.ClassDeclaration(
                    "C",
                    members: new[]
                    {
                        codeDefFactory.MethodDeclaration(
                            "Dummy",
                            returnType: null,
                            statements: new[]
                            {
                                codeDefFactory.LocalDeclarationStatement("test", expression)
                            })
                    })
                );
        }
 
        internal static void Test(
            Func<SyntaxGenerator, SyntaxNode> nodeCreator,
            string cs, string csSimple,
            string vb, string vbSimple)
        {
            Assert.True(cs != null || csSimple != null || vb != null || vbSimple != null,
                $"At least one of {nameof(cs)}, {nameof(csSimple)}, {nameof(vb)}, {nameof(vbSimple)} must be provided");
 
            using var workspace = new AdhocWorkspace();
 
            if (cs != null || csSimple != null)
            {
                var codeDefFactory = workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService<SyntaxGenerator>();
 
                var node = nodeCreator(codeDefFactory);
                node = node.NormalizeWhitespace();
 
                if (cs != null)
                {
                    TokenUtilities.AssertTokensEqual(cs, node.ToFullString(), LanguageNames.CSharp);
                }
 
                if (csSimple != null)
                {
                    var simplifiedRootNode = Simplify(workspace, WrapExpressionInBoilerplate(node, codeDefFactory), LanguageNames.CSharp);
                    var expression = simplifiedRootNode.DescendantNodes().OfType<EqualsValueClauseSyntax>().First().Value;
 
                    TokenUtilities.AssertTokensEqual(csSimple, expression.NormalizeWhitespace().ToFullString(), LanguageNames.CSharp);
                }
            }
 
            if (vb != null || vbSimple != null)
            {
                var codeDefFactory = workspace.Services.GetLanguageServices(LanguageNames.VisualBasic).GetRequiredService<SyntaxGenerator>();
 
                var node = nodeCreator(codeDefFactory);
                node = node.NormalizeWhitespace();
 
                if (vb != null)
                {
                    TokenUtilities.AssertTokensEqual(vb, node.ToFullString(), LanguageNames.VisualBasic);
                }
 
                if (vbSimple != null)
                {
                    var simplifiedRootNode = Simplify(workspace, WrapExpressionInBoilerplate(node, codeDefFactory), LanguageNames.VisualBasic);
                    var expression = simplifiedRootNode.DescendantNodes().OfType<EqualsValueSyntax>().First().Value;
 
                    TokenUtilities.AssertTokensEqual(vbSimple, expression.NormalizeWhitespace().ToFullString(), LanguageNames.VisualBasic);
                }
            }
        }
 
        protected static ITypeSymbol CreateClass(string name)
        {
            return CodeGenerationSymbolFactory.CreateNamedTypeSymbol(
                attributes: default, accessibility: default, modifiers: default, TypeKind.Class, name);
        }
    }
}