Skip to content

Commit

Permalink
Update ConstructorArgumentsShouldMatchAnalyzer to handle Func<T> cons…
Browse files Browse the repository at this point in the history
…tructor
  • Loading branch information
Latta committed Dec 3, 2024
1 parent ac4a82c commit 3017509
Showing 1 changed file with 47 additions and 3 deletions.
50 changes: 47 additions & 3 deletions src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ private static void VerifyInterfaceMockAttempt(
}

private static void AnalyzeCompilation(CompilationStartAnalysisContext context)

Check failure on line 144 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

; expected

Check failure on line 144 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

; expected
context.RegisterSyntaxNodeAction(context => AnalyzeObjectCreation(context, knownSymbols), SyntaxKind.ObjectCreationExpression);

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Invalid token '(' in class, record, struct, or interface member declaration

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Tuple must contain at least two elements.

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

) expected

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Invalid token '=>' in class, record, struct, or interface member declaration

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Identifier expected

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Identifier expected

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

; expected

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Invalid token ',' in class, record, struct, or interface member declaration

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Invalid token ')' in class, record, struct, or interface member declaration

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Invalid token '(' in class, record, struct, or interface member declaration

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Tuple must contain at least two elements.

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

) expected

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Invalid token '=>' in class, record, struct, or interface member declaration

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Identifier expected

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Identifier expected

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

; expected

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Invalid token ',' in class, record, struct, or interface member declaration

Check failure on line 145 in src/Analyzers/ConstructorArgumentsShouldMatchAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Invalid token ')' in class, record, struct, or interface member declaration
context.RegisterSyntaxNodeAction(context => AnalyzeInvocationExpression(context, knownSymbols), SyntaxKind.InvocationExpression);
{
context.CancellationToken.ThrowIfCancellationRequested();

Expand All @@ -165,8 +167,6 @@ private static void AnalyzeCompilation(CompilationStartAnalysisContext context)
}

// These are for classes
context.RegisterSyntaxNodeAction(context => AnalyzeNewObject(context, knownSymbols), SyntaxKind.ObjectCreationExpression);
context.RegisterSyntaxNodeAction(context => AnalyzeInstanceCall(context, knownSymbols), SyntaxKind.InvocationExpression);
}

private static void AnalyzeInstanceCall(SyntaxNodeAnalysisContext context, MoqKnownSymbols knownSymbols)
Expand Down Expand Up @@ -411,6 +411,11 @@ private static void VerifyMockAttempt(
}
}

private static void VerifyClassMockAttempt(
SyntaxNodeAnalysisContext context,
ITypeSymbol mockedClass,
ArgumentListSyntax? argumentList,
ArgumentSyntax[] arguments)
private static void VerifyClassMockAttempt(
SyntaxNodeAnalysisContext context,
ITypeSymbol mockedClass,
Expand All @@ -423,6 +428,13 @@ private static void VerifyClassMockAttempt(
.Where(methodSymbol => methodSymbol.IsConstructor())
.ToArray();

// Check if the first argument is a Func<T>
if (arguments.Length > 0 && IsFactoryMethodArgument(context, arguments[0]))
{
// If it's a Func<T>, we don't need to check constructor arguments
return;
}

// Bail out early if there are no arguments on constructors or no constructors at all
(bool IsEmpty, Location Location) constructorIsEmpty = ConstructorIsEmpty(constructors, argumentList, context);
if (constructorIsEmpty.IsEmpty)
Expand All @@ -439,4 +451,36 @@ private static void VerifyClassMockAttempt(
context.ReportDiagnostic(diagnostic);
}
}
}

private static bool IsFactoryMethodArgument(SyntaxNodeAnalysisContext context, ArgumentSyntax argument)
{
var symbolInfo = context.SemanticModel.GetSymbolInfo(argument.Expression);
if (symbolInfo.Symbol is IMethodSymbol methodSymbol)
{
var containingType = methodSymbol.ContainingType;
return containingType != null && containingType.Name == "Func" && containingType.TypeArguments.Length == 1;
}
return false;
}
{
IMethodSymbol[] constructors = mockedClass
.GetMembers()
.OfType<IMethodSymbol>()
.Where(methodSymbol => methodSymbol.IsConstructor())
.ToArray();

// Bail out early if there are no arguments on constructors or no constructors at all
(bool IsEmpty, Location Location) constructorIsEmpty = ConstructorIsEmpty(constructors, argumentList, context);
if (constructorIsEmpty.IsEmpty)
{
Diagnostic diagnostic = constructorIsEmpty.Location.CreateDiagnostic(ClassMustHaveMatchingConstructor, argumentList);
context.ReportDiagnostic(diagnostic);
return;
}

// We have constructors, now we need to check if the arguments match any of them
if (!AnyConstructorsFound(constructors, arguments, context))
{
Diagnostic diagnostic = constructorIsEmpty.Location.CreateDiagnostic(ClassMustHaveMatchingConstructor, argumentList);
context.ReportDiagnostic(diagnostic);
}

0 comments on commit 3017509

Please sign in to comment.