| File: Microsoft.NetCore.Analyzers\Runtime\UseEnvironmentMembers.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.Linq; 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> /// CA1837: <inheritdoc cref="UseEnvironmentProcessIdTitle"/> /// CA1839: <inheritdoc cref="UseEnvironmentProcessPathTitle"/> /// CA1840: <inheritdoc cref="UseEnvironmentCurrentManagedThreadIdTitle"/> /// </summary> [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] public sealed class UseEnvironmentMembers : DiagnosticAnalyzer { internal const string EnvironmentProcessIdRuleId = "CA1837"; internal const string EnvironmentProcessPathRuleId = "CA1839"; internal const string EnvironmentCurrentManagedThreadIdRuleId = "CA1840"; // Process.GetCurrentProcess().Id => Environment.ProcessId internal static readonly DiagnosticDescriptor UseEnvironmentProcessIdRule = DiagnosticDescriptorHelper.Create(EnvironmentProcessIdRuleId, CreateLocalizableResourceString(nameof(UseEnvironmentProcessIdTitle)), CreateLocalizableResourceString(nameof(UseEnvironmentProcessIdMessage)), DiagnosticCategory.Performance, RuleLevel.IdeSuggestion, CreateLocalizableResourceString(nameof(UseEnvironmentProcessIdDescription)), isPortedFxCopRule: false, isDataflowRule: false); // Process.GetCurrentProcess().MainModule.FileName => Environment.ProcessPath internal static readonly DiagnosticDescriptor UseEnvironmentProcessPathRule = DiagnosticDescriptorHelper.Create(EnvironmentProcessPathRuleId, CreateLocalizableResourceString(nameof(UseEnvironmentProcessPathTitle)), CreateLocalizableResourceString(nameof(UseEnvironmentProcessPathMessage)), DiagnosticCategory.Performance, RuleLevel.IdeSuggestion, CreateLocalizableResourceString(nameof(UseEnvironmentProcessPathDescription)), isPortedFxCopRule: false, isDataflowRule: false); // Thread.CurrentThread.ManagedThreadId => Environment.CurrentManagedThreadId internal static readonly DiagnosticDescriptor UseEnvironmentCurrentManagedThreadIdRule = DiagnosticDescriptorHelper.Create(EnvironmentCurrentManagedThreadIdRuleId, CreateLocalizableResourceString(nameof(UseEnvironmentCurrentManagedThreadIdTitle)), CreateLocalizableResourceString(nameof(UseEnvironmentCurrentManagedThreadIdMessage)), DiagnosticCategory.Performance, RuleLevel.IdeSuggestion, CreateLocalizableResourceString(nameof(UseEnvironmentCurrentManagedThreadIdDescription)), isPortedFxCopRule: false, isDataflowRule: false); public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(UseEnvironmentProcessIdRule, UseEnvironmentProcessPathRule, UseEnvironmentCurrentManagedThreadIdRule); public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(context => { // Require that Environment / Process / ProcessModule / Thread exist. if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemEnvironment, out var environmentType) || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemDiagnosticsProcess, out var processType) || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemDiagnosticsProcessModule, out var processModuleType) || !context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingThread, out var threadType)) { return; } // Get the various members needed from Environment, Process, ProcessModule, and Thread. var environmentProcessIdSymbol = environmentType.GetMembers("ProcessId").FirstOrDefault(); var environmentProcessPathSymbol = environmentType.GetMembers("ProcessPath").FirstOrDefault(); var environmentCurrentManagedThreadIdSymbol = environmentType.GetMembers("CurrentManagedThreadId").FirstOrDefault(); var processGetCurrentProcessSymbol = processType.GetMembers("GetCurrentProcess").FirstOrDefault(); var processIdSymbol = processType.GetMembers("Id").FirstOrDefault(); var processMainModuleSymbol = processType.GetMembers("MainModule").FirstOrDefault(); var processModuleFileNameSymbol = processModuleType.GetMembers("FileName").FirstOrDefault(); var threadCurrentThreadSymbol = threadType.GetMembers("CurrentThread").FirstOrDefault(); var threadManagedThreadId = threadType.GetMembers("ManagedThreadId").FirstOrDefault(); // This one analyzer looks for multiple things, so figure out which we have the symbols to enable. bool lookForProcessId = processGetCurrentProcessSymbol != null && processIdSymbol != null && environmentProcessIdSymbol != null; bool lookForProcessPath = processGetCurrentProcessSymbol != null && processMainModuleSymbol != null && processModuleFileNameSymbol != null && environmentProcessPathSymbol != null; bool lookForCurrentManagedThreadId = threadCurrentThreadSymbol != null && threadManagedThreadId != null && environmentCurrentManagedThreadIdSymbol != null; if (!lookForProcessId && !lookForProcessPath && !lookForCurrentManagedThreadId) { return; } // Everything we're looking for is a property, so find all property references. context.RegisterOperationAction(context => { var initialPropRef = (IPropertyReferenceOperation)context.Operation; // Process.GetCurrentProcess().Id if (lookForProcessId && SymbolEqualityComparer.Default.Equals(initialPropRef.Property, processIdSymbol)) { if (initialPropRef.Instance is IInvocationOperation getCurrentProcess && SymbolEqualityComparer.Default.Equals(getCurrentProcess.TargetMethod, processGetCurrentProcessSymbol)) { context.ReportDiagnostic(initialPropRef.CreateDiagnostic(UseEnvironmentProcessIdRule)); } return; } // Process.GetCurrentProcess().MainModule.FileName if (lookForProcessPath && SymbolEqualityComparer.Default.Equals(initialPropRef.Property, processModuleFileNameSymbol)) { if (initialPropRef.Instance is IPropertyReferenceOperation mainModule && SymbolEqualityComparer.Default.Equals(mainModule.Property, processMainModuleSymbol) && mainModule.Instance is IInvocationOperation getCurrentProcess && SymbolEqualityComparer.Default.Equals(getCurrentProcess.TargetMethod, processGetCurrentProcessSymbol)) { context.ReportDiagnostic(initialPropRef.CreateDiagnostic(UseEnvironmentProcessPathRule)); } return; } // Thread.CurrentThread.ManagedThreadId if (lookForCurrentManagedThreadId && SymbolEqualityComparer.Default.Equals(initialPropRef.Property, threadManagedThreadId)) { if (initialPropRef.Instance is IPropertyReferenceOperation currentThread && SymbolEqualityComparer.Default.Equals(currentThread.Property, threadCurrentThreadSymbol)) { context.ReportDiagnostic(initialPropRef.CreateDiagnostic(UseEnvironmentCurrentManagedThreadIdRule)); } return; } }, OperationKind.PropertyReference); }); } } }