File: CSharpDoNotUseDebugAssertForInterpolatedStrings.cs
Web Access
Project: src\src\RoslynAnalyzers\Roslyn.Diagnostics.Analyzers\CSharp\Roslyn.Diagnostics.CSharp.Analyzers.csproj (Roslyn.Diagnostics.CSharp.Analyzers)
// 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.Immutable;
using Analyzer.Utilities;
using Analyzer.Utilities.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using Roslyn.Diagnostics.Analyzers;
 
namespace Roslyn.Diagnostics.CSharp.Analyzers
{
    using static RoslynDiagnosticsAnalyzersResources;
 
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public sealed class CSharpDoNotUseDebugAssertForInterpolatedStrings : DiagnosticAnalyzer
    {
        internal static readonly DiagnosticDescriptor Rule = new(
            RoslynDiagnosticIds.DoNotUseInterpolatedStringsWithDebugAssertRuleId,
            CreateLocalizableResourceString(nameof(DoNotUseInterpolatedStringsWithDebugAssertTitle)),
            CreateLocalizableResourceString(nameof(DoNotUseInterpolatedStringsWithDebugAssertMessage)),
            DiagnosticCategory.RoslynDiagnosticsPerformance,
            DiagnosticSeverity.Warning,
            isEnabledByDefault: false,
            description: CreateLocalizableResourceString(nameof(DoNotUseInterpolatedStringsWithDebugAssertDescription)),
            helpLinkUri: null,
            customTags: WellKnownDiagnosticTagsExtensions.Telemetry);
 
        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);
 
        public override void Initialize(AnalysisContext context)
        {
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
            context.EnableConcurrentExecution();
 
            context.RegisterCompilationStartAction(context =>
            {
                var debugType = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemDiagnosticsDebug);
 
                if (debugType is null)
                {
                    return;
                }
 
                IMethodSymbol? assertMethod = null;
 
                foreach (var member in debugType.GetMembers("Assert"))
                {
                    if (member is IMethodSymbol { Parameters: [{ Type.SpecialType: SpecialType.System_Boolean }, { Type.SpecialType: SpecialType.System_String }] } method)
                    {
                        assertMethod = method;
                        break;
                    }
                }
 
                if (assertMethod is null)
                {
                    return;
                }
 
                context.RegisterOperationAction(context =>
                {
                    var invocation = (IInvocationOperation)context.Operation;
 
                    if (invocation.TargetMethod.Equals(assertMethod) &&
                        invocation.Arguments is [_, IArgumentOperation { Value: IInterpolatedStringOperation { ConstantValue.HasValue: false } }])
                    {
                        context.ReportDiagnostic(invocation.CreateDiagnostic(Rule));
                    }
                }, OperationKind.Invocation);
            });
        }
    }
}