File: BestFriendOnPublicDeclarationsAnalyzer.cs
Web Access
Project: src\tools-local\Microsoft.ML.InternalCodeAnalyzer\Microsoft.ML.InternalCodeAnalyzer.csproj (Microsoft.ML.InternalCodeAnalyzer)
// 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.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
 
namespace Microsoft.ML.InternalCodeAnalyzer
{
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public sealed class BestFriendOnPublicDeclarationsAnalyzer : DiagnosticAnalyzer
    {
        private const string Category = "Access";
        internal const string DiagnosticId = "MSML_BestFriendOnPublicDeclaration";
 
        private const string Title = "Public declarations should not have " + AttributeName + " attribute.";
        private const string Format = "The " + AttributeName + " should not be applied to publicly visible members.";
 
        private const string Description =
            "The " + AttributeName + " attribute is not valid on public identifiers.";
 
        private static readonly DiagnosticDescriptor Rule =
            new DiagnosticDescriptor(DiagnosticId, Title, Format, Category,
                DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);
 
        private const string AttributeName = "Microsoft.ML.BestFriendAttribute";
 
        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
            ImmutableArray.Create(Rule);
 
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
 
            context.RegisterCompilationStartAction(CompilationStart);
        }
 
        private void CompilationStart(CompilationStartAnalysisContext context)
        {
            var list = new List<string> { AttributeName, "Microsoft.ML.Internal.CpuMath.Core.BestFriendAttribute" };
 
            foreach (var attributeName in list)
            {
                var attribute = context.Compilation.GetTypeByMetadataName(attributeName);
 
                if (attribute == null)
                    continue;
 
                context.RegisterSymbolAction(c => AnalyzeCore(c, attribute), SymbolKind.NamedType, SymbolKind.Method, SymbolKind.Field, SymbolKind.Property);
            }
        }
 
        private void AnalyzeCore(SymbolAnalysisContext context, INamedTypeSymbol attributeType)
        {
            if (context.Symbol.DeclaredAccessibility != Accessibility.Public)
                return;
 
            var attribute = context.Symbol.GetAttributes().FirstOrDefault(a => Equals(a.AttributeClass, attributeType));
            if (attribute == null)
                return;
 
            var diagnostic = Diagnostic.Create(Rule, attribute.ApplicationSyntaxReference.GetSyntax().GetLocation(), context.Symbol.Name);
            context.ReportDiagnostic(diagnostic);
        }
    }
}