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