Index: clang-tidy/ClangTidy.h =================================================================== --- clang-tidy/ClangTidy.h +++ clang-tidy/ClangTidy.h @@ -17,7 +17,9 @@ #include "clang/Basic/SourceManager.h" #include "clang/Tooling/Refactoring.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/YAMLTraits.h" #include #include #include @@ -47,22 +49,28 @@ /// Reads the option with the check-local name \p LocalName from the /// \c CheckOptions. If the corresponding key is not present, returns /// \p Default. - std::string get(StringRef LocalName, std::string Default) const; + std::string get(StringRef LocalName, StringRef Default) const; - /// \brief Read a named option from the \c Context and parse it as an integral - /// type \c T. + /// \brief Read a named option from the \c Context and parse it as any + /// type \c T that has ScalarTraits<>. /// /// Reads the option with the check-local name \p LocalName from the /// \c CheckOptions. If the corresponding key is not present, returns /// \p Default. template - typename std::enable_if::value, T>::type + typename std::enable_if::value, + llvm::ErrorOr>::type get(StringRef LocalName, T Default) const { - std::string Value = get(LocalName, ""); - T Result = Default; - if (!Value.empty()) - StringRef(Value).getAsInteger(10, Result); - return Result; + std::string String = get(LocalName, ""); + if (String.empty()) + return Default; + + T Value; + StringRef Result = + llvm::yaml::ScalarTraits::input(String, nullptr, Value); + if (!Result.empty()) + return llvm::make_error_code(llvm::errc::invalid_argument); + return Value; } /// \brief Stores an option with the check-local name \p LocalName with string @@ -70,10 +78,17 @@ void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const; - /// \brief Stores an option with the check-local name \p LocalName with - /// \c int64_t value \p Value to \p Options. - void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, - int64_t Value) const; + /// \brief Stores an option with the check-local name \p LocalName of any + /// type that has ScalarTraits<>. + template + typename std::enable_if::value, void>::type + store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, + const T &Value) { + std::string Storage; + llvm::raw_string_ostream Buffer(Storage); + llvm::yaml::ScalarTraits::output(Value, nullptr, Buffer); + store(Options, LocalName, Buffer.str()); + } private: std::string NamePrefix; Index: clang-tidy/ClangTidy.cpp =================================================================== --- clang-tidy/ClangTidy.cpp +++ clang-tidy/ClangTidy.cpp @@ -319,7 +319,7 @@ const ClangTidyOptions::OptionMap &CheckOptions) : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {} -std::string OptionsView::get(StringRef LocalName, std::string Default) const { +std::string OptionsView::get(StringRef LocalName, StringRef Default) const { const auto &Iter = CheckOptions.find(NamePrefix + LocalName.str()); if (Iter != CheckOptions.end()) return Iter->second; @@ -331,11 +331,6 @@ Options[NamePrefix + LocalName.str()] = Value; } -void OptionsView::store(ClangTidyOptions::OptionMap &Options, - StringRef LocalName, int64_t Value) const { - store(Options, LocalName, llvm::itostr(Value)); -} - std::vector getCheckNames(const ClangTidyOptions &Options) { clang::tidy::ClangTidyContext Context( llvm::make_unique(ClangTidyGlobalOptions(), Index: clang-tidy/misc/FunctionSize.cpp =================================================================== --- clang-tidy/misc/FunctionSize.cpp +++ clang-tidy/misc/FunctionSize.cpp @@ -17,9 +17,9 @@ FunctionSizeCheck::FunctionSizeCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), - LineThreshold(Options.get("LineThreshold", -1U)), - StatementThreshold(Options.get("StatementThreshold", 800U)), - BranchThreshold(Options.get("BranchThreshold", -1U)) {} + LineThreshold(*Options.get("LineThreshold", -1U)), + StatementThreshold(*Options.get("StatementThreshold", 800U)), + BranchThreshold(*Options.get("BranchThreshold", -1U)) {} void FunctionSizeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "LineThreshold", LineThreshold); Index: clang-tidy/readability/NamespaceCommentCheck.cpp =================================================================== --- clang-tidy/readability/NamespaceCommentCheck.cpp +++ clang-tidy/readability/NamespaceCommentCheck.cpp @@ -25,9 +25,9 @@ NamespaceCommentPattern("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" "namespace( +([a-zA-Z0-9_]+))? *(\\*/)?$", llvm::Regex::IgnoreCase), - ShortNamespaceLines(Options.get("ShortNamespaceLines", 1u)), - SpacesBeforeComments(Options.get("SpacesBeforeComments", - Name.startswith("google") ? 2u : 1u)) {} + ShortNamespaceLines(*Options.get("ShortNamespaceLines", 1u)), + SpacesBeforeComments(*Options.get("SpacesBeforeComments", + Name.startswith("google") ? 2u : 1u)) {} void NamespaceCommentCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "ShortNamespaceLines", ShortNamespaceLines); Index: unittests/clang-tidy/ClangTidyOptionsTest.cpp =================================================================== --- unittests/clang-tidy/ClangTidyOptionsTest.cpp +++ unittests/clang-tidy/ClangTidyOptionsTest.cpp @@ -1,3 +1,4 @@ +#include "ClangTidy.h" #include "ClangTidyOptions.h" #include "gtest/gtest.h" @@ -54,7 +55,7 @@ EXPECT_EQ(1000u, Options.LineFilter[2].LineRanges[0].second); } -TEST(ParseConfiguration, ValidConfiguration) { +TEST(ParseConfiguration, BaseConfiguration) { llvm::ErrorOr Options = parseConfiguration("Checks: \"-*,misc-*\"\n" "HeaderFilterRegex: \".*\"\n" @@ -67,6 +68,36 @@ EXPECT_EQ("some.user", *Options->User); } +TEST(ParseConfiguration, CheckOptions) { + llvm::ErrorOr Options = + parseConfiguration("CheckOptions:\n" + " - key: test-check.String\n" + " value: ' qwe !@#* '\n" + " - key: test-check.IntegerPositive\n" + " value: 12345\n" + " - key: test-check.IntegerNegative\n" + " value: -67890\n" + " - key: test-check.BooleanTrue\n" + " value: true\n" + " - key: test-check.BooleanFalse\n" + " value: false\n" + " - key: test-check.BooleanInvalid\n" + " value: asdf\n" + ); + EXPECT_TRUE(!!Options); + OptionsView Opt("test-check", Options->CheckOptions); + EXPECT_EQ("qqq", Opt.get("NonExistent", "qqq")); + EXPECT_EQ(-123, *Opt.get("NonExistent", -123)); + EXPECT_EQ(123U, *Opt.get("NonExistent", 123U)); + EXPECT_EQ(" qwe !@#* ", Opt.get("String", "")); + EXPECT_EQ(12345, *Opt.get("IntegerPositive", 0)); + EXPECT_EQ(12345U, *Opt.get("IntegerPositive", 0U)); + EXPECT_EQ(-67890, *Opt.get("IntegerNegative", 0)); + EXPECT_TRUE(*Opt.get("BooleanTrue", false)); + EXPECT_FALSE(*Opt.get("BooleanFalse", true)); + EXPECT_FALSE(Opt.get("BooleanInvalid", true)); +} + } // namespace test } // namespace tidy } // namespace clang