Пример #1
0
            public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
            {
                if (methodImpl is null)
                {
                    return(node);
                }
                if (semanticModel.GetDeclaredSymbol(node) is not IMethodSymbol m)
                {
                    return(node);
                }

                if (m.MethodKind == MethodKind.Ordinary ||
                    m.MethodKind == MethodKind.ExplicitInterfaceImplementation)
                {
                    if (m.GetAttributes()
                        .Select(at => at.AttributeClass)
                        .Contains(methodImpl, SymbolEqualityComparer.Default))
                    {
                        return(node);
                    }

                    return(node.AddAttributeLists(SyntaxHelpers.AggressiveInliningAttributeList));
                }
                return(node);
            }
Пример #2
0
    /// <summary>
    /// Creates a <see cref="CompilationUnitSyntax"/> instance wrapping the given method.
    /// </summary>
    /// <param name="hierarchyInfo">The <see cref="HierarchyInfo"/> instance for the current type.</param>
    /// <param name="methodDeclaration">The <see cref="MethodDeclarationSyntax"/> item to insert.</param>
    /// <param name="canUseSkipLocalsInit">Whether <c>[SkipLocalsInit]</c> can be used.</param>
    /// <returns>A <see cref="CompilationUnitSyntax"/> object wrapping <paramref name="methodDeclaration"/>.</returns>
    private static CompilationUnitSyntax GetCompilationUnitFromMethod(
        HierarchyInfo hierarchyInfo,
        MethodDeclarationSyntax methodDeclaration,
        bool canUseSkipLocalsInit)
    {
        // Method attributes
        List <AttributeListSyntax> attributes = new()
        {
            AttributeList(SingletonSeparatedList(
                              Attribute(IdentifierName("global::System.CodeDom.Compiler.GeneratedCode")).AddArgumentListArguments(
                                  AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(ID2D1ShaderGenerator).FullName))),
                                  AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(ID2D1ShaderGenerator).Assembly.GetName().Version.ToString())))))),
            AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Diagnostics.DebuggerNonUserCode")))),
            AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage")))),
            AttributeList(SingletonSeparatedList(
                              Attribute(IdentifierName("global::System.ComponentModel.EditorBrowsable")).AddArgumentListArguments(
                                  AttributeArgument(ParseExpression("global::System.ComponentModel.EditorBrowsableState.Never"))))),
            AttributeList(SingletonSeparatedList(
                              Attribute(IdentifierName("global::System.Obsolete")).AddArgumentListArguments(
                                  AttributeArgument(LiteralExpression(
                                                        SyntaxKind.StringLiteralExpression,
                                                        Literal("This method is not intended to be used directly by user code"))))))
        };

        // Add [SkipLocalsInit] if the target project allows it
        if (canUseSkipLocalsInit)
        {
            attributes.Add(AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Runtime.CompilerServices.SkipLocalsInit")))));
        }

        return(hierarchyInfo.GetSyntax(methodDeclaration.AddAttributeLists(attributes.ToArray())));
    }
}
Пример #3
0
            public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
            {
                node = (MethodDeclarationSyntax)base.VisitMethodDeclaration(node);

                if (CrossArchSyntaxMap.IsPotentialCrossArch(node))
                {
                    var originalName = node.Identifier.ValueText;
                    var name         = originalName;
                    HandleArchSpecific(node, out var removeNode, out var attributeList, ref name);
                    if (removeNode)
                    {
                        return(null);
                    }

                    if (name != originalName)
                    {
                        node =
                            node.WithIdentifier(SyntaxFactory.ParseToken(name));
                    }

                    if (attributeList != null)
                    {
                        node = node.AddAttributeLists(attributeList);
                    }
                }

                return(node);
            }
Пример #4
0
        public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
        {
            node = (MethodDeclarationSyntax)base.VisitMethodDeclaration(node);

            if (!node.Modifiers.Any(x => x.ValueText == "public"))
            {
                return(node);
            }

            if ((node.ReturnType as PredefinedTypeSyntax)?.Keyword.ValueText != "void" &&
                !(node.Modifiers.Any(x => x.ValueText == "async") && node.ReturnType.ToFullString().Contains("Task")))
            {
                return(node);
            }

            if (node.ParameterList.Parameters.Any())
            {
                return(node);
            }

            if (node.AttributeLists.SelectMany(x => x.Attributes).Any())
            {
                return(node);
            }

            return(node.AddAttributeLists(new AttributeListSyntax[]
            {
                SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(
                                                SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("Test"))))
            }));
        }
Пример #5
0
        private async Task <Solution> AddThrowsAttributeAsync(Document document, MethodDeclarationSyntax methodDecl, SyntaxToken diagnosticSpan, CancellationToken cancellationToken)
        {
            var semModel = await document.GetSemanticModelAsync();

            var syntaxRoot = await document.GetSyntaxRootAsync();

            var exceptionType = diagnosticSpan
                                .Parent
                                .AncestorsAndSelf()
                                .Select(x => semModel.GetTypeInfo(x))
                                .FirstOrDefault(x => x.Type != null);

            ITypeSymbol exceptionSymbol = exceptionType.Type;

            bool hasUsing = syntaxRoot.DescendantNodes().OfType <UsingDirectiveSyntax>()
                            .Any(u => u.Name.ToString() == ThrowsAttributeNamespace);

            var newMethodDecl = methodDecl.AddAttributeLists(
                SyntaxFactory.AttributeList(
                    SyntaxFactory.SingletonSeparatedList(
                        CreateThrowsAttribute(await document.GetSemanticModelAsync(), methodDecl, exceptionSymbol, !hasUsing)
                        )
                    )
                ).WithoutLeadingTrivia();

            return(document.WithSyntaxRoot(
                       syntaxRoot.ReplaceNode(methodDecl, newMethodDecl)
                       ).Project.Solution);
        }
        private static SyntaxNode AddAttribute(SyntaxNode root, MethodDeclarationSyntax methodNode, string name)
        {
            var attribute     = SyntaxFactory.Attribute(SyntaxFactory.ParseName(name));
            var attributeList = SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList <AttributeSyntax>().Add(attribute));
            var newClassNode  = methodNode.AddAttributeLists(attributeList);

            return(root.ReplaceNode(methodNode, newClassNode));
        }
Пример #7
0
        public static MethodDeclarationSyntax CreateMethod(MethodGenerationData data)
        {
            Debug.Assert(!string.IsNullOrEmpty(data.m_MethodName), "Trying to generate a method with null or empty method name!");
            Debug.Assert(!string.IsNullOrEmpty(data.m_MethodReturnType), "Trying to generate a method with null or empty return type!");
            Debug.Assert(data.m_MethodBodyStatements != null && data.m_MethodBodyStatements.Count > 0, "Trying to generate a method with no body!");

            MethodDeclarationSyntax syntax = SyntaxFactory
                                             .MethodDeclaration(SyntaxFactory.ParseTypeName(data.m_MethodReturnType), data.m_MethodName)
                                             .AddModifiers(CodeGenerationUtility.CreateProtectionLevelToken(data.m_ProtectionLevel));

            switch (data.m_InheritanceKeyword)
            {
            case FunctionInheritanceKeyword.STATIC: syntax = syntax.AddModifiers(SyntaxFactory.Token(SyntaxKind.StaticKeyword)); break;

            case FunctionInheritanceKeyword.OVERRIDE: syntax = syntax.AddModifiers(SyntaxFactory.Token(SyntaxKind.OverrideKeyword)); break;

            case FunctionInheritanceKeyword.VIRTUAL: syntax = syntax.AddModifiers(SyntaxFactory.Token(SyntaxKind.VirtualKeyword)); break;
            }

            if (data.m_IsAsync)
            {
                bool canMakeAsync = false;

                for (int i = 0; i < s_AcceptedAsyncReturnTypes.Length; i++)
                {
                    if (!data.m_MethodReturnType.Contains(s_AcceptedAsyncReturnTypes[i]))
                    {
                        continue;
                    }

                    canMakeAsync = true;
                    break;
                }

                Debug.Assert(canMakeAsync, "Trying to generate async function but the return type is not supported! Please make the return type either void, Task or UniTask");

                if (canMakeAsync)
                {
                    syntax = syntax.AddModifiers(SyntaxFactory.Token(SyntaxKind.AsyncKeyword));
                }
            }

            syntax = syntax.AddAttributeLists(AttributeGenerationService.CreateAttributeListSyntaxes(data.m_Attributes));

            foreach (var param in data.m_MethodParams)
            {
                syntax = syntax.AddParameterListParameters(CodeGenerationUtility.CreateParameterSyntax(param.m_ParamName, param.m_ParamType));
            }

            foreach (var statement in data.m_MethodBodyStatements)
            {
                syntax = syntax.AddBodyStatements((SyntaxFactory.ParseStatement(statement)));
            }

            return(syntax);
        }
Пример #8
0
        private static async Task <Document> AddNewAttribute(Document document, MethodDeclarationSyntax methodDeclaration, NameSyntax qualifiedName, CancellationToken cancellationToken)
        {
            var newAttribute     = SyntaxFactory.Attribute(qualifiedName);
            var newAttributeList = SyntaxFactory.AttributeList().AddAttributes(newAttribute).WithAdditionalAnnotations(Formatter.Annotation);
            var newDeclaration   = methodDeclaration.AddAttributeLists(newAttributeList);

            var oldRoot = await document.GetSyntaxRootAsync(cancellationToken);

            var newRoot = oldRoot !.ReplaceNode(methodDeclaration, newDeclaration);

            return(document.WithSyntaxRoot(newRoot));
        }
Пример #9
0
        public static MethodDeclarationSyntax AddNeo4JDatabaseAttribute(
            this MethodDeclarationSyntax methodSyntax,
            string databaseName)
        {
            AttributeSyntax attribute =
                Attribute(IdentifierName(Global(UseNeo4JDatabaseAttribute)))
                .AddArgumentListArguments(
                    AttributeArgument(
                        LiteralExpression(
                            SyntaxKind.NumericLiteralExpression,
                            Literal(databaseName)))
                    .WithNameColon(
                        NameColon(IdentifierName(nameof(databaseName)))));

            return(methodSyntax.AddAttributeLists(AttributeList(SingletonSeparatedList(attribute))));
        }
Пример #10
0
        private MethodDeclarationSyntax FixAsyncFunctionMethod(MethodDeclarationSyntax targetMethod, CancellationToken cancellationToken)
        {
            MethodDeclarationSyntax updatedmethod = targetMethod;

            var name      = SyntaxFactory.ParseName("NetStitch.Operation");
            var attribute = SyntaxFactory.Attribute(name);

            var attributeList = new SeparatedSyntaxList <AttributeSyntax>();

            attributeList = attributeList.Add(attribute);
            var list = SyntaxFactory.AttributeList(attributeList);

            updatedmethod = updatedmethod.AddAttributeLists(list);

            if (updatedmethod.Identifier.Text.IsAsyncSuffixTarget())
            {
                updatedmethod = updatedmethod.ReplaceToken(updatedmethod.Identifier, SyntaxFactory.Identifier(updatedmethod.Identifier + "Async"));
            }

            if (updatedmethod.ParameterList.Parameters.Count == 0)
            {
                /*
                 * #if !___server___
                 *      System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)
                 * #endif
                 */
                updatedmethod = updatedmethod.AddParameterListParameters(
                    SyntaxFactory.Parameter(
                        SyntaxFactory.Identifier("cancellationToken")
                        .WithLeadingTrivia(SyntaxFactory.Whitespace(" "))
                        .WithTrailingTrivia(SyntaxFactory.Whitespace(" "))
                        )
                    .WithLeadingTrivia(SyntaxFactory.Whitespace(" "))
                    .WithType(
                        SyntaxFactory.ParseTypeName(typeof(CancellationToken).FullName))
                    .WithLeadingTrivia(SyntaxFactory.Whitespace("    " + "    "))
                    .WithDefault(
                        SyntaxFactory.EqualsValueClause(
                            SyntaxFactory.DefaultExpression(
                                SyntaxFactory.ParseTypeName(typeof(CancellationToken).FullName)
                                )
                            .WithLeadingTrivia(SyntaxFactory.Whitespace(" "))
                            )
                        )
                    .WithLeadingTrivia(
                        SyntaxFactory.Trivia(SyntaxFactory.IfDirectiveTrivia(SyntaxFactory.IdentifierName("!___server___"), false, false, false)),
                        SyntaxFactory.EndOfLine("\r\n"),
                        SyntaxFactory.Whitespace("    " + "    ")
                        )
                    .WithTrailingTrivia(
                        SyntaxFactory.EndOfLine("\r\n"),
                        SyntaxFactory.Trivia(
                            SyntaxFactory.EndIfDirectiveTrivia(false)
                            .WithTrailingTrivia(
                                SyntaxFactory.EndOfLine("\r\n"),
                                SyntaxFactory.Whitespace("    " + "    ")
                                ))
                        ));
            }
            else
            {
                /*
                 * #if !___server___
                 *     , System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)
                 * #endif
                 */
                updatedmethod = updatedmethod.AddParameterListParameters(
                    SyntaxFactory.Parameter(
                        SyntaxFactory.Identifier("cancellationToken")
                        .WithLeadingTrivia(SyntaxFactory.Whitespace(" "))
                        .WithTrailingTrivia(SyntaxFactory.Whitespace(" "))
                        )
                    .WithLeadingTrivia(SyntaxFactory.Whitespace(" "))
                    .WithType(
                        SyntaxFactory.ParseTypeName(typeof(CancellationToken).FullName))
                    .WithLeadingTrivia(SyntaxFactory.Whitespace("    " + "    "))
                    .WithDefault(
                        SyntaxFactory.EqualsValueClause(
                            SyntaxFactory.DefaultExpression(
                                SyntaxFactory.ParseTypeName(typeof(CancellationToken).FullName)
                                )
                            .WithLeadingTrivia(SyntaxFactory.Whitespace(" "))
                            )
                        )
                    .WithLeadingTrivia(SyntaxFactory.Whitespace(" "))
                    .WithTrailingTrivia(
                        SyntaxFactory.EndOfLine("\r\n"),
                        SyntaxFactory.Trivia(
                            SyntaxFactory.EndIfDirectiveTrivia(false)
                            .WithTrailingTrivia(
                                SyntaxFactory.EndOfLine("\r\n"),
                                SyntaxFactory.Whitespace("    " + "    ")
                                ))
                        ));

                var commaToken = updatedmethod.ParameterList.ChildTokens().Where(x => x.IsKind(SyntaxKind.CommaToken)).Last();

                var newToken = commaToken.WithLeadingTrivia(
                    SyntaxFactory.Whitespace("\r\n"),
                    SyntaxFactory.Trivia(SyntaxFactory.IfDirectiveTrivia(SyntaxFactory.IdentifierName("!___server___"), false, false, false)),
                    SyntaxFactory.EndOfLine("\r\n"),
                    SyntaxFactory.Whitespace("    " + "    ")
                    );

                var newParameterList = updatedmethod.ParameterList.ReplaceToken(commaToken, newToken);

                updatedmethod = updatedmethod.ReplaceNode(updatedmethod.ParameterList, newParameterList);
            }

            return(updatedmethod);
        }
Пример #11
0
 public static MethodDeclarationSyntax WithAttributes(this MethodDeclarationSyntax node, params AttributeSyntax[] attributes)
 {
     return(node.AddAttributeLists(AttributeList(SeparatedList(attributes))));
 }
            public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
            {
                if (methodImplAttribute is null)
                {
                    return(node);
                }
                if (methodImplOptions is null)
                {
                    return(node);
                }
                if (semanticModel.GetDeclaredSymbol(node) is not IMethodSymbol m)
                {
                    return(node);
                }

                if (m.MethodKind is
                    not(MethodKind.ExplicitInterfaceImplementation or MethodKind.Ordinary))
                {
                    return(node);
                }

                if (m.GetAttributes()
                    .FirstOrDefault(at => SymbolEqualityComparer.Default.Equals(at.AttributeClass, methodImplAttribute)) is not {
                } attr ||
                    attr.ApplicationSyntaxReference?.GetSyntax() is not AttributeSyntax syntax)
                {
                    return(node.AddAttributeLists(AttributeList(SingletonSeparatedList(aggressiveInliningAttribute))));
                }

                if (attr.ConstructorArguments.Length > 0)
                {
                    var arg = attr.ConstructorArguments[0];
                    if (arg.Kind is TypedConstantKind.Primitive or TypedConstantKind.Enum)
                    {
                        try
                        {
                            if (((MethodImplOptions)Convert.ToInt32(arg.Value)).HasFlag(MethodImplOptions.AggressiveInlining))
                            {
                                return(node);
                            }
                        }
                        catch
                        {
                        }
                    }
                }

                var list = new List <AttributeListSyntax>(node.AttributeLists.Count);

                foreach (var attributeList in node.AttributeLists)
                {
                    if (attributeList.Attributes.Contains(syntax))
                    {
                        var replaced = attributeList.Attributes.Replace(syntax, AddAggressiveInlining(syntax, attr));
                        list.Add(AttributeList(replaced));
                    }
                    else
                    {
                        list.Add(attributeList);
                    }
                }
                return(node.WithAttributeLists(new SyntaxList <AttributeListSyntax>(list)));
            }
Пример #13
0
        private MethodDeclarationSyntax ProcessTestMethod(MethodDeclarationSyntax node)
        {
            // Replace protected keyword with public
            SyntaxToken replaceToPublic(SyntaxToken token)
            {
                if (token.IsKind(SyntaxKind.ProtectedKeyword))
                {
                    token = SyntaxFactory.Token(token.LeadingTrivia, SyntaxKind.PublicKeyword, token.TrailingTrivia);
                }
                return(token);
            }

            var modifiers = node.Modifiers.Select(replaceToPublic);

            node = node.WithModifiers(new SyntaxTokenList(modifiers));

            // Replace method name with Component_Type_Methodname
            var methodName         = node.ChildTokens().First((x) => x.IsKind(SyntaxKind.IdentifierToken));
            var testTypeName       = testType.ToString("G").Substring(0, 1).ToUpperInvariant() + "_";
            var componentName      = GetComponentName(node);
            var shortComponentName = string.IsNullOrEmpty(componentName) ? componentName : componentName.Substring(0, 2).ToUpperInvariant() + "_";
            var newMethodName      = SyntaxFactory.Identifier(methodName.LeadingTrivia, $"{shortComponentName}{testTypeName}{methodName.ValueText}", methodName.TrailingTrivia);

            node = node.ReplaceToken(methodName, newMethodName);

            // Call original method instead of logic
            var isAsyncMethod = node.Modifiers.Any((x) => x.IsKind(SyntaxKind.AsyncKeyword));
            // hack for proper indentation: margin-to-method indentation + 1/2
            var indentTrivia     = node.QueryNodesOrTokensAtPath(SyntaxKind.Block, SyntaxKind.OpenBraceToken).First().GetLeadingTrivia().First();
            var indentTriviaHalf = SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, new string(' ', indentTrivia.ToString().Length / 2));
            ExpressionStatementSyntax body;

            if (isAsyncMethod)
            {
                body = SyntaxFactory.ExpressionStatement(
                    SyntaxFactory.AwaitExpression(
                        SyntaxFactory.Token(new SyntaxTriviaList(indentTrivia, indentTriviaHalf), SyntaxKind.AwaitKeyword, TestHelper.Space.AsList()),
                        SyntaxFactory.InvocationExpression(SyntaxFactory.IdentifierName(methodName.ValueText))
                        ),
                    TestHelper.Semicolon
                    );
            }
            else
            {
                body = SyntaxFactory.ExpressionStatement(
                    SyntaxFactory.InvocationExpression(
                        SyntaxFactory.IdentifierName(
                            SyntaxFactory.Identifier(
                                new SyntaxTriviaList(indentTrivia, indentTriviaHalf),
                                methodName.ValueText,
                                TestHelper.Empty.AsList()
                                )
                            )
                        ),
                    TestHelper.Semicolon
                    );
            }

            var bodyList = new SyntaxList <StatementSyntax>(body);

            Debug.Assert(indentTrivia.IsKind(SyntaxKind.WhitespaceTrivia));
            var openBrace  = SyntaxFactory.Token(indentTrivia.AsList(), SyntaxKind.OpenBraceToken, TestHelper.NewLine.AsList());
            var closeBrace = SyntaxFactory.Token(indentTrivia.AsList(), SyntaxKind.CloseBraceToken, TestHelper.NewLine.AsList());

            node = node.WithBody(SyntaxFactory.Block(openBrace, bodyList, closeBrace));

            // Export TestType arguments and decorate the method with them individually
            var arguments = GetTestTypeArguments(node);

            MethodDeclarationSyntax createNewAttribute(string attributeName)
            {
                return(node.AddAttributeLists(
                           SyntaxFactory.AttributeList(
                               SyntaxFactory.SeparatedList(new[] {
                    SyntaxFactory.Attribute(
                        SyntaxFactory.IdentifierName(attributeName)
                        )
                }
                                                           )
                               )
                           .WithTrailingTrivia(node.AttributeLists.First().GetTrailingTrivia())
                           .WithLeadingTrivia(indentTrivia)
                           ));
            }

            if (arguments.SmokeTest)
            {
                node = createNewAttribute("SmokeTest");
            }
            if (arguments.Devel)
            {
                node = createNewAttribute("DevelTest");
            }
            if (arguments.Production)
            {
                node = createNewAttribute("ProductionTest");
            }

            if (!string.IsNullOrEmpty(componentName))
            {
                node = createNewAttribute(componentName + "Component");
            }

            // Remove unused attributes
            var removableAttrLists = node.AttributeLists.Where((attribList) => attribList.Attributes.Any((attrib) =>
            {
                var testTypes     = new[] { "TestComponent", "InMemoryTest", "LocalTest", "RemoteTest" }.ToList();
                var attributeName = attrib.Name.GetText().ToString();
                return(testTypes.Contains(attributeName));
            }));

            node = node.RemoveNodes(removableAttrLists, SyntaxRemoveOptions.KeepNoTrivia);

            return(node);
        }
Пример #14
0
 public static MethodDeclarationSyntax WithNonActionAttribute(this MethodDeclarationSyntax node)
 => node.AddAttributeLists(AttributeList(SingletonSeparatedList(Attribute(IdentifierName("NonAction")))));
Пример #15
0
 public static MethodDeclarationSyntax WithGeneratedNonUserCodeAttributes(this MethodDeclarationSyntax node)
 => node.AddAttributeLists(GeneratedNonUserCodeAttributeList());
Пример #16
0
 public static MethodDeclarationSyntax AddAttributeLists(this MethodDeclarationSyntax syntax, IEnumerable <AttributeListSyntax> lists)
 {
     return(syntax.AddAttributeLists(lists.ToArray()));
 }
    /// <summary>
    /// Creates a <see cref="CompilationUnitSyntax"/> instance wrapping the given method.
    /// </summary>
    /// <param name="hierarchyInfo">The <see cref="HierarchyInfo"/> instance for the current type.</param>
    /// <param name="methodDeclaration">The <see cref="MethodDeclarationSyntax"/> item to insert.</param>
    /// <param name="canUseSkipLocalsInit">Whether <c>[SkipLocalsInit]</c> can be used.</param>
    /// <returns>A <see cref="CompilationUnitSyntax"/> object wrapping <paramref name="methodDeclaration"/>.</returns>
    private static CompilationUnitSyntax GetCompilationUnitFromMethod(
        HierarchyInfo hierarchyInfo,
        MethodDeclarationSyntax methodDeclaration,
        bool canUseSkipLocalsInit)
    {
        // Method attributes
        List <AttributeListSyntax> attributes = new()
        {
            AttributeList(SingletonSeparatedList(
                              Attribute(IdentifierName("global::System.CodeDom.Compiler.GeneratedCode")).AddArgumentListArguments(
                                  AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(IShaderGenerator).FullName))),
                                  AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(IShaderGenerator).Assembly.GetName().Version.ToString())))))),
            AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Diagnostics.DebuggerNonUserCode")))),
            AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage")))),
            AttributeList(SingletonSeparatedList(
                              Attribute(IdentifierName("global::System.ComponentModel.EditorBrowsable")).AddArgumentListArguments(
                                  AttributeArgument(ParseExpression("global::System.ComponentModel.EditorBrowsableState.Never"))))),
            AttributeList(SingletonSeparatedList(
                              Attribute(IdentifierName("global::System.Obsolete")).AddArgumentListArguments(
                                  AttributeArgument(LiteralExpression(
                                                        SyntaxKind.StringLiteralExpression,
                                                        Literal("This method is not intended to be used directly by user code"))))))
        };

        // Add [SkipLocalsInit] if the target project allows it
        if (canUseSkipLocalsInit)
        {
            attributes.Add(AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Runtime.CompilerServices.SkipLocalsInit")))));
        }

        // Create the partial shader type declaration with the given method implementation.
        // This code produces a struct declaration as follows:
        //
        // partial struct <SHADER_TYPE>
        // {
        //     <METHOD>
        // }
        StructDeclarationSyntax structDeclarationSyntax =
            StructDeclaration(hierarchyInfo.Names[0])
            .AddModifiers(Token(SyntaxKind.PartialKeyword))
            .AddMembers(methodDeclaration.AddAttributeLists(attributes.ToArray()));

        TypeDeclarationSyntax typeDeclarationSyntax = structDeclarationSyntax;

        // Add all parent types in ascending order, if any
        foreach (string parentType in hierarchyInfo.Names.AsSpan().Slice(1))
        {
            typeDeclarationSyntax =
                ClassDeclaration(parentType)
                .AddModifiers(Token(SyntaxKind.PartialKeyword))
                .AddMembers(typeDeclarationSyntax);
        }

        // Create the compilation unit with disabled warnings, target namespace and generated type.
        // This will produce code as follows:
        //
        // #pragma warning disable
        //
        // namespace <NAMESPACE>;
        //
        // <TYPE_HIERARCHY>
        return
            (CompilationUnit().AddMembers(
                 FileScopedNamespaceDeclaration(IdentifierName(hierarchyInfo.Namespace))
                 .AddMembers(typeDeclarationSyntax)
                 .WithNamespaceKeyword(Token(TriviaList(
                                                 Trivia(PragmaWarningDirectiveTrivia(Token(SyntaxKind.DisableKeyword), true))),
                                             SyntaxKind.NamespaceKeyword,
                                             TriviaList())))
             .NormalizeWhitespace(eol: "\n"));
    }
}