10#include "../clang-tidy/ClangTidyModuleRegistry.h"
11#include "../clang-tidy/ClangTidyOptions.h"
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/SmallString.h"
19#include "llvm/ADT/StringExtras.h"
20#include "llvm/ADT/StringSet.h"
21#include "llvm/Support/Allocator.h"
22#include "llvm/Support/Process.h"
23#include "llvm/Support/SourceMgr.h"
32class DotClangTidyCache :
private FileCache {
35 mutable std::shared_ptr<const tidy::ClangTidyOptions> Value;
40 std::shared_ptr<const tidy::ClangTidyOptions>
41 get(
const ThreadsafeFS &TFS,
42 std::chrono::steady_clock::time_point FreshTime)
const {
43 std::shared_ptr<const tidy::ClangTidyOptions> Result;
46 [
this](std::optional<llvm::StringRef> Data) {
48 if (Data && !Data->empty()) {
49 auto Diagnostics = [](const llvm::SMDiagnostic &D) {
50 switch (D.getKind()) {
51 case llvm::SourceMgr::DK_Error:
52 elog(
"tidy-config error at {0}:{1}:{2}: {3}", D.getFilename(),
53 D.getLineNo(), D.getColumnNo(), D.getMessage());
55 case llvm::SourceMgr::DK_Warning:
56 log(
"tidy-config warning at {0}:{1}:{2}: {3}", D.getFilename(),
57 D.getLineNo(), D.getColumnNo(), D.getMessage());
59 case llvm::SourceMgr::DK_Note:
60 case llvm::SourceMgr::DK_Remark:
61 vlog(
"tidy-config note at {0}:{1}:{2}: {3}", D.getFilename(),
62 D.getLineNo(), D.getColumnNo(), D.getMessage());
68 Value = std::make_shared<const tidy::ClangTidyOptions>(
71 elog(
"Error parsing clang-tidy configuration in {0}: {1}", path(),
72 Parsed.getError().message());
75 [&]() { Result = Value; });
85class DotClangTidyTree {
86 const ThreadsafeFS &FS;
88 std::chrono::steady_clock::duration MaxStaleness;
90 mutable std::mutex Mu;
94 mutable llvm::StringMap<DotClangTidyCache> Cache;
97 DotClangTidyTree(
const ThreadsafeFS &FS)
98 : FS(FS), RelPath(
".clang-tidy"), MaxStaleness(std::chrono::seconds(5)) {}
100 void apply(tidy::ClangTidyOptions &Result,
PathRef AbsPath) {
101 namespace path = llvm::sys::path;
102 assert(path::is_absolute(AbsPath));
106 llvm::SmallVector<DotClangTidyCache *> Caches;
108 std::lock_guard<std::mutex> Lock(Mu);
111 auto It = Cache.find(Ancestor);
113 if (It == Cache.end()) {
114 llvm::SmallString<256> ConfigPath = Ancestor;
115 path::append(ConfigPath, RelPath);
116 It = Cache.try_emplace(Ancestor, ConfigPath.str()).first;
118 Caches.push_back(&It->second);
123 std::chrono::steady_clock::time_point FreshTime =
124 std::chrono::steady_clock::now() - MaxStaleness;
125 llvm::SmallVector<std::shared_ptr<const tidy::ClangTidyOptions>>
127 for (
const DotClangTidyCache *Cache : Caches)
128 if (
auto Config = Cache->get(FS, FreshTime)) {
129 OptionStack.push_back(std::move(
Config));
130 if (!OptionStack.back()->InheritParentConfig.value_or(
false))
134 for (
auto &Option : llvm::reverse(OptionStack))
135 Result.mergeWith(*Option, Order++);
142 llvm::StringRef List) {
145 if (!Checks || Checks->empty()) {
146 Checks.emplace(List);
149 *Checks = llvm::join_items(
",", *Checks, List);
153 static const std::optional<std::string> User = [] {
154 std::optional<std::string> Ret = llvm::sys::Process::GetEnv(
"USER");
157 return llvm::sys::Process::GetEnv(
"USERNAME");
176 ",",
"readability-misleading-indentation",
"readability-deleted-default",
177 "bugprone-integer-division",
"bugprone-sizeof-expression",
178 "bugprone-suspicious-missing-comma",
"bugprone-unused-raii",
179 "bugprone-unused-return-value",
"misc-unused-using-decls",
180 "misc-unused-alias-decls",
"misc-definitions-in-headers");
182 if (!Opts.Checks || Opts.Checks->empty())
188 llvm::StringRef WarningsAsErrors) {
189 return [Checks = std::string(Checks),
190 WarningsAsErrors = std::string(WarningsAsErrors)](
198 constexpr llvm::StringLiteral
Separator(
",");
199 static const std::string BadChecks = llvm::join_items(
206 "-misc-include-cleaner",
212 "-llvm-header-guard",
"-modernize-macro-to-enum",
219 "-bugprone-use-after-move",
221 "-hicpp-invalid-access-moved",
224 "-bugprone-unchecked-optional-access");
226 size_t Size = BadChecks.size();
227 for (
const std::string &Str : ExtraBadChecks) {
231 if (LLVM_LIKELY(Str.front() !=
'-'))
235 std::string DisableGlob;
236 DisableGlob.reserve(Size);
237 DisableGlob += BadChecks;
238 for (
const std::string &Str : ExtraBadChecks) {
242 if (LLVM_LIKELY(Str.front() !=
'-'))
243 DisableGlob.push_back(
'-');
249 if (Opts.Checks && !Opts.Checks->empty())
250 Opts.Checks->append(DisableList);
256 const auto &CurTidyConfig = Config::current().Diagnostics.ClangTidy;
257 if (!CurTidyConfig.Checks.empty())
260 for (
const auto &CheckOption : CurTidyConfig.CheckOptions)
261 Opts.CheckOptions.insert_or_assign(CheckOption.getKey(),
263 CheckOption.getValue(), 10000U));
268 return [Tree = std::make_unique<DotClangTidyTree>(TFS)](
280 for (
const auto &Provider : Providers)
289 static const auto *DefaultOpts = [] {
292 Opts->Checks->clear();
295 auto Opts = *DefaultOpts;
302 assert(!Check.empty());
303 assert(!Check.contains(
'*') && !Check.contains(
',') &&
304 "isRegisteredCheck doesn't support globs");
305 assert(Check.ltrim().front() !=
'-');
307 static const llvm::StringSet<llvm::BumpPtrAllocator> AllChecks = [] {
308 llvm::StringSet<llvm::BumpPtrAllocator> Result;
310 for (tidy::ClangTidyModuleRegistry::entry
E :
311 tidy::ClangTidyModuleRegistry::entries())
312 E.instantiate()->addCheckFactories(Factories);
313 for (
const auto &Factory : Factories)
314 Result.insert(Factory.getKey());
318 return AllChecks.contains(Check);
322 static auto &Fast = *
new llvm::StringMap<bool>{
323#define FAST(CHECK, TIME) {#CHECK,true},
324#define SLOW(CHECK, TIME) {#CHECK,false},
327 if (
auto It = Fast.find(Check); It != Fast.end())
static cl::opt< std::string > Config("config", desc(R"(
Specifies a configuration in YAML/JSON format:
-config="{Checks:' *', CheckOptions:{x:y}}"
When the value is empty, clang-tidy will
attempt to find a file named .clang-tidy for
each source file in its parent directories.
)"), cl::init(""), cl::cat(ClangTidyCategory))
const char DefaultChecks[]
std::string Filename
Filename as a string.
WantDiagnostics Diagnostics
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
A collection of ClangTidyCheckFactory instances.
llvm::function_ref< void(tidy::ClangTidyOptions &, llvm::StringRef)> TidyProviderRef
A factory to modify a tidy::ClangTidyOptions that doesn't hold any state.
TidyProvider combine(std::vector< TidyProvider > Providers)
std::string Path
A typedef to represent a file path.
bool isRegisteredTidyCheck(llvm::StringRef Check)
Returns if Check is a registered clang-tidy check.
std::optional< bool > isFastTidyCheck(llvm::StringRef Check)
Returns if Check is known-fast, known-slow, or its speed is unknown.
TidyProvider addTidyChecks(llvm::StringRef Checks, llvm::StringRef WarningsAsErrors)
Provider the enables a specific set of checks and warnings as errors.
PathRef absoluteParent(PathRef Path)
Variant of parent_path that operates only on absolute paths.
static void mergeCheckList(std::optional< std::string > &Checks, llvm::StringRef List)
TidyProvider provideClangTidyFiles(ThreadsafeFS &TFS)
Provider that searches for .clang-tidy configuration files in the directory tree.
tidy::ClangTidyOptions getTidyOptionsForFile(TidyProviderRef Provider, llvm::StringRef Filename)
TidyProvider disableUnusableChecks(llvm::ArrayRef< std::string > ExtraBadChecks)
Provider that will disable checks known to not work with clangd.
TidyProvider provideDefaultChecks()
Provider that will enable a nice set of default checks if none are specified.
llvm::unique_function< void(tidy::ClangTidyOptions &, llvm::StringRef) const > TidyProvider
A factory to modify a tidy::ClangTidyOptions.
TidyProvider provideClangdConfig()
llvm::StringRef PathRef
A typedef to represent a ref to file path.
void elog(const char *Fmt, Ts &&... Vals)
TidyProvider provideEnvironment()
Provider that just sets the defaults.
llvm::ErrorOr< ClangTidyOptions > parseConfigurationWithDiags(llvm::MemoryBufferRef Config, DiagCallback Handler)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Helper structure for storing option value with priority of the value.
Contains options for clang-tidy.
static ClangTidyOptions getDefaults()
These options are used for all settings that haven't been overridden by the OptionsProvider.