Skip to content

Commit ee1a907

Browse files
committed
* Use a single point of truth (CmdLineExtensions.GetCommandLineFields) to determine which fields are used: non-static, no [Ignore] attribute, and ordered by base type first
* Static field in Test1.cs no longer needs [Ignore] because of that * Some more minor code cleanup
1 parent 40a95ed commit ee1a907

File tree

3 files changed

+16
-19
lines changed

3 files changed

+16
-19
lines changed

Src/CmdLineExtensions.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,8 @@ namespace RT.CommandLine;
88

99
static class CmdLineExtensions
1010
{
11-
public static string[] GetOrderedOptionAttributeNames(this MemberInfo member)
12-
{
13-
var attr = member.GetCustomAttributes<OptionAttribute>().FirstOrDefault();
14-
return attr == null ? null : attr.Names.OrderBy(compareOptionNames).ToArray();
15-
}
11+
public static string[] GetOrderedOptionAttributeNames(this MemberInfo member) =>
12+
member.GetCustomAttributes<OptionAttribute>().FirstOrDefault()?.Names.OrderBy(compareOptionNames).ToArray();
1613

1714
private static int compareOptionNames(string opt1, string opt2)
1815
{
@@ -70,4 +67,9 @@ public static ConsoleColoredString FormatParameterUsage(this FieldInfo field, bo
7067
field.GetOrderedOptionAttributeNames().First().Color(CmdLineColor.Option),
7168
"<".Color(CmdLineColor.FieldBrackets) + field.Name.Color(CmdLineColor.Field) + ">".Color(CmdLineColor.FieldBrackets));
7269
}
70+
71+
public static IEnumerable<FieldInfo> GetCommandLineFields(this Type type) =>
72+
type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
73+
.Where(f => !f.IsDefined<IgnoreAttribute>())
74+
.OrderBy(f => f.DeclaringType.SelectChain(t => t.BaseType).Count());
7375
}

Src/CommandLine.cs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -219,11 +219,8 @@ private static object parseCommandLine(string[] args, Type type, int i, Func<Con
219219
FieldInfo swallowingField = null;
220220
var haveSeenOptionalPositional = false;
221221

222-
foreach (var field in type.GetFields())
222+
foreach (var field in type.GetCommandLineFields())
223223
{
224-
if (field.IsDefined<IgnoreAttribute>())
225-
continue;
226-
227224
var positional = field.IsDefined<IsPositionalAttribute>();
228225
var option = field.GetCustomAttributes<OptionAttribute>().FirstOrDefault();
229226
var mandatory = field.IsDefined<IsMandatoryAttribute>();
@@ -745,11 +742,13 @@ private static void getFieldsForHelp(Type type, out List<FieldInfo> optionalOpti
745742
optionalPositional = [];
746743
mandatoryPositional = [];
747744

748-
foreach (var field in type.GetFields().Where(f => !f.IsDefined<UndocumentedAttribute>() && !f.IsDefined<IgnoreAttribute>()))
749-
(field.IsDefined<IsMandatoryAttribute>()
745+
foreach (var field in type.GetCommandLineFields().Where(f => !f.IsDefined<UndocumentedAttribute>()))
746+
{
747+
var fieldInfos = field.IsDefined<IsMandatoryAttribute>()
750748
? (field.IsDefined<IsPositionalAttribute>() ? mandatoryPositional : mandatoryOptions)
751-
: (field.IsDefined<IsPositionalAttribute>() ? optionalPositional : optionalOptions)
752-
).Add(field);
749+
: (field.IsDefined<IsPositionalAttribute>() ? optionalPositional : optionalOptions);
750+
fieldInfos.Add(field);
751+
}
753752
}
754753

755754
private static ConsoleColoredString getDocumentation(MemberInfo member, Func<ConsoleColoredString, ConsoleColoredString> helpProcessor) =>
@@ -794,11 +793,8 @@ private static void postBuildStep(IPostBuildReporter rep, Type commandLineType,
794793

795794
checkDocumentation(rep, commandLineType, classDocRecommended);
796795

797-
foreach (var field in commandLineType.GetFields())
796+
foreach (var field in commandLineType.GetCommandLineFields())
798797
{
799-
if (field.IsDefined<IgnoreAttribute>())
800-
continue;
801-
802798
if (lastField != null)
803799
rep.Error($"The type of {lastField.DeclaringType.FullName}.{lastField.Name} necessitates that it is the last one in the class.", "class " + commandLineType.Name, field.Name);
804800

@@ -876,7 +872,7 @@ private static void postBuildStep(IPostBuildReporter rep, Type commandLineType,
876872
{
877873
// check that the non-default enum values’ Options are present and do not clash
878874
var optionNames = enumField.GetOrderedOptionAttributeNames();
879-
if (optionNames == null || !optionNames.Any())
875+
if (optionNames == null || optionNames.Length > 0)
880876
rep.Error($"{field.FieldType.FullName}.{enumField.Name} (used by {commandLineType.FullName}.{field.Name}): Enum value must have an [Option] attribute with at least one option name (unless it is the field's default value and the field is optional).", "enum " + field.FieldType.Name, enumField.Name);
881877
else
882878
checkOptionsUnique(rep, optionNames, optionTaken, commandLineType, field, enumField);

Tests/Test1.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ class Test1Cmd : ICommandLineValidatable
1212
[IsPositional, IsMandatory]
1313
public Test1SubcommandBase Subcommand;
1414

15-
[Ignore]
1615
public static int ValidateCalled = 0;
1716

1817
public ConsoleColoredString Validate()

0 commit comments

Comments
 (0)