/// <summary>
        /// Gets diagnostics for this <see cref="SyntaxNode"/> an all child elements.
        /// </summary>
        public IReadOnlyList <Diagnostic> GetContainedDiagnostics(DiagnosticsInclude include = DiagnosticsInclude.Syntactic | DiagnosticsInclude.Semantic, CancellationToken cancellationToken = default(CancellationToken))
        {
            var list = new List <Diagnostic>();

            GatherDiagnostics(this, list, include, cancellationToken: cancellationToken);
            return(list.AsReadOnly());
        }
        protected static void GatherDiagnostics(
            SyntaxElement root,
            List <Diagnostic> diagnostics,
            DiagnosticsInclude include,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            bool includeSyntax    = (include & DiagnosticsInclude.Syntactic) != 0;
            bool includeSemantic  = (include & DiagnosticsInclude.Semantic) != 0;
            bool includeExpansion = (include & DiagnosticsInclude.Expansion) != 0;

            var fnDescend = (include == DiagnosticsInclude.Syntactic)
                ? (Func <SyntaxElement, bool>)((SyntaxElement e) => e.ContainsSyntaxDiagnostics)
                : null;

            SyntaxElement.WalkElements(root,
                                       fnBefore: element =>
            {
                if (element.HasSyntaxDiagnostics && includeSyntax)
                {
                    // each syntax diagnostic is located at the element that carries it.
                    diagnostics.AddRange(element.SyntaxDiagnostics.Select(d => d.HasLocation ? d : SetLocation(d, element)));
                }

                if (includeSemantic && element is SyntaxNode node && node.SemanticDiagnostics.Count > 0)
                {
                    diagnostics.AddRange(node.SemanticDiagnostics);
                }
            },
        protected static void GatherDiagnostics(
            SyntaxElement element,
            List <Diagnostic> diagnostics,
            DiagnosticsInclude include,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            bool includeSyntax    = (include & DiagnosticsInclude.Syntactic) != 0;
            bool includeSemantic  = (include & DiagnosticsInclude.Semantic) != 0;
            bool includeExpansion = (include & DiagnosticsInclude.Expansion) != 0;

            if (element.HasSyntaxDiagnostics && includeSyntax)
            {
                // each syntax diagnostic is located at the element that carries it.
                diagnostics.AddRange(element.SyntaxDiagnostics.Select(d => d.HasLocation ? d : SetLocation(d, element)));
            }

            if (includeSemantic && element is SyntaxNode node && node.SemanticDiagnostics.Count > 0)
            {
                diagnostics.AddRange(node.SemanticDiagnostics);
            }

            if (includeSemantic || (includeSyntax && element.ContainsSyntaxDiagnostics))
            {
                for (int i = 0, n = element.ChildCount; i < n; i++)
                {
                    var child = element.GetChild(i);
                    if (child != null)
                    {
                        GatherDiagnostics(child, diagnostics, include, cancellationToken);
                    }
                }
            }

            if (includeExpansion && element is Expression expr && expr.GetExpansion() is SyntaxNode expansion)
            {
                var originalCount = diagnostics.Count;
                GatherDiagnostics(expansion, diagnostics, include, cancellationToken);

                if (diagnostics.Count > originalCount)
                {
                    var name     = expr.ReferencedSymbol?.Name ?? "<unknown>";
                    var location = expr is FunctionCallExpression fc ? fc.Name : expr;
                    var errors   = diagnostics[originalCount].Message;
                    var dx       = DiagnosticFacts.GetErrorInExpansion(name, errors).WithLocation(location);
                    diagnostics.SetCount(originalCount);
                    diagnostics.Add(dx);
                }
            }
        }