-
Notifications
You must be signed in to change notification settings - Fork 4
refactor: eliminate DRY violations across analyzer pairs #1044
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
819a99d
ab1d7ab
503330a
1d5024d
756e0a4
2037953
d6e681f
1cc8bf0
7a3e91e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,8 +11,39 @@ | |
| /// </remarks> | ||
| public abstract class MockBehaviorDiagnosticAnalyzerBase : DiagnosticAnalyzer | ||
| { | ||
| /// <summary> | ||
| /// Extracts the mocked type name from the operation for use in diagnostic messages. | ||
| /// </summary> | ||
| /// <param name="operation">The operation being analyzed.</param> | ||
| /// <param name="target">The target method symbol.</param> | ||
| /// <returns>The display name of the mocked type.</returns> | ||
| internal static string GetMockedTypeName(IOperation operation, IMethodSymbol target) | ||
| { | ||
| // For object creation (new Mock<T>), get the type argument from the Mock<T> type | ||
| if (operation is IObjectCreationOperation objectCreation | ||
| && objectCreation.Type is INamedTypeSymbol namedType | ||
| && namedType.TypeArguments.Length > 0) | ||
| { | ||
| return namedType.TypeArguments[0].ToDisplayString(); | ||
| } | ||
|
|
||
| // For method invocation (Mock.Of<T>), get the type argument from the method | ||
| if (operation is IInvocationOperation invocation && invocation.TargetMethod.TypeArguments.Length > 0) | ||
| { | ||
| return invocation.TargetMethod.TypeArguments[0].ToDisplayString(); | ||
| } | ||
|
|
||
| // Try the containing type's type arguments (e.g. Mock<T>.ctor) | ||
| if (target.ContainingType?.TypeArguments.Length > 0) | ||
| { | ||
| return target.ContainingType.TypeArguments[0].ToDisplayString(); | ||
| } | ||
|
|
||
| return "T"; | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public override void Initialize(AnalysisContext context) | ||
|
Check failure on line 46 in src/Analyzers/MockBehaviorDiagnosticAnalyzerBase.cs
|
||
| { | ||
| context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | ||
| context.EnableConcurrentExecution(); | ||
|
|
@@ -22,6 +53,116 @@ | |
|
|
||
| private protected abstract void AnalyzeCore(OperationAnalysisContext context, IMethodSymbol target, ImmutableArray<IArgumentOperation> arguments, MoqKnownSymbols knownSymbols); | ||
|
|
||
| /// <summary> | ||
| /// Attempts to report a diagnostic for a MockBehavior parameter issue. | ||
| /// </summary> | ||
| /// <param name="context">The operation analysis context.</param> | ||
| /// <param name="method">The method to check for MockBehavior parameter.</param> | ||
| /// <param name="knownSymbols">The known Moq symbols.</param> | ||
| /// <param name="rule">The diagnostic rule to report.</param> | ||
| /// <param name="editType">The type of edit for the code fix.</param> | ||
| /// <returns>True if a diagnostic was reported; otherwise, false.</returns> | ||
| internal bool TryReportMockBehaviorDiagnostic( | ||
|
Check failure on line 65 in src/Analyzers/MockBehaviorDiagnosticAnalyzerBase.cs
|
||
| OperationAnalysisContext context, | ||
| IMethodSymbol method, | ||
| MoqKnownSymbols knownSymbols, | ||
| DiagnosticDescriptor rule, | ||
| DiagnosticEditProperties.EditType editType) | ||
| { | ||
| if (!method.TryGetParameterOfType(knownSymbols.MockBehavior!, out IParameterSymbol? parameterMatch, cancellationToken: context.CancellationToken)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| ImmutableDictionary<string, string?> properties = new DiagnosticEditProperties | ||
| { | ||
| TypeOfEdit = editType, | ||
| EditPosition = parameterMatch.Ordinal, | ||
| }.ToImmutableDictionary(); | ||
|
|
||
| context.ReportDiagnostic(context.Operation.CreateDiagnostic(rule, properties)); | ||
| return true; | ||
|
rjmurillo-bot marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| /// <summary> | ||
| /// Attempts to report a diagnostic for a MockBehavior parameter issue, with message format arguments. | ||
| /// </summary> | ||
| /// <param name="context">The operation analysis context.</param> | ||
| /// <param name="method">The method to check for MockBehavior parameter.</param> | ||
| /// <param name="knownSymbols">The known Moq symbols.</param> | ||
| /// <param name="rule">The diagnostic rule to report.</param> | ||
| /// <param name="editType">The type of edit for the code fix.</param> | ||
| /// <param name="messageArgs">Arguments to format into the diagnostic message.</param> | ||
| /// <returns>True if a diagnostic was reported; otherwise, false.</returns> | ||
| internal bool TryReportMockBehaviorDiagnostic( | ||
| OperationAnalysisContext context, | ||
| IMethodSymbol method, | ||
| MoqKnownSymbols knownSymbols, | ||
| DiagnosticDescriptor rule, | ||
| DiagnosticEditProperties.EditType editType, | ||
|
rjmurillo-bot marked this conversation as resolved.
Outdated
rjmurillo-bot marked this conversation as resolved.
|
||
| params object[] messageArgs) | ||
| { | ||
| if (!method.TryGetParameterOfType(knownSymbols.MockBehavior!, out IParameterSymbol? parameterMatch, cancellationToken: context.CancellationToken)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| ImmutableDictionary<string, string?> properties = new DiagnosticEditProperties | ||
| { | ||
| TypeOfEdit = editType, | ||
| EditPosition = parameterMatch.Ordinal, | ||
| }.ToImmutableDictionary(); | ||
|
|
||
| context.ReportDiagnostic(context.Operation.CreateDiagnostic(rule, properties, messageArgs)); | ||
| return true; | ||
|
rjmurillo-bot marked this conversation as resolved.
|
||
| } | ||
|
|
||
| /// <summary> | ||
| /// Attempts to handle missing MockBehavior parameter by checking for overloads that accept it. | ||
| /// </summary> | ||
| /// <param name="context">The operation analysis context.</param> | ||
| /// <param name="mockParameter">The MockBehavior parameter (should be null to trigger overload check).</param> | ||
| /// <param name="target">The target method to check for overloads.</param> | ||
| /// <param name="knownSymbols">The known Moq symbols.</param> | ||
| /// <param name="rule">The diagnostic rule to report.</param> | ||
| /// <returns>True if a diagnostic was reported; otherwise, false.</returns> | ||
| internal bool TryHandleMissingMockBehaviorParameter( | ||
| OperationAnalysisContext context, | ||
| IParameterSymbol? mockParameter, | ||
| IMethodSymbol target, | ||
| MoqKnownSymbols knownSymbols, | ||
| DiagnosticDescriptor rule) | ||
| { | ||
| // If the target method doesn't have a MockBehavior parameter, check if there's an overload that does | ||
| return mockParameter is null | ||
| && target.TryGetOverloadWithParameterOfType(knownSymbols.MockBehavior!, out IMethodSymbol? methodMatch, out _, cancellationToken: context.CancellationToken) | ||
| && TryReportMockBehaviorDiagnostic(context, methodMatch, knownSymbols, rule, DiagnosticEditProperties.EditType.Insert); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Attempts to handle missing MockBehavior parameter by checking for overloads that accept it, | ||
| /// with message format arguments. | ||
| /// </summary> | ||
| /// <param name="context">The operation analysis context.</param> | ||
| /// <param name="mockParameter">The MockBehavior parameter (should be null to trigger overload check).</param> | ||
| /// <param name="target">The target method to check for overloads.</param> | ||
| /// <param name="knownSymbols">The known Moq symbols.</param> | ||
| /// <param name="rule">The diagnostic rule to report.</param> | ||
| /// <param name="messageArgs">Arguments to format into the diagnostic message.</param> | ||
| /// <returns>True if a diagnostic was reported; otherwise, false.</returns> | ||
| internal bool TryHandleMissingMockBehaviorParameter( | ||
| OperationAnalysisContext context, | ||
| IParameterSymbol? mockParameter, | ||
| IMethodSymbol target, | ||
| MoqKnownSymbols knownSymbols, | ||
| DiagnosticDescriptor rule, | ||
|
rjmurillo-bot marked this conversation as resolved.
Outdated
rjmurillo-bot marked this conversation as resolved.
|
||
| params object[] messageArgs) | ||
| { | ||
| return mockParameter is null | ||
| && target.TryGetOverloadWithParameterOfType(knownSymbols.MockBehavior!, out IMethodSymbol? methodMatch, out _, cancellationToken: context.CancellationToken) | ||
| && TryReportMockBehaviorDiagnostic(context, methodMatch, knownSymbols, rule, DiagnosticEditProperties.EditType.Insert, messageArgs); | ||
| } | ||
|
|
||
| private void RegisterCompilationStartAction(CompilationStartAnalysisContext context) | ||
| { | ||
| MoqKnownSymbols knownSymbols = new(context.Compilation); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.