From 60b58648cad3b6588e7451aa2d5be0de9b1d0233 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 24 Feb 2025 19:35:40 +0100 Subject: [PATCH] Added rule regarding the random class --- .../AnalyzerReleases.Shipped.md | 3 +- .../SourceCodeRules/Identifier.cs | 1 + .../RandomInstantiationAnalyzer.cs | 55 +++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 app/SourceCodeRules/SourceCodeRules/UsageAnalyzers/RandomInstantiationAnalyzer.cs diff --git a/app/SourceCodeRules/SourceCodeRules/AnalyzerReleases.Shipped.md b/app/SourceCodeRules/SourceCodeRules/AnalyzerReleases.Shipped.md index bbbad53b..f2d4d4d9 100644 --- a/app/SourceCodeRules/SourceCodeRules/AnalyzerReleases.Shipped.md +++ b/app/SourceCodeRules/SourceCodeRules/AnalyzerReleases.Shipped.md @@ -6,4 +6,5 @@ -----------|----------|----------|------------------------ MWAIS0001 | Usage | Error | ProviderAccessAnalyzer MWAIS0002 | Naming | Error | ConstStaticAnalyzer - MWAIS0003 | Naming | Error | UnderscorePrefixAnalyzer \ No newline at end of file + MWAIS0003 | Naming | Error | UnderscorePrefixAnalyzer + MWAIS0004 | Usage | Error | RandomInstantiationAnalyzer \ No newline at end of file diff --git a/app/SourceCodeRules/SourceCodeRules/Identifier.cs b/app/SourceCodeRules/SourceCodeRules/Identifier.cs index ab7408f9..81eca55f 100644 --- a/app/SourceCodeRules/SourceCodeRules/Identifier.cs +++ b/app/SourceCodeRules/SourceCodeRules/Identifier.cs @@ -5,4 +5,5 @@ public static class Identifier public const string PROVIDER_ACCESS_ANALYZER = $"{Tools.ID_PREFIX}0001"; public const string CONST_STATIC_ANALYZER = $"{Tools.ID_PREFIX}0002"; public const string UNDERSCORE_PREFIX_ANALYZER = $"{Tools.ID_PREFIX}0003"; + public const string RANDOM_INSTANTIATION_ANALYZER = $"{Tools.ID_PREFIX}0004"; } \ No newline at end of file diff --git a/app/SourceCodeRules/SourceCodeRules/UsageAnalyzers/RandomInstantiationAnalyzer.cs b/app/SourceCodeRules/SourceCodeRules/UsageAnalyzers/RandomInstantiationAnalyzer.cs new file mode 100644 index 00000000..8244aa8e --- /dev/null +++ b/app/SourceCodeRules/SourceCodeRules/UsageAnalyzers/RandomInstantiationAnalyzer.cs @@ -0,0 +1,55 @@ +using System.Collections.Immutable; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace SourceCodeRules.UsageAnalyzers; + +#pragma warning disable RS1038 +[DiagnosticAnalyzer(LanguageNames.CSharp)] +#pragma warning restore RS1038 +public class RandomInstantiationAnalyzer : DiagnosticAnalyzer +{ + private const string DIAGNOSTIC_ID = Identifier.RANDOM_INSTANTIATION_ANALYZER; + + private static readonly string TITLE = "Direct instantiation of Random is not allowed"; + + private static readonly string MESSAGE_FORMAT = "Do not use 'new Random()'. Instead, inject and use the ThreadSafeRandom service from the DI container."; + + private static readonly string DESCRIPTION = "Using 'new Random()' can lead to issues in multi-threaded scenarios. Use the ThreadSafeRandom service instead."; + + private const string CATEGORY = "Usage"; + + private static readonly DiagnosticDescriptor RULE = new( + DIAGNOSTIC_ID, + TITLE, + MESSAGE_FORMAT, + CATEGORY, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: DESCRIPTION); + + public override ImmutableArray SupportedDiagnostics => [RULE]; + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + context.RegisterSyntaxNodeAction(this.AnalyzeObjectCreation, SyntaxKind.ObjectCreationExpression); + } + + private void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context) + { + var objectCreation = (ObjectCreationExpressionSyntax)context.Node; + if (context.SemanticModel.GetSymbolInfo(objectCreation.Type).Symbol is not ITypeSymbol typeSymbol) + return; + + if (typeSymbol.ToString() == "System.Random" || typeSymbol is { Name: "Random", ContainingNamespace.Name: "System" }) + { + var diagnostic = Diagnostic.Create(RULE, objectCreation.GetLocation()); + context.ReportDiagnostic(diagnostic); + } + } +} \ No newline at end of file