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