11#include "clang/Basic/LLVM.h"
12#include "llvm/ADT/SmallString.h"
13#include "llvm/Support/Debug.h"
14#include "llvm/Support/Errc.h"
15#include "llvm/Support/FileSystem.h"
16#include "llvm/Support/MemoryBufferRef.h"
17#include "llvm/Support/Path.h"
18#include "llvm/Support/YAMLTraits.h"
22#define DEBUG_TYPE "clang-tidy-options"
34template <>
struct SequenceTraits<
FileFilter::LineRange> {
35 static size_t size(IO &IO, FileFilter::LineRange &
Range) {
36 return Range.first == 0 ? 0 :
Range.second == 0 ? 1 : 2;
38 static unsigned &
element(IO &IO, FileFilter::LineRange &
Range,
size_t Index) {
40 IO.setError(
"Too many elements in line range.");
41 return Index == 0 ?
Range.first :
Range.second;
47 IO.mapRequired(
"name", File.Name);
48 IO.mapOptional(
"lines", File.LineRanges);
51 if (File.Name.empty())
52 return "No file name specified";
53 for (
const FileFilter::LineRange &
Range : File.LineRanges) {
55 return "Invalid line range";
62 static void mapping(IO &IO, ClangTidyOptions::StringPair &KeyValue) {
63 IO.mapRequired(
"key", KeyValue.first);
64 IO.mapRequired(
"value", KeyValue.second);
70 NOptionMap(IO &,
const ClangTidyOptions::OptionMap &OptionMap) {
71 Options.reserve(OptionMap.size());
72 for (
const auto &KeyValue : OptionMap)
73 Options.emplace_back(std::string(KeyValue.getKey()), KeyValue.getValue().Value);
76 ClangTidyOptions::OptionMap Map;
77 for (
const auto &KeyValue :
Options)
78 Map[KeyValue.first] = ClangTidyOptions::ClangTidyValue(KeyValue.second);
81 std::vector<ClangTidyOptions::StringPair>
Options;
85void yamlize(IO &IO, ClangTidyOptions::OptionMap &Options,
bool,
87 if (IO.outputting()) {
90 for (
auto &Key : Options) {
93 IO.preflightKey(Key.getKey().data(),
true,
false, UseDefault, SaveInfo);
94 StringRef S = Key.getValue().Value;
95 IO.scalarString(S, needsQuotes(S));
96 IO.postflightKey(SaveInfo);
102 Input &I =
reinterpret_cast<Input &
>(IO);
103 if (isa<SequenceNode>(I.getCurrentNode())) {
104 MappingNormalization<NOptionMap, ClangTidyOptions::OptionMap> NOpts(
107 yamlize(IO, NOpts->Options,
true, Ctx);
108 }
else if (isa<MappingNode>(I.getCurrentNode())) {
110 for (StringRef Key : IO.keys()) {
111 IO.mapRequired(Key.data(), Options[Key].Value);
115 IO.setError(
"expected a sequence or map");
122 bool Ignored =
false;
123 IO.mapOptional(
"Checks", Options.
Checks);
126 IO.mapOptional(
"ImplementationFileExtensions",
129 IO.mapOptional(
"AnalyzeTemporaryDtors", Ignored);
130 IO.mapOptional(
"FormatStyle", Options.
FormatStyle);
131 IO.mapOptional(
"User", Options.
User);
133 IO.mapOptional(
"ExtraArgs", Options.
ExtraArgs);
136 IO.mapOptional(
"UseColor", Options.
UseColor);
153 Options.
User = std::nullopt;
154 for (
const ClangTidyModuleRegistry::entry &Module :
155 ClangTidyModuleRegistry::entries())
156 Options.
mergeWith(Module.instantiate()->getModuleOptions(), 0);
164 Dest->insert(Dest->end(),
Src->begin(),
Src->end());
171 const std::optional<std::string> &
Src) {
173 Dest = (Dest && !Dest->empty() ? *Dest +
"," :
"") + *
Src;
201 KeyValue.getValue().Priority + Order));
207 unsigned Order)
const {
209 Result.mergeWith(Other, Order);
216 "command-line option '-checks'";
219 "command-line option '-config'";
224 unsigned Priority = 0;
226 Result.mergeWith(Source.first, ++Priority);
230std::vector<OptionsSource>
232 std::vector<OptionsSource> Result;
240 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
242 std::move(DefaultOptions),
243 std::move(OverrideOptions), std::move(FS)),
244 ConfigOptions(std::move(ConfigOptions)) {}
246std::vector<OptionsSource>
248 std::vector<OptionsSource> RawOptions =
251 LLVM_DEBUG(llvm::dbgs()
252 <<
"Getting options for file " <<
FileName <<
"...\n");
253 assert(
FS &&
"FS must be set.");
255 llvm::SmallString<128> AbsoluteFilePath(
FileName);
257 if (!
FS->makeAbsolute(AbsoluteFilePath)) {
261 RawOptions.emplace_back(ConfigOptions,
271 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
273 std::move(DefaultOptions)),
274 OverrideOptions(std::move(OverrideOptions)), FS(std::move(VFS)) {
276 FS = llvm::vfs::getRealFileSystem();
285 std::move(DefaultOptions)),
286 OverrideOptions(std::move(OverrideOptions)),
287 ConfigHandlers(std::move(ConfigHandlers)) {}
290 llvm::StringRef AbsolutePath, std::vector<OptionsSource> &CurOptions) {
291 auto CurSize = CurOptions.size();
295 StringRef
Path = llvm::sys::path::parent_path(AbsolutePath);
296 for (StringRef CurrentPath =
Path; !CurrentPath.empty();
297 CurrentPath = llvm::sys::path::parent_path(CurrentPath)) {
298 std::optional<OptionsSource> Result;
302 Result = Iter->second;
309 while (
Path != CurrentPath) {
310 LLVM_DEBUG(llvm::dbgs()
311 <<
"Caching configuration for path " <<
Path <<
".\n");
314 Path = llvm::sys::path::parent_path(
Path);
318 CurOptions.push_back(*Result);
319 if (!Result->first.InheritParentConfig.value_or(
false))
325 std::reverse(CurOptions.begin() + CurSize, CurOptions.end());
331 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
333 std::move(DefaultOptions),
334 std::move(OverrideOptions), std::move(VFS)) {}
341 std::move(GlobalOptions), std::move(DefaultOptions),
342 std::move(OverrideOptions), std::move(ConfigHandlers)) {}
347std::vector<OptionsSource>
349 LLVM_DEBUG(llvm::dbgs() <<
"Getting options for file " <<
FileName
351 assert(
FS &&
"FS must be set.");
353 llvm::SmallString<128> AbsoluteFilePath(
FileName);
355 if (
FS->makeAbsolute(AbsoluteFilePath))
358 std::vector<OptionsSource> RawOptions =
364 RawOptions.push_back(CommandLineOptions);
368std::optional<OptionsSource>
372 llvm::ErrorOr<llvm::vfs::Status> DirectoryStatus =
FS->status(
Directory);
374 if (!DirectoryStatus || !DirectoryStatus->isDirectory()) {
375 llvm::errs() <<
"Error reading configuration from " <<
Directory
376 <<
": directory doesn't exist.\n";
382 llvm::sys::path::append(
ConfigFile, ConfigHandler.first);
383 LLVM_DEBUG(llvm::dbgs() <<
"Trying " <<
ConfigFile <<
"...\n");
385 llvm::ErrorOr<llvm::vfs::Status> FileStatus =
FS->status(
ConfigFile);
387 if (!FileStatus || !FileStatus->isRegularFile())
390 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
Text =
392 if (std::error_code EC =
Text.getError()) {
393 llvm::errs() <<
"Can't read " <<
ConfigFile <<
": " << EC.message()
400 if ((*Text)->getBuffer().empty())
402 llvm::ErrorOr<ClangTidyOptions> ParsedOptions =
403 ConfigHandler.second({(*Text)->getBuffer(),
ConfigFile});
404 if (!ParsedOptions) {
405 if (ParsedOptions.getError())
406 llvm::errs() <<
"Error parsing " <<
ConfigFile <<
": "
407 << ParsedOptions.getError().message() <<
"\n";
420 return Input.error();
423llvm::ErrorOr<ClangTidyOptions>
425 llvm::yaml::Input Input(
Config);
429 return Input.error();
437llvm::ErrorOr<ClangTidyOptions>
445 return Input.error();
451 llvm::raw_string_ostream Stream(
Text);
452 llvm::yaml::Output
Output(Stream);
static cl::opt< std::string > ConfigFile("config-file", desc(R"(
Specify the path of .clang-tidy or custom config file:
e.g. --config-file=/some/path/myTidyConfigFile
This option internally works exactly the same way as
--config option after reading specified config file.
Use either --config-file or --config, not both.
)"), 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 > LineFilter("line-filter", desc(R"(
List of files with line ranges to filter the
warnings. Can be used together with
-header-filter. The format of the list is a
JSON array of objects:
[
{"name":"file1.cpp","lines":[[1,3],[5,7]]},
{"name":"file2.h"}
]
)"), cl::init(""), cl::cat(ClangTidyCategory))
clang::tidy::ClangTidyOptionsProvider::OptionsSource OptionsSource
CharSourceRange Range
SourceRange for the file name.
std::vector< HeaderHandle > Path
llvm::StringRef Directory
std::pair< ClangTidyOptions, std::string > OptionsSource
ClangTidyOptions and its source.
ClangTidyOptions getOptions(llvm::StringRef FileName)
Returns options applying to a specific translation unit with the specified FileName.
static const char OptionsSourceTypeCheckCommandLineOption[]
virtual std::vector< OptionsSource > getRawOptions(llvm::StringRef FileName)=0
Returns an ordered vector of OptionsSources, in order of increasing priority.
static const char OptionsSourceTypeConfigCommandLineOption[]
static const char OptionsSourceTypeDefaultBinary[]
ConfigOptionsProvider(ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, ClangTidyOptions ConfigOptions, ClangTidyOptions OverrideOptions, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS=nullptr)
std::vector< OptionsSource > getRawOptions(llvm::StringRef FileName) override
Returns an ordered vector of OptionsSources, in order of increasing priority.
Implementation of the ClangTidyOptionsProvider interface, which returns the same options for all file...
std::vector< OptionsSource > getRawOptions(llvm::StringRef FileName) override
Returns an ordered vector of OptionsSources, in order of increasing priority.
std::vector< ConfigFileHandler > ConfigFileHandlers
Configuration file handlers listed in the order of priority.
ClangTidyOptions OverrideOptions
std::optional< OptionsSource > tryReadConfigFile(llvm::StringRef Directory)
Try to read configuration files from Directory using registered ConfigHandlers.
llvm::StringMap< OptionsSource > CachedOptions
ConfigFileHandlers ConfigHandlers
std::pair< std::string, std::function< llvm::ErrorOr< ClangTidyOptions >(llvm::MemoryBufferRef)> > ConfigFileHandler
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS
FileOptionsBaseProvider(ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, ClangTidyOptions OverrideOptions, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS)
void addRawFileOptions(llvm::StringRef AbsolutePath, std::vector< OptionsSource > &CurOptions)
std::vector< OptionsSource > getRawOptions(llvm::StringRef FileName) override
Returns an ordered vector of OptionsSources, in order of increasing priority.
FileOptionsProvider(ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, ClangTidyOptions OverrideOptions, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS=nullptr)
Initializes the FileOptionsProvider instance.
std::error_code parseLineFilter(StringRef LineFilter, clang::tidy::ClangTidyGlobalOptions &Options)
Parses -line-filter option and stores it to the Options.
static void diagHandlerImpl(const llvm::SMDiagnostic &Diag, void *Ctx)
static void mergeVectors(std::optional< T > &Dest, const std::optional< T > &Src)
llvm::function_ref< void(const llvm::SMDiagnostic &)> DiagCallback
llvm::ErrorOr< ClangTidyOptions > parseConfigurationWithDiags(llvm::MemoryBufferRef Config, DiagCallback Handler)
static void mergeCommaSeparatedLists(std::optional< std::string > &Dest, const std::optional< std::string > &Src)
std::string configurationAsText(const ClangTidyOptions &Options)
Serializes configuration to a YAML-encoded string.
llvm::ErrorOr< ClangTidyOptions > parseConfiguration(llvm::MemoryBufferRef Config)
Parses configuration from JSON and returns ClangTidyOptions or an error.
static void overrideValue(std::optional< T > &Dest, const std::optional< T > &Src)
void yamlize(IO &IO, ClangTidyOptions::OptionMap &Options, bool, EmptyContext &Ctx)
std::vector< FileFilter > LineFilter
Output warnings from certain line ranges of certain files only.
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.
ClangTidyOptions merge(const ClangTidyOptions &Other, unsigned Order) const
Creates a new ClangTidyOptions instance combined from all fields of this instance overridden by the f...
std::optional< bool > InheritParentConfig
Only used in the FileOptionsProvider and ConfigOptionsProvider.
std::optional< std::string > HeaderFilterRegex
Output warnings from headers matching this filter.
std::optional< std::string > Checks
Checks filter.
std::optional< std::string > WarningsAsErrors
WarningsAsErrors filter.
std::optional< std::vector< std::string > > ImplementationFileExtensions
File extensions to consider to determine if a given diagnostic is located is located in an implementa...
ClangTidyOptions & mergeWith(const ClangTidyOptions &Other, unsigned Order)
Overwrites all fields in here by the fields of Other that have a value.
std::optional< std::string > User
Specifies the name or e-mail of the user running clang-tidy.
std::optional< std::vector< std::string > > HeaderFileExtensions
File extensions to consider to determine if a given diagnostic is located in a header file.
std::optional< bool > UseColor
Use colors in diagnostics. If missing, it will be auto detected.
std::optional< bool > SystemHeaders
Output warnings from system headers matching HeaderFilterRegex.
static ClangTidyOptions getDefaults()
These options are used for all settings that haven't been overridden by the OptionsProvider.
std::optional< ArgList > ExtraArgsBefore
Add extra compilation arguments to the start of the list.
std::optional< std::string > FormatStyle
Format code around applied fixes with clang-format using this style.
std::optional< ArgList > ExtraArgs
Add extra compilation arguments to the end of the list.
Contains a list of line ranges in a single file.
std::pair< unsigned, unsigned > LineRange
LineRange is a pair<start, end> (inclusive).
static void mapping(IO &IO, ClangTidyOptions &Options)
static void mapping(IO &IO, ClangTidyOptions::StringPair &KeyValue)
static std::string validate(IO &Io, FileFilter &File)
static void mapping(IO &IO, FileFilter &File)
ClangTidyOptions::OptionMap denormalize(IO &)
NOptionMap(IO &, const ClangTidyOptions::OptionMap &OptionMap)
std::vector< ClangTidyOptions::StringPair > Options
static unsigned & element(IO &IO, FileFilter::LineRange &Range, size_t Index)
static size_t size(IO &IO, FileFilter::LineRange &Range)