diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -70,7 +70,8 @@ NOptionMap(IO &, const ClangTidyOptions::OptionMap &OptionMap) { Options.reserve(OptionMap.size()); for (const auto &KeyValue : OptionMap) - Options.emplace_back(std::string(KeyValue.getKey()), KeyValue.getValue().Value); + Options.emplace_back(std::string(KeyValue.getKey()), + KeyValue.getValue().Value); } ClangTidyOptions::OptionMap denormalize(IO &) { ClangTidyOptions::OptionMap Map; @@ -117,10 +118,58 @@ } } +struct ChecksVariant { + std::optional AsString; + std::optional> AsVector; +}; + +template <> +void yamlize(IO &IO, ChecksVariant &Checks, bool, EmptyContext &Ctx) { + if (!IO.outputting()) { + // Special case for reading from YAML + // Must support reading from both a string or a list + Input &I = reinterpret_cast(IO); + + if (isa(I.getCurrentNode()) || + isa(I.getCurrentNode())) { + Checks.AsString = std::string(); + yamlize(IO, *Checks.AsString, true, Ctx); + } else if (isa(I.getCurrentNode())) { + Checks.AsVector = std::vector(); + yamlize(IO, *Checks.AsVector, true, Ctx); + } else { + IO.setError("expected string or sequence"); + } + } +} + +static void mapChecks(IO &IO, std::optional &Checks) { + if (IO.outputting()) { + // Output as a string + IO.mapOptional("Checks", Checks); + } else { + // Input as either a string or a list + ChecksVariant ChecksAsVariant; + IO.mapOptional("Checks", ChecksAsVariant); + + // If we got the input as string, assign directly + if (ChecksAsVariant.AsString) { + Checks = ChecksAsVariant.AsString; + } + // If we got the input as a list, concatenate the items to create string + else if (ChecksAsVariant.AsVector) { + Checks = std::string(); + for (std::string const &check : *ChecksAsVariant.AsVector) { + *Checks += check + ","; + } + } + } +} + template <> struct MappingTraits { static void mapping(IO &IO, ClangTidyOptions &Options) { bool Ignored = false; - IO.mapOptional("Checks", Options.Checks); + mapChecks(IO, Options.Checks); IO.mapOptional("WarningsAsErrors", Options.WarningsAsErrors); IO.mapOptional("HeaderFileExtensions", Options.HeaderFileExtensions); IO.mapOptional("ImplementationFileExtensions",