aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/clang16/tools/extra/clang-tidy/utils/TransformerClangTidyCheck.cpp
diff options
context:
space:
mode:
authorthegeorg <thegeorg@yandex-team.com>2024-03-13 13:58:24 +0300
committerthegeorg <thegeorg@yandex-team.com>2024-03-13 14:11:53 +0300
commit11a895b7e15d1c5a1f52706396b82e3f9db953cb (patch)
treefabc6d883b0f946151f61ae7865cee9f529a1fdd /contrib/libs/clang16/tools/extra/clang-tidy/utils/TransformerClangTidyCheck.cpp
parent9685917341315774aad5733b1793b1e533a88bbb (diff)
downloadydb-11a895b7e15d1c5a1f52706396b82e3f9db953cb.tar.gz
Export clang-format16 via ydblib project
6e6be3a95868fde888d801b7590af4044049563f
Diffstat (limited to 'contrib/libs/clang16/tools/extra/clang-tidy/utils/TransformerClangTidyCheck.cpp')
-rw-r--r--contrib/libs/clang16/tools/extra/clang-tidy/utils/TransformerClangTidyCheck.cpp158
1 files changed, 158 insertions, 0 deletions
diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/utils/TransformerClangTidyCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/utils/TransformerClangTidyCheck.cpp
new file mode 100644
index 0000000000..dcdbcd36cb
--- /dev/null
+++ b/contrib/libs/clang16/tools/extra/clang-tidy/utils/TransformerClangTidyCheck.cpp
@@ -0,0 +1,158 @@
+//===---------- TransformerClangTidyCheck.cpp - clang-tidy ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TransformerClangTidyCheck.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/STLExtras.h"
+#include <optional>
+
+namespace clang::tidy::utils {
+using transformer::RewriteRuleWith;
+
+#ifndef NDEBUG
+static bool hasGenerator(const transformer::Generator<std::string> &G) {
+ return G != nullptr;
+}
+#endif
+
+static void verifyRule(const RewriteRuleWith<std::string> &Rule) {
+ assert(llvm::all_of(Rule.Metadata, hasGenerator) &&
+ "clang-tidy checks must have an explanation by default;"
+ " explicitly provide an empty explanation if none is desired");
+}
+
+// If a string unintentionally containing '%' is passed as a diagnostic, Clang
+// will claim the string is ill-formed and assert-fail. This function escapes
+// such strings so they can be safely used in diagnostics.
+std::string escapeForDiagnostic(std::string ToEscape) {
+ // Optimize for the common case that the string does not contain `%` at the
+ // cost of an extra scan over the string in the slow case.
+ auto Pos = ToEscape.find('%');
+ if (Pos == ToEscape.npos)
+ return ToEscape;
+
+ std::string Result;
+ Result.reserve(ToEscape.size());
+ // Convert position to a count.
+ ++Pos;
+ Result.append(ToEscape, 0, Pos);
+ Result += '%';
+
+ for (auto N = ToEscape.size(); Pos < N; ++Pos) {
+ const char C = ToEscape.at(Pos);
+ Result += C;
+ if (C == '%')
+ Result += '%';
+ }
+
+ return Result;
+}
+
+TransformerClangTidyCheck::TransformerClangTidyCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ Inserter(Options.getLocalOrGlobal("IncludeStyle", IncludeSorter::IS_LLVM),
+ areDiagsSelfContained()) {}
+
+// This constructor cannot dispatch to the simpler one (below), because, in
+// order to get meaningful results from `getLangOpts` and `Options`, we need the
+// `ClangTidyCheck()` constructor to have been called. If we were to dispatch,
+// we would be accessing `getLangOpts` and `Options` before the underlying
+// `ClangTidyCheck` instance was properly initialized.
+TransformerClangTidyCheck::TransformerClangTidyCheck(
+ std::function<std::optional<RewriteRuleWith<std::string>>(
+ const LangOptions &, const OptionsView &)>
+ MakeRule,
+ StringRef Name, ClangTidyContext *Context)
+ : TransformerClangTidyCheck(Name, Context) {
+ if (std::optional<RewriteRuleWith<std::string>> R =
+ MakeRule(getLangOpts(), Options))
+ setRule(std::move(*R));
+}
+
+TransformerClangTidyCheck::TransformerClangTidyCheck(
+ RewriteRuleWith<std::string> R, StringRef Name, ClangTidyContext *Context)
+ : TransformerClangTidyCheck(Name, Context) {
+ setRule(std::move(R));
+}
+
+void TransformerClangTidyCheck::setRule(
+ transformer::RewriteRuleWith<std::string> R) {
+ verifyRule(R);
+ Rule = std::move(R);
+}
+
+void TransformerClangTidyCheck::registerPPCallbacks(
+ const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
+ Inserter.registerPreprocessor(PP);
+}
+
+void TransformerClangTidyCheck::registerMatchers(
+ ast_matchers::MatchFinder *Finder) {
+ if (!Rule.Cases.empty())
+ for (auto &Matcher : transformer::detail::buildMatchers(Rule))
+ Finder->addDynamicMatcher(Matcher, this);
+}
+
+void TransformerClangTidyCheck::check(
+ const ast_matchers::MatchFinder::MatchResult &Result) {
+ if (Result.Context->getDiagnostics().hasErrorOccurred())
+ return;
+
+ size_t I = transformer::detail::findSelectedCase(Result, Rule);
+ Expected<SmallVector<transformer::Edit, 1>> Edits =
+ Rule.Cases[I].Edits(Result);
+ if (!Edits) {
+ llvm::errs() << "Rewrite failed: " << llvm::toString(Edits.takeError())
+ << "\n";
+ return;
+ }
+
+ // No rewrite applied, but no error encountered either.
+ if (Edits->empty())
+ return;
+
+ Expected<std::string> Explanation = Rule.Metadata[I]->eval(Result);
+ if (!Explanation) {
+ llvm::errs() << "Error in explanation: "
+ << llvm::toString(Explanation.takeError()) << "\n";
+ return;
+ }
+
+ // Associate the diagnostic with the location of the first change.
+ {
+ DiagnosticBuilder Diag =
+ diag((*Edits)[0].Range.getBegin(), escapeForDiagnostic(*Explanation));
+ for (const auto &T : *Edits) {
+ switch (T.Kind) {
+ case transformer::EditKind::Range:
+ Diag << FixItHint::CreateReplacement(T.Range, T.Replacement);
+ break;
+ case transformer::EditKind::AddInclude:
+ Diag << Inserter.createIncludeInsertion(
+ Result.SourceManager->getFileID(T.Range.getBegin()), T.Replacement);
+ break;
+ }
+ }
+ }
+ // Emit potential notes.
+ for (const auto &T : *Edits) {
+ if (!T.Note.empty()) {
+ diag(T.Range.getBegin(), escapeForDiagnostic(T.Note),
+ DiagnosticIDs::Note);
+ }
+ }
+}
+
+void TransformerClangTidyCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IncludeStyle", Inserter.getStyle());
+}
+
+} // namespace clang::tidy::utils