File: Diagnostics\SuppressMessageAttributeTests.DiagnosticAnalyzers.cs
Web Access
Project: src\src\Compilers\Test\Core\Microsoft.CodeAnalysis.Test.Utilities.csproj (Microsoft.CodeAnalysis.Test.Utilities)
// 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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.UnitTests.Diagnostics
{
    public partial class SuppressMessageAttributeTests
    {
        protected const string TestDiagnosticCategory = "Test";
        protected const string TestDiagnosticMessageTemplate = "{0}";
 
        protected class WarningOnCompilationEndedAnalyzer : DiagnosticAnalyzer
        {
            public const string Id = "CompilationEnded";
            private static readonly DiagnosticDescriptor s_rule = GetRule(Id);
 
            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            {
                get
                {
                    return ImmutableArray.Create(s_rule);
                }
            }
 
            public override void Initialize(AnalysisContext analysisContext)
            {
                analysisContext.RegisterCompilationAction(
                    (context) =>
                        {
                            context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, Location.None, messageArgs: Id));
                        }
                    );
            }
        }
 
        // Produces a warning on the declaration of any symbol whose name starts with a specified prefix
        protected class WarningOnNamePrefixDeclarationAnalyzer : DiagnosticAnalyzer
        {
            public const string Id = "Declaration";
            private static readonly DiagnosticDescriptor s_rule = GetRule(Id);
 
            private readonly string _errorSymbolPrefix;
 
            public WarningOnNamePrefixDeclarationAnalyzer(string errorSymbolPrefix)
            {
                _errorSymbolPrefix = errorSymbolPrefix;
            }
 
            public override void Initialize(AnalysisContext analysisContext)
            {
                analysisContext.RegisterSymbolAction(
                    (context) =>
                        {
                            if (context.Symbol.Name.StartsWith(_errorSymbolPrefix, StringComparison.Ordinal))
                            {
                                context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, context.Symbol.Locations.First(), messageArgs: context.Symbol.Name));
                            }
                        },
                    SymbolKind.Event,
                    SymbolKind.Field,
                    SymbolKind.Method,
                    SymbolKind.NamedType,
                    SymbolKind.Namespace,
                    SymbolKind.Property);
            }
 
            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            {
                get
                {
                    return ImmutableArray.Create(s_rule);
                }
            }
        }
 
        // Produces a warning on the declaration of any named type
        protected class WarningOnTypeDeclarationAnalyzer : DiagnosticAnalyzer
        {
            public const string TypeId = "TypeDeclaration";
            private static readonly DiagnosticDescriptor s_rule = GetRule(TypeId);
 
            public override void Initialize(AnalysisContext analysisContext)
            {
                analysisContext.RegisterSymbolAction(
                    (context) =>
                        {
                            context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, context.Symbol.Locations.First(), messageArgs: context.Symbol.Name));
                        },
                    SymbolKind.NamedType);
            }
 
            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            {
                get
                {
                    return ImmutableArray.Create(s_rule);
                }
            }
        }
 
        // Produces a warning for the end of every code body and every invocation expression within that code body
        protected class WarningOnCodeBodyAnalyzer : DiagnosticAnalyzer
        {
            public const string Id = "CodeBody";
            private static readonly DiagnosticDescriptor s_rule = GetRule(Id);
 
            private readonly string _language;
 
            public WarningOnCodeBodyAnalyzer(string language)
            {
                _language = language;
            }
 
            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            {
                get
                {
                    return ImmutableArray.Create(s_rule);
                }
            }
 
            public override void Initialize(AnalysisContext analysisContext)
            {
                if (_language == LanguageNames.CSharp)
                {
                    analysisContext.RegisterCodeBlockStartAction<CSharp.SyntaxKind>(new CSharpCodeBodyAnalyzer().Initialize);
                }
                else
                {
                    analysisContext.RegisterCodeBlockStartAction<VisualBasic.SyntaxKind>(new BasicCodeBodyAnalyzer().Initialize);
                }
            }
 
            protected class CSharpCodeBodyAnalyzer
            {
                public void Initialize(CodeBlockStartAnalysisContext<CSharp.SyntaxKind> analysisContext)
                {
                    analysisContext.RegisterCodeBlockEndAction(
                        (context) =>
                            {
                                context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, context.OwningSymbol.Locations.First(), messageArgs: context.OwningSymbol.Name + ":end"));
                            });
 
                    analysisContext.RegisterSyntaxNodeAction(
                        (context) =>
                            {
                                context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, context.Node.GetLocation(), messageArgs: context.Node.ToFullString()));
                            },
                        CSharp.SyntaxKind.InvocationExpression);
                }
            }
 
            protected class BasicCodeBodyAnalyzer
            {
                public void Initialize(CodeBlockStartAnalysisContext<VisualBasic.SyntaxKind> analysisContext)
                {
                    analysisContext.RegisterCodeBlockEndAction(
                        (context) =>
                            {
                                context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, context.OwningSymbol.Locations.First(), messageArgs: context.OwningSymbol.Name + ":end"));
                            });
 
                    analysisContext.RegisterSyntaxNodeAction(
                        (context) =>
                            {
                                context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, context.Node.GetLocation(), messageArgs: context.Node.ToFullString()));
                            },
                        VisualBasic.SyntaxKind.InvocationExpression);
                }
            }
        }
 
        // Produces a warning for each comment trivium in a syntax tree
        protected class WarningOnCommentAnalyzer : DiagnosticAnalyzer
        {
            public const string Id = "Comment";
            private static readonly DiagnosticDescriptor s_rule = GetRule(Id);
 
            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            {
                get
                {
                    return ImmutableArray.Create(s_rule);
                }
            }
 
            public override void Initialize(AnalysisContext analysisContext)
            {
                analysisContext.RegisterSyntaxTreeAction(
                    (context) =>
                        {
                            var comments = context.Tree.GetRoot().DescendantTrivia()
                               .Where(t =>
                                   t.IsKind(SyntaxKind.SingleLineCommentTrivia) ||
                                   t.IsKind(SyntaxKind.MultiLineCommentTrivia) ||
                                   t.IsKind(VisualBasic.SyntaxKind.CommentTrivia));
 
                            foreach (var comment in comments)
                            {
                                context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, comment.GetLocation(), messageArgs: comment.ToFullString()));
                            }
                        });
            }
        }
 
        // Produces a warning for each token overlapping the given span in a syntax tree
        protected class WarningOnTokenAnalyzer : DiagnosticAnalyzer
        {
            public const string Id = "Token";
            private static readonly DiagnosticDescriptor s_rule = GetRule(Id);
            private readonly IList<TextSpan> _spans;
 
            public WarningOnTokenAnalyzer(IList<TextSpan> spans)
            {
                _spans = spans;
            }
 
            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            {
                get
                {
                    return ImmutableArray.Create(s_rule);
                }
            }
 
            public override void Initialize(AnalysisContext analysisContext)
            {
                analysisContext.RegisterSyntaxTreeAction(
                    (context) =>
                        {
                            foreach (var nodeOrToken in context.Tree.GetRoot().DescendantNodesAndTokens())
                            {
                                if (nodeOrToken.IsToken && _spans.Any(s => s.OverlapsWith(nodeOrToken.FullSpan)))
                                {
                                    context.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(s_rule, nodeOrToken.GetLocation(), messageArgs: nodeOrToken.ToString()));
                                }
                            }
                        });
            }
        }
 
        // Throws an exception on every AnalyzeSymbol on named types
        protected class ThrowExceptionForEachNamedTypeAnalyzer : DiagnosticAnalyzer
        {
            public const string Id = "ThrowException";
            private static readonly DiagnosticDescriptor s_rule = GetRule(Id);
            private readonly ExceptionDispatchInfo _exceptionDispatchInfo;
 
            public ThrowExceptionForEachNamedTypeAnalyzer(ExceptionDispatchInfo exceptionDispatchInfo)
            {
                _exceptionDispatchInfo = exceptionDispatchInfo;
            }
 
            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            {
                get
                {
                    return ImmutableArray.Create(s_rule);
                }
            }
 
            public string AssemblyName { get; private set; }
 
            public override void Initialize(AnalysisContext analysisContext)
            {
                analysisContext.RegisterCompilationStartAction(context => AssemblyName = context.Compilation.AssemblyName);
 
                analysisContext.RegisterSymbolAction(
                    (context) =>
                    {
                        _exceptionDispatchInfo.Throw();
                    },
                    SymbolKind.NamedType);
            }
        }
 
        protected class ThrowExceptionFromSupportedDiagnostics : DiagnosticAnalyzer
        {
            private readonly Exception _exception;
 
            public ThrowExceptionFromSupportedDiagnostics(Exception exception)
            {
                _exception = exception;
            }
 
            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            {
                get
                {
                    ExceptionDispatchInfo.Capture(_exception).Throw();
                    throw ExceptionUtilities.Unreachable();
                }
            }
 
            public override void Initialize(AnalysisContext analysisContext)
                => throw ExceptionUtilities.Unreachable();
        }
 
        protected static DiagnosticDescriptor GetRule(string id)
        {
            return new DiagnosticDescriptor(
                id,
                id,
                TestDiagnosticMessageTemplate,
                TestDiagnosticCategory,
                DiagnosticSeverity.Warning,
                isEnabledByDefault: true);
        }
    }
}