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());
67 llvm::MemoryBufferRef(*Data, path()), Diagnostics))
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) {
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");
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",
213 "-cppcoreguidelines-macro-to-enum",
220 "-bugprone-use-after-move",
222 "-hicpp-invalid-access-moved",
225 "-bugprone-unchecked-optional-access");
227 size_t Size = BadChecks.size();
228 for (
const std::string &Str : ExtraBadChecks) {
232 if (LLVM_LIKELY(Str.front() !=
'-'))
236 std::string DisableGlob;
237 DisableGlob.reserve(Size);
238 DisableGlob += BadChecks;
239 for (
const std::string &Str : ExtraBadChecks) {
243 if (LLVM_LIKELY(Str.front() !=
'-'))
244 DisableGlob.push_back(
'-');
251 Opts.
Checks->append(DisableList);
258 if (!CurTidyConfig.Checks.empty())
261 for (
const auto &CheckOption : CurTidyConfig.CheckOptions)
262 Opts.
CheckOptions.insert_or_assign(CheckOption.getKey(),
264 CheckOption.getValue(), 10000U));
269 return [Tree = std::make_unique<DotClangTidyTree>(TFS)](
271 Tree->apply(Opts, Filename);
280 llvm::StringRef Filename) {
281 for (
const auto &Provider : Providers)
282 Provider(Opts, Filename);
287 llvm::StringRef Filename) {
290 static const auto *DefaultOpts = [] {
293 Opts->Checks->clear();
296 auto Opts = *DefaultOpts;
298 Provider(Opts, Filename);
303 assert(!Check.empty());
304 assert(!Check.contains(
'*') && !Check.contains(
',') &&
305 "isRegisteredCheck doesn't support globs");
306 assert(Check.ltrim().front() !=
'-');
308 static const llvm::StringSet<llvm::BumpPtrAllocator> AllChecks = [] {
309 llvm::StringSet<llvm::BumpPtrAllocator> Result;
311 for (tidy::ClangTidyModuleRegistry::entry E :
312 tidy::ClangTidyModuleRegistry::entries())
313 E.instantiate()->addCheckFactories(Factories);
314 for (
const auto &Factory : Factories)
315 Result.insert(Factory.getKey());
319 return AllChecks.contains(Check);
323 static auto &Fast = *
new llvm::StringMap<bool>{
324#define FAST(CHECK, TIME) {#CHECK,true},
325#define SLOW(CHECK, TIME) {#CHECK,false},
328 if (
auto It = Fast.find(Check); It != Fast.end())
static cl::opt< std::string > WarningsAsErrors("warnings-as-errors", desc(R"(
Upgrades warnings to errors. Same format as
'-checks'.
This option's value is appended to the value of
the 'WarningsAsErrors' option in .clang-tidy
file, if any.
)"), cl::init(""), cl::cat(ClangTidyCategory))
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))
static cl::opt< std::string > Checks("checks", desc(R"(
Comma-separated list of globs with optional '-'
prefix. Globs are processed in order of
appearance in the list. Globs without '-'
prefix add checks with matching names to the
set, globs with the '-' prefix remove checks
with matching names from the set of enabled
checks. This option's value is appended to the
value of the 'Checks' option in .clang-tidy
file, if any.
)"), cl::init(""), cl::cat(ClangTidyCategory))
const char DefaultChecks[]
Base class for threadsafe cache of data read from a file on disk.
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
A collection of ClangTidyCheckFactory instances.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
llvm::unique_function< void(tidy::ClangTidyOptions &, llvm::StringRef) const > TidyProvider
A factory to modify a tidy::ClangTidyOptions.
TidyProvider combine(std::vector< TidyProvider > Providers)
bool isRegisteredTidyCheck(llvm::StringRef Check)
Returns if Check is a registered clang-tidy check.
void vlog(const char *Fmt, Ts &&... Vals)
llvm::function_ref< void(tidy::ClangTidyOptions &, llvm::StringRef)> TidyProviderRef
A factory to modify a tidy::ClangTidyOptions that doesn't hold any state.
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.
void log(const char *Fmt, Ts &&... Vals)
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.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
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.
std::string Path
A typedef to represent a file path.
TidyProvider provideDefaultChecks()
Provider that will enable a nice set of default checks if none are specified.
TidyProvider provideClangdConfig()
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++ -*-===//
struct clang::clangd::Config::@224206046260313204212274150166346126315121140114::@177170157270305170147304143303331271375010045063 ClangTidy
Configures what clang-tidy checks to run and options to use with them.
static const Config & current()
Returns the Config of the current Context, or an empty configuration.
struct clang::clangd::Config::@224206046260313204212274150166346126315121140114 Diagnostics
Controls warnings and errors when parsing code.
Helper structure for storing option value with priority of the value.
Contains options for clang-tidy.
OptionMap CheckOptions
Key-value mapping used to store check-specific options.
std::optional< std::string > Checks
Checks filter.
std::optional< std::string > User
Specifies the name or e-mail of the user running clang-tidy.
static ClangTidyOptions getDefaults()
These options are used for all settings that haven't been overridden by the OptionsProvider.