From c2d631000d6018e8cd1734544d6c9980c6da5222 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Wed, 29 Jan 2014 18:54:17 +0000 Subject: [PATCH] [CommandLine] Aliases require an value if their target requires a value. This can still be overridden by explicitly setting a value requirement on the alias option, but by default it should be the same. PR18649 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@200407 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Support/CommandLine.h | 10 +++++ lib/Support/CommandLine.cpp | 7 ++++ unittests/Support/CommandLineTest.cpp | 55 ++++++++++++++++++++++++++- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h index 774c214933b..515b0bd00f9 100644 --- a/include/llvm/Support/CommandLine.h +++ b/include/llvm/Support/CommandLine.h @@ -249,6 +249,12 @@ public: // void addArgument(); + /// Unregisters this option from the CommandLine system. + /// + /// This option must have been the last option registered. + /// For testing purposes only. + void removeArgument(); + Option *getNextRegisteredOption() const { return NextRegistered; } // Return the width of the option tag for printing... @@ -1646,6 +1652,10 @@ class alias : public Option { virtual void printOptionValue(size_t /*GlobalWidth*/, bool /*Force*/) const LLVM_OVERRIDE {} + virtual ValueExpected getValueExpectedFlagDefault() const LLVM_OVERRIDE { + return AliasFor->getValueExpectedFlag(); + } + void done() { if (!hasArgStr()) error("cl::alias must have argument name specified!"); diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index 1b4d2c72875..16db4d63960 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -111,6 +111,13 @@ void Option::addArgument() { MarkOptionsChanged(); } +void Option::removeArgument() { + assert(NextRegistered != 0 && "argument never registered"); + assert(RegisteredOptionList == this && "argument is not the last registered"); + RegisteredOptionList = NextRegistered; + MarkOptionsChanged(); +} + // This collects the different option categories that have been registered. typedef SmallPtrSet OptionCatSet; static ManagedStatic RegisteredOptionCategories; diff --git a/unittests/Support/CommandLineTest.cpp b/unittests/Support/CommandLineTest.cpp index a132eadad0f..e1d1fa59e58 100644 --- a/unittests/Support/CommandLineTest.cpp +++ b/unittests/Support/CommandLineTest.cpp @@ -42,6 +42,33 @@ class TempEnvVar { const char *const name; }; +template +class StackOption : public cl::opt { + using Base = cl::opt; +public: + // One option... + template + explicit StackOption(const M0t &M0) : Base(M0) {} + + // Two options... + template + StackOption(const M0t &M0, const M1t &M1) : Base(M0, M1) {} + + // Three options... + template + StackOption(const M0t &M0, const M1t &M1, const M2t &M2) : Base(M0, M1, M2) {} + + // Four options... + template + StackOption(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3) + : Base(M0, M1, M2, M3) {} + + ~StackOption() { + this->removeArgument(); + } +}; + + cl::OptionCategory TestCategory("Test Options", "Description"); cl::opt TestOption("test-option", cl::desc("old description")); TEST(CommandLineTest, ModifyExisitingOption) { @@ -103,7 +130,7 @@ TEST(CommandLineTest, ParseEnvironment) { // command line system will still hold a pointer to a deallocated cl::Option. TEST(CommandLineTest, ParseEnvironmentToLocalVar) { // Put cl::opt on stack to check for proper initialization of fields. - cl::opt EnvironmentTestOptionLocal("env-test-opt-local"); + StackOption EnvironmentTestOptionLocal("env-test-opt-local"); TempEnvVar TEV(test_env_var, "-env-test-opt-local=hello-local"); EXPECT_EQ("", EnvironmentTestOptionLocal); cl::ParseEnvironmentOptions("CommandLineTest", test_env_var); @@ -113,7 +140,7 @@ TEST(CommandLineTest, ParseEnvironmentToLocalVar) { #endif // SKIP_ENVIRONMENT_TESTS TEST(CommandLineTest, UseOptionCategory) { - cl::opt TestOption2("test-option", cl::cat(TestCategory)); + StackOption TestOption2("test-option", cl::cat(TestCategory)); ASSERT_EQ(&TestCategory,TestOption2.Category) << "Failed to assign Option " "Category."; @@ -161,4 +188,28 @@ TEST(CommandLineTest, TokenizeWindowsCommandLine) { array_lengthof(Output)); } +TEST(CommandLineTest, AliasesWithArguments) { + static const size_t ARGC = 3; + const char *const Inputs[][ARGC] = { + { "-tool", "-actual=x", "-extra" }, + { "-tool", "-actual", "x" }, + { "-tool", "-alias=x", "-extra" }, + { "-tool", "-alias", "x" } + }; + + for (size_t i = 0, e = array_lengthof(Inputs); i < e; ++i) { + StackOption Actual("actual"); + StackOption Extra("extra"); + StackOption Input(cl::Positional); + + cl::alias Alias("alias", llvm::cl::aliasopt(Actual)); + + cl::ParseCommandLineOptions(ARGC, Inputs[i]); + EXPECT_EQ("x", Actual); + EXPECT_EQ(0, Input.getNumOccurrences()); + + Alias.removeArgument(); + } +} + } // anonymous namespace -- 2.34.1