clang-tools  11.0.0
TransformerClangTidyCheck.cpp
Go to the documentation of this file.
1 //===---------- TransformerClangTidyCheck.cpp - clang-tidy ----------------===//
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 
10 #include "clang/Lex/Preprocessor.h"
11 #include "llvm/ADT/STLExtras.h"
12 
13 namespace clang {
14 namespace tidy {
15 namespace utils {
16 using transformer::RewriteRule;
17 
18 #ifndef NDEBUG
19 static bool hasExplanation(const RewriteRule::Case &C) {
20  return C.Explanation != nullptr;
21 }
22 #endif
23 
24 // This constructor cannot dispatch to the simpler one (below), because, in
25 // order to get meaningful results from `getLangOpts` and `Options`, we need the
26 // `ClangTidyCheck()` constructor to have been called. If we were to dispatch,
27 // we would be accessing `getLangOpts` and `Options` before the underlying
28 // `ClangTidyCheck` instance was properly initialized.
30  std::function<Optional<RewriteRule>(const LangOptions &,
31  const OptionsView &)>
32  MakeRule,
33  StringRef Name, ClangTidyContext *Context)
34  : ClangTidyCheck(Name, Context), Rule(MakeRule(getLangOpts(), Options)),
35  IncludeStyle(Options.getLocalOrGlobal("IncludeStyle",
36  IncludeSorter::IS_LLVM)) {
37  if (Rule)
38  assert(llvm::all_of(Rule->Cases, hasExplanation) &&
39  "clang-tidy checks must have an explanation by default;"
40  " explicitly provide an empty explanation if none is desired");
41 }
42 
43 TransformerClangTidyCheck::TransformerClangTidyCheck(RewriteRule R,
44  StringRef Name,
45  ClangTidyContext *Context)
46  : ClangTidyCheck(Name, Context), Rule(std::move(R)),
47  IncludeStyle(Options.getLocalOrGlobal("IncludeStyle",
48  IncludeSorter::IS_LLVM)) {
49  assert(llvm::all_of(Rule->Cases, hasExplanation) &&
50  "clang-tidy checks must have an explanation by default;"
51  " explicitly provide an empty explanation if none is desired");
52 }
53 
54 void TransformerClangTidyCheck::registerPPCallbacks(
55  const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
56  // Only allocate and register the IncludeInsert when some `Case` will add
57  // includes.
58  if (Rule && llvm::any_of(Rule->Cases, [](const RewriteRule::Case &C) {
59  return !C.AddedIncludes.empty();
60  })) {
61  Inserter =
62  std::make_unique<IncludeInserter>(SM, getLangOpts(), IncludeStyle);
63  PP->addPPCallbacks(Inserter->CreatePPCallbacks());
64  }
65 }
66 
67 void TransformerClangTidyCheck::registerMatchers(
68  ast_matchers::MatchFinder *Finder) {
69  if (Rule)
70  for (auto &Matcher : transformer::detail::buildMatchers(*Rule))
71  Finder->addDynamicMatcher(Matcher, this);
72 }
73 
74 void TransformerClangTidyCheck::check(
75  const ast_matchers::MatchFinder::MatchResult &Result) {
76  if (Result.Context->getDiagnostics().hasErrorOccurred())
77  return;
78 
79  assert(Rule && "check() should not fire if Rule is None");
80  RewriteRule::Case Case = transformer::detail::findSelectedCase(Result, *Rule);
81  Expected<SmallVector<transformer::Edit, 1>> Edits = Case.Edits(Result);
82  if (!Edits) {
83  llvm::errs() << "Rewrite failed: " << llvm::toString(Edits.takeError())
84  << "\n";
85  return;
86  }
87 
88  // No rewrite applied, but no error encountered either.
89  if (Edits->empty())
90  return;
91 
92  Expected<std::string> Explanation = Case.Explanation->eval(Result);
93  if (!Explanation) {
94  llvm::errs() << "Error in explanation: "
95  << llvm::toString(Explanation.takeError()) << "\n";
96  return;
97  }
98 
99  // Associate the diagnostic with the location of the first change.
100  DiagnosticBuilder Diag = diag((*Edits)[0].Range.getBegin(), *Explanation);
101  for (const auto &T : *Edits)
102  Diag << FixItHint::CreateReplacement(T.Range, T.Replacement);
103 
104  for (const auto &I : Case.AddedIncludes) {
105  Diag << Inserter->CreateIncludeInsertion(
106  Result.SourceManager->getMainFileID(), I.first,
107  /*IsAngled=*/I.second == transformer::IncludeFormat::Angled);
108  }
109 }
110 
111 void TransformerClangTidyCheck::storeOptions(
113  Options.store(Opts, "IncludeStyle", IncludeStyle);
114 }
115 
116 } // namespace utils
117 } // namespace tidy
118 } // namespace clang
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
clang::tidy::abseil::MakeRule
static llvm::Optional< transformer::RewriteRule > MakeRule(const LangOptions &LangOpts, const ClangTidyCheck::OptionsView &Options)
Definition: StringFindStrContainsCheck.cpp:39
TransformerClangTidyCheck.h
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidyCheck.h:114
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:76
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::tidy::utils::TransformerClangTidyCheck::TransformerClangTidyCheck
TransformerClangTidyCheck(std::function< Optional< transformer::RewriteRule >(const LangOptions &, const OptionsView &)> MakeRule, StringRef Name, ClangTidyContext *Context)
clang::tidy::bugprone::PP
static Preprocessor * PP
Definition: BadSignalToKillThreadCheck.cpp:29
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::tidy::cppcoreguidelines::toString
static llvm::StringRef toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K)
Definition: SpecialMemberFunctionsCheck.cpp:60
clang::tidy::utils::hasExplanation
static bool hasExplanation(const RewriteRule::Case &C)
Definition: TransformerClangTidyCheck.cpp:19
clang::tidy::ClangTidyOptions::OptionMap
std::map< std::string, ClangTidyValue > OptionMap
Definition: ClangTidyOptions.h:111