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/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>> ; |
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> ; |
86 | |
87 | /// \brief Exclude warnings from headers matching this filter, even if they |
88 | /// match \c HeaderFilterRegex. |
89 | std::optional<std::string> ; |
90 | |
91 | /// Output warnings from system headers matching \c HeaderFilterRegex. |
92 | std::optional<bool> ; |
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> ; |
136 | |
137 | /// Add extra compilation arguments to the start of the list. |
138 | std::optional<ArgList> ; |
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 = |
208 | std::pair<std::string, std::function<llvm::ErrorOr<ClangTidyOptions>( |
209 | llvm::MemoryBufferRef)>>; |
210 | |
211 | /// Configuration file handlers listed in the order of priority. |
212 | /// |
213 | /// Custom configuration file formats can be supported by constructing the |
214 | /// list of handlers and passing it to the appropriate \c FileOptionsProvider |
215 | /// constructor. E.g. initialization of a \c FileOptionsProvider with support |
216 | /// of a custom configuration file format for files named ".my-tidy-config" |
217 | /// could look similar to this: |
218 | /// \code |
219 | /// FileOptionsProvider::ConfigFileHandlers ConfigHandlers; |
220 | /// ConfigHandlers.emplace_back(".my-tidy-config", parseMyConfigFormat); |
221 | /// ConfigHandlers.emplace_back(".clang-tidy", parseConfiguration); |
222 | /// return std::make_unique<FileOptionsProvider>( |
223 | /// GlobalOptions, DefaultOptions, OverrideOptions, ConfigHandlers); |
224 | /// \endcode |
225 | /// |
226 | /// With the order of handlers shown above, the ".my-tidy-config" file would |
227 | /// take precedence over ".clang-tidy" if both reside in the same directory. |
228 | using ConfigFileHandlers = std::vector<ConfigFileHandler>; |
229 | |
230 | FileOptionsBaseProvider(ClangTidyGlobalOptions GlobalOptions, |
231 | ClangTidyOptions DefaultOptions, |
232 | ClangTidyOptions OverrideOptions, |
233 | llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS); |
234 | |
235 | FileOptionsBaseProvider(ClangTidyGlobalOptions GlobalOptions, |
236 | ClangTidyOptions DefaultOptions, |
237 | ClangTidyOptions OverrideOptions, |
238 | ConfigFileHandlers ConfigHandlers); |
239 | |
240 | void addRawFileOptions(llvm::StringRef AbsolutePath, |
241 | std::vector<OptionsSource> &CurOptions); |
242 | |
243 | llvm::ErrorOr<llvm::SmallString<128>> |
244 | getNormalizedAbsolutePath(llvm::StringRef AbsolutePath); |
245 | |
246 | /// Try to read configuration files from \p Directory using registered |
247 | /// \c ConfigHandlers. |
248 | std::optional<OptionsSource> tryReadConfigFile(llvm::StringRef Directory); |
249 | |
250 | struct OptionsCache { |
251 | llvm::StringMap<size_t> Memorized; |
252 | llvm::SmallVector<OptionsSource, 4U> Storage; |
253 | } CachedOptions; |
254 | ClangTidyOptions OverrideOptions; |
255 | ConfigFileHandlers ConfigHandlers; |
256 | llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; |
257 | }; |
258 | |
259 | /// Implementation of ClangTidyOptions interface, which is used for |
260 | /// '-config' command-line option. |
261 | class ConfigOptionsProvider : public FileOptionsBaseProvider { |
262 | public: |
263 | ConfigOptionsProvider( |
264 | ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, |
265 | ClangTidyOptions ConfigOptions, ClangTidyOptions OverrideOptions, |
266 | llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr); |
267 | std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override; |
268 | |
269 | private: |
270 | ClangTidyOptions ConfigOptions; |
271 | }; |
272 | |
273 | /// Implementation of the \c ClangTidyOptionsProvider interface, which |
274 | /// tries to find a configuration file in the closest parent directory of each |
275 | /// source file. |
276 | /// |
277 | /// By default, files named ".clang-tidy" will be considered, and the |
278 | /// \c clang::tidy::parseConfiguration function will be used for parsing, but a |
279 | /// custom set of configuration file names and parsing functions can be |
280 | /// specified using the appropriate constructor. |
281 | class FileOptionsProvider : public FileOptionsBaseProvider { |
282 | public: |
283 | /// Initializes the \c FileOptionsProvider instance. |
284 | /// |
285 | /// \param GlobalOptions are just stored and returned to the caller of |
286 | /// \c getGlobalOptions. |
287 | /// |
288 | /// \param DefaultOptions are used for all settings not specified in a |
289 | /// configuration file. |
290 | /// |
291 | /// If any of the \param OverrideOptions fields are set, they will override |
292 | /// whatever options are read from the configuration file. |
293 | FileOptionsProvider( |
294 | ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, |
295 | ClangTidyOptions OverrideOptions, |
296 | llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr); |
297 | |
298 | /// Initializes the \c FileOptionsProvider instance with a custom set |
299 | /// of configuration file handlers. |
300 | /// |
301 | /// \param GlobalOptions are just stored and returned to the caller of |
302 | /// \c getGlobalOptions. |
303 | /// |
304 | /// \param DefaultOptions are used for all settings not specified in a |
305 | /// configuration file. |
306 | /// |
307 | /// If any of the \param OverrideOptions fields are set, they will override |
308 | /// whatever options are read from the configuration file. |
309 | /// |
310 | /// \param ConfigHandlers specifies a custom set of configuration file |
311 | /// handlers. Each handler is a pair of configuration file name and a function |
312 | /// that can parse configuration from this file type. The configuration files |
313 | /// in each directory are searched for in the order of appearance in |
314 | /// \p ConfigHandlers. |
315 | FileOptionsProvider(ClangTidyGlobalOptions GlobalOptions, |
316 | ClangTidyOptions DefaultOptions, |
317 | ClangTidyOptions OverrideOptions, |
318 | ConfigFileHandlers ConfigHandlers); |
319 | |
320 | std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override; |
321 | }; |
322 | |
323 | /// Parses LineFilter from JSON and stores it to the \p Options. |
324 | std::error_code parseLineFilter(llvm::StringRef LineFilter, |
325 | ClangTidyGlobalOptions &Options); |
326 | |
327 | /// Parses configuration from JSON and returns \c ClangTidyOptions or an |
328 | /// error. |
329 | llvm::ErrorOr<ClangTidyOptions> |
330 | parseConfiguration(llvm::MemoryBufferRef Config); |
331 | |
332 | using DiagCallback = llvm::function_ref<void(const llvm::SMDiagnostic &)>; |
333 | |
334 | llvm::ErrorOr<ClangTidyOptions> |
335 | parseConfigurationWithDiags(llvm::MemoryBufferRef Config, DiagCallback Handler); |
336 | |
337 | /// Serializes configuration to a YAML-encoded string. |
338 | std::string configurationAsText(const ClangTidyOptions &Options); |
339 | |
340 | } // namespace clang::tidy |
341 | |
342 | #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H |
343 | |