diff options
author | Yitzhak Mandelbaum <yitzhakm@google.com> | 2019-07-18 17:44:54 +0000 |
---|---|---|
committer | Yitzhak Mandelbaum <yitzhakm@google.com> | 2019-07-18 17:44:54 +0000 |
commit | 3f1ab737e2199415c072fd6624a728949eb30342 (patch) | |
tree | be9e838e6419cb2aa74a70d382a25702fdadb80c /clang/unittests/Tooling/TransformerTest.cpp | |
parent | 3e93131dd292800fd9f56c93a81d85fb86e3116f (diff) | |
download | llvm-3f1ab737e2199415c072fd6624a728949eb30342.zip llvm-3f1ab737e2199415c072fd6624a728949eb30342.tar.gz llvm-3f1ab737e2199415c072fd6624a728949eb30342.tar.bz2 |
[LibTooling] Relax Transformer to allow rewriting macro expansions
Summary:
Currently, Transformer rejects any changes to source locations inside macro
expansions. This change relaxes that constraint to allow rewrites when the
entirety of the expansion is replaced, since that can be mapped to replacing the
entirety of the expansion range in the file source. This change makes
Transformer consistent with the handling of edit ranges in `clang::edit::Commit`
(which is used, for example, for applying `FixItHint`s from diagnostics).
Reviewers: ilya-biryukov
Subscribers: gribozavr, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64518
llvm-svn: 366473
Diffstat (limited to 'clang/unittests/Tooling/TransformerTest.cpp')
-rw-r--r-- | clang/unittests/Tooling/TransformerTest.cpp | 124 |
1 files changed, 102 insertions, 22 deletions
diff --git a/clang/unittests/Tooling/TransformerTest.cpp b/clang/unittests/Tooling/TransformerTest.cpp index 64f511b..dcf77fe 100644 --- a/clang/unittests/Tooling/TransformerTest.cpp +++ b/clang/unittests/Tooling/TransformerTest.cpp @@ -137,7 +137,7 @@ protected: TransformerTest() { appendToHeader(KHeaderContents); } }; -// Given string s, change strlen($s.c_str()) to $s.size(). +// Given string s, change strlen($s.c_str()) to REPLACED. static RewriteRule ruleStrlenSize() { StringRef StringExpr = "strexpr"; auto StringType = namedDecl(hasAnyName("::basic_string", "::string")); @@ -163,17 +163,6 @@ TEST_F(TransformerTest, NoMatch) { testRule(ruleStrlenSize(), Input, Input); } -// Tests that expressions in macro arguments are rewritten (when applicable). -TEST_F(TransformerTest, StrlenSizeMacro) { - std::string Input = R"cc( -#define ID(e) e - int f(string s) { return ID(strlen(s.c_str())); })cc"; - std::string Expected = R"cc( -#define ID(e) e - int f(string s) { return ID(REPLACED); })cc"; - testRule(ruleStrlenSize(), Input, Expected); -} - // Tests replacing an expression. TEST_F(TransformerTest, Flag) { StringRef Flag = "flag"; @@ -619,23 +608,114 @@ TEST_F(TransformerTest, ErrorOccurredMatchSkipped) { EXPECT_EQ(ErrorCount, 0); } -TEST_F(TransformerTest, NoTransformationInMacro) { +// Transformation of macro source text when the change encompasses the entirety +// of the expanded text. +TEST_F(TransformerTest, SimpleMacro) { + std::string Input = R"cc( +#define ZERO 0 + int f(string s) { return ZERO; } + )cc"; + std::string Expected = R"cc( +#define ZERO 0 + int f(string s) { return 999; } + )cc"; + + StringRef zero = "zero"; + RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), + change(node(zero), text("999"))); + testRule(R, Input, Expected); +} + +// Transformation of macro source text when the change encompasses the entirety +// of the expanded text, for the case of function-style macros. +TEST_F(TransformerTest, FunctionMacro) { std::string Input = R"cc( #define MACRO(str) strlen((str).c_str()) - int f(string s) { return MACRO(s); })cc"; - testRule(ruleStrlenSize(), Input, Input); + int f(string s) { return MACRO(s); } + )cc"; + std::string Expected = R"cc( +#define MACRO(str) strlen((str).c_str()) + int f(string s) { return REPLACED; } + )cc"; + + testRule(ruleStrlenSize(), Input, Expected); +} + +// Tests that expressions in macro arguments can be rewritten. +TEST_F(TransformerTest, MacroArg) { + std::string Input = R"cc( +#define PLUS(e) e + 1 + int f(string s) { return PLUS(strlen(s.c_str())); } + )cc"; + std::string Expected = R"cc( +#define PLUS(e) e + 1 + int f(string s) { return PLUS(REPLACED); } + )cc"; + + testRule(ruleStrlenSize(), Input, Expected); } -// This test handles the corner case where a macro called within another macro -// expands to matching code, but the matched code is an argument to the nested -// macro. A simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() -// will get this wrong, and transform the code. This test verifies that no such -// transformation occurs. -TEST_F(TransformerTest, NoTransformationInNestedMacro) { +// Tests that expressions in macro arguments can be rewritten, even when the +// macro call occurs inside another macro's definition. +TEST_F(TransformerTest, MacroArgInMacroDef) { std::string Input = R"cc( #define NESTED(e) e #define MACRO(str) NESTED(strlen((str).c_str())) - int f(string s) { return MACRO(s); })cc"; + int f(string s) { return MACRO(s); } + )cc"; + std::string Expected = R"cc( +#define NESTED(e) e +#define MACRO(str) NESTED(strlen((str).c_str())) + int f(string s) { return REPLACED; } + )cc"; + + testRule(ruleStrlenSize(), Input, Expected); +} + +// Tests the corner case of the identity macro, specifically that it is +// discarded in the rewrite rather than preserved (like PLUS is preserved in the +// previous test). This behavior is of dubious value (and marked with a FIXME +// in the code), but we test it to verify (and demonstrate) how this case is +// handled. +TEST_F(TransformerTest, IdentityMacro) { + std::string Input = R"cc( +#define ID(e) e + int f(string s) { return ID(strlen(s.c_str())); } + )cc"; + std::string Expected = R"cc( +#define ID(e) e + int f(string s) { return REPLACED; } + )cc"; + + testRule(ruleStrlenSize(), 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 +// suffice. +TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) { + std::string Input = R"cc( +#define ZERO_PLUS 0 + 3 + int f(string s) { return ZERO_PLUS; })cc"; + + StringRef zero = "zero"; + RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), + change(node(zero), text("0"))); + testRule(R, Input, Input); +} + +// This test handles the corner case where a macro expands within another macro +// to matching code, but that code is an argument to the nested macro call. A +// simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get +// this wrong, and transform the code. +TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) { + std::string Input = R"cc( +#define NESTED(e) e +#define MACRO(str) 1 + NESTED(strlen((str).c_str())) + int f(string s) { return MACRO(s); } + )cc"; + testRule(ruleStrlenSize(), Input, Input); } } // namespace |