Skip to content

Commit

Permalink
Add analyzer for missing required modifier (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
viceroypenguin authored May 10, 2024
1 parent e451aca commit 6cc9bf3
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ IV0004 | ImmediateValidations | Error | ValidatorClassAnalyzer
IV0005 | ImmediateValidations | Error | ValidatorClassAnalyzer
IV0006 | ImmediateValidations | Error | ValidatorClassAnalyzer
IV0007 | ImmediateValidations | Error | ValidatorClassAnalyzer
IV0008 | ImmediateValidations | Error | ValidatorClassAnalyzer
1 change: 1 addition & 0 deletions src/Immediate.Validations.Analyzers/DiagnosticIds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ public static class DiagnosticIds
public const string IV0005ValidateMethodIsMissingParameter = "IV0005";
public const string IV0006ValidateMethodHasExtraParameter = "IV0006";
public const string IV0007ValidateMethodParameterIsIncorrectType = "IV0007";
public const string IV0008ValidatePropertyMustBeRequired = "IV0008";
}
26 changes: 26 additions & 0 deletions src/Immediate.Validations.Analyzers/ValidatorClassAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ public sealed class ValidatorClassAnalyzer : DiagnosticAnalyzer
description: "`Validate()` parameters must exist as properties on the containing Validator class."
);

public static readonly DiagnosticDescriptor ValidatePropertyMustBeRequired =
new(
id: DiagnosticIds.IV0008ValidatePropertyMustBeRequired,
title: "Validator property must be `required`",
messageFormat: "Property `{0}` must have the `required` modifier",
category: "ImmediateValidations",
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true,
description: "`Validate()` parameters without a default value require values to be set on their matching properties."
);

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
ImmutableArray.Create<DiagnosticDescriptor>(
[
Expand All @@ -95,6 +106,7 @@ public sealed class ValidatorClassAnalyzer : DiagnosticAnalyzer
ValidateMethodIsMissingParameter,
ValidateMethodHasExtraParameter,
ValidateMethodParameterIsIncorrectType,
ValidatePropertyMustBeRequired,
]);

public override void Initialize(AnalysisContext context)
Expand Down Expand Up @@ -236,6 +248,20 @@ private void AnalyzeSymbol(SymbolAnalysisContext context)
)
);
}

if (
!parameter.HasExplicitDefaultValue
&& !property.IsRequired
)
{
context.ReportDiagnostic(
Diagnostic.Create(
ValidatePropertyMustBeRequired,
property.Locations[0],
property.Name
)
);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,33 @@ public static (bool Invalid, string? DefaultMessage) ValidateProperty(int value,
"""
).RunAsync();

[Fact]
public async Task ValidateMethodGeneralParameterVarianceShouldWarn() =>
await AnalyzerTestHelpers.CreateAnalyzerTest<ValidatorClassAnalyzer>(
"""
using Immediate.Validations.Shared;
public sealed class GreaterThanAttribute : ValidatorAttribute
{
public required int {|IV0005:Alpha|} { get; init; }
public required int {|IV0005:Charlie|} { get; init; }
public required int {|IV0005:Echo|} { get; init; }
public static (bool Invalid, string? DefaultMessage) ValidateProperty(
int value,
int {|IV0006:bravo|},
int {|IV0006:delta|},
int {|IV0006:foxtrot|}
)
{
return value <= 0
? (true, "Property must not be `null`.")
: default;
}
}
"""
).RunAsync();

[Fact]
public async Task ValidateMethodMismatchTypesShouldWarn1() =>
await AnalyzerTestHelpers.CreateAnalyzerTest<ValidatorClassAnalyzer>(
Expand Down Expand Up @@ -179,4 +206,25 @@ public static (bool Invalid, string? DefaultMessage) ValidateProperty(string val
}
"""
).RunAsync();

[Fact]
public async Task ValidatePropertyMissingRequiredShouldWarn() =>
await AnalyzerTestHelpers.CreateAnalyzerTest<ValidatorClassAnalyzer>(
"""
using Immediate.Validations.Shared;
public sealed class GreaterThanAttribute : ValidatorAttribute
{
public int {|IV0008:Operand|} { get; init; }
public static (bool Invalid, string? DefaultMessage) ValidateProperty(int value, int operand)
{
return value <= operand
? (true, "Property must not be `null`.")
: default;
}
}
"""
).RunAsync();

}

0 comments on commit 6cc9bf3

Please sign in to comment.