Skip to content

Commit

Permalink
Report error when property is annotated with multiple parser-related …
Browse files Browse the repository at this point in the history
…attributes
  • Loading branch information
DoctorKrolic committed Mar 17, 2024
1 parent 1a3762e commit 16f63e6
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ Rule ID | Category | Severity | Notes
--------|----------|----------|-------
ARGP0034 | ArgumentParsing | Error |
ARGP0035 | ArgumentParsing | Warning |
ARGP0036 | ArgumentParsing | Error |
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,9 @@ private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo) Extr
}
}

if (!isOption && !isParameter && !isRemainingParameters)
var countOfParserRelatedAttributes = (isOption ? 1 : 0) + (isParameter ? 1 : 0) + (isRemainingParameters ? 1 : 0);

if (countOfParserRelatedAttributes == 0)
{
if (property.IsRequired)
{
Expand All @@ -228,6 +230,10 @@ private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo) Extr

continue;
}
else if (countOfParserRelatedAttributes > 1)
{
return default;
}

if (property is not { DeclaredAccessibility: >= Accessibility.Internal, SetMethod.DeclaredAccessibility: >= Accessibility.Internal })
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public sealed class OptionsTypeAnalyzer : DiagnosticAnalyzer
DiagnosticDescriptors.DuplicateRemainingParameters,
DiagnosticDescriptors.InvalidRemainingParametersPropertyType,
DiagnosticDescriptors.TooLowAccessibilityOfOptionsType,
DiagnosticDescriptors.NoOptionNames);
DiagnosticDescriptors.NoOptionNames,
DiagnosticDescriptors.PropertyCannotHaveMultipleParserRoles);

public override void Initialize(AnalysisContext context)
{
Expand Down Expand Up @@ -204,7 +205,9 @@ private static void AnalyzeOptionsType(SymbolAnalysisContext context, KnownTypes
var propertyType = property.Type;
var propertyLocation = property.Locations.First();

if (!isOption && !isParameter && !isRemainingParameters)
var countOfParserRelatedAttributes = (isOption ? 1 : 0) + (isParameter ? 1 : 0) + (isRemainingParameters ? 1 : 0);

if (countOfParserRelatedAttributes == 0)
{
if (property.IsRequired &&
property.SetMethod is not null &&
Expand All @@ -218,6 +221,12 @@ property.SetMethod is not null &&

continue;
}
else if (countOfParserRelatedAttributes > 1)
{
context.ReportDiagnostic(
Diagnostic.Create(
DiagnosticDescriptors.PropertyCannotHaveMultipleParserRoles, propertyLocation));
}

if (property.DeclaredAccessibility < Accessibility.Internal)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,12 @@ public static class DiagnosticDescriptors
category: ArgumentParsingCategoryName,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public static readonly DiagnosticDescriptor PropertyCannotHaveMultipleParserRoles = new(
id: "ARGP0036",
title: "Property cannot have multiple parser roles",
messageFormat: "Property cannot have multiple parser roles, meaning it cannot be annotated with multiple parser-related attributes",
category: ArgumentParsingCategoryName,
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);
}
31 changes: 31 additions & 0 deletions tests/ArgumentParsing.Tests.Unit/ArgumentParserGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2413,6 +2413,37 @@ class MyOptions
await VerifyGeneratorAsync(source);
}

[Fact]
public async Task OptionsType_MultipleParserRelatedAttributes()
{
var source = """
partial class C
{
[GeneratedArgumentParser]
private static partial ParseResult<MyOptions> {|CS8795:ParseArguments|}(string[] args);
}
[OptionsType]
class MyOptions
{
[Option]
[Parameter(0)]
public string Prop1 { get; set; }
[Parameter(1)]
[RemainingParameters]
public string Prop2 { get; set; }
[Option]
[Parameter(2)]
[RemainingParameters]
public string Prop3 { get; set; }
}
""";

await VerifyGeneratorAsync(source);
}

private static async Task VerifyGeneratorAsync(string source, params (string Hint, string Content)[] generatedDocuments)
{
var test = new CSharpSourceGeneratorTest<ArgumentParserGenerator>()
Expand Down
31 changes: 31 additions & 0 deletions tests/ArgumentParsing.Tests.Unit/OptionsTypeAnalyzerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1348,4 +1348,35 @@ class MyOptions

await VerifyAnalyzerAsync(source);
}

[Fact]
public async Task MultipleParserRelatedAttributes()
{
var source = """
partial class C
{
[GeneratedArgumentParser]
private static partial ParseResult<MyOptions> {|CS8795:ParseArguments|}(string[] args);
}
[OptionsType]
class MyOptions
{
[Option]
[Parameter(0)]
public string {|ARGP0036:Prop1|} { get; set; }
[Parameter(1)]
[RemainingParameters]
public string {|ARGP0036:Prop2|} { get; set; }
[Option]
[Parameter(2)]
[RemainingParameters]
public string {|ARGP0036:Prop3|} { get; set; }
}
""";

await VerifyAnalyzerAsync(source);
}
}

0 comments on commit 16f63e6

Please sign in to comment.