Created
June 25, 2024 11:53
-
-
Save SolarianZ/234ab549a570f4775cf5ce037c1b958d to your computer and use it in GitHub Desktop.
{"category": "C#/Analyzer", "keywords": "C#, Roslyn, Analyzer, override, call, base"} A Roslyn analyzer used to prevent calling the base class method implementation when overriding a method.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// < !--Add to YOUR_PROJECT.csproj-- > | |
// < Project Sdk = "Microsoft.NET.Sdk" > | |
// | |
// < !--... --> | |
// | |
// < ItemGroup > | |
// < Analyzer Include = "ABSOLUTE_OR_RELATIVE_FOLDER\DontCallBaseImplementation.dll" /> | |
// </ ItemGroup > | |
// | |
// < !--... --> | |
// | |
// </ Project > | |
// | |
// https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/tutorials/how-to-write-csharp-analyzer-code-fix | |
using System; | |
using System.Collections.Immutable; | |
using System.Linq; | |
using Microsoft.CodeAnalysis; | |
using Microsoft.CodeAnalysis.CSharp; | |
using Microsoft.CodeAnalysis.CSharp.Syntax; | |
using Microsoft.CodeAnalysis.Diagnostics; | |
namespace DontCallBaseImplementation | |
{ | |
[AttributeUsage(AttributeTargets.Method, Inherited = false)] | |
public class DontCallBaseImplementationAttribute : Attribute { } | |
[DiagnosticAnalyzer(LanguageNames.CSharp)] | |
public class DontCallBaseImplementationAnalyzer : DiagnosticAnalyzer | |
{ | |
public const string DiagnosticId = "DontCallBaseImplementation"; | |
private static readonly LocalizableString Title = "Invalid base method implementation call"; | |
private static readonly LocalizableString MessageFormat = "Method '{0}' with [DontCallBaseImplementationAttribute] should not call base method implementation"; | |
private static readonly LocalizableString Description = "The method in the derived class calls the base method implementation which is marked with [DontCallBaseImplementationAttribute]."; | |
private const string Category = "Usage"; | |
private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, | |
DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description); | |
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } } | |
public override void Initialize(AnalysisContext context) | |
{ | |
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | |
context.EnableConcurrentExecution(); | |
context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.InvocationExpression); | |
} | |
private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context) | |
{ | |
InvocationExpressionSyntax invocationExpression = (InvocationExpressionSyntax)context.Node; | |
if (invocationExpression.Expression is MemberAccessExpressionSyntax memberAccess && | |
memberAccess.Expression is BaseExpressionSyntax) | |
{ | |
IMethodSymbol invokedSymbol = context.SemanticModel.GetSymbolInfo(invocationExpression).Symbol as IMethodSymbol; | |
if (invokedSymbol == null) return; | |
IMethodSymbol currentMethod = context.ContainingSymbol as IMethodSymbol; | |
IMethodSymbol baseMethod = currentMethod?.OverriddenMethod; | |
if (!SymbolEqualityComparer.Default.Equals(invokedSymbol, baseMethod)) return; | |
AttributeData dontCallBaseImplAttr = baseMethod.GetAttributes() | |
.FirstOrDefault(attr => attr.AttributeClass.Name == nameof(DontCallBaseImplementationAttribute)); | |
if (dontCallBaseImplAttr != null) | |
{ | |
Diagnostic diagnostic = Diagnostic.Create(Rule, invocationExpression.GetLocation(), memberAccess.Name); | |
context.ReportDiagnostic(diagnostic); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment