From 6f8f5cb77efd100e5d4916db871b18c88cf49ed0 Mon Sep 17 00:00:00 2001 From: Yitzhak Mandelbaum Date: Thu, 22 Oct 2020 14:03:59 +0000 Subject: [PATCH] [libTooling] Add function to Transformer to create a no-op edit. This functionality is commonly needed in clang tidy checks (based on transformer) that only print warnings, without suggesting any edits. The no-op edit allows the user to associate a diagnostic message with a source location. Differential Revision: https://reviews.llvm.org/D89961 --- clang/include/clang/Tooling/Transformer/RewriteRule.h | 7 ++++++- clang/lib/Tooling/Transformer/RewriteRule.cpp | 18 ++++++++++++++++++ clang/unittests/Tooling/TransformerTest.cpp | 8 ++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Tooling/Transformer/RewriteRule.h b/clang/include/clang/Tooling/Transformer/RewriteRule.h index 4bdcc8d..13d0eda 100644 --- a/clang/include/clang/Tooling/Transformer/RewriteRule.h +++ b/clang/include/clang/Tooling/Transformer/RewriteRule.h @@ -107,7 +107,7 @@ struct ASTEdit { TextGenerator Replacement; TextGenerator Note; // Not all transformations will want or need to attach metadata and therefore - // should not be requierd to do so. + // should not be required to do so. AnyGenerator Metadata = [](const ast_matchers::MatchFinder::MatchResult &) -> llvm::Expected { return llvm::Expected(llvm::Any()); @@ -131,6 +131,11 @@ EditGenerator editList(llvm::SmallVector Edits); /// Generates no edits. inline EditGenerator noEdits() { return editList({}); } +/// Generates a single, no-op edit anchored at the start location of the +/// specified range. A `noopEdit` may be preferred over `noEdits` to associate a +/// diagnostic `Explanation` with the rule. +EditGenerator noopEdit(RangeSelector Anchor); + /// Version of `ifBound` specialized to `ASTEdit`. inline EditGenerator ifBound(std::string ID, ASTEdit TrueEdit, ASTEdit FalseEdit) { diff --git a/clang/lib/Tooling/Transformer/RewriteRule.cpp b/clang/lib/Tooling/Transformer/RewriteRule.cpp index 03921e0..e0467d2 100644 --- a/clang/lib/Tooling/Transformer/RewriteRule.cpp +++ b/clang/lib/Tooling/Transformer/RewriteRule.cpp @@ -73,6 +73,24 @@ EditGenerator transformer::edit(ASTEdit Edit) { }; } +EditGenerator transformer::noopEdit(RangeSelector Anchor) { + return [Anchor = std::move(Anchor)](const MatchResult &Result) + -> Expected> { + Expected Range = Anchor(Result); + if (!Range) + return Range.takeError(); + // In case the range is inside a macro expansion, map the location back to a + // "real" source location. + SourceLocation Begin = + Result.SourceManager->getSpellingLoc(Range->getBegin()); + Edit E; + // Implicitly, leave `E.Replacement` as the empty string. + E.Kind = EditKind::Range; + E.Range = CharSourceRange::getCharRange(Begin, Begin); + return SmallVector{E}; + }; +} + EditGenerator transformer::flattenVector(SmallVector Generators) { if (Generators.size() == 1) diff --git a/clang/unittests/Tooling/TransformerTest.cpp b/clang/unittests/Tooling/TransformerTest.cpp index a8d6d3d..ff735cd 100644 --- a/clang/unittests/Tooling/TransformerTest.cpp +++ b/clang/unittests/Tooling/TransformerTest.cpp @@ -426,6 +426,14 @@ TEST_F(TransformerTest, NoEdits) { testRule(makeRule(returnStmt().bind("return"), noEdits()), Input, Input); } +TEST_F(TransformerTest, NoopEdit) { + using transformer::node; + using transformer::noopEdit; + std::string Input = "int f(int x) { return x; }"; + testRule(makeRule(returnStmt().bind("return"), noopEdit(node("return"))), + Input, Input); +} + TEST_F(TransformerTest, IfBound2Args) { using transformer::ifBound; std::string Input = "int f(int x) { return x; }"; -- 2.7.4