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