1 | //===--- ClangTidyOptions.cpp - 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 | #include "ClangTidyOptions.h" |
10 | #include "ClangTidyModuleRegistry.h" |
11 | #include "clang/Basic/LLVM.h" |
12 | #include "llvm/ADT/SmallString.h" |
13 | #include "llvm/Support/Debug.h" |
14 | #include "llvm/Support/ErrorOr.h" |
15 | #include "llvm/Support/MemoryBufferRef.h" |
16 | #include "llvm/Support/Path.h" |
17 | #include "llvm/Support/YAMLTraits.h" |
18 | #include <algorithm> |
19 | #include <optional> |
20 | #include <utility> |
21 | |
22 | #define DEBUG_TYPE "clang-tidy-options" |
23 | |
24 | using clang::tidy::ClangTidyOptions; |
25 | using clang::tidy::FileFilter; |
26 | using OptionsSource = clang::tidy::ClangTidyOptionsProvider::OptionsSource; |
27 | |
28 | LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter) |
29 | LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter::LineRange) |
30 | |
31 | namespace llvm::yaml { |
32 | |
33 | // Map std::pair<int, int> to a JSON array of size 2. |
34 | template <> struct SequenceTraits<FileFilter::LineRange> { |
35 | static size_t size(IO &IO, FileFilter::LineRange &Range) { |
36 | return Range.first == 0 ? 0 : Range.second == 0 ? 1 : 2; |
37 | } |
38 | static unsigned &element(IO &IO, FileFilter::LineRange &Range, size_t Index) { |
39 | if (Index > 1) |
40 | IO.setError("Too many elements in line range."); |
41 | return Index == 0 ? Range.first : Range.second; |
42 | } |
43 | }; |
44 | |
45 | template <> struct MappingTraits<FileFilter> { |
46 | static void mapping(IO &IO, FileFilter &File) { |
47 | IO.mapRequired(Key: "name", Val&: File.Name); |
48 | IO.mapOptional(Key: "lines", Val&: File.LineRanges); |
49 | } |
50 | static std::string validate(IO &Io, FileFilter &File) { |
51 | if (File.Name.empty()) |
52 | return "No file name specified"; |
53 | for (const FileFilter::LineRange &Range : File.LineRanges) { |
54 | if (Range.first <= 0 || Range.second <= 0) |
55 | return "Invalid line range"; |
56 | } |
57 | return ""; |
58 | } |
59 | }; |
60 | |
61 | template <> struct MappingTraits<ClangTidyOptions::StringPair> { |
62 | static void mapping(IO &IO, ClangTidyOptions::StringPair &KeyValue) { |
63 | IO.mapRequired(Key: "key", Val&: KeyValue.first); |
64 | IO.mapRequired(Key: "value", Val&: KeyValue.second); |
65 | } |
66 | }; |
67 | |
68 | struct NOptionMap { |
69 | NOptionMap(IO &) {} |
70 | NOptionMap(IO &, const ClangTidyOptions::OptionMap &OptionMap) { |
71 | Options.reserve(n: OptionMap.size()); |
72 | for (const auto &KeyValue : OptionMap) |
73 | Options.emplace_back(args: std::string(KeyValue.getKey()), |
74 | args: KeyValue.getValue().Value); |
75 | } |
76 | ClangTidyOptions::OptionMap denormalize(IO &) { |
77 | ClangTidyOptions::OptionMap Map; |
78 | for (const auto &KeyValue : Options) |
79 | Map[KeyValue.first] = ClangTidyOptions::ClangTidyValue(KeyValue.second); |
80 | return Map; |
81 | } |
82 | std::vector<ClangTidyOptions::StringPair> Options; |
83 | }; |
84 | |
85 | template <> |
86 | void yamlize(IO &IO, ClangTidyOptions::OptionMap &Val, bool, |
87 | EmptyContext &Ctx) { |
88 | if (IO.outputting()) { |
89 | // Ensure check options are sorted |
90 | std::vector<std::pair<StringRef, StringRef>> SortedOptions; |
91 | SortedOptions.reserve(n: Val.size()); |
92 | for (auto &Key : Val) { |
93 | SortedOptions.emplace_back(args: Key.getKey(), args&: Key.getValue().Value); |
94 | } |
95 | std::sort(first: SortedOptions.begin(), last: SortedOptions.end()); |
96 | |
97 | IO.beginMapping(); |
98 | // Only output as a map |
99 | for (auto &Option : SortedOptions) { |
100 | bool UseDefault = false; |
101 | void *SaveInfo = nullptr; |
102 | IO.preflightKey(Option.first.data(), true, false, UseDefault, SaveInfo); |
103 | IO.scalarString(Option.second, needsQuotes(S: Option.second)); |
104 | IO.postflightKey(SaveInfo); |
105 | } |
106 | IO.endMapping(); |
107 | } else { |
108 | // We need custom logic here to support the old method of specifying check |
109 | // options using a list of maps containing key and value keys. |
110 | auto &I = reinterpret_cast<Input &>(IO); |
111 | if (isa<SequenceNode>(Val: I.getCurrentNode())) { |
112 | MappingNormalization<NOptionMap, ClangTidyOptions::OptionMap> NOpts(IO, |
113 | Val); |
114 | EmptyContext Ctx; |
115 | yamlize(io&: IO, Seq&: NOpts->Options, true, Ctx); |
116 | } else if (isa<MappingNode>(Val: I.getCurrentNode())) { |
117 | IO.beginMapping(); |
118 | for (StringRef Key : IO.keys()) { |
119 | IO.mapRequired(Key: Key.data(), Val&: Val[Key].Value); |
120 | } |
121 | IO.endMapping(); |
122 | } else { |
123 | IO.setError("expected a sequence or map"); |
124 | } |
125 | } |
126 | } |
127 | |
128 | struct ChecksVariant { |
129 | std::optional<std::string> AsString; |
130 | std::optional<std::vector<std::string>> AsVector; |
131 | }; |
132 | |
133 | template <> void yamlize(IO &IO, ChecksVariant &Val, bool, EmptyContext &Ctx) { |
134 | if (!IO.outputting()) { |
135 | // Special case for reading from YAML |
136 | // Must support reading from both a string or a list |
137 | auto &I = reinterpret_cast<Input &>(IO); |
138 | if (isa<ScalarNode, BlockScalarNode>(Val: I.getCurrentNode())) { |
139 | Val.AsString = std::string(); |
140 | yamlize(io&: IO, Val&: *Val.AsString, true, Ctx); |
141 | } else if (isa<SequenceNode>(Val: I.getCurrentNode())) { |
142 | Val.AsVector = std::vector<std::string>(); |
143 | yamlize(io&: IO, Seq&: *Val.AsVector, true, Ctx); |
144 | } else { |
145 | IO.setError("expected string or sequence"); |
146 | } |
147 | } |
148 | } |
149 | |
150 | static void mapChecks(IO &IO, std::optional<std::string> &Checks) { |
151 | if (IO.outputting()) { |
152 | // Output always a string |
153 | IO.mapOptional(Key: "Checks", Val&: Checks); |
154 | } else { |
155 | // Input as either a string or a list |
156 | ChecksVariant ChecksAsVariant; |
157 | IO.mapOptional(Key: "Checks", Val&: ChecksAsVariant); |
158 | if (ChecksAsVariant.AsString) |
159 | Checks = ChecksAsVariant.AsString; |
160 | else if (ChecksAsVariant.AsVector) |
161 | Checks = llvm::join(R&: *ChecksAsVariant.AsVector, Separator: ","); |
162 | } |
163 | } |
164 | |
165 | template <> struct MappingTraits<ClangTidyOptions> { |
166 | static void mapping(IO &IO, ClangTidyOptions &Options) { |
167 | mapChecks(IO, Checks&: Options.Checks); |
168 | IO.mapOptional(Key: "WarningsAsErrors", Val&: Options.WarningsAsErrors); |
169 | IO.mapOptional(Key: "HeaderFileExtensions", Val&: Options.HeaderFileExtensions); |
170 | IO.mapOptional(Key: "ImplementationFileExtensions", |
171 | Val&: Options.ImplementationFileExtensions); |
172 | IO.mapOptional(Key: "HeaderFilterRegex", Val&: Options.HeaderFilterRegex); |
173 | IO.mapOptional(Key: "ExcludeHeaderFilterRegex", |
174 | Val&: Options.ExcludeHeaderFilterRegex); |
175 | IO.mapOptional(Key: "FormatStyle", Val&: Options.FormatStyle); |
176 | IO.mapOptional(Key: "User", Val&: Options.User); |
177 | IO.mapOptional(Key: "CheckOptions", Val&: Options.CheckOptions); |
178 | IO.mapOptional(Key: "ExtraArgs", Val&: Options.ExtraArgs); |
179 | IO.mapOptional(Key: "ExtraArgsBefore", Val&: Options.ExtraArgsBefore); |
180 | IO.mapOptional(Key: "InheritParentConfig", Val&: Options.InheritParentConfig); |
181 | IO.mapOptional(Key: "UseColor", Val&: Options.UseColor); |
182 | IO.mapOptional(Key: "SystemHeaders", Val&: Options.SystemHeaders); |
183 | } |
184 | }; |
185 | |
186 | } // namespace llvm::yaml |
187 | |
188 | namespace clang::tidy { |
189 | |
190 | ClangTidyOptions ClangTidyOptions::getDefaults() { |
191 | ClangTidyOptions Options; |
192 | Options.Checks = ""; |
193 | Options.WarningsAsErrors = ""; |
194 | Options.HeaderFileExtensions = {"", "h", "hh", "hpp", "hxx"}; |
195 | Options.ImplementationFileExtensions = {"c", "cc", "cpp", "cxx"}; |
196 | Options.HeaderFilterRegex = ""; |
197 | Options.ExcludeHeaderFilterRegex = ""; |
198 | Options.SystemHeaders = false; |
199 | Options.FormatStyle = "none"; |
200 | Options.User = std::nullopt; |
201 | for (const ClangTidyModuleRegistry::entry &Module : |
202 | ClangTidyModuleRegistry::entries()) |
203 | Options.mergeWith(Other: Module.instantiate()->getModuleOptions(), Order: 0); |
204 | return Options; |
205 | } |
206 | |
207 | template <typename T> |
208 | static void mergeVectors(std::optional<T> &Dest, const std::optional<T> &Src) { |
209 | if (Src) { |
210 | if (Dest) |
211 | Dest->insert(Dest->end(), Src->begin(), Src->end()); |
212 | else |
213 | Dest = Src; |
214 | } |
215 | } |
216 | |
217 | static void mergeCommaSeparatedLists(std::optional<std::string> &Dest, |
218 | const std::optional<std::string> &Src) { |
219 | if (Src) |
220 | Dest = (Dest && !Dest->empty() ? *Dest + ",": "") + *Src; |
221 | } |
222 | |
223 | template <typename T> |
224 | static void overrideValue(std::optional<T> &Dest, const std::optional<T> &Src) { |
225 | if (Src) |
226 | Dest = Src; |
227 | } |
228 | |
229 | ClangTidyOptions &ClangTidyOptions::mergeWith(const ClangTidyOptions &Other, |
230 | unsigned Order) { |
231 | mergeCommaSeparatedLists(Dest&: Checks, Src: Other.Checks); |
232 | mergeCommaSeparatedLists(Dest&: WarningsAsErrors, Src: Other.WarningsAsErrors); |
233 | overrideValue(Dest&: HeaderFileExtensions, Src: Other.HeaderFileExtensions); |
234 | overrideValue(Dest&: ImplementationFileExtensions, |
235 | Src: Other.ImplementationFileExtensions); |
236 | overrideValue(Dest&: HeaderFilterRegex, Src: Other.HeaderFilterRegex); |
237 | overrideValue(Dest&: ExcludeHeaderFilterRegex, Src: Other.ExcludeHeaderFilterRegex); |
238 | overrideValue(Dest&: SystemHeaders, Src: Other.SystemHeaders); |
239 | overrideValue(Dest&: FormatStyle, Src: Other.FormatStyle); |
240 | overrideValue(Dest&: User, Src: Other.User); |
241 | overrideValue(Dest&: UseColor, Src: Other.UseColor); |
242 | mergeVectors(Dest&: ExtraArgs, Src: Other.ExtraArgs); |
243 | mergeVectors(Dest&: ExtraArgsBefore, Src: Other.ExtraArgsBefore); |
244 | |
245 | for (const auto &KeyValue : Other.CheckOptions) { |
246 | CheckOptions.insert_or_assign( |
247 | Key: KeyValue.getKey(), |
248 | Val: ClangTidyValue(KeyValue.getValue().Value, |
249 | KeyValue.getValue().Priority + Order)); |
250 | } |
251 | return *this; |
252 | } |
253 | |
254 | ClangTidyOptions ClangTidyOptions::merge(const ClangTidyOptions &Other, |
255 | unsigned Order) const { |
256 | ClangTidyOptions Result = *this; |
257 | Result.mergeWith(Other, Order); |
258 | return Result; |
259 | } |
260 | |
261 | const char ClangTidyOptionsProvider::OptionsSourceTypeDefaultBinary[] = |
262 | "clang-tidy binary"; |
263 | const char ClangTidyOptionsProvider::OptionsSourceTypeCheckCommandLineOption[] = |
264 | "command-line option '-checks'"; |
265 | const char |
266 | ClangTidyOptionsProvider::OptionsSourceTypeConfigCommandLineOption[] = |
267 | "command-line option '-config'"; |
268 | |
269 | ClangTidyOptions |
270 | ClangTidyOptionsProvider::getOptions(llvm::StringRef FileName) { |
271 | ClangTidyOptions Result; |
272 | unsigned Priority = 0; |
273 | for (auto &Source : getRawOptions(FileName)) |
274 | Result.mergeWith(Other: Source.first, Order: ++Priority); |
275 | return Result; |
276 | } |
277 | |
278 | std::vector<OptionsSource> |
279 | DefaultOptionsProvider::getRawOptions(llvm::StringRef FileName) { |
280 | std::vector<OptionsSource> Result; |
281 | Result.emplace_back(args&: DefaultOptions, args: OptionsSourceTypeDefaultBinary); |
282 | return Result; |
283 | } |
284 | |
285 | ConfigOptionsProvider::ConfigOptionsProvider( |
286 | ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, |
287 | ClangTidyOptions ConfigOptions, ClangTidyOptions OverrideOptions, |
288 | llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) |
289 | : FileOptionsBaseProvider(std::move(GlobalOptions), |
290 | std::move(DefaultOptions), |
291 | std::move(OverrideOptions), std::move(FS)), |
292 | ConfigOptions(std::move(ConfigOptions)) {} |
293 | |
294 | std::vector<OptionsSource> |
295 | ConfigOptionsProvider::getRawOptions(llvm::StringRef FileName) { |
296 | std::vector<OptionsSource> RawOptions = |
297 | DefaultOptionsProvider::getRawOptions(FileName); |
298 | if (ConfigOptions.InheritParentConfig.value_or(u: false)) { |
299 | LLVM_DEBUG(llvm::dbgs() |
300 | << "Getting options for file "<< FileName << "...\n"); |
301 | |
302 | llvm::ErrorOr<llvm::SmallString<128>> AbsoluteFilePath = |
303 | getNormalizedAbsolutePath(AbsolutePath: FileName); |
304 | if (AbsoluteFilePath) { |
305 | addRawFileOptions(AbsolutePath: AbsoluteFilePath->str(), CurOptions&: RawOptions); |
306 | } |
307 | } |
308 | RawOptions.emplace_back(args&: ConfigOptions, |
309 | args: OptionsSourceTypeConfigCommandLineOption); |
310 | RawOptions.emplace_back(args&: OverrideOptions, |
311 | args: OptionsSourceTypeCheckCommandLineOption); |
312 | return RawOptions; |
313 | } |
314 | |
315 | FileOptionsBaseProvider::FileOptionsBaseProvider( |
316 | ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, |
317 | ClangTidyOptions OverrideOptions, |
318 | llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) |
319 | : DefaultOptionsProvider(std::move(GlobalOptions), |
320 | std::move(DefaultOptions)), |
321 | OverrideOptions(std::move(OverrideOptions)), FS(std::move(VFS)) { |
322 | if (!FS) |
323 | FS = llvm::vfs::getRealFileSystem(); |
324 | ConfigHandlers.emplace_back(args: ".clang-tidy", args&: parseConfiguration); |
325 | } |
326 | |
327 | FileOptionsBaseProvider::FileOptionsBaseProvider( |
328 | ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, |
329 | ClangTidyOptions OverrideOptions, |
330 | FileOptionsBaseProvider::ConfigFileHandlers ConfigHandlers) |
331 | : DefaultOptionsProvider(std::move(GlobalOptions), |
332 | std::move(DefaultOptions)), |
333 | OverrideOptions(std::move(OverrideOptions)), |
334 | ConfigHandlers(std::move(ConfigHandlers)) {} |
335 | |
336 | llvm::ErrorOr<llvm::SmallString<128>> |
337 | FileOptionsBaseProvider::getNormalizedAbsolutePath(llvm::StringRef Path) { |
338 | assert(FS && "FS must be set."); |
339 | llvm::SmallString<128> NormalizedAbsolutePath = {Path}; |
340 | std::error_code Err = FS->makeAbsolute(Path&: NormalizedAbsolutePath); |
341 | if (Err) |
342 | return Err; |
343 | llvm::sys::path::remove_dots(path&: NormalizedAbsolutePath, /*remove_dot_dot=*/true); |
344 | return NormalizedAbsolutePath; |
345 | } |
346 | |
347 | void FileOptionsBaseProvider::addRawFileOptions( |
348 | llvm::StringRef AbsolutePath, std::vector<OptionsSource> &CurOptions) { |
349 | auto CurSize = CurOptions.size(); |
350 | // Look for a suitable configuration file in all parent directories of the |
351 | // file. Start with the immediate parent directory and move up. |
352 | StringRef RootPath = llvm::sys::path::parent_path(path: AbsolutePath); |
353 | auto MemorizedConfigFile = |
354 | [this, &RootPath](StringRef CurrentPath) -> std::optional<OptionsSource> { |
355 | const auto Iter = CachedOptions.Memorized.find(Key: CurrentPath); |
356 | if (Iter != CachedOptions.Memorized.end()) |
357 | return CachedOptions.Storage[Iter->second]; |
358 | std::optional<OptionsSource> OptionsSource = tryReadConfigFile(Directory: CurrentPath); |
359 | if (OptionsSource) { |
360 | const size_t Index = CachedOptions.Storage.size(); |
361 | CachedOptions.Storage.emplace_back(Args&: OptionsSource.value()); |
362 | while (RootPath != CurrentPath) { |
363 | LLVM_DEBUG(llvm::dbgs() |
364 | << "Caching configuration for path "<< RootPath << ".\n"); |
365 | CachedOptions.Memorized[RootPath] = Index; |
366 | RootPath = llvm::sys::path::parent_path(path: RootPath); |
367 | } |
368 | CachedOptions.Memorized[CurrentPath] = Index; |
369 | RootPath = llvm::sys::path::parent_path(path: CurrentPath); |
370 | } |
371 | return OptionsSource; |
372 | }; |
373 | for (StringRef CurrentPath = RootPath; !CurrentPath.empty(); |
374 | CurrentPath = llvm::sys::path::parent_path(path: CurrentPath)) { |
375 | if (std::optional<OptionsSource> Result = |
376 | MemorizedConfigFile(CurrentPath)) { |
377 | CurOptions.emplace_back(args&: Result.value()); |
378 | if (!Result->first.InheritParentConfig.value_or(u: false)) |
379 | break; |
380 | } |
381 | } |
382 | // Reverse order of file configs because closer configs should have higher |
383 | // priority. |
384 | std::reverse(first: CurOptions.begin() + CurSize, last: CurOptions.end()); |
385 | } |
386 | |
387 | FileOptionsProvider::FileOptionsProvider( |
388 | ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, |
389 | ClangTidyOptions OverrideOptions, |
390 | llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) |
391 | : FileOptionsBaseProvider(std::move(GlobalOptions), |
392 | std::move(DefaultOptions), |
393 | std::move(OverrideOptions), std::move(VFS)) {} |
394 | |
395 | FileOptionsProvider::FileOptionsProvider( |
396 | ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, |
397 | ClangTidyOptions OverrideOptions, |
398 | FileOptionsBaseProvider::ConfigFileHandlers ConfigHandlers) |
399 | : FileOptionsBaseProvider( |
400 | std::move(GlobalOptions), std::move(DefaultOptions), |
401 | std::move(OverrideOptions), std::move(ConfigHandlers)) {} |
402 | |
403 | // FIXME: This method has some common logic with clang::format::getStyle(). |
404 | // Consider pulling out common bits to a findParentFileWithName function or |
405 | // similar. |
406 | std::vector<OptionsSource> |
407 | FileOptionsProvider::getRawOptions(StringRef FileName) { |
408 | LLVM_DEBUG(llvm::dbgs() << "Getting options for file "<< FileName |
409 | << "...\n"); |
410 | |
411 | llvm::ErrorOr<llvm::SmallString<128>> AbsoluteFilePath = |
412 | getNormalizedAbsolutePath(Path: FileName); |
413 | if (!AbsoluteFilePath) |
414 | return {}; |
415 | |
416 | std::vector<OptionsSource> RawOptions = |
417 | DefaultOptionsProvider::getRawOptions(FileName: AbsoluteFilePath->str()); |
418 | addRawFileOptions(AbsolutePath: AbsoluteFilePath->str(), CurOptions&: RawOptions); |
419 | OptionsSource CommandLineOptions(OverrideOptions, |
420 | OptionsSourceTypeCheckCommandLineOption); |
421 | |
422 | RawOptions.push_back(x: CommandLineOptions); |
423 | return RawOptions; |
424 | } |
425 | |
426 | std::optional<OptionsSource> |
427 | FileOptionsBaseProvider::tryReadConfigFile(StringRef Directory) { |
428 | assert(!Directory.empty()); |
429 | |
430 | llvm::ErrorOr<llvm::vfs::Status> DirectoryStatus = FS->status(Path: Directory); |
431 | |
432 | if (!DirectoryStatus || !DirectoryStatus->isDirectory()) { |
433 | llvm::errs() << "Error reading configuration from "<< Directory |
434 | << ": directory doesn't exist.\n"; |
435 | return std::nullopt; |
436 | } |
437 | |
438 | for (const ConfigFileHandler &ConfigHandler : ConfigHandlers) { |
439 | SmallString<128> ConfigFile(Directory); |
440 | llvm::sys::path::append(path&: ConfigFile, a: ConfigHandler.first); |
441 | LLVM_DEBUG(llvm::dbgs() << "Trying "<< ConfigFile << "...\n"); |
442 | |
443 | llvm::ErrorOr<llvm::vfs::Status> FileStatus = FS->status(Path: ConfigFile); |
444 | |
445 | if (!FileStatus || !FileStatus->isRegularFile()) |
446 | continue; |
447 | |
448 | llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = |
449 | FS->getBufferForFile(Name: ConfigFile); |
450 | if (std::error_code EC = Text.getError()) { |
451 | llvm::errs() << "Can't read "<< ConfigFile << ": "<< EC.message() |
452 | << "\n"; |
453 | continue; |
454 | } |
455 | |
456 | // Skip empty files, e.g. files opened for writing via shell output |
457 | // redirection. |
458 | if ((*Text)->getBuffer().empty()) |
459 | continue; |
460 | llvm::ErrorOr<ClangTidyOptions> ParsedOptions = |
461 | ConfigHandler.second({(*Text)->getBuffer(), ConfigFile}); |
462 | if (!ParsedOptions) { |
463 | if (ParsedOptions.getError()) |
464 | llvm::errs() << "Error parsing "<< ConfigFile << ": " |
465 | << ParsedOptions.getError().message() << "\n"; |
466 | continue; |
467 | } |
468 | return OptionsSource(*ParsedOptions, std::string(ConfigFile)); |
469 | } |
470 | return std::nullopt; |
471 | } |
472 | |
473 | /// Parses -line-filter option and stores it to the \c Options. |
474 | std::error_code parseLineFilter(StringRef LineFilter, |
475 | clang::tidy::ClangTidyGlobalOptions &Options) { |
476 | llvm::yaml::Input Input(LineFilter); |
477 | Input >> Options.LineFilter; |
478 | return Input.error(); |
479 | } |
480 | |
481 | llvm::ErrorOr<ClangTidyOptions> |
482 | parseConfiguration(llvm::MemoryBufferRef Config) { |
483 | llvm::yaml::Input Input(Config); |
484 | ClangTidyOptions Options; |
485 | Input >> Options; |
486 | if (Input.error()) |
487 | return Input.error(); |
488 | return Options; |
489 | } |
490 | |
491 | static void diagHandlerImpl(const llvm::SMDiagnostic &Diag, void *Ctx) { |
492 | (*reinterpret_cast<DiagCallback *>(Ctx))(Diag); |
493 | } |
494 | |
495 | llvm::ErrorOr<ClangTidyOptions> |
496 | parseConfigurationWithDiags(llvm::MemoryBufferRef Config, |
497 | DiagCallback Handler) { |
498 | llvm::yaml::Input Input(Config, nullptr, Handler ? diagHandlerImpl : nullptr, |
499 | &Handler); |
500 | ClangTidyOptions Options; |
501 | Input >> Options; |
502 | if (Input.error()) |
503 | return Input.error(); |
504 | return Options; |
505 | } |
506 | |
507 | std::string configurationAsText(const ClangTidyOptions &Options) { |
508 | std::string Text; |
509 | llvm::raw_string_ostream Stream(Text); |
510 | llvm::yaml::Output Output(Stream); |
511 | // We use the same mapping method for input and output, so we need a non-const |
512 | // reference here. |
513 | ClangTidyOptions NonConstValue = Options; |
514 | Output << NonConstValue; |
515 | return Stream.str(); |
516 | } |
517 | |
518 | } // namespace clang::tidy |
519 |
Definitions
- SequenceTraits
- size
- element
- MappingTraits
- mapping
- validate
- MappingTraits
- mapping
- NOptionMap
- NOptionMap
- NOptionMap
- denormalize
- yamlize
- ChecksVariant
- yamlize
- mapChecks
- MappingTraits
- mapping
- getDefaults
- mergeVectors
- mergeCommaSeparatedLists
- overrideValue
- mergeWith
- merge
- OptionsSourceTypeDefaultBinary
- OptionsSourceTypeCheckCommandLineOption
- OptionsSourceTypeConfigCommandLineOption
- getOptions
- getRawOptions
- ConfigOptionsProvider
- getRawOptions
- FileOptionsBaseProvider
- FileOptionsBaseProvider
- getNormalizedAbsolutePath
- addRawFileOptions
- FileOptionsProvider
- FileOptionsProvider
- getRawOptions
- tryReadConfigFile
- parseLineFilter
- parseConfiguration
- diagHandlerImpl
- parseConfigurationWithDiags
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more