From 03bc7eb123db247215352c11ffd8569ea2770d11 Mon Sep 17 00:00:00 2001 From: Yitzhak Mandelbaum Date: Fri, 27 Sep 2019 15:26:04 +0000 Subject: [libTooling] Transformer: refine `SourceLocation` specified as anchor of changes. Summary: Every change triggered by a rewrite rule is anchored at a particular location in the source code. This patch refines how that location is chosen and defines it as an explicit function so it can be shared by other Transformer implementations. This patch was inspired by a bug found by a clang tidy, wherein two changes were anchored at the same location (the expansion loc of the macro) resulting in the discarding of the second change. Reviewers: gribozavr Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D66652 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373093 91177308-0d34-0410-b5e6-96231b3b80d8 --- unittests/Tooling/TransformerTest.cpp | 51 +++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'unittests') diff --git a/unittests/Tooling/TransformerTest.cpp b/unittests/Tooling/TransformerTest.cpp index 554e586c3c..5d55182f82 100644 --- a/unittests/Tooling/TransformerTest.cpp +++ b/unittests/Tooling/TransformerTest.cpp @@ -710,6 +710,57 @@ TEST_F(TransformerTest, IdentityMacro) { testRule(ruleStrlenSize(), Input, Expected); } +// Tests that two changes in a single macro expansion do not lead to conflicts +// in applying the changes. +TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) { + std::string Input = R"cc( +#define PLUS(a,b) (a) + (b) + int f() { return PLUS(3, 4); } + )cc"; + std::string Expected = R"cc( +#define PLUS(a,b) (a) + (b) + int f() { return PLUS(LIT, LIT); } + )cc"; + + testRule(makeRule(integerLiteral(), change(text("LIT"))), Input, Expected); +} + +// Tests case where the rule's match spans both source from the macro and its +// arg, with the begin location (the "anchor") being the arg. +TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) { + std::string Input = R"cc( +#define PLUS_ONE(a) a + 1 + int f() { return PLUS_ONE(3); } + )cc"; + std::string Expected = R"cc( +#define PLUS_ONE(a) a + 1 + int f() { return PLUS_ONE(LIT); } + )cc"; + + StringRef E = "expr"; + testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))), + change(node(E), text("LIT"))), + Input, Expected); +} + +// Tests case where the rule's match spans both source from the macro and its +// arg, with the begin location (the "anchor") being inside the macro. +TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) { + std::string Input = R"cc( +#define PLUS_ONE(a) 1 + a + int f() { return PLUS_ONE(3); } + )cc"; + std::string Expected = R"cc( +#define PLUS_ONE(a) 1 + a + int f() { return PLUS_ONE(LIT); } + )cc"; + + StringRef E = "expr"; + testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))), + change(node(E), text("LIT"))), + Input, Expected); +} + // No rewrite is applied when the changed text does not encompass the entirety // of the expanded text. That is, the edit would have to be applied to the // macro's definition to succeed and editing the expansion point would not -- cgit v1.2.1