diff options
author | Yitzhak Mandelbaum <yitzhakm@google.com> | 2019-08-13 12:31:29 +0000 |
---|---|---|
committer | Yitzhak Mandelbaum <yitzhakm@google.com> | 2019-08-13 12:31:29 +0000 |
commit | 42b957aad7b293eef34ed5c2da7ebde4fab997c9 (patch) | |
tree | 087c94cd0c25bfd949e3b4c937252e9a8fdb3356 /clang/unittests/Tooling/TransformerTest.cpp | |
parent | 2515640aee7725c29104ec3a60dae345a3dbdb07 (diff) | |
download | llvm-42b957aad7b293eef34ed5c2da7ebde4fab997c9.zip llvm-42b957aad7b293eef34ed5c2da7ebde4fab997c9.tar.gz llvm-42b957aad7b293eef34ed5c2da7ebde4fab997c9.tar.bz2 |
[libTooling] In Transformer, generalize `applyFirst` to admit rules with incompatible matchers.
Summary:
This patch removes an (artificial) limitation of `applyFirst`, which requires
that all of the rules' matchers can be grouped together in a single `anyOf()`.
This change generalizes the code to group the matchers into separate `anyOf`s
based on compatibility. Correspondingly, `buildMatcher` is changed to
`buildMatchers`, to allow for returning a set of matchers rather than just one.
Reviewers: gribozavr
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D65877
llvm-svn: 368681
Diffstat (limited to 'clang/unittests/Tooling/TransformerTest.cpp')
-rw-r--r-- | clang/unittests/Tooling/TransformerTest.cpp | 126 |
1 files changed, 80 insertions, 46 deletions
diff --git a/clang/unittests/Tooling/TransformerTest.cpp b/clang/unittests/Tooling/TransformerTest.cpp index dcf77fe..554e586 100644 --- a/clang/unittests/Tooling/TransformerTest.cpp +++ b/clang/unittests/Tooling/TransformerTest.cpp @@ -482,65 +482,85 @@ TEST_F(TransformerTest, OrderedRuleUnrelated) { testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected); } -// Version of ruleStrlenSizeAny that inserts a method with a different name than -// ruleStrlenSize, so we can tell their effect apart. -RewriteRule ruleStrlenSizeDistinct() { - StringRef S; - return makeRule( - callExpr(callee(functionDecl(hasName("strlen"))), - hasArgument(0, cxxMemberCallExpr( - on(expr().bind(S)), - callee(cxxMethodDecl(hasName("c_str")))))), - change(text("DISTINCT"))); -} - TEST_F(TransformerTest, OrderedRuleRelated) { std::string Input = R"cc( - namespace foo { - struct mystring { - char* c_str(); - }; - int f(mystring s) { return strlen(s.c_str()); } - } // namespace foo - int g(string s) { return strlen(s.c_str()); } + void f1(); + void f2(); + void call_f1() { f1(); } + void call_f2() { f2(); } )cc"; std::string Expected = R"cc( - namespace foo { - struct mystring { - char* c_str(); - }; - int f(mystring s) { return DISTINCT; } - } // namespace foo - int g(string s) { return REPLACED; } + void f1(); + void f2(); + void call_f1() { REPLACE_F1; } + void call_f2() { REPLACE_F1_OR_F2; } )cc"; - testRule(applyFirst({ruleStrlenSize(), ruleStrlenSizeDistinct()}), Input, - Expected); + RewriteRule ReplaceF1 = + makeRule(callExpr(callee(functionDecl(hasName("f1")))), + change(text("REPLACE_F1"))); + RewriteRule ReplaceF1OrF2 = + makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), + change(text("REPLACE_F1_OR_F2"))); + testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected); } -// Change the order of the rules to get a different result. +// Change the order of the rules to get a different result. When `ReplaceF1OrF2` +// comes first, it applies for both uses, so `ReplaceF1` never applies. TEST_F(TransformerTest, OrderedRuleRelatedSwapped) { std::string Input = R"cc( - namespace foo { - struct mystring { - char* c_str(); - }; - int f(mystring s) { return strlen(s.c_str()); } - } // namespace foo - int g(string s) { return strlen(s.c_str()); } + void f1(); + void f2(); + void call_f1() { f1(); } + void call_f2() { f2(); } )cc"; std::string Expected = R"cc( - namespace foo { - struct mystring { - char* c_str(); - }; - int f(mystring s) { return DISTINCT; } - } // namespace foo - int g(string s) { return DISTINCT; } + void f1(); + void f2(); + void call_f1() { REPLACE_F1_OR_F2; } + void call_f2() { REPLACE_F1_OR_F2; } + )cc"; + + RewriteRule ReplaceF1 = + makeRule(callExpr(callee(functionDecl(hasName("f1")))), + change(text("REPLACE_F1"))); + RewriteRule ReplaceF1OrF2 = + makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), + change(text("REPLACE_F1_OR_F2"))); + testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected); +} + +// Verify that a set of rules whose matchers have different base kinds works +// properly, including that `applyFirst` produces multiple matchers. We test +// two different kinds of rules: Expr and Decl. We place the Decl rule in the +// middle to test that `buildMatchers` works even when the kinds aren't grouped +// together. +TEST_F(TransformerTest, OrderedRuleMultipleKinds) { + std::string Input = R"cc( + void f1(); + void f2(); + void call_f1() { f1(); } + void call_f2() { f2(); } )cc"; - - testRule(applyFirst({ruleStrlenSizeDistinct(), ruleStrlenSize()}), Input, - Expected); + std::string Expected = R"cc( + void f1(); + void DECL_RULE(); + void call_f1() { REPLACE_F1; } + void call_f2() { REPLACE_F1_OR_F2; } + )cc"; + + RewriteRule ReplaceF1 = + makeRule(callExpr(callee(functionDecl(hasName("f1")))), + change(text("REPLACE_F1"))); + RewriteRule ReplaceF1OrF2 = + makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), + change(text("REPLACE_F1_OR_F2"))); + RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"), + change(name("fun"), text("DECL_RULE"))); + + RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2}); + EXPECT_EQ(tooling::detail::buildMatchers(Rule).size(), 2UL); + testRule(Rule, Input, Expected); } // @@ -718,4 +738,18 @@ TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) { testRule(ruleStrlenSize(), Input, Input); } + +#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST +// Verifies that `Type` and `QualType` are not allowed as top-level matchers in +// rules. +TEST(TransformerDeathTest, OrderedRuleTypes) { + RewriteRule QualTypeRule = makeRule(qualType(), change(text("Q"))); + EXPECT_DEATH(tooling::detail::buildMatchers(QualTypeRule), + "Matcher must be.*node matcher"); + + RewriteRule TypeRule = makeRule(arrayType(), change(text("T"))); + EXPECT_DEATH(tooling::detail::buildMatchers(TypeRule), + "Matcher must be.*node matcher"); +} +#endif } // namespace |