Skip to content
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

Report diagnostic if DynamicData is referencing a member that's not method/property (e.g, field) (and some cleanup) #4383

Merged
merged 4 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 41 additions & 29 deletions src/Analyzers/MSTest.Analyzers/DynamicDataShouldBeValidAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public sealed class DynamicDataShouldBeValidAnalyzer : DiagnosticAnalyzer
internal static readonly DiagnosticDescriptor SourceTypeMethodRule = NotTestMethodRule
.WithMessage(new(nameof(Resources.DynamicDataShouldBeValidMessageFormat_SourceTypeMethod), Resources.ResourceManager, typeof(Resources)));

internal static readonly DiagnosticDescriptor SourceTypeNotPropertyOrMethodRule = NotTestMethodRule
.WithMessage(new(nameof(Resources.DynamicDataShouldBeValidMessageFormat_SourceTypeNotPropertyOrMethod), Resources.ResourceManager, typeof(Resources)));

internal static readonly DiagnosticDescriptor MemberMethodRule = NotTestMethodRule
.WithMessage(new(nameof(Resources.DynamicDataShouldBeValidMessageFormat_MemberMethod), Resources.ResourceManager, typeof(Resources)));

Expand All @@ -59,8 +62,17 @@ public sealed class DynamicDataShouldBeValidAnalyzer : DiagnosticAnalyzer
internal static readonly DiagnosticDescriptor DisplayMethodSignatureRule = NotTestMethodRule
.WithMessage(new(nameof(Resources.DynamicDataShouldBeValidMessageFormat_DisplayMethodSignature), Resources.ResourceManager, typeof(Resources)));

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }
= ImmutableArray.Create(NotTestMethodRule);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(
NotTestMethodRule,
MemberNotFoundRule,
FoundTooManyMembersRule,
SourceTypePropertyRule,
SourceTypeMethodRule,
SourceTypeNotPropertyOrMethodRule,
MemberMethodRule,
MemberTypeRule,
DataMemberSignatureRule,
DisplayMethodSignatureRule);

public override void Initialize(AnalysisContext context)
{
Expand Down Expand Up @@ -91,7 +103,7 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo
var methodSymbol = (IMethodSymbol)context.Symbol;

bool isTestMethod = false;
List<AttributeData> dynamicDataAttributes = new();
bool hasDynamicDataAttribute = false;
foreach (AttributeData methodAttribute in methodSymbol.GetAttributes())
{
// Current method should be a test method or should inherit from the TestMethod attribute.
Expand All @@ -103,26 +115,15 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo

if (SymbolEqualityComparer.Default.Equals(methodAttribute.AttributeClass, dynamicDataAttributeSymbol))
{
dynamicDataAttributes.Add(methodAttribute);
hasDynamicDataAttribute = true;
AnalyzeAttribute(context, methodAttribute, methodSymbol, dynamicDataSourceTypeSymbol, ienumerableTypeSymbol, itupleTypeSymbol, methodInfoTypeSymbol);
}
}

// Check if attribute is set on a test method.
if (!isTestMethod)
{
if (dynamicDataAttributes.Count > 0)
{
context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotTestMethodRule));
}

return;
}

// Check each data row attribute.
foreach (AttributeData attribute in dynamicDataAttributes)
if (!isTestMethod && hasDynamicDataAttribute)
{
AnalyzeAttribute(context, attribute, methodSymbol, dynamicDataSourceTypeSymbol, ienumerableTypeSymbol, itupleTypeSymbol,
methodInfoTypeSymbol);
context.ReportDiagnostic(methodSymbol.CreateDiagnostic(NotTestMethodRule));
}
}

Expand Down Expand Up @@ -192,18 +193,29 @@ private static void AnalyzeDataSource(SymbolAnalysisContext context, AttributeDa

ISymbol member = potentialMembers[0];

// If the member is a property and the data source type is not set to property, report a diagnostic.
if (member.Kind == SymbolKind.Property && dataSourceType is not (DynamicDataSourceTypeProperty or DynamicDataSourceTypeAutoDetect))
switch (member.Kind)
{
context.ReportDiagnostic(attributeSyntax.CreateDiagnostic(SourceTypePropertyRule, declaringType.Name, memberName));
return;
}

// If the member is a method and the data source type is not set to method, report a diagnostic.
if (member.Kind == SymbolKind.Method && dataSourceType is not (DynamicDataSourceTypeMethod or DynamicDataSourceTypeAutoDetect))
{
context.ReportDiagnostic(attributeSyntax.CreateDiagnostic(SourceTypeMethodRule, declaringType.Name, memberName));
return;
case SymbolKind.Property:
// If the member is a property and the data source type is not set to property or auto detect, report a diagnostic.
if (dataSourceType is not (DynamicDataSourceTypeProperty or DynamicDataSourceTypeAutoDetect))
{
context.ReportDiagnostic(attributeSyntax.CreateDiagnostic(SourceTypePropertyRule, declaringType.Name, memberName));
return;
}

break;
case SymbolKind.Method:
// If the member is a method and the data source type is not set to method or auto detect, report a diagnostic.
if (dataSourceType is not (DynamicDataSourceTypeMethod or DynamicDataSourceTypeAutoDetect))
{
context.ReportDiagnostic(attributeSyntax.CreateDiagnostic(SourceTypeMethodRule, declaringType.Name, memberName));
return;
}

break;
default:
context.ReportDiagnostic(attributeSyntax.CreateDiagnostic(SourceTypeNotPropertyOrMethodRule, declaringType.Name, memberName));
return;
}

if (!member.IsStatic)
Expand Down
13 changes: 11 additions & 2 deletions src/Analyzers/MSTest.Analyzers/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions src/Analyzers/MSTest.Analyzers/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ The type declaring these methods should also respect the following rules:
<value>'[DynamicDta]' member '{0}.{1}' is found more than once</value>
</data>
<data name="DynamicDataShouldBeValidMessageFormat_SourceTypeProperty" xml:space="preserve">
<value>'[DynamicData]' member '{0}.{1}' is a property so you should set 'DynamicDataSourceType.Property'</value>
<value>'[DynamicData]' member '{0}.{1}' is a property so you should use 'DynamicDataSourceType.AutoDetect' or 'DynamicDataSourceType.Property' (auto detect is the default when not specified explicitly, and is recommended)</value>
</data>
<data name="DynamicDataShouldBeValidMessageFormat_MemberMethod" xml:space="preserve">
<value>'[DynamicData]' member '{0}.{1}' should be a method</value>
Expand All @@ -502,7 +502,7 @@ The type declaring these methods should also respect the following rules:
<value>'[DynamicData]' referenced member '{0}.{1}' should return 'IEnumerable&lt;object[]&gt;', 'IEnumerable&lt;Tuple&gt;` or 'IEnumerable&lt;ValueTuple&gt;'</value>
</data>
<data name="DynamicDataShouldBeValidMessageFormat_SourceTypeMethod" xml:space="preserve">
<value>'[DynamicData]' member '{0}.{1}' is a method so you should set 'DynamicDataSourceType.Method'</value>
<value>'[DynamicData]' member '{0}.{1}' is a method so you should use 'DynamicDataSourceType.AutoDetect' or 'DynamicDataSourceType.Method' (auto detect is the default when not specified explicitly, and is recommended)</value>
</data>
<data name="DynamicDataShouldBeValidMessageFormat_DisplayMethodSignature" xml:space="preserve">
<value>'[DynamicData]' display name method '{0}.{1}' signature is invalid</value>
Expand Down Expand Up @@ -540,4 +540,7 @@ The type declaring these methods should also respect the following rules:
<data name="DataRowShouldBeValidMessageFormat_GenericTypeArgumentConflictingTypes" xml:space="preserve">
<value>Found two conflicting types for generic parameter '{0}'. The conflicting types are '{1}' and '{2}'.</value>
</data>
<data name="DynamicDataShouldBeValidMessageFormat_SourceTypeNotPropertyOrMethod" xml:space="preserve">
<value>'[DynamicData]' member '{0}.{1}' is not a property nor a method. Only properties and methods are supported.</value>
</data>
</root>
13 changes: 9 additions & 4 deletions src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -363,13 +363,18 @@ Typ deklarující tyto metody by měl také respektovat následující pravidla:
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_SourceTypeMethod">
<source>'[DynamicData]' member '{0}.{1}' is a method so you should set 'DynamicDataSourceType.Method'</source>
<target state="translated">Člen [DynamicData] {0}.{1} je metoda, takže byste měli nastavit DynamicDataSourceType.Method.</target>
<source>'[DynamicData]' member '{0}.{1}' is a method so you should use 'DynamicDataSourceType.AutoDetect' or 'DynamicDataSourceType.Method' (auto detect is the default when not specified explicitly, and is recommended)</source>
<target state="needs-review-translation">Člen [DynamicData] {0}.{1} je metoda, takže byste měli nastavit DynamicDataSourceType.Method.</target>
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_SourceTypeNotPropertyOrMethod">
<source>'[DynamicData]' member '{0}.{1}' is not a property nor a method. Only properties and methods are supported.</source>
<target state="new">'[DynamicData]' member '{0}.{1}' is not a property nor a method. Only properties and methods are supported.</target>
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_SourceTypeProperty">
<source>'[DynamicData]' member '{0}.{1}' is a property so you should set 'DynamicDataSourceType.Property'</source>
<target state="translated">Člen [DynamicData] {0}.{1} je vlastnost, takže byste měli nastavit DynamicDataSourceType.Property.</target>
<source>'[DynamicData]' member '{0}.{1}' is a property so you should use 'DynamicDataSourceType.AutoDetect' or 'DynamicDataSourceType.Property' (auto detect is the default when not specified explicitly, and is recommended)</source>
<target state="needs-review-translation">Člen [DynamicData] {0}.{1} je vlastnost, takže byste měli nastavit DynamicDataSourceType.Property.</target>
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_TooManyMembers">
Expand Down
13 changes: 9 additions & 4 deletions src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -365,13 +365,18 @@ Der Typ, der diese Methoden deklariert, sollte auch die folgenden Regeln beachte
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_SourceTypeMethod">
<source>'[DynamicData]' member '{0}.{1}' is a method so you should set 'DynamicDataSourceType.Method'</source>
<target state="translated">"[DynamicData]"-Element "{0}.{1}" ist eine Methode, daher sollten Sie "DynamicDataSourceType.Method" festlegen.</target>
<source>'[DynamicData]' member '{0}.{1}' is a method so you should use 'DynamicDataSourceType.AutoDetect' or 'DynamicDataSourceType.Method' (auto detect is the default when not specified explicitly, and is recommended)</source>
<target state="needs-review-translation">"[DynamicData]"-Element "{0}.{1}" ist eine Methode, daher sollten Sie "DynamicDataSourceType.Method" festlegen.</target>
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_SourceTypeNotPropertyOrMethod">
<source>'[DynamicData]' member '{0}.{1}' is not a property nor a method. Only properties and methods are supported.</source>
<target state="new">'[DynamicData]' member '{0}.{1}' is not a property nor a method. Only properties and methods are supported.</target>
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_SourceTypeProperty">
<source>'[DynamicData]' member '{0}.{1}' is a property so you should set 'DynamicDataSourceType.Property'</source>
<target state="translated">"[DynamicData]"-Element "{0}.{1}" ist eine Eigenschaft, daher sollten Sie "DynamicDataSourceType.Property" festlegen.</target>
<source>'[DynamicData]' member '{0}.{1}' is a property so you should use 'DynamicDataSourceType.AutoDetect' or 'DynamicDataSourceType.Property' (auto detect is the default when not specified explicitly, and is recommended)</source>
<target state="needs-review-translation">"[DynamicData]"-Element "{0}.{1}" ist eine Eigenschaft, daher sollten Sie "DynamicDataSourceType.Property" festlegen.</target>
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_TooManyMembers">
Expand Down
13 changes: 9 additions & 4 deletions src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -363,13 +363,18 @@ El tipo que declara estos métodos también debe respetar las reglas siguientes:
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_SourceTypeMethod">
<source>'[DynamicData]' member '{0}.{1}' is a method so you should set 'DynamicDataSourceType.Method'</source>
<target state="translated">El miembro de '{0}.{1}' de '[DynamicData]' es un método, por lo que debe establecert 'DynamicDataSourceType.Method'</target>
<source>'[DynamicData]' member '{0}.{1}' is a method so you should use 'DynamicDataSourceType.AutoDetect' or 'DynamicDataSourceType.Method' (auto detect is the default when not specified explicitly, and is recommended)</source>
<target state="needs-review-translation">El miembro de '{0}.{1}' de '[DynamicData]' es un método, por lo que debe establecert 'DynamicDataSourceType.Method'</target>
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_SourceTypeNotPropertyOrMethod">
<source>'[DynamicData]' member '{0}.{1}' is not a property nor a method. Only properties and methods are supported.</source>
<target state="new">'[DynamicData]' member '{0}.{1}' is not a property nor a method. Only properties and methods are supported.</target>
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_SourceTypeProperty">
<source>'[DynamicData]' member '{0}.{1}' is a property so you should set 'DynamicDataSourceType.Property'</source>
<target state="translated">El miembro de '{0}.{1}' de '[DynamicData]' es una propiedad, por lo que debe establecer 'DynamicDataSourceType.Property'</target>
<source>'[DynamicData]' member '{0}.{1}' is a property so you should use 'DynamicDataSourceType.AutoDetect' or 'DynamicDataSourceType.Property' (auto detect is the default when not specified explicitly, and is recommended)</source>
<target state="needs-review-translation">El miembro de '{0}.{1}' de '[DynamicData]' es una propiedad, por lo que debe establecer 'DynamicDataSourceType.Property'</target>
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_TooManyMembers">
Expand Down
13 changes: 9 additions & 4 deletions src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -363,13 +363,18 @@ Le type doit être une classe
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_SourceTypeMethod">
<source>'[DynamicData]' member '{0}.{1}' is a method so you should set 'DynamicDataSourceType.Method'</source>
<target state="translated">Membre '[DynamicData]' '{0}.{1}' est une méthode, vous devez donc définir 'DynamicDataSourceType.Method'</target>
<source>'[DynamicData]' member '{0}.{1}' is a method so you should use 'DynamicDataSourceType.AutoDetect' or 'DynamicDataSourceType.Method' (auto detect is the default when not specified explicitly, and is recommended)</source>
<target state="needs-review-translation">Membre '[DynamicData]' '{0}.{1}' est une méthode, vous devez donc définir 'DynamicDataSourceType.Method'</target>
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_SourceTypeNotPropertyOrMethod">
<source>'[DynamicData]' member '{0}.{1}' is not a property nor a method. Only properties and methods are supported.</source>
<target state="new">'[DynamicData]' member '{0}.{1}' is not a property nor a method. Only properties and methods are supported.</target>
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_SourceTypeProperty">
<source>'[DynamicData]' member '{0}.{1}' is a property so you should set 'DynamicDataSourceType.Property'</source>
<target state="translated">Membre '[DynamicData]' '{0}.{1}' est une propriété, vous devez donc définir 'DynamicDataSourceType.Property'</target>
<source>'[DynamicData]' member '{0}.{1}' is a property so you should use 'DynamicDataSourceType.AutoDetect' or 'DynamicDataSourceType.Property' (auto detect is the default when not specified explicitly, and is recommended)</source>
<target state="needs-review-translation">Membre '[DynamicData]' '{0}.{1}' est une propriété, vous devez donc définir 'DynamicDataSourceType.Property'</target>
<note />
</trans-unit>
<trans-unit id="DynamicDataShouldBeValidMessageFormat_TooManyMembers">
Expand Down
Loading
Loading