diff options
author | Yitzhak Mandelbaum <yitzhakm@google.com> | 2019-05-17 14:23:33 +0000 |
---|---|---|
committer | Yitzhak Mandelbaum <yitzhakm@google.com> | 2019-05-17 14:23:33 +0000 |
commit | 8369a9beb7edbcebc0a07dd8155ac6e17f12ad93 (patch) | |
tree | 8353045ef1bde3c3f6e0ff0b63df1158695c3658 /clang/unittests/Tooling/TransformerTest.cpp | |
parent | f3a3b93f5453e4e07d449c1ed733c9ac8cfb4b58 (diff) | |
download | llvm-8369a9beb7edbcebc0a07dd8155ac6e17f12ad93.zip llvm-8369a9beb7edbcebc0a07dd8155ac6e17f12ad93.tar.gz llvm-8369a9beb7edbcebc0a07dd8155ac6e17f12ad93.tar.bz2 |
[LibTooling] Add support to Transformer for composing rules as an ordered choice.
This revision updates `RewriteRule` to support multiple subrules that are
interpreted as an ordered-choice (apply the first one that matches). With this
feature, users can write the rules that appear later in the list of subrules
knowing that previous rules' patterns *have not matched*, freeing them from
reasoning about those cases in the current pattern.
Reviewers: ilya-biryukov
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D61335
llvm-svn: 361037
Diffstat (limited to 'clang/unittests/Tooling/TransformerTest.cpp')
-rw-r--r-- | clang/unittests/Tooling/TransformerTest.cpp | 91 |
1 files changed, 89 insertions, 2 deletions
diff --git a/clang/unittests/Tooling/TransformerTest.cpp b/clang/unittests/Tooling/TransformerTest.cpp index e07d9b7..7e8cd6e 100644 --- a/clang/unittests/Tooling/TransformerTest.cpp +++ b/clang/unittests/Tooling/TransformerTest.cpp @@ -116,7 +116,8 @@ protected: }; } - void testRule(RewriteRule Rule, StringRef Input, StringRef Expected) { + template <typename R> + void testRule(R Rule, StringRef Input, StringRef Expected) { Transformer T(std::move(Rule), consumer()); T.registerMatchers(&MatchFinder); compareSnippets(Expected, rewrite(Input)); @@ -147,7 +148,7 @@ static RewriteRule ruleStrlenSize() { .bind(StringExpr)), callee(cxxMethodDecl(hasName("c_str")))))), change<clang::Expr>("REPLACED")); - R.Explanation = text("Use size() method directly on string."); + R.Cases[0].Explanation = text("Use size() method directly on string."); return R; } @@ -375,6 +376,92 @@ TEST_F(TransformerTest, MultiChange) { Input, Expected); } +TEST_F(TransformerTest, OrderedRuleUnrelated) { + StringRef Flag = "flag"; + RewriteRule FlagRule = makeRule( + cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( + hasName("proto::ProtoCommandLineFlag")))) + .bind(Flag)), + unless(callee(cxxMethodDecl(hasName("GetProto"))))), + change<clang::Expr>(Flag, "PROTO")); + + std::string Input = R"cc( + proto::ProtoCommandLineFlag flag; + int x = flag.foo(); + int y = flag.GetProto().foo(); + int f(string s) { return strlen(s.c_str()); } + )cc"; + std::string Expected = R"cc( + proto::ProtoCommandLineFlag flag; + int x = PROTO.foo(); + int y = flag.GetProto().foo(); + int f(string s) { return REPLACED; } + )cc"; + + 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<clang::Expr>("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()); } + )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; } + )cc"; + + testRule(applyFirst({ruleStrlenSize(), ruleStrlenSizeDistinct()}), Input, + Expected); +} + +// Change the order of the rules to get a different result. +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()); } + )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; } + )cc"; + + testRule(applyFirst({ruleStrlenSizeDistinct(), ruleStrlenSize()}), Input, + Expected); +} + // // Negative tests (where we expect no transformation to occur). // |