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