Skip to content

Commit 5bbdb5c

Browse files
authored
chore: create proper diagnostics for AutoFixture (#1917)
* chore: create proper diagnostics for AutoFixture * create descriptors and analyzers * added analyzers to base tests * segregated autofixture0001 * rename diagnostics to RSAF * reran diagnostics after rename * implement rsaf0002 * add rsaf0003 clean up a bunch of tests
1 parent ecc5c79 commit 5bbdb5c

316 files changed

Lines changed: 4025 additions & 2207 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/Testing.AutoFixtures/AutoFixtureGenerator+StaticGenerator.cs

Lines changed: 45 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Text.RegularExpressions;
2+
23
using Microsoft.CodeAnalysis;
34
using Microsoft.CodeAnalysis.CSharp;
45
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -134,12 +135,10 @@ Compilation compilation
134135
{
135136
var isAbstract = parameterSymbol.IsAbstract;
136137
var isInterface = parameterSymbol.Type.TypeKind == TypeKind.Interface;
137-
var isValueType = parameterSymbol.Type.IsValueType;
138138

139139
var symbolName = $"_{parameterSymbol.Name}";
140-
if (!isAbstract && !isInterface)
141-
{
142-
return FieldDeclaration(
140+
return !isAbstract && !isInterface
141+
? FieldDeclaration(
143142
VariableDeclaration(
144143
IdentifierName(
145144
Identifier(
@@ -171,10 +170,8 @@ Compilation compilation
171170
TokenList(
172171
Token(SyntaxKind.PrivateKeyword)
173172
)
174-
);
175-
}
176-
177-
return FieldDeclaration(
173+
)
174+
: FieldDeclaration(
178175
VariableDeclaration(
179176
IdentifierName(
180177
Identifier(
@@ -233,7 +230,7 @@ private static MemberDeclarationSyntax BuildBuildMethod(
233230
IEnumerable<IParameterSymbol> parameterSymbols
234231
)
235232
{
236-
List<SyntaxNodeOrToken> list = new();
233+
List<SyntaxNodeOrToken> list = [];
237234
foreach (var parameterSymbol in parameterSymbols)
238235
{
239236
list.Add(Argument(IdentifierName($"_{parameterSymbol.Name}")));
@@ -379,17 +376,14 @@ private static MemberDeclarationSyntax WithPropertyMethod(IParameterSymbol const
379376

380377
SyntaxToken withTypeOrParameterName(IParameterSymbol parameterSymbol)
381378
{
382-
var primitiveName = $"{char.ToUpper(parameterSymbol.Name[0])}{parameterSymbol.Name.Substring(1, parameterSymbol.Name.Length - 1)}";
379+
var primitiveName = $"{ char.ToUpper(parameterSymbol.Name[0]).ToString()}{parameterSymbol.Name[1..]}";
383380
var splitLastCamel = useParameterName(parameterSymbol) ? primitiveName : SplitLastCamel(parameterSymbol);
384381
return Identifier($"With{splitLastCamel}");
385382
}
386383

387-
bool useParameterName(IParameterSymbol parameterSymbol)
388-
{
389-
return parameterSymbol.Type.TypeKind != TypeKind.Interface
390-
|| parameterSymbol.Type.IsValueType
391-
|| !parameterSymbol.Type.IsAbstract;
392-
}
384+
bool useParameterName(IParameterSymbol parameterSymbol) => parameterSymbol.Type.TypeKind != TypeKind.Interface
385+
|| parameterSymbol.Type.IsValueType
386+
|| !parameterSymbol.Type.IsAbstract;
393387
}
394388

395389
private static MemberDeclarationSyntax BuildOperator(string className, string fixtureName) =>
@@ -495,9 +489,8 @@ private static InvocationExpressionSyntax GetFieldInvocation(Compilation compila
495489
{
496490
var fakeItEasy = compilation.GetTypeByMetadataName("FakeItEasy.Fake");
497491

498-
if (fakeItEasy is { })
499-
{
500-
return InvocationExpression(
492+
return fakeItEasy is { }
493+
? InvocationExpression(
501494
MemberAccessExpression(
502495
SyntaxKind.SimpleMemberAccessExpression,
503496
IdentifierName("A"),
@@ -508,10 +501,8 @@ private static InvocationExpressionSyntax GetFieldInvocation(Compilation compila
508501
typeArgumentListSyntax(symbol)
509502
)
510503
)
511-
);
512-
}
513-
514-
return InvocationExpression(
504+
)
505+
: InvocationExpression(
515506
MemberAccessExpression(
516507
SyntaxKind.SimpleMemberAccessExpression,
517508
IdentifierName(
@@ -529,32 +520,11 @@ private static InvocationExpressionSyntax GetFieldInvocation(Compilation compila
529520
)
530521
)
531522
);
532-
533-
TypeArgumentListSyntax typeArgumentListSyntax(IParameterSymbol parameterSymbol)
534-
{
535-
return TypeArgumentList(
536-
SingletonSeparatedList<TypeSyntax>(
537-
ParseName(parameterSymbol.Type.GetGenericDisplayName())
538-
)
523+
static TypeArgumentListSyntax typeArgumentListSyntax(IParameterSymbol parameterSymbol) => TypeArgumentList(
524+
SingletonSeparatedList<TypeSyntax>(
525+
ParseName(parameterSymbol.Type.GetGenericDisplayName())
526+
)
539527
);
540-
}
541-
}
542-
543-
private static void ReportDiagnostic(
544-
SourceProductionContext productionContext,
545-
DiagnosticDescriptor diagnosticDescriptor,
546-
IEnumerable<Location> locations
547-
)
548-
{
549-
ReportDiagnostic(productionContext, diagnosticDescriptor, locations.ToArray());
550-
}
551-
552-
private static void ReportDiagnostic(SourceProductionContext productionContext, DiagnosticDescriptor diagnosticDescriptor, params Location[] locations)
553-
{
554-
foreach (var location in locations)
555-
{
556-
productionContext.ReportDiagnostic(Diagnostic.Create(diagnosticDescriptor, location));
557-
}
558528
}
559529

560530
private const string Fixture = nameof(Fixture);
@@ -563,57 +533,38 @@ private static void ReportDiagnostic(SourceProductionContext productionContext,
563533
{
564534
var targetSymbol = syntaxContext.TargetSymbol as INamedTypeSymbol;
565535

566-
if (syntaxContext.Attributes[0].ConstructorArguments.Length == 0)
567-
{
568-
return targetSymbol;
569-
}
570-
571-
if (syntaxContext.Attributes[0].ConstructorArguments[0].Value is INamedTypeSymbol namedTypeSymbol)
572-
{
573-
return namedTypeSymbol;
574-
}
575-
576-
return null;
577-
}
578-
579-
580-
private static bool ReportAutoFixture0001(INamedTypeSymbol classForFixture, SourceProductionContext productionContext)
581-
{
582-
if (classForFixture.Constructors.All(x => x.Parameters.IsDefaultOrEmpty))
583-
{
584-
ReportDiagnostic(productionContext, Diagnostics.AutoFixture0001, classForFixture.Locations);
585-
return true;
586-
}
587-
588-
return false;
536+
return syntaxContext.Attributes[0].ConstructorArguments.Length == 0
537+
? targetSymbol
538+
: syntaxContext.Attributes[0].ConstructorArguments[0].Value is INamedTypeSymbol namedTypeSymbol ? namedTypeSymbol : null;
589539
}
590540

541+
private static bool ReportAutoFixture0001(INamedTypeSymbol classForFixture, SourceProductionContext productionContext) => classForFixture.Constructors.All(methodSymbol => methodSymbol.Parameters.IsDefaultOrEmpty);
591542

592543
private static bool ReportAutoFixture0002(INamedTypeSymbol namedTypeSymbol, SourceProductionContext productionContext)
593544
{
594-
var reported = false;
595-
foreach (var location in namedTypeSymbol
596-
.Constructors
597-
.SelectMany(methodSymbol => methodSymbol.Parameters)
598-
.Distinct(ParameterReductionComparer.Default)
599-
.Select(parameterSymbol => new { parameterSymbol, isArrayType = parameterSymbol.Type is IArrayTypeSymbol })
600-
.Select(
601-
tuple => new
602-
{
603-
tuple.isArrayType,
604-
tuple.parameterSymbol,
605-
hasParamsKeyWord = tuple.parameterSymbol.ToDisplayString().Contains("params"),
606-
}
607-
)
608-
.Where(tuple => tuple.isArrayType && tuple.hasParamsKeyWord)
609-
.SelectMany(tuple => tuple.parameterSymbol.Locations))
610-
{
611-
productionContext.ReportDiagnostic(Diagnostic.Create(Diagnostics.AutoFixture0002, location));
612-
if (!reported)
613-
{
614-
reported = true;
615-
}
616-
}
545+
const bool reported = false;
546+
// foreach (var location in namedTypeSymbol
547+
// .Constructors
548+
// .SelectMany(methodSymbol => methodSymbol.Parameters)
549+
// .Distinct(ParameterReductionComparer.Default)
550+
// .Select(parameterSymbol => new { parameterSymbol, isArrayType = parameterSymbol.Type is IArrayTypeSymbol })
551+
// .Select(
552+
// tuple => new
553+
// {
554+
// tuple.isArrayType,
555+
// tuple.parameterSymbol,
556+
// hasParamsKeyWord = tuple.parameterSymbol.ToDisplayString().Contains("params"),
557+
// }
558+
// )
559+
// .Where(tuple => tuple.isArrayType && tuple.hasParamsKeyWord)
560+
// .SelectMany(tuple => tuple.parameterSymbol.Locations))
561+
// {
562+
// productionContext.ReportDiagnostic(Diagnostic.Create(Rsaf0002.Descriptor, location));
563+
// if (!reported)
564+
// {
565+
// reported = true;
566+
// }
567+
// }
617568

618569
return reported;
619570
}

src/Testing.AutoFixtures/AutoFixtureGenerator.cs

Lines changed: 10 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace Rocket.Surgery.Extensions.Testing.AutoFixtures;
66

77
[Generator]
8-
public partial class AutoFixtureGenerator : IIncrementalGenerator //, ISourceGenerator
8+
public partial class AutoFixtureGenerator : IIncrementalGenerator
99
{
1010
private static void CurrentGenerator(
1111
INamedTypeSymbol namedTypeSymbol,
@@ -51,14 +51,14 @@ Compilation compilation
5151
);
5252

5353
var classDeclaration = BuildClassDeclaration(fixtureName)
54-
.WithMembers(new(fullList));
54+
.WithMembers([.. fullList]);
5555

5656
var namespaceDeclaration = BuildNamespace(targetSymbol)
5757
.WithMembers(new(classDeclaration));
5858

5959
var usingDirectives = new HashSet<string>(
6060
parameterSymbols
61-
.Select(symbol => symbol.Type.ContainingNamespace?.ToDisplayString() ?? string.Empty)
61+
.Select(symbol => symbol.Type.ContainingNamespace?.ToDisplayString() ?? "")
6262
.Where(x => !string.IsNullOrWhiteSpace(x))
6363
.Distinct()
6464
)
@@ -112,20 +112,19 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
112112

113113
context.RegisterSourceOutput(syntaxProvider, generateFixtureBuilder);
114114

115-
context.RegisterPostInitializationOutput(
116-
initializationContext =>
117-
{
118-
initializationContext.AddSource("AutoFixtureAttribute.g.cs", Attribute.Source());
119-
initializationContext.AddSource($"{nameof(AutoFixtureBase)}.g.cs", AutoFixtureBase.Source);
120-
}
115+
context.RegisterPostInitializationOutput(initializationContext =>
116+
{
117+
initializationContext.AddSource("AutoFixtureAttribute.g.cs", Attribute.Source());
118+
initializationContext.AddSource($"{nameof(AutoFixtureBase)}.g.cs", AutoFixtureBase.Source);
119+
}
121120
);
122121

123-
void generateFixtureBuilder(
122+
static void generateFixtureBuilder(
124123
SourceProductionContext productionContext,
125124
(GeneratorAttributeSyntaxContext context, Compilation compilation) valueTuple
126125
)
127126
{
128-
( var syntaxContext, var compilation ) = valueTuple;
127+
(var syntaxContext, var compilation) = valueTuple;
129128

130129
var classForFixture = GetClassForFixture(syntaxContext);
131130

@@ -148,37 +147,4 @@ void generateFixtureBuilder(
148147
CurrentGenerator(classForFixture, syntaxContext.TargetSymbol, productionContext, compilation);
149148
}
150149
}
151-
152-
internal class ParameterReductionComparer : IEqualityComparer<IParameterSymbol>
153-
{
154-
public static IEqualityComparer<IParameterSymbol> Default { get; } = new ParameterReductionComparer();
155-
156-
public bool Equals(IParameterSymbol x, IParameterSymbol y) =>
157-
( x.Type.Equals(y.Type) && x.Name.Equals(y.Name) ) || SymbolEqualityComparer.Default.Equals(x, y);
158-
159-
public int GetHashCode(IParameterSymbol obj) => SymbolEqualityComparer.Default.GetHashCode(obj.Type) + obj.Type.GetHashCode() + obj.Name.GetHashCode();
160-
}
161-
162-
internal class NamespaceComparer : IComparer<string>
163-
{
164-
public static NamespaceComparer Default { get; } = new();
165-
166-
public int Compare(string x, string y)
167-
{
168-
// Check if both namespaces start with "System"
169-
var xIsSystem = x.StartsWith("System", StringComparison.Ordinal);
170-
var yIsSystem = y.StartsWith("System", StringComparison.Ordinal);
171-
172-
return xIsSystem switch
173-
{
174-
// If only one of them starts with "System", prioritize it
175-
true when !yIsSystem => -1,
176-
false when yIsSystem => 1,
177-
// If both start with "System" or neither does, compare them alphabetically
178-
true when yIsSystem => string.Compare(x, y, StringComparison.Ordinal),
179-
false when !yIsSystem => string.Compare(x, y, StringComparison.Ordinal),
180-
_ => xIsSystem ? -1 : 1,
181-
};
182-
}
183-
}
184150
}

src/Testing.AutoFixtures/Diagnostics.cs

Lines changed: 0 additions & 33 deletions
This file was deleted.

0 commit comments

Comments
 (0)