diff options
author | Brad King <brad.king@kitware.com> | 2022-07-06 15:30:22 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2022-07-07 13:48:58 (GMT) |
commit | e6d1e29ffa6bd3141a769d1281f3407ed0774139 (patch) | |
tree | 667e168e1643d72da6c88433c3c71a26c4fdcb0e | |
parent | 4c50f639c7e67098eba14bc41869dd5c354d0da6 (diff) | |
download | CMake-e6d1e29ffa6bd3141a769d1281f3407ed0774139.zip CMake-e6d1e29ffa6bd3141a769d1281f3407ed0774139.tar.gz CMake-e6d1e29ffa6bd3141a769d1281f3407ed0774139.tar.bz2 |
cmArgumentParser: Model maybe-empty and non-empty lists with wrapper types
Previously bindings to `std::vector<std::string>` required at least one
value. Some clients have been filtering `keywordsMissingValue` to
support keywords followed by empty lists. Instead, require clients to
specify whether a keyword's list can be empty as part of the binding
type.
-rw-r--r-- | Source/CTest/cmCTestCoverageCommand.h | 3 | ||||
-rw-r--r-- | Source/CTest/cmCTestSubmitCommand.h | 7 | ||||
-rw-r--r-- | Source/CTest/cmCTestUploadCommand.h | 3 | ||||
-rw-r--r-- | Source/cmArgumentParser.cxx | 11 | ||||
-rw-r--r-- | Source/cmArgumentParser.h | 5 | ||||
-rw-r--r-- | Source/cmArgumentParserTypes.h | 19 | ||||
-rw-r--r-- | Source/cmCMakeLanguageCommand.cxx | 3 | ||||
-rw-r--r-- | Source/cmDefinePropertyCommand.cxx | 5 | ||||
-rw-r--r-- | Source/cmExportCommand.cxx | 3 | ||||
-rw-r--r-- | Source/cmFileCommand.cxx | 72 | ||||
-rw-r--r-- | Source/cmInstallCommand.cxx | 60 | ||||
-rw-r--r-- | Source/cmInstallCommandArguments.h | 5 | ||||
-rw-r--r-- | Source/cmParseArgumentsCommand.cxx | 4 | ||||
-rw-r--r-- | Source/cmTargetSourcesCommand.cxx | 5 | ||||
-rw-r--r-- | Tests/CMakeLib/testArgumentParser.cxx | 17 |
15 files changed, 128 insertions, 94 deletions
diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h index dc8f71e..55c68b2 100644 --- a/Source/CTest/cmCTestCoverageCommand.h +++ b/Source/CTest/cmCTestCoverageCommand.h @@ -11,6 +11,7 @@ #include <cm/memory> #include <cm/optional> +#include "cmArgumentParserTypes.h" // IWYU pragma: keep #include "cmCTestHandlerCommand.h" #include "cmCommand.h" @@ -44,5 +45,5 @@ protected: void BindArguments() override; cmCTestGenericHandler* InitializeHandler() override; - cm::optional<std::vector<std::string>> Labels; + cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Labels; }; diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h index 903bb64..b67f182 100644 --- a/Source/CTest/cmCTestSubmitCommand.h +++ b/Source/CTest/cmCTestSubmitCommand.h @@ -10,6 +10,7 @@ #include <cm/optional> +#include "cmArgumentParserTypes.h" #include "cmCTestHandlerCommand.h" class cmCommand; @@ -50,7 +51,7 @@ protected: std::string RetryDelay; std::string SubmitURL; - cm::optional<std::vector<std::string>> Files; - std::vector<std::string> HttpHeaders; - cm::optional<std::vector<std::string>> Parts; + cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Files; + ArgumentParser::MaybeEmpty<std::vector<std::string>> HttpHeaders; + cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Parts; }; diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h index 0dad2bf..a9d1dd2 100644 --- a/Source/CTest/cmCTestUploadCommand.h +++ b/Source/CTest/cmCTestUploadCommand.h @@ -10,6 +10,7 @@ #include <cm/memory> +#include "cmArgumentParserTypes.h" #include "cmCTestHandlerCommand.h" #include "cmCommand.h" @@ -45,5 +46,5 @@ protected: void CheckArguments() override; cmCTestGenericHandler* InitializeHandler() override; - std::vector<std::string> Files; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Files; }; diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx index 1a05dbc..1bb9051 100644 --- a/Source/cmArgumentParser.cxx +++ b/Source/cmArgumentParser.cxx @@ -4,6 +4,8 @@ #include <algorithm> +#include "cmArgumentParserTypes.h" + namespace ArgumentParser { auto ActionMap::Emplace(cm::string_view name, Action action) @@ -44,7 +46,14 @@ void Instance::Bind(std::string& val) this->ExpectValue = true; } -void Instance::Bind(std::vector<std::string>& val) +void Instance::Bind(MaybeEmpty<std::vector<std::string>>& val) +{ + this->CurrentString = nullptr; + this->CurrentList = &val; + this->ExpectValue = false; +} + +void Instance::Bind(NonEmpty<std::vector<std::string>>& val) { this->CurrentString = nullptr; this->CurrentList = &val; diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h index 8be5a9c..2f0a76d 100644 --- a/Source/cmArgumentParser.h +++ b/Source/cmArgumentParser.h @@ -14,6 +14,8 @@ #include <cm/string_view> #include <cmext/string_view> +#include "cmArgumentParserTypes.h" // IWYU pragma: keep + namespace ArgumentParser { class Instance; @@ -37,7 +39,8 @@ public: void Bind(bool& val); void Bind(std::string& val); - void Bind(std::vector<std::string>& val); + void Bind(MaybeEmpty<std::vector<std::string>>& val); + void Bind(NonEmpty<std::vector<std::string>>& val); void Bind(std::vector<std::vector<std::string>>& val); // cm::optional<> records the presence the keyword to which it binds. diff --git a/Source/cmArgumentParserTypes.h b/Source/cmArgumentParserTypes.h new file mode 100644 index 0000000..7d4ce6f --- /dev/null +++ b/Source/cmArgumentParserTypes.h @@ -0,0 +1,19 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +namespace ArgumentParser { + +template <typename T> +struct MaybeEmpty : public T +{ +}; + +template <typename T> +struct NonEmpty : public T +{ +}; + +} // namespace ArgumentParser diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx index 287f45b..76561c3 100644 --- a/Source/cmCMakeLanguageCommand.cxx +++ b/Source/cmCMakeLanguageCommand.cxx @@ -14,6 +14,7 @@ #include <cmext/string_view> #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmDependencyProvider.h" #include "cmExecutionStatus.h" #include "cmGlobalGenerator.h" @@ -237,7 +238,7 @@ bool cmCMakeLanguageCommandSET_DEPENDENCY_PROVIDER( struct SetProviderArgs { std::string Command; - std::vector<std::string> Methods; + ArgumentParser::NonEmpty<std::vector<std::string>> Methods; }; auto const ArgsParser = diff --git a/Source/cmDefinePropertyCommand.cxx b/Source/cmDefinePropertyCommand.cxx index faefcb8..31ee665 100644 --- a/Source/cmDefinePropertyCommand.cxx +++ b/Source/cmDefinePropertyCommand.cxx @@ -8,6 +8,7 @@ #include <cmext/string_view> #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmProperty.h" @@ -51,8 +52,8 @@ bool cmDefinePropertyCommand(std::vector<std::string> const& args, // Parse remaining arguments. bool inherited = false; std::string PropertyName; - std::vector<std::string> BriefDocs; - std::vector<std::string> FullDocs; + ArgumentParser::NonEmpty<std::vector<std::string>> BriefDocs; + ArgumentParser::NonEmpty<std::vector<std::string>> FullDocs; std::string initializeFromVariable; cmArgumentParser<void> parser; diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 4071f99..a58f2b7 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -13,6 +13,7 @@ #include "cmsys/RegularExpression.hxx" #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmExecutionStatus.h" #include "cmExperimental.h" #include "cmExportBuildAndroidMKGenerator.h" @@ -58,7 +59,7 @@ bool cmExportCommand(std::vector<std::string> const& args, struct Arguments { std::string ExportSetName; - cm::optional<std::vector<std::string>> Targets; + cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Targets; std::string Namespace; std::string Filename; std::string AndroidMKFile; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 45ec343..22ab5f7 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -30,6 +30,7 @@ #include "cmAlgorithms.h" #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmCMakePath.h" #include "cmCryptoHash.h" #include "cmELF.h" @@ -2505,7 +2506,7 @@ bool HandleGenerateCommand(std::vector<std::string> const& args, cm::optional<std::string> NewLineStyle; bool NoSourcePermissions = false; bool UseSourcePermissions = false; - std::vector<std::string> FilePermissions; + ArgumentParser::NonEmpty<std::vector<std::string>> FilePermissions; }; static auto const parser = @@ -3052,17 +3053,18 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args, std::string ConflictingDependenciesPrefix; std::string RPathPrefix; std::string BundleExecutable; - std::vector<std::string> Executables; - std::vector<std::string> Libraries; - std::vector<std::string> Directories; - std::vector<std::string> Modules; - std::vector<std::string> PreIncludeRegexes; - std::vector<std::string> PreExcludeRegexes; - std::vector<std::string> PostIncludeRegexes; - std::vector<std::string> PostExcludeRegexes; - std::vector<std::string> PostIncludeFiles; - std::vector<std::string> PostExcludeFiles; - std::vector<std::string> PostExcludeFilesStrict; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Executables; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Libraries; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Directories; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Modules; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PreIncludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PreExcludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeFiles; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeFiles; + ArgumentParser::MaybeEmpty<std::vector<std::string>> + PostExcludeFilesStrict; }; static auto const parser = @@ -3098,25 +3100,10 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args, return false; } - // Arguments that are allowed to be empty lists. Keep entries sorted! - static const std::vector<cm::string_view> LIST_ARGS = { - "DIRECTORIES"_s, - "EXECUTABLES"_s, - "LIBRARIES"_s, - "MODULES"_s, - "POST_EXCLUDE_FILES"_s, - "POST_EXCLUDE_FILES_STRICT"_s, - "POST_EXCLUDE_REGEXES"_s, - "POST_INCLUDE_FILES"_s, - "POST_INCLUDE_REGEXES"_s, - "PRE_EXCLUDE_REGEXES"_s, - "PRE_INCLUDE_REGEXES"_s, - }; - auto kwbegin = keywordsMissingValues.cbegin(); - auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS); - if (kwend != kwbegin) { - status.SetError(cmStrCat("Keywords missing values:\n ", - cmJoin(cmMakeRange(kwbegin, kwend), "\n "))); + if (!keywordsMissingValues.empty()) { + status.SetError( + cmStrCat("Keywords missing values:\n ", + cmJoin(cmMakeRange(keywordsMissingValues), "\n "))); cmSystemTools::SetFatalErrorOccurred(); return false; } @@ -3362,7 +3349,8 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args, std::string CompressionLevel; std::string MTime; bool Verbose = false; - std::vector<std::string> Paths; + // "PATHS" requires at least one value, but use a custom check below. + ArgumentParser::MaybeEmpty<std::vector<std::string>> Paths; }; static auto const parser = @@ -3393,7 +3381,6 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args, // value, but it has long been accidentally accepted without // one and treated as if an empty value were given. // Fixing this would require a policy. - "PATHS"_s, // "PATHS" is here only so we can issue a custom error below. }; auto kwbegin = keywordsMissingValues.cbegin(); auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS); @@ -3496,7 +3483,7 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args, bool Verbose = false; bool ListOnly = false; std::string Destination; - std::vector<std::string> Patterns; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Patterns; bool Touch = false; }; @@ -3520,13 +3507,10 @@ bool HandleArchiveExtractCommand(std::vector<std::string> const& args, return false; } - // Arguments that are allowed to be empty lists. Keep entries sorted! - static const std::vector<cm::string_view> LIST_ARGS = { "PATTERNS"_s }; - auto kwbegin = keywordsMissingValues.cbegin(); - auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS); - if (kwend != kwbegin) { - status.SetError(cmStrCat("Keywords missing values:\n ", - cmJoin(cmMakeRange(kwbegin, kwend), "\n "))); + if (!keywordsMissingValues.empty()) { + status.SetError( + cmStrCat("Keywords missing values:\n ", + cmJoin(cmMakeRange(keywordsMissingValues), "\n "))); cmSystemTools::SetFatalErrorOccurred(); return false; } @@ -3620,9 +3604,9 @@ bool HandleChmodCommandImpl(std::vector<std::string> const& args, bool recurse, struct Arguments { - std::vector<std::string> Permissions; - std::vector<std::string> FilePermissions; - std::vector<std::string> DirectoryPermissions; + ArgumentParser::NonEmpty<std::vector<std::string>> Permissions; + ArgumentParser::NonEmpty<std::vector<std::string>> FilePermissions; + ArgumentParser::NonEmpty<std::vector<std::string>> DirectoryPermissions; }; static auto const parser = diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 35ddf34..b1044a8 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -19,6 +19,7 @@ #include "cmsys/Glob.hxx" #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmExecutionStatus.h" #include "cmExperimental.h" #include "cmExportSet.h" @@ -57,13 +58,13 @@ namespace { struct RuntimeDependenciesArgs { - std::vector<std::string> Directories; - std::vector<std::string> PreIncludeRegexes; - std::vector<std::string> PreExcludeRegexes; - std::vector<std::string> PostIncludeRegexes; - std::vector<std::string> PostExcludeRegexes; - std::vector<std::string> PostIncludeFiles; - std::vector<std::string> PostExcludeFiles; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Directories; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PreIncludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PreExcludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeRegexes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostIncludeFiles; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PostExcludeFiles; }; auto const RuntimeDependenciesArgHelper = @@ -406,18 +407,18 @@ bool HandleTargetsMode(std::vector<std::string> const& args, struct ArgVectors { - std::vector<std::string> Archive; - std::vector<std::string> Library; - std::vector<std::string> Runtime; - std::vector<std::string> Object; - std::vector<std::string> Framework; - std::vector<std::string> Bundle; - std::vector<std::string> Includes; - std::vector<std::string> PrivateHeader; - std::vector<std::string> PublicHeader; - std::vector<std::string> Resource; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Archive; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Library; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Object; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Bundle; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Includes; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PrivateHeader; + ArgumentParser::MaybeEmpty<std::vector<std::string>> PublicHeader; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Resource; + ArgumentParser::MaybeEmpty<std::vector<std::string>> CxxModulesBmi; std::vector<std::vector<std::string>> FileSets; - std::vector<std::string> CxxModulesBmi; }; static auto const argHelper = @@ -441,9 +442,10 @@ bool HandleTargetsMode(std::vector<std::string> const& args, // now parse the generic args (i.e. the ones not specialized on LIBRARY/ // ARCHIVE, RUNTIME etc. (see above) // These generic args also contain the targets and the export stuff - std::vector<std::string> targetList; + ArgumentParser::MaybeEmpty<std::vector<std::string>> targetList; std::string exports; - cm::optional<std::vector<std::string>> runtimeDependenciesArgVector; + cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> + runtimeDependenciesArgVector; std::string runtimeDependencySetArg; std::vector<std::string> unknownArgs; cmInstallCommandArguments genericArgs(helper.DefaultComponentName); @@ -1251,10 +1253,10 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args, struct ArgVectors { - std::vector<std::string> Library; - std::vector<std::string> Runtime; - std::vector<std::string> Framework; - std::vector<std::string> Bundle; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Library; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Bundle; }; static auto const argHelper = cmArgumentParser<ArgVectors>{} @@ -1268,7 +1270,7 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args, // now parse the generic args (i.e. the ones not specialized on LIBRARY, // RUNTIME etc. (see above) - std::vector<std::string> targetList; + ArgumentParser::MaybeEmpty<std::vector<std::string>> targetList; std::string runtimeDependencySetArg; std::vector<std::string> unknownArgs; cmInstallCommandArguments genericArgs(helper.DefaultComponentName); @@ -1509,7 +1511,7 @@ bool HandleFilesMode(std::vector<std::string> const& args, // This is the FILES mode. bool programs = (args[0] == "PROGRAMS"); cmInstallCommandArguments ica(helper.DefaultComponentName); - std::vector<std::string> files; + ArgumentParser::MaybeEmpty<std::vector<std::string>> files; ica.Bind(programs ? "PROGRAMS"_s : "FILES"_s, files); std::vector<std::string> unknownArgs; ica.Parse(args, &unknownArgs); @@ -2140,9 +2142,9 @@ bool HandleRuntimeDependencySetMode(std::vector<std::string> const& args, struct ArgVectors { - std::vector<std::string> Library; - std::vector<std::string> Runtime; - std::vector<std::string> Framework; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Library; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Runtime; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Framework; }; static auto const argHelper = cmArgumentParser<ArgVectors>{} diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h index 79bd945..6e46aac 100644 --- a/Source/cmInstallCommandArguments.h +++ b/Source/cmInstallCommandArguments.h @@ -8,6 +8,7 @@ #include <vector> #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" class cmInstallCommandArguments : public cmArgumentParser<void> { @@ -44,8 +45,8 @@ private: std::string NamelinkComponent; bool ExcludeFromAll = false; std::string Rename; - std::vector<std::string> Permissions; - std::vector<std::string> Configurations; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Permissions; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Configurations; bool Optional = false; bool NamelinkOnly = false; bool NamelinkSkip = false; diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx index 5ea35e8..31538b6 100644 --- a/Source/cmParseArgumentsCommand.cxx +++ b/Source/cmParseArgumentsCommand.cxx @@ -10,6 +10,7 @@ #include <cm/string_view> #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -41,7 +42,8 @@ namespace { using options_map = std::map<std::string, bool>; using single_map = std::map<std::string, std::string>; -using multi_map = std::map<std::string, std::vector<std::string>>; +using multi_map = + std::map<std::string, ArgumentParser::NonEmpty<std::vector<std::string>>>; using options_set = std::set<cm::string_view>; struct UserArgumentParser : public cmArgumentParser<void> diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx index 74945fa..e2b0213 100644 --- a/Source/cmTargetSourcesCommand.cxx +++ b/Source/cmTargetSourcesCommand.cxx @@ -9,6 +9,7 @@ #include <cmext/string_view> #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" #include "cmExperimental.h" #include "cmFileSet.h" #include "cmGeneratorExpression.h" @@ -28,8 +29,8 @@ struct FileSetArgs { std::string Type; std::string FileSet; - std::vector<std::string> BaseDirs; - std::vector<std::string> Files; + ArgumentParser::MaybeEmpty<std::vector<std::string>> BaseDirs; + ArgumentParser::MaybeEmpty<std::vector<std::string>> Files; }; auto const FileSetArgsParser = cmArgumentParser<FileSetArgs>() diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx index 52c5861..85650ed 100644 --- a/Tests/CMakeLib/testArgumentParser.cxx +++ b/Tests/CMakeLib/testArgumentParser.cxx @@ -11,6 +11,7 @@ #include <cmext/string_view> #include "cmArgumentParser.h" +#include "cmArgumentParserTypes.h" namespace { @@ -23,11 +24,12 @@ struct Result cm::optional<std::string> String2; cm::optional<std::string> String3; - std::vector<std::string> List1; - std::vector<std::string> List2; - cm::optional<std::vector<std::string>> List3; - cm::optional<std::vector<std::string>> List4; - cm::optional<std::vector<std::string>> List5; + ArgumentParser::NonEmpty<std::vector<std::string>> List1; + ArgumentParser::NonEmpty<std::vector<std::string>> List2; + cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> List3; + cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> List4; + cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> List5; + cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> List6; std::vector<std::vector<std::string>> Multi1; std::vector<std::vector<std::string>> Multi2; @@ -48,6 +50,7 @@ std::initializer_list<cm::string_view> const args = { "LIST_3", "foo", // ... with continuation "LIST_4", // list arg missing values, presence captured // "LIST_5", // list arg that is not present + "LIST_6", // list arg allowed to be empty "MULTI_2", // multi list with 0 lists "MULTI_3", "foo", "bar", // multi list with first list with two elems "MULTI_3", "bar", "foo", // multi list with second list with two elems @@ -88,6 +91,8 @@ bool verifyResult(Result const& result, ASSERT_TRUE(result.List4); ASSERT_TRUE(result.List4->empty()); ASSERT_TRUE(!result.List5); + ASSERT_TRUE(result.List6); + ASSERT_TRUE(result.List6->empty()); ASSERT_TRUE(result.Multi1.empty()); ASSERT_TRUE(result.Multi2.size() == 1); @@ -122,6 +127,7 @@ bool testArgumentParserDynamic() .Bind("LIST_3"_s, result.List3) .Bind("LIST_4"_s, result.List4) .Bind("LIST_5"_s, result.List5) + .Bind("LIST_6"_s, result.List6) .Bind("MULTI_1"_s, result.Multi1) .Bind("MULTI_2"_s, result.Multi2) .Bind("MULTI_3"_s, result.Multi3) @@ -145,6 +151,7 @@ bool testArgumentParserStatic() .Bind("LIST_3"_s, &Result::List3) .Bind("LIST_4"_s, &Result::List4) .Bind("LIST_5"_s, &Result::List5) + .Bind("LIST_6"_s, &Result::List6) .Bind("MULTI_1"_s, &Result::Multi1) .Bind("MULTI_2"_s, &Result::Multi2) .Bind("MULTI_3"_s, &Result::Multi3) |