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