xref: /llvm-project/clang-tools-extra/clang-tidy/ClangTidyOptions.h (revision 0249554ee1ac49e6f1d93fa78a55971fc706f635)
1 //===--- ClangTidyOptions.h - clang-tidy ------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
10 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
11 
12 #include "llvm/ADT/IntrusiveRefCntPtr.h"
13 #include "llvm/ADT/SmallString.h"
14 #include "llvm/ADT/StringMap.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Support/ErrorOr.h"
17 #include "llvm/Support/MemoryBufferRef.h"
18 #include "llvm/Support/VirtualFileSystem.h"
19 #include <functional>
20 #include <optional>
21 #include <string>
22 #include <system_error>
23 #include <utility>
24 #include <vector>
25 
26 namespace clang::tidy {
27 
28 /// Contains a list of line ranges in a single file.
29 struct FileFilter {
30   /// File name.
31   std::string Name;
32 
33   /// LineRange is a pair<start, end> (inclusive).
34   using LineRange = std::pair<unsigned int, unsigned int>;
35 
36   /// A list of line ranges in this file, for which we show warnings.
37   std::vector<LineRange> LineRanges;
38 };
39 
40 /// Global options. These options are neither stored nor read from
41 /// configuration files.
42 struct ClangTidyGlobalOptions {
43   /// Output warnings from certain line ranges of certain files only.
44   /// If empty, no warnings will be filtered.
45   std::vector<FileFilter> LineFilter;
46 };
47 
48 /// Contains options for clang-tidy. These options may be read from
49 /// configuration files, and may be different for different translation units.
50 struct ClangTidyOptions {
51   /// These options are used for all settings that haven't been
52   /// overridden by the \c OptionsProvider.
53   ///
54   /// Allow no checks and no headers by default. This method initializes
55   /// check-specific options by calling \c ClangTidyModule::getModuleOptions()
56   /// of each registered \c ClangTidyModule.
57   static ClangTidyOptions getDefaults();
58 
59   /// Overwrites all fields in here by the fields of \p Other that have a value.
60   /// \p Order specifies precedence of \p Other option.
61   ClangTidyOptions &mergeWith(const ClangTidyOptions &Other, unsigned Order);
62 
63   /// Creates a new \c ClangTidyOptions instance combined from all fields
64   /// of this instance overridden by the fields of \p Other that have a value.
65   /// \p Order specifies precedence of \p Other option.
66   [[nodiscard]] ClangTidyOptions merge(const ClangTidyOptions &Other,
67                                        unsigned Order) const;
68 
69   /// Checks filter.
70   std::optional<std::string> Checks;
71 
72   /// WarningsAsErrors filter.
73   std::optional<std::string> WarningsAsErrors;
74 
75   /// File extensions to consider to determine if a given diagnostic is located
76   /// in a header file.
77   std::optional<std::vector<std::string>> HeaderFileExtensions;
78 
79   /// File extensions to consider to determine if a given diagnostic is located
80   /// is located in an implementation file.
81   std::optional<std::vector<std::string>> ImplementationFileExtensions;
82 
83   /// Output warnings from headers matching this filter. Warnings from
84   /// main files will always be displayed.
85   std::optional<std::string> HeaderFilterRegex;
86 
87   /// \brief Exclude warnings from headers matching this filter, even if they
88   /// match \c HeaderFilterRegex.
89   std::optional<std::string> ExcludeHeaderFilterRegex;
90 
91   /// Output warnings from system headers matching \c HeaderFilterRegex.
92   std::optional<bool> SystemHeaders;
93 
94   /// Format code around applied fixes with clang-format using this
95   /// style.
96   ///
97   /// Can be one of:
98   ///   * 'none' - don't format code around applied fixes;
99   ///   * 'llvm', 'google', 'mozilla' or other predefined clang-format style
100   ///     names;
101   ///   * 'file' - use the .clang-format file in the closest parent directory of
102   ///     each source file;
103   ///   * '{inline-formatting-style-in-yaml-format}'.
104   ///
105   /// See clang-format documentation for more about configuring format style.
106   std::optional<std::string> FormatStyle;
107 
108   /// Specifies the name or e-mail of the user running clang-tidy.
109   ///
110   /// This option is used, for example, to place the correct user name in TODO()
111   /// comments in the relevant check.
112   std::optional<std::string> User;
113 
114   /// Helper structure for storing option value with priority of the value.
115   struct ClangTidyValue {
116     ClangTidyValue() = default;
117     ClangTidyValue(const char *Value) : Value(Value) {}
118     ClangTidyValue(llvm::StringRef Value, unsigned Priority = 0)
119         : Value(Value), Priority(Priority) {}
120 
121     std::string Value;
122     /// Priority stores relative precedence of the value loaded from config
123     /// files to disambiguate local vs global value from different levels.
124     unsigned Priority = 0;
125   };
126   using StringPair = std::pair<std::string, std::string>;
127   using OptionMap = llvm::StringMap<ClangTidyValue>;
128 
129   /// Key-value mapping used to store check-specific options.
130   OptionMap CheckOptions;
131 
132   using ArgList = std::vector<std::string>;
133 
134   /// Add extra compilation arguments to the end of the list.
135   std::optional<ArgList> ExtraArgs;
136 
137   /// Add extra compilation arguments to the start of the list.
138   std::optional<ArgList> ExtraArgsBefore;
139 
140   /// Only used in the FileOptionsProvider and ConfigOptionsProvider. If true
141   /// and using a FileOptionsProvider, it will take a configuration file in the
142   /// parent directory (if any exists) and apply this config file on top of the
143   /// parent one. IF true and using a ConfigOptionsProvider, it will apply this
144   /// config on top of any configuration file it finds in the directory using
145   /// the same logic as FileOptionsProvider. If false or missing, only this
146   /// configuration file will be used.
147   std::optional<bool> InheritParentConfig;
148 
149   /// Use colors in diagnostics. If missing, it will be auto detected.
150   std::optional<bool> UseColor;
151 };
152 
153 /// Abstract interface for retrieving various ClangTidy options.
154 class ClangTidyOptionsProvider {
155 public:
156   static const char OptionsSourceTypeDefaultBinary[];
157   static const char OptionsSourceTypeCheckCommandLineOption[];
158   static const char OptionsSourceTypeConfigCommandLineOption[];
159 
160   virtual ~ClangTidyOptionsProvider() {}
161 
162   /// Returns global options, which are independent of the file.
163   virtual const ClangTidyGlobalOptions &getGlobalOptions() = 0;
164 
165   /// ClangTidyOptions and its source.
166   //
167   /// clang-tidy has 3 types of the sources in order of increasing priority:
168   ///    * clang-tidy binary.
169   ///    * '-config' commandline option or a specific configuration file. If the
170   ///       commandline option is specified, clang-tidy will ignore the
171   ///       configuration file.
172   ///    * '-checks' commandline option.
173   using OptionsSource = std::pair<ClangTidyOptions, std::string>;
174 
175   /// Returns an ordered vector of OptionsSources, in order of increasing
176   /// priority.
177   virtual std::vector<OptionsSource>
178   getRawOptions(llvm::StringRef FileName) = 0;
179 
180   /// Returns options applying to a specific translation unit with the
181   /// specified \p FileName.
182   ClangTidyOptions getOptions(llvm::StringRef FileName);
183 };
184 
185 /// Implementation of the \c ClangTidyOptionsProvider interface, which
186 /// returns the same options for all files.
187 class DefaultOptionsProvider : public ClangTidyOptionsProvider {
188 public:
189   DefaultOptionsProvider(ClangTidyGlobalOptions GlobalOptions,
190                          ClangTidyOptions Options)
191       : GlobalOptions(std::move(GlobalOptions)),
192         DefaultOptions(std::move(Options)) {}
193   const ClangTidyGlobalOptions &getGlobalOptions() override {
194     return GlobalOptions;
195   }
196   std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override;
197 
198 private:
199   ClangTidyGlobalOptions GlobalOptions;
200   ClangTidyOptions DefaultOptions;
201 };
202 
203 class FileOptionsBaseProvider : public DefaultOptionsProvider {
204 protected:
205   // A pair of configuration file base name and a function parsing
206   // configuration from text in the corresponding format.
207   using ConfigFileHandler = std::pair<std::string, std::function<llvm::ErrorOr<ClangTidyOptions> (llvm::MemoryBufferRef)>>;
208 
209   /// Configuration file handlers listed in the order of priority.
210   ///
211   /// Custom configuration file formats can be supported by constructing the
212   /// list of handlers and passing it to the appropriate \c FileOptionsProvider
213   /// constructor. E.g. initialization of a \c FileOptionsProvider with support
214   /// of a custom configuration file format for files named ".my-tidy-config"
215   /// could look similar to this:
216   /// \code
217   /// FileOptionsProvider::ConfigFileHandlers ConfigHandlers;
218   /// ConfigHandlers.emplace_back(".my-tidy-config", parseMyConfigFormat);
219   /// ConfigHandlers.emplace_back(".clang-tidy", parseConfiguration);
220   /// return std::make_unique<FileOptionsProvider>(
221   ///     GlobalOptions, DefaultOptions, OverrideOptions, ConfigHandlers);
222   /// \endcode
223   ///
224   /// With the order of handlers shown above, the ".my-tidy-config" file would
225   /// take precedence over ".clang-tidy" if both reside in the same directory.
226   using ConfigFileHandlers = std::vector<ConfigFileHandler>;
227 
228   FileOptionsBaseProvider(ClangTidyGlobalOptions GlobalOptions,
229                           ClangTidyOptions DefaultOptions,
230                           ClangTidyOptions OverrideOptions,
231                           llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS);
232 
233   FileOptionsBaseProvider(ClangTidyGlobalOptions GlobalOptions,
234                           ClangTidyOptions DefaultOptions,
235                           ClangTidyOptions OverrideOptions,
236                           ConfigFileHandlers ConfigHandlers);
237 
238   void addRawFileOptions(llvm::StringRef AbsolutePath,
239                          std::vector<OptionsSource> &CurOptions);
240 
241   llvm::ErrorOr<llvm::SmallString<128>>
242   getNormalizedAbsolutePath(llvm::StringRef AbsolutePath);
243 
244   /// Try to read configuration files from \p Directory using registered
245   /// \c ConfigHandlers.
246   std::optional<OptionsSource> tryReadConfigFile(llvm::StringRef Directory);
247 
248   struct OptionsCache {
249     llvm::StringMap<size_t> Memorized;
250     llvm::SmallVector<OptionsSource, 4U> Storage;
251   } CachedOptions;
252   ClangTidyOptions OverrideOptions;
253   ConfigFileHandlers ConfigHandlers;
254   llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
255 };
256 
257 /// Implementation of ClangTidyOptions interface, which is used for
258 /// '-config' command-line option.
259 class ConfigOptionsProvider : public FileOptionsBaseProvider {
260 public:
261   ConfigOptionsProvider(
262       ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions,
263       ClangTidyOptions ConfigOptions, ClangTidyOptions OverrideOptions,
264       llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr);
265   std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override;
266 
267 private:
268   ClangTidyOptions ConfigOptions;
269 };
270 
271 /// Implementation of the \c ClangTidyOptionsProvider interface, which
272 /// tries to find a configuration file in the closest parent directory of each
273 /// source file.
274 ///
275 /// By default, files named ".clang-tidy" will be considered, and the
276 /// \c clang::tidy::parseConfiguration function will be used for parsing, but a
277 /// custom set of configuration file names and parsing functions can be
278 /// specified using the appropriate constructor.
279 class FileOptionsProvider : public FileOptionsBaseProvider {
280 public:
281   /// Initializes the \c FileOptionsProvider instance.
282   ///
283   /// \param GlobalOptions are just stored and returned to the caller of
284   /// \c getGlobalOptions.
285   ///
286   /// \param DefaultOptions are used for all settings not specified in a
287   /// configuration file.
288   ///
289   /// If any of the \param OverrideOptions fields are set, they will override
290   /// whatever options are read from the configuration file.
291   FileOptionsProvider(
292       ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions,
293       ClangTidyOptions OverrideOptions,
294       llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr);
295 
296   /// Initializes the \c FileOptionsProvider instance with a custom set
297   /// of configuration file handlers.
298   ///
299   /// \param GlobalOptions are just stored and returned to the caller of
300   /// \c getGlobalOptions.
301   ///
302   /// \param DefaultOptions are used for all settings not specified in a
303   /// configuration file.
304   ///
305   /// If any of the \param OverrideOptions fields are set, they will override
306   /// whatever options are read from the configuration file.
307   ///
308   /// \param ConfigHandlers specifies a custom set of configuration file
309   /// handlers. Each handler is a pair of configuration file name and a function
310   /// that can parse configuration from this file type. The configuration files
311   /// in each directory are searched for in the order of appearance in
312   /// \p ConfigHandlers.
313   FileOptionsProvider(ClangTidyGlobalOptions GlobalOptions,
314                       ClangTidyOptions DefaultOptions,
315                       ClangTidyOptions OverrideOptions,
316                       ConfigFileHandlers ConfigHandlers);
317 
318   std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override;
319 };
320 
321 /// Parses LineFilter from JSON and stores it to the \p Options.
322 std::error_code parseLineFilter(llvm::StringRef LineFilter,
323                                 ClangTidyGlobalOptions &Options);
324 
325 /// Parses configuration from JSON and returns \c ClangTidyOptions or an
326 /// error.
327 llvm::ErrorOr<ClangTidyOptions>
328 parseConfiguration(llvm::MemoryBufferRef Config);
329 
330 using DiagCallback = llvm::function_ref<void(const llvm::SMDiagnostic &)>;
331 
332 llvm::ErrorOr<ClangTidyOptions>
333 parseConfigurationWithDiags(llvm::MemoryBufferRef Config, DiagCallback Handler);
334 
335 /// Serializes configuration to a YAML-encoded string.
336 std::string configurationAsText(const ClangTidyOptions &Options);
337 
338 } // namespace clang::tidy
339 
340 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
341