| File: Microsoft.NetCore.Analyzers\Runtime\InitializeStaticFieldsInline.cs | Web Access |
| Project: src\sdk\src\Microsoft.CodeAnalysis.NetAnalyzers\src\Microsoft.CodeAnalysis.NetAnalyzers\Microsoft.CodeAnalysis.NetAnalyzers.csproj (Microsoft.CodeAnalysis.NetAnalyzers) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; using System.Threading; using Analyzer.Utilities; using Analyzer.Utilities.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; namespace Microsoft.NetCore.Analyzers.Runtime { using static MicrosoftNetCoreAnalyzersResources; /// <summary> /// CA1810: <inheritdoc cref="InitializeReferenceTypeStaticFieldsInlineTitle"/> /// CA2207: <inheritdoc cref="InitializeValueTypeStaticFieldsInlineTitle"/> /// </summary> [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] public sealed class InitializeStaticFieldsInlineAnalyzer : DiagnosticAnalyzer { internal const string CA1810RuleId = "CA1810"; internal const string CA2207RuleId = "CA2207"; private static readonly LocalizableString s_localizableMessage = CreateLocalizableResourceString(nameof(InitializeStaticFieldsInlineMessage)); internal static readonly DiagnosticDescriptor CA1810Rule = DiagnosticDescriptorHelper.Create( CA1810RuleId, CreateLocalizableResourceString(nameof(InitializeReferenceTypeStaticFieldsInlineTitle)), s_localizableMessage, DiagnosticCategory.Performance, RuleLevel.Disabled, // May tie this to performance sensitive attribute. description: CreateLocalizableResourceString(nameof(InitializeReferenceTypeStaticFieldsInlineDescription)), isPortedFxCopRule: true, isDataflowRule: false); internal static readonly DiagnosticDescriptor CA2207Rule = DiagnosticDescriptorHelper.Create( CA2207RuleId, CreateLocalizableResourceString(nameof(InitializeValueTypeStaticFieldsInlineTitle)), s_localizableMessage, DiagnosticCategory.Usage, RuleLevel.Disabled, // May tie this to performance sensitive attribute. description: CreateLocalizableResourceString(nameof(InitializeValueTypeStaticFieldsInlineDescription)), isPortedFxCopRule: true, isDataflowRule: false); public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(CA1810Rule, CA2207Rule); public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterOperationBlockStartAction(context => { if (context.OwningSymbol is not IMethodSymbol method || !method.IsStatic || method.MethodKind != MethodKind.StaticConstructor) { return; } var isStaticCtorMandatory = new AtomicBoolean(); var initializesStaticField = false; context.RegisterOperationAction(context => { var assignment = (IAssignmentOperation)context.Operation; if (!isStaticCtorMandatory.Value && assignment.Target is IFieldReferenceOperation fieldReference && fieldReference.Member.IsStatic) { if (assignment.GetAncestor<IAnonymousFunctionOperation>(OperationKind.AnonymousFunction) != null) { isStaticCtorMandatory.Value = true; } else { initializesStaticField = true; } } }, OperationKind.SimpleAssignment); context.RegisterOperationAction(context => { isStaticCtorMandatory.Value = true; }, OperationKind.EventAssignment); context.RegisterOperationBlockEndAction(context => { if (initializesStaticField && !isStaticCtorMandatory.Value) { context.ReportDiagnostic( method.CreateDiagnostic( method.ContainingType.IsReferenceType ? CA1810Rule : CA2207Rule, method.ContainingType.Name)); } }); }); } private class AtomicBoolean { private const int TRUE_VALUE = 1; private const int FALSE_VALUE = 0; private int zeroOrOne = FALSE_VALUE; public AtomicBoolean(bool initialValue = false) { zeroOrOne = initialValue ? TRUE_VALUE : FALSE_VALUE; } public bool Value { get => Interlocked.CompareExchange(ref zeroOrOne, TRUE_VALUE, TRUE_VALUE) == TRUE_VALUE; set { if (value) { Interlocked.CompareExchange(ref zeroOrOne, TRUE_VALUE, FALSE_VALUE); } else { Interlocked.CompareExchange(ref zeroOrOne, FALSE_VALUE, TRUE_VALUE); } } } } } }