aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/clang16/tools/extra/clang-tidy/ClangTidyOptions.cpp
diff options
context:
space:
mode:
authorthegeorg <thegeorg@yandex-team.com>2024-03-13 13:58:24 +0300
committerthegeorg <thegeorg@yandex-team.com>2024-03-13 14:11:53 +0300
commit11a895b7e15d1c5a1f52706396b82e3f9db953cb (patch)
treefabc6d883b0f946151f61ae7865cee9f529a1fdd /contrib/libs/clang16/tools/extra/clang-tidy/ClangTidyOptions.cpp
parent9685917341315774aad5733b1793b1e533a88bbb (diff)
downloadydb-11a895b7e15d1c5a1f52706396b82e3f9db953cb.tar.gz
Export clang-format16 via ydblib project
6e6be3a95868fde888d801b7590af4044049563f
Diffstat (limited to 'contrib/libs/clang16/tools/extra/clang-tidy/ClangTidyOptions.cpp')
-rw-r--r--contrib/libs/clang16/tools/extra/clang-tidy/ClangTidyOptions.cpp452
1 files changed, 452 insertions, 0 deletions
diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/ClangTidyOptions.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/ClangTidyOptions.cpp
new file mode 100644
index 0000000000..808929b11f
--- /dev/null
+++ b/contrib/libs/clang16/tools/extra/clang-tidy/ClangTidyOptions.cpp
@@ -0,0 +1,452 @@
+//===--- ClangTidyOptions.cpp - clang-tidy ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidyOptions.h"
+#include "ClangTidyModuleRegistry.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBufferRef.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <optional>
+#include <utility>
+
+#define DEBUG_TYPE "clang-tidy-options"
+
+using clang::tidy::ClangTidyOptions;
+using clang::tidy::FileFilter;
+using OptionsSource = clang::tidy::ClangTidyOptionsProvider::OptionsSource;
+
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter::LineRange)
+
+namespace llvm::yaml {
+
+// Map std::pair<int, int> to a JSON array of size 2.
+template <> struct SequenceTraits<FileFilter::LineRange> {
+ static size_t size(IO &IO, FileFilter::LineRange &Range) {
+ return Range.first == 0 ? 0 : Range.second == 0 ? 1 : 2;
+ }
+ static unsigned &element(IO &IO, FileFilter::LineRange &Range, size_t Index) {
+ if (Index > 1)
+ IO.setError("Too many elements in line range.");
+ return Index == 0 ? Range.first : Range.second;
+ }
+};
+
+template <> struct MappingTraits<FileFilter> {
+ static void mapping(IO &IO, FileFilter &File) {
+ IO.mapRequired("name", File.Name);
+ IO.mapOptional("lines", File.LineRanges);
+ }
+ static std::string validate(IO &Io, FileFilter &File) {
+ if (File.Name.empty())
+ return "No file name specified";
+ for (const FileFilter::LineRange &Range : File.LineRanges) {
+ if (Range.first <= 0 || Range.second <= 0)
+ return "Invalid line range";
+ }
+ return "";
+ }
+};
+
+template <> struct MappingTraits<ClangTidyOptions::StringPair> {
+ static void mapping(IO &IO, ClangTidyOptions::StringPair &KeyValue) {
+ IO.mapRequired("key", KeyValue.first);
+ IO.mapRequired("value", KeyValue.second);
+ }
+};
+
+struct NOptionMap {
+ NOptionMap(IO &) {}
+ 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);
+ }
+ ClangTidyOptions::OptionMap denormalize(IO &) {
+ ClangTidyOptions::OptionMap Map;
+ for (const auto &KeyValue : Options)
+ Map[KeyValue.first] = ClangTidyOptions::ClangTidyValue(KeyValue.second);
+ return Map;
+ }
+ std::vector<ClangTidyOptions::StringPair> Options;
+};
+
+template <>
+void yamlize(IO &IO, ClangTidyOptions::OptionMap &Options, bool,
+ EmptyContext &Ctx) {
+ if (IO.outputting()) {
+ IO.beginMapping();
+ // Only output as a map
+ for (auto &Key : Options) {
+ bool UseDefault;
+ void *SaveInfo;
+ IO.preflightKey(Key.getKey().data(), true, false, UseDefault, SaveInfo);
+ StringRef S = Key.getValue().Value;
+ IO.scalarString(S, needsQuotes(S));
+ IO.postflightKey(SaveInfo);
+ }
+ IO.endMapping();
+ } else {
+ // We need custom logic here to support the old method of specifying check
+ // options using a list of maps containing key and value keys.
+ Input &I = reinterpret_cast<Input &>(IO);
+ if (isa<SequenceNode>(I.getCurrentNode())) {
+ MappingNormalization<NOptionMap, ClangTidyOptions::OptionMap> NOpts(
+ IO, Options);
+ EmptyContext Ctx;
+ yamlize(IO, NOpts->Options, true, Ctx);
+ } else if (isa<MappingNode>(I.getCurrentNode())) {
+ IO.beginMapping();
+ for (StringRef Key : IO.keys()) {
+ IO.mapRequired(Key.data(), Options[Key].Value);
+ }
+ IO.endMapping();
+ } else {
+ IO.setError("expected a sequence or map");
+ }
+ }
+}
+
+template <> struct MappingTraits<ClangTidyOptions> {
+ static void mapping(IO &IO, ClangTidyOptions &Options) {
+ bool Ignored = false;
+ IO.mapOptional("Checks", Options.Checks);
+ IO.mapOptional("WarningsAsErrors", Options.WarningsAsErrors);
+ IO.mapOptional("HeaderFilterRegex", Options.HeaderFilterRegex);
+ IO.mapOptional("AnalyzeTemporaryDtors", Ignored); // deprecated
+ IO.mapOptional("FormatStyle", Options.FormatStyle);
+ IO.mapOptional("User", Options.User);
+ IO.mapOptional("CheckOptions", Options.CheckOptions);
+ IO.mapOptional("ExtraArgs", Options.ExtraArgs);
+ IO.mapOptional("ExtraArgsBefore", Options.ExtraArgsBefore);
+ IO.mapOptional("InheritParentConfig", Options.InheritParentConfig);
+ IO.mapOptional("UseColor", Options.UseColor);
+ }
+};
+
+} // namespace llvm::yaml
+
+namespace clang::tidy {
+
+ClangTidyOptions ClangTidyOptions::getDefaults() {
+ ClangTidyOptions Options;
+ Options.Checks = "";
+ Options.WarningsAsErrors = "";
+ Options.HeaderFilterRegex = "";
+ Options.SystemHeaders = false;
+ Options.FormatStyle = "none";
+ Options.User = std::nullopt;
+ for (const ClangTidyModuleRegistry::entry &Module :
+ ClangTidyModuleRegistry::entries())
+ Options.mergeWith(Module.instantiate()->getModuleOptions(), 0);
+ return Options;
+}
+
+template <typename T>
+static void mergeVectors(std::optional<T> &Dest, const std::optional<T> &Src) {
+ if (Src) {
+ if (Dest)
+ Dest->insert(Dest->end(), Src->begin(), Src->end());
+ else
+ Dest = Src;
+ }
+}
+
+static void mergeCommaSeparatedLists(std::optional<std::string> &Dest,
+ const std::optional<std::string> &Src) {
+ if (Src)
+ Dest = (Dest && !Dest->empty() ? *Dest + "," : "") + *Src;
+}
+
+template <typename T>
+static void overrideValue(std::optional<T> &Dest, const std::optional<T> &Src) {
+ if (Src)
+ Dest = Src;
+}
+
+ClangTidyOptions &ClangTidyOptions::mergeWith(const ClangTidyOptions &Other,
+ unsigned Order) {
+ mergeCommaSeparatedLists(Checks, Other.Checks);
+ mergeCommaSeparatedLists(WarningsAsErrors, Other.WarningsAsErrors);
+ overrideValue(HeaderFilterRegex, Other.HeaderFilterRegex);
+ overrideValue(SystemHeaders, Other.SystemHeaders);
+ overrideValue(FormatStyle, Other.FormatStyle);
+ overrideValue(User, Other.User);
+ overrideValue(UseColor, Other.UseColor);
+ mergeVectors(ExtraArgs, Other.ExtraArgs);
+ mergeVectors(ExtraArgsBefore, Other.ExtraArgsBefore);
+
+ for (const auto &KeyValue : Other.CheckOptions) {
+ CheckOptions.insert_or_assign(
+ KeyValue.getKey(),
+ ClangTidyValue(KeyValue.getValue().Value,
+ KeyValue.getValue().Priority + Order));
+ }
+ return *this;
+}
+
+ClangTidyOptions ClangTidyOptions::merge(const ClangTidyOptions &Other,
+ unsigned Order) const {
+ ClangTidyOptions Result = *this;
+ Result.mergeWith(Other, Order);
+ return Result;
+}
+
+const char ClangTidyOptionsProvider::OptionsSourceTypeDefaultBinary[] =
+ "clang-tidy binary";
+const char ClangTidyOptionsProvider::OptionsSourceTypeCheckCommandLineOption[] =
+ "command-line option '-checks'";
+const char
+ ClangTidyOptionsProvider::OptionsSourceTypeConfigCommandLineOption[] =
+ "command-line option '-config'";
+
+ClangTidyOptions
+ClangTidyOptionsProvider::getOptions(llvm::StringRef FileName) {
+ ClangTidyOptions Result;
+ unsigned Priority = 0;
+ for (auto &Source : getRawOptions(FileName))
+ Result.mergeWith(Source.first, ++Priority);
+ return Result;
+}
+
+std::vector<OptionsSource>
+DefaultOptionsProvider::getRawOptions(llvm::StringRef FileName) {
+ std::vector<OptionsSource> Result;
+ Result.emplace_back(DefaultOptions, OptionsSourceTypeDefaultBinary);
+ return Result;
+}
+
+ConfigOptionsProvider::ConfigOptionsProvider(
+ ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions,
+ ClangTidyOptions ConfigOptions, ClangTidyOptions OverrideOptions,
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
+ : FileOptionsBaseProvider(std::move(GlobalOptions),
+ std::move(DefaultOptions),
+ std::move(OverrideOptions), std::move(FS)),
+ ConfigOptions(std::move(ConfigOptions)) {}
+
+std::vector<OptionsSource>
+ConfigOptionsProvider::getRawOptions(llvm::StringRef FileName) {
+ std::vector<OptionsSource> RawOptions =
+ DefaultOptionsProvider::getRawOptions(FileName);
+ if (ConfigOptions.InheritParentConfig.value_or(false)) {
+ LLVM_DEBUG(llvm::dbgs()
+ << "Getting options for file " << FileName << "...\n");
+ assert(FS && "FS must be set.");
+
+ llvm::SmallString<128> AbsoluteFilePath(FileName);
+
+ if (!FS->makeAbsolute(AbsoluteFilePath)) {
+ addRawFileOptions(AbsoluteFilePath, RawOptions);
+ }
+ }
+ RawOptions.emplace_back(ConfigOptions,
+ OptionsSourceTypeConfigCommandLineOption);
+ RawOptions.emplace_back(OverrideOptions,
+ OptionsSourceTypeCheckCommandLineOption);
+ return RawOptions;
+}
+
+FileOptionsBaseProvider::FileOptionsBaseProvider(
+ ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions,
+ ClangTidyOptions OverrideOptions,
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
+ : DefaultOptionsProvider(std::move(GlobalOptions),
+ std::move(DefaultOptions)),
+ OverrideOptions(std::move(OverrideOptions)), FS(std::move(VFS)) {
+ if (!FS)
+ FS = llvm::vfs::getRealFileSystem();
+ ConfigHandlers.emplace_back(".clang-tidy", parseConfiguration);
+}
+
+FileOptionsBaseProvider::FileOptionsBaseProvider(
+ ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions,
+ ClangTidyOptions OverrideOptions,
+ FileOptionsBaseProvider::ConfigFileHandlers ConfigHandlers)
+ : DefaultOptionsProvider(std::move(GlobalOptions),
+ std::move(DefaultOptions)),
+ OverrideOptions(std::move(OverrideOptions)),
+ ConfigHandlers(std::move(ConfigHandlers)) {}
+
+void FileOptionsBaseProvider::addRawFileOptions(
+ llvm::StringRef AbsolutePath, std::vector<OptionsSource> &CurOptions) {
+ auto CurSize = CurOptions.size();
+
+ // Look for a suitable configuration file in all parent directories of the
+ // file. Start with the immediate parent directory and move up.
+ StringRef Path = llvm::sys::path::parent_path(AbsolutePath);
+ for (StringRef CurrentPath = Path; !CurrentPath.empty();
+ CurrentPath = llvm::sys::path::parent_path(CurrentPath)) {
+ std::optional<OptionsSource> Result;
+
+ auto Iter = CachedOptions.find(CurrentPath);
+ if (Iter != CachedOptions.end())
+ Result = Iter->second;
+
+ if (!Result)
+ Result = tryReadConfigFile(CurrentPath);
+
+ if (Result) {
+ // Store cached value for all intermediate directories.
+ while (Path != CurrentPath) {
+ LLVM_DEBUG(llvm::dbgs()
+ << "Caching configuration for path " << Path << ".\n");
+ if (!CachedOptions.count(Path))
+ CachedOptions[Path] = *Result;
+ Path = llvm::sys::path::parent_path(Path);
+ }
+ CachedOptions[Path] = *Result;
+
+ CurOptions.push_back(*Result);
+ if (!Result->first.InheritParentConfig.value_or(false))
+ break;
+ }
+ }
+ // Reverse order of file configs because closer configs should have higher
+ // priority.
+ std::reverse(CurOptions.begin() + CurSize, CurOptions.end());
+}
+
+FileOptionsProvider::FileOptionsProvider(
+ ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions,
+ ClangTidyOptions OverrideOptions,
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
+ : FileOptionsBaseProvider(std::move(GlobalOptions),
+ std::move(DefaultOptions),
+ std::move(OverrideOptions), std::move(VFS)) {}
+
+FileOptionsProvider::FileOptionsProvider(
+ ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions,
+ ClangTidyOptions OverrideOptions,
+ FileOptionsBaseProvider::ConfigFileHandlers ConfigHandlers)
+ : FileOptionsBaseProvider(
+ std::move(GlobalOptions), std::move(DefaultOptions),
+ std::move(OverrideOptions), std::move(ConfigHandlers)) {}
+
+// FIXME: This method has some common logic with clang::format::getStyle().
+// Consider pulling out common bits to a findParentFileWithName function or
+// similar.
+std::vector<OptionsSource>
+FileOptionsProvider::getRawOptions(StringRef FileName) {
+ LLVM_DEBUG(llvm::dbgs() << "Getting options for file " << FileName
+ << "...\n");
+ assert(FS && "FS must be set.");
+
+ llvm::SmallString<128> AbsoluteFilePath(FileName);
+
+ if (FS->makeAbsolute(AbsoluteFilePath))
+ return {};
+
+ std::vector<OptionsSource> RawOptions =
+ DefaultOptionsProvider::getRawOptions(AbsoluteFilePath.str());
+ addRawFileOptions(AbsoluteFilePath, RawOptions);
+ OptionsSource CommandLineOptions(OverrideOptions,
+ OptionsSourceTypeCheckCommandLineOption);
+
+ RawOptions.push_back(CommandLineOptions);
+ return RawOptions;
+}
+
+std::optional<OptionsSource>
+FileOptionsBaseProvider::tryReadConfigFile(StringRef Directory) {
+ assert(!Directory.empty());
+
+ llvm::ErrorOr<llvm::vfs::Status> DirectoryStatus = FS->status(Directory);
+
+ if (!DirectoryStatus || !DirectoryStatus->isDirectory()) {
+ llvm::errs() << "Error reading configuration from " << Directory
+ << ": directory doesn't exist.\n";
+ return std::nullopt;
+ }
+
+ for (const ConfigFileHandler &ConfigHandler : ConfigHandlers) {
+ SmallString<128> ConfigFile(Directory);
+ llvm::sys::path::append(ConfigFile, ConfigHandler.first);
+ LLVM_DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
+
+ llvm::ErrorOr<llvm::vfs::Status> FileStatus = FS->status(ConfigFile);
+
+ if (!FileStatus || !FileStatus->isRegularFile())
+ continue;
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
+ FS->getBufferForFile(ConfigFile);
+ if (std::error_code EC = Text.getError()) {
+ llvm::errs() << "Can't read " << ConfigFile << ": " << EC.message()
+ << "\n";
+ continue;
+ }
+
+ // Skip empty files, e.g. files opened for writing via shell output
+ // redirection.
+ if ((*Text)->getBuffer().empty())
+ continue;
+ llvm::ErrorOr<ClangTidyOptions> ParsedOptions =
+ ConfigHandler.second({(*Text)->getBuffer(), ConfigFile});
+ if (!ParsedOptions) {
+ if (ParsedOptions.getError())
+ llvm::errs() << "Error parsing " << ConfigFile << ": "
+ << ParsedOptions.getError().message() << "\n";
+ continue;
+ }
+ return OptionsSource(*ParsedOptions, std::string(ConfigFile));
+ }
+ return std::nullopt;
+}
+
+/// Parses -line-filter option and stores it to the \c Options.
+std::error_code parseLineFilter(StringRef LineFilter,
+ clang::tidy::ClangTidyGlobalOptions &Options) {
+ llvm::yaml::Input Input(LineFilter);
+ Input >> Options.LineFilter;
+ return Input.error();
+}
+
+llvm::ErrorOr<ClangTidyOptions>
+parseConfiguration(llvm::MemoryBufferRef Config) {
+ llvm::yaml::Input Input(Config);
+ ClangTidyOptions Options;
+ Input >> Options;
+ if (Input.error())
+ return Input.error();
+ return Options;
+}
+
+static void diagHandlerImpl(const llvm::SMDiagnostic &Diag, void *Ctx) {
+ (*reinterpret_cast<DiagCallback *>(Ctx))(Diag);
+}
+
+llvm::ErrorOr<ClangTidyOptions>
+parseConfigurationWithDiags(llvm::MemoryBufferRef Config,
+ DiagCallback Handler) {
+ llvm::yaml::Input Input(Config, nullptr, Handler ? diagHandlerImpl : nullptr,
+ &Handler);
+ ClangTidyOptions Options;
+ Input >> Options;
+ if (Input.error())
+ return Input.error();
+ return Options;
+}
+
+std::string configurationAsText(const ClangTidyOptions &Options) {
+ std::string Text;
+ llvm::raw_string_ostream Stream(Text);
+ llvm::yaml::Output Output(Stream);
+ // We use the same mapping method for input and output, so we need a non-const
+ // reference here.
+ ClangTidyOptions NonConstValue = Options;
+ Output << NonConstValue;
+ return Stream.str();
+}
+
+} // namespace clang::tidy