1fdd98782SYitzhak Mandelbaum //===- unittest/Tooling/TransformerTest.cpp -------------------------------===// 2fdd98782SYitzhak Mandelbaum // 3fdd98782SYitzhak Mandelbaum // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fdd98782SYitzhak Mandelbaum // See https://llvm.org/LICENSE.txt for license information. 5fdd98782SYitzhak Mandelbaum // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fdd98782SYitzhak Mandelbaum // 7fdd98782SYitzhak Mandelbaum //===----------------------------------------------------------------------===// 8fdd98782SYitzhak Mandelbaum 9fbdf8352SYitzhak Mandelbaum #include "clang/Tooling/Transformer/Transformer.h" 10fdd98782SYitzhak Mandelbaum #include "clang/ASTMatchers/ASTMatchers.h" 11fdd98782SYitzhak Mandelbaum #include "clang/Tooling/Tooling.h" 126c683aa8SYitzhak Mandelbaum #include "clang/Tooling/Transformer/RangeSelector.h" 13cf428778SYitzhak Mandelbaum #include "clang/Tooling/Transformer/RewriteRule.h" 146c683aa8SYitzhak Mandelbaum #include "clang/Tooling/Transformer/Stencil.h" 15aecc59c5SYitzhak Mandelbaum #include "llvm/Support/Errc.h" 16aecc59c5SYitzhak Mandelbaum #include "llvm/Support/Error.h" 17fdd98782SYitzhak Mandelbaum #include "gmock/gmock.h" 18fdd98782SYitzhak Mandelbaum #include "gtest/gtest.h" 19fdd98782SYitzhak Mandelbaum 20fa1552e8SYitzhak Mandelbaum using namespace clang; 21fa1552e8SYitzhak Mandelbaum using namespace tooling; 22fa1552e8SYitzhak Mandelbaum using namespace ast_matchers; 23fdd98782SYitzhak Mandelbaum namespace { 24d8c1f43dSYitzhak Mandelbaum using ::testing::ElementsAre; 25aecc59c5SYitzhak Mandelbaum using ::testing::IsEmpty; 266c683aa8SYitzhak Mandelbaum using transformer::cat; 276c683aa8SYitzhak Mandelbaum using transformer::changeTo; 28d4f39031SYitzhak Mandelbaum using transformer::rewriteDescendants; 298bb47cd8SYitzhak Mandelbaum using transformer::RewriteRule; 30aecc59c5SYitzhak Mandelbaum 31fdd98782SYitzhak Mandelbaum constexpr char KHeaderContents[] = R"cc( 32fdd98782SYitzhak Mandelbaum struct string { 33fdd98782SYitzhak Mandelbaum string(const char*); 34fdd98782SYitzhak Mandelbaum char* c_str(); 35fdd98782SYitzhak Mandelbaum int size(); 36fdd98782SYitzhak Mandelbaum }; 37fdd98782SYitzhak Mandelbaum int strlen(const char*); 38fdd98782SYitzhak Mandelbaum 39fdd98782SYitzhak Mandelbaum namespace proto { 40fdd98782SYitzhak Mandelbaum struct PCFProto { 41fdd98782SYitzhak Mandelbaum int foo(); 42fdd98782SYitzhak Mandelbaum }; 43fdd98782SYitzhak Mandelbaum struct ProtoCommandLineFlag : PCFProto { 44fdd98782SYitzhak Mandelbaum PCFProto& GetProto(); 45fdd98782SYitzhak Mandelbaum }; 46fdd98782SYitzhak Mandelbaum } // namespace proto 47fa1552e8SYitzhak Mandelbaum class Logger {}; 48fa1552e8SYitzhak Mandelbaum void operator<<(Logger& l, string msg); 49fa1552e8SYitzhak Mandelbaum Logger& log(int level); 50fdd98782SYitzhak Mandelbaum )cc"; 51fdd98782SYitzhak Mandelbaum 52fdd98782SYitzhak Mandelbaum static ast_matchers::internal::Matcher<clang::QualType> 53fdd98782SYitzhak Mandelbaum isOrPointsTo(const clang::ast_matchers::DeclarationMatcher &TypeMatcher) { 54fdd98782SYitzhak Mandelbaum return anyOf(hasDeclaration(TypeMatcher), pointsTo(TypeMatcher)); 55fdd98782SYitzhak Mandelbaum } 56fdd98782SYitzhak Mandelbaum 57fdd98782SYitzhak Mandelbaum static std::string format(StringRef Code) { 58fdd98782SYitzhak Mandelbaum const std::vector<Range> Ranges(1, Range(0, Code.size())); 59fdd98782SYitzhak Mandelbaum auto Style = format::getLLVMStyle(); 60fdd98782SYitzhak Mandelbaum const auto Replacements = format::reformat(Style, Code, Ranges); 61fdd98782SYitzhak Mandelbaum auto Formatted = applyAllReplacements(Code, Replacements); 62fdd98782SYitzhak Mandelbaum if (!Formatted) { 63fdd98782SYitzhak Mandelbaum ADD_FAILURE() << "Could not format code: " 64fdd98782SYitzhak Mandelbaum << llvm::toString(Formatted.takeError()); 65fdd98782SYitzhak Mandelbaum return std::string(); 66fdd98782SYitzhak Mandelbaum } 67fdd98782SYitzhak Mandelbaum return *Formatted; 68fdd98782SYitzhak Mandelbaum } 69fdd98782SYitzhak Mandelbaum 70fdd98782SYitzhak Mandelbaum static void compareSnippets(StringRef Expected, 71fdd98782SYitzhak Mandelbaum const llvm::Optional<std::string> &MaybeActual) { 72fdd98782SYitzhak Mandelbaum ASSERT_TRUE(MaybeActual) << "Rewrite failed. Expecting: " << Expected; 73fdd98782SYitzhak Mandelbaum auto Actual = *MaybeActual; 74fdd98782SYitzhak Mandelbaum std::string HL = "#include \"header.h\"\n"; 75fdd98782SYitzhak Mandelbaum auto I = Actual.find(HL); 76fdd98782SYitzhak Mandelbaum if (I != std::string::npos) 77fdd98782SYitzhak Mandelbaum Actual.erase(I, HL.size()); 78fdd98782SYitzhak Mandelbaum EXPECT_EQ(format(Expected), format(Actual)); 79fdd98782SYitzhak Mandelbaum } 80fdd98782SYitzhak Mandelbaum 81fdd98782SYitzhak Mandelbaum // FIXME: consider separating this class into its own file(s). 82fdd98782SYitzhak Mandelbaum class ClangRefactoringTestBase : public testing::Test { 83fdd98782SYitzhak Mandelbaum protected: 84fdd98782SYitzhak Mandelbaum void appendToHeader(StringRef S) { FileContents[0].second += S; } 85fdd98782SYitzhak Mandelbaum 86fdd98782SYitzhak Mandelbaum void addFile(StringRef Filename, StringRef Content) { 87757bdc64SBenjamin Kramer FileContents.emplace_back(std::string(Filename), std::string(Content)); 88fdd98782SYitzhak Mandelbaum } 89fdd98782SYitzhak Mandelbaum 90fdd98782SYitzhak Mandelbaum llvm::Optional<std::string> rewrite(StringRef Input) { 91fdd98782SYitzhak Mandelbaum std::string Code = ("#include \"header.h\"\n" + Input).str(); 92fdd98782SYitzhak Mandelbaum auto Factory = newFrontendActionFactory(&MatchFinder); 93fdd98782SYitzhak Mandelbaum if (!runToolOnCodeWithArgs( 94fdd98782SYitzhak Mandelbaum Factory->create(), Code, std::vector<std::string>(), "input.cc", 95fdd98782SYitzhak Mandelbaum "clang-tool", std::make_shared<PCHContainerOperations>(), 96fdd98782SYitzhak Mandelbaum FileContents)) { 97aecc59c5SYitzhak Mandelbaum llvm::errs() << "Running tool failed.\n"; 98fdd98782SYitzhak Mandelbaum return None; 99fdd98782SYitzhak Mandelbaum } 100aecc59c5SYitzhak Mandelbaum if (ErrorCount != 0) { 101aecc59c5SYitzhak Mandelbaum llvm::errs() << "Generating changes failed.\n"; 102aecc59c5SYitzhak Mandelbaum return None; 103aecc59c5SYitzhak Mandelbaum } 104aecc59c5SYitzhak Mandelbaum auto ChangedCode = 105fdd98782SYitzhak Mandelbaum applyAtomicChanges("input.cc", Code, Changes, ApplyChangesSpec()); 106aecc59c5SYitzhak Mandelbaum if (!ChangedCode) { 107aecc59c5SYitzhak Mandelbaum llvm::errs() << "Applying changes failed: " 108aecc59c5SYitzhak Mandelbaum << llvm::toString(ChangedCode.takeError()) << "\n"; 109fdd98782SYitzhak Mandelbaum return None; 110fdd98782SYitzhak Mandelbaum } 111aecc59c5SYitzhak Mandelbaum return *ChangedCode; 112aecc59c5SYitzhak Mandelbaum } 113aecc59c5SYitzhak Mandelbaum 114aecc59c5SYitzhak Mandelbaum Transformer::ChangeConsumer consumer() { 115aecc59c5SYitzhak Mandelbaum return [this](Expected<AtomicChange> C) { 116aecc59c5SYitzhak Mandelbaum if (C) { 117aecc59c5SYitzhak Mandelbaum Changes.push_back(std::move(*C)); 118aecc59c5SYitzhak Mandelbaum } else { 119c332a984SYitzhak Mandelbaum // FIXME: stash this error rather then printing. 120c332a984SYitzhak Mandelbaum llvm::errs() << "Error generating changes: " 121c332a984SYitzhak Mandelbaum << llvm::toString(C.takeError()) << "\n"; 122aecc59c5SYitzhak Mandelbaum ++ErrorCount; 123aecc59c5SYitzhak Mandelbaum } 124aecc59c5SYitzhak Mandelbaum }; 125fdd98782SYitzhak Mandelbaum } 126fdd98782SYitzhak Mandelbaum 1278369a9beSYitzhak Mandelbaum template <typename R> 1288369a9beSYitzhak Mandelbaum void testRule(R Rule, StringRef Input, StringRef Expected) { 129*96ed6793SFangrui Song Transformers.push_back( 130*96ed6793SFangrui Song std::make_unique<Transformer>(std::move(Rule), consumer())); 131*96ed6793SFangrui Song Transformers.back()->registerMatchers(&MatchFinder); 132fdd98782SYitzhak Mandelbaum compareSnippets(Expected, rewrite(Input)); 133fdd98782SYitzhak Mandelbaum } 134fdd98782SYitzhak Mandelbaum 135*96ed6793SFangrui Song // Transformers are referenced by MatchFinder. 136*96ed6793SFangrui Song std::vector<std::unique_ptr<Transformer>> Transformers; 137fdd98782SYitzhak Mandelbaum clang::ast_matchers::MatchFinder MatchFinder; 138aecc59c5SYitzhak Mandelbaum // Records whether any errors occurred in individual changes. 139aecc59c5SYitzhak Mandelbaum int ErrorCount = 0; 140fdd98782SYitzhak Mandelbaum AtomicChanges Changes; 141fdd98782SYitzhak Mandelbaum 142fdd98782SYitzhak Mandelbaum private: 143fdd98782SYitzhak Mandelbaum FileContentMappings FileContents = {{"header.h", ""}}; 144fdd98782SYitzhak Mandelbaum }; 145fdd98782SYitzhak Mandelbaum 146fdd98782SYitzhak Mandelbaum class TransformerTest : public ClangRefactoringTestBase { 147fdd98782SYitzhak Mandelbaum protected: 148fdd98782SYitzhak Mandelbaum TransformerTest() { appendToHeader(KHeaderContents); } 149fdd98782SYitzhak Mandelbaum }; 150fdd98782SYitzhak Mandelbaum 1513f1ab737SYitzhak Mandelbaum // Given string s, change strlen($s.c_str()) to REPLACED. 152fdd98782SYitzhak Mandelbaum static RewriteRule ruleStrlenSize() { 153fdd98782SYitzhak Mandelbaum StringRef StringExpr = "strexpr"; 154fdd98782SYitzhak Mandelbaum auto StringType = namedDecl(hasAnyName("::basic_string", "::string")); 155fa1552e8SYitzhak Mandelbaum auto R = makeRule( 156fa1552e8SYitzhak Mandelbaum callExpr(callee(functionDecl(hasName("strlen"))), 157fdd98782SYitzhak Mandelbaum hasArgument(0, cxxMemberCallExpr( 158fdd98782SYitzhak Mandelbaum on(expr(hasType(isOrPointsTo(StringType))) 159fdd98782SYitzhak Mandelbaum .bind(StringExpr)), 160fa1552e8SYitzhak Mandelbaum callee(cxxMethodDecl(hasName("c_str")))))), 1619f97480cSYitzhak Mandelbaum changeTo(cat("REPLACED")), cat("Use size() method directly on string.")); 162fa1552e8SYitzhak Mandelbaum return R; 163fdd98782SYitzhak Mandelbaum } 164fdd98782SYitzhak Mandelbaum 165fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, StrlenSize) { 166fdd98782SYitzhak Mandelbaum std::string Input = "int f(string s) { return strlen(s.c_str()); }"; 167fdd98782SYitzhak Mandelbaum std::string Expected = "int f(string s) { return REPLACED; }"; 168fdd98782SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Expected); 169fdd98782SYitzhak Mandelbaum } 170fdd98782SYitzhak Mandelbaum 171fdd98782SYitzhak Mandelbaum // Tests that no change is applied when a match is not expected. 172fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NoMatch) { 173fdd98782SYitzhak Mandelbaum std::string Input = "int f(string s) { return s.size(); }"; 174fdd98782SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Input); 175fdd98782SYitzhak Mandelbaum } 176fdd98782SYitzhak Mandelbaum 177fdd98782SYitzhak Mandelbaum // Tests replacing an expression. 178fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, Flag) { 179fdd98782SYitzhak Mandelbaum StringRef Flag = "flag"; 180fa1552e8SYitzhak Mandelbaum RewriteRule Rule = makeRule( 181fa1552e8SYitzhak Mandelbaum cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( 182fa1552e8SYitzhak Mandelbaum hasName("proto::ProtoCommandLineFlag")))) 183fdd98782SYitzhak Mandelbaum .bind(Flag)), 184fa1552e8SYitzhak Mandelbaum unless(callee(cxxMethodDecl(hasName("GetProto"))))), 185adcd0268SBenjamin Kramer changeTo(node(std::string(Flag)), cat("EXPR"))); 186fdd98782SYitzhak Mandelbaum 187fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 188fdd98782SYitzhak Mandelbaum proto::ProtoCommandLineFlag flag; 189fdd98782SYitzhak Mandelbaum int x = flag.foo(); 190fdd98782SYitzhak Mandelbaum int y = flag.GetProto().foo(); 191fdd98782SYitzhak Mandelbaum )cc"; 192fdd98782SYitzhak Mandelbaum std::string Expected = R"cc( 193fdd98782SYitzhak Mandelbaum proto::ProtoCommandLineFlag flag; 194fdd98782SYitzhak Mandelbaum int x = EXPR.foo(); 195fdd98782SYitzhak Mandelbaum int y = flag.GetProto().foo(); 196fdd98782SYitzhak Mandelbaum )cc"; 197fdd98782SYitzhak Mandelbaum 198fdd98782SYitzhak Mandelbaum testRule(std::move(Rule), Input, Expected); 199fdd98782SYitzhak Mandelbaum } 200fdd98782SYitzhak Mandelbaum 201727bdcb2SYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeQuoted) { 202d8c1f43dSYitzhak Mandelbaum RewriteRule Rule = 203d8c1f43dSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasName("f")))), 204d8c1f43dSYitzhak Mandelbaum {addInclude("clang/OtherLib.h"), changeTo(cat("other()"))}); 205d8c1f43dSYitzhak Mandelbaum 206d8c1f43dSYitzhak Mandelbaum std::string Input = R"cc( 207d8c1f43dSYitzhak Mandelbaum int f(int x); 208d8c1f43dSYitzhak Mandelbaum int h(int x) { return f(x); } 209d8c1f43dSYitzhak Mandelbaum )cc"; 210d8c1f43dSYitzhak Mandelbaum std::string Expected = R"cc(#include "clang/OtherLib.h" 211d8c1f43dSYitzhak Mandelbaum 212d8c1f43dSYitzhak Mandelbaum int f(int x); 213d8c1f43dSYitzhak Mandelbaum int h(int x) { return other(); } 214d8c1f43dSYitzhak Mandelbaum )cc"; 215d8c1f43dSYitzhak Mandelbaum 216d8c1f43dSYitzhak Mandelbaum testRule(Rule, Input, Expected); 217d8c1f43dSYitzhak Mandelbaum } 218d8c1f43dSYitzhak Mandelbaum 219d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeAngled) { 220d8c1f43dSYitzhak Mandelbaum RewriteRule Rule = makeRule( 221d8c1f43dSYitzhak Mandelbaum callExpr(callee(functionDecl(hasName("f")))), 222d8c1f43dSYitzhak Mandelbaum {addInclude("clang/OtherLib.h", transformer::IncludeFormat::Angled), 223d8c1f43dSYitzhak Mandelbaum changeTo(cat("other()"))}); 224d8c1f43dSYitzhak Mandelbaum 225d8c1f43dSYitzhak Mandelbaum std::string Input = R"cc( 226d8c1f43dSYitzhak Mandelbaum int f(int x); 227d8c1f43dSYitzhak Mandelbaum int h(int x) { return f(x); } 228d8c1f43dSYitzhak Mandelbaum )cc"; 229d8c1f43dSYitzhak Mandelbaum std::string Expected = R"cc(#include <clang/OtherLib.h> 230d8c1f43dSYitzhak Mandelbaum 231d8c1f43dSYitzhak Mandelbaum int f(int x); 232d8c1f43dSYitzhak Mandelbaum int h(int x) { return other(); } 233d8c1f43dSYitzhak Mandelbaum )cc"; 234d8c1f43dSYitzhak Mandelbaum 235d8c1f43dSYitzhak Mandelbaum testRule(Rule, Input, Expected); 236d8c1f43dSYitzhak Mandelbaum } 237d8c1f43dSYitzhak Mandelbaum 238d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeQuotedForRule) { 239727bdcb2SYitzhak Mandelbaum RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))), 2409f97480cSYitzhak Mandelbaum changeTo(cat("other()"))); 241727bdcb2SYitzhak Mandelbaum addInclude(Rule, "clang/OtherLib.h"); 242727bdcb2SYitzhak Mandelbaum 243727bdcb2SYitzhak Mandelbaum std::string Input = R"cc( 244727bdcb2SYitzhak Mandelbaum int f(int x); 245727bdcb2SYitzhak Mandelbaum int h(int x) { return f(x); } 246727bdcb2SYitzhak Mandelbaum )cc"; 247727bdcb2SYitzhak Mandelbaum std::string Expected = R"cc(#include "clang/OtherLib.h" 248727bdcb2SYitzhak Mandelbaum 249727bdcb2SYitzhak Mandelbaum int f(int x); 250727bdcb2SYitzhak Mandelbaum int h(int x) { return other(); } 251727bdcb2SYitzhak Mandelbaum )cc"; 252727bdcb2SYitzhak Mandelbaum 253727bdcb2SYitzhak Mandelbaum testRule(Rule, Input, Expected); 254727bdcb2SYitzhak Mandelbaum } 255727bdcb2SYitzhak Mandelbaum 256d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeAngledForRule) { 257727bdcb2SYitzhak Mandelbaum RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))), 2589f97480cSYitzhak Mandelbaum changeTo(cat("other()"))); 2598bb47cd8SYitzhak Mandelbaum addInclude(Rule, "clang/OtherLib.h", transformer::IncludeFormat::Angled); 260727bdcb2SYitzhak Mandelbaum 261727bdcb2SYitzhak Mandelbaum std::string Input = R"cc( 262727bdcb2SYitzhak Mandelbaum int f(int x); 263727bdcb2SYitzhak Mandelbaum int h(int x) { return f(x); } 264727bdcb2SYitzhak Mandelbaum )cc"; 265727bdcb2SYitzhak Mandelbaum std::string Expected = R"cc(#include <clang/OtherLib.h> 266727bdcb2SYitzhak Mandelbaum 267727bdcb2SYitzhak Mandelbaum int f(int x); 268727bdcb2SYitzhak Mandelbaum int h(int x) { return other(); } 269727bdcb2SYitzhak Mandelbaum )cc"; 270727bdcb2SYitzhak Mandelbaum 271727bdcb2SYitzhak Mandelbaum testRule(Rule, Input, Expected); 272727bdcb2SYitzhak Mandelbaum } 273727bdcb2SYitzhak Mandelbaum 274fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameNamedDecl) { 275fdd98782SYitzhak Mandelbaum StringRef Fun = "fun"; 2763ec50e29SYitzhak Mandelbaum RewriteRule Rule = makeRule(functionDecl(hasName("bad")).bind(Fun), 277adcd0268SBenjamin Kramer changeTo(name(std::string(Fun)), cat("good"))); 278fdd98782SYitzhak Mandelbaum 279fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 280fdd98782SYitzhak Mandelbaum int bad(int x); 281fdd98782SYitzhak Mandelbaum int bad(int x) { return x * x; } 282fdd98782SYitzhak Mandelbaum )cc"; 283fdd98782SYitzhak Mandelbaum std::string Expected = R"cc( 284fdd98782SYitzhak Mandelbaum int good(int x); 285fdd98782SYitzhak Mandelbaum int good(int x) { return x * x; } 286fdd98782SYitzhak Mandelbaum )cc"; 287fdd98782SYitzhak Mandelbaum 288fdd98782SYitzhak Mandelbaum testRule(Rule, Input, Expected); 289fdd98782SYitzhak Mandelbaum } 290fdd98782SYitzhak Mandelbaum 291fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameDeclRef) { 292fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 293fdd98782SYitzhak Mandelbaum template <typename T> 294fdd98782SYitzhak Mandelbaum T bad(T x) { 295fdd98782SYitzhak Mandelbaum return x; 296fdd98782SYitzhak Mandelbaum } 297fdd98782SYitzhak Mandelbaum int neutral(int x) { return bad<int>(x) * x; } 298fdd98782SYitzhak Mandelbaum )cc"; 299fdd98782SYitzhak Mandelbaum std::string Expected = R"cc( 300fdd98782SYitzhak Mandelbaum template <typename T> 301fdd98782SYitzhak Mandelbaum T bad(T x) { 302fdd98782SYitzhak Mandelbaum return x; 303fdd98782SYitzhak Mandelbaum } 304fdd98782SYitzhak Mandelbaum int neutral(int x) { return good<int>(x) * x; } 305fdd98782SYitzhak Mandelbaum )cc"; 306fdd98782SYitzhak Mandelbaum 307fdd98782SYitzhak Mandelbaum StringRef Ref = "ref"; 308fa1552e8SYitzhak Mandelbaum testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref), 309adcd0268SBenjamin Kramer changeTo(name(std::string(Ref)), cat("good"))), 310fdd98782SYitzhak Mandelbaum Input, Expected); 311fdd98782SYitzhak Mandelbaum } 312fdd98782SYitzhak Mandelbaum 313fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameDeclRefFailure) { 314fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 315fdd98782SYitzhak Mandelbaum struct Y { 316fdd98782SYitzhak Mandelbaum int operator*(); 317fdd98782SYitzhak Mandelbaum }; 318fdd98782SYitzhak Mandelbaum int neutral(int x) { 319fdd98782SYitzhak Mandelbaum Y y; 320fdd98782SYitzhak Mandelbaum int (Y::*ptr)() = &Y::operator*; 321fdd98782SYitzhak Mandelbaum return *y + x; 322fdd98782SYitzhak Mandelbaum } 323fdd98782SYitzhak Mandelbaum )cc"; 324fdd98782SYitzhak Mandelbaum 325fdd98782SYitzhak Mandelbaum StringRef Ref = "ref"; 326a5dadbe1SYitzhak Mandelbaum Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref), 327adcd0268SBenjamin Kramer changeTo(name(std::string(Ref)), cat("good"))), 328a5dadbe1SYitzhak Mandelbaum consumer()); 329a5dadbe1SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 330a5dadbe1SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 331fdd98782SYitzhak Mandelbaum } 332fdd98782SYitzhak Mandelbaum 333fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMember) { 334fdd98782SYitzhak Mandelbaum StringRef E = "expr"; 335fa1552e8SYitzhak Mandelbaum RewriteRule Rule = makeRule(memberExpr(member(hasName("bad"))).bind(E), 336adcd0268SBenjamin Kramer changeTo(member(std::string(E)), cat("good"))); 337fdd98782SYitzhak Mandelbaum 338fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 339fdd98782SYitzhak Mandelbaum struct S { 340fdd98782SYitzhak Mandelbaum int bad; 341fdd98782SYitzhak Mandelbaum }; 342fdd98782SYitzhak Mandelbaum int g() { 343fdd98782SYitzhak Mandelbaum S s; 344fdd98782SYitzhak Mandelbaum return s.bad; 345fdd98782SYitzhak Mandelbaum } 346fdd98782SYitzhak Mandelbaum )cc"; 347fdd98782SYitzhak Mandelbaum std::string Expected = R"cc( 348fdd98782SYitzhak Mandelbaum struct S { 349fdd98782SYitzhak Mandelbaum int bad; 350fdd98782SYitzhak Mandelbaum }; 351fdd98782SYitzhak Mandelbaum int g() { 352fdd98782SYitzhak Mandelbaum S s; 353fdd98782SYitzhak Mandelbaum return s.good; 354fdd98782SYitzhak Mandelbaum } 355fdd98782SYitzhak Mandelbaum )cc"; 356fdd98782SYitzhak Mandelbaum 357fdd98782SYitzhak Mandelbaum testRule(Rule, Input, Expected); 358fdd98782SYitzhak Mandelbaum } 359fdd98782SYitzhak Mandelbaum 360fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMemberQualified) { 361fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 362fdd98782SYitzhak Mandelbaum struct S { 363fdd98782SYitzhak Mandelbaum int bad; 364fdd98782SYitzhak Mandelbaum int good; 365fdd98782SYitzhak Mandelbaum }; 366fdd98782SYitzhak Mandelbaum struct T : public S { 367fdd98782SYitzhak Mandelbaum int bad; 368fdd98782SYitzhak Mandelbaum }; 369fdd98782SYitzhak Mandelbaum int g() { 370fdd98782SYitzhak Mandelbaum T t; 371fdd98782SYitzhak Mandelbaum return t.S::bad; 372fdd98782SYitzhak Mandelbaum } 373fdd98782SYitzhak Mandelbaum )cc"; 374fdd98782SYitzhak Mandelbaum std::string Expected = R"cc( 375fdd98782SYitzhak Mandelbaum struct S { 376fdd98782SYitzhak Mandelbaum int bad; 377fdd98782SYitzhak Mandelbaum int good; 378fdd98782SYitzhak Mandelbaum }; 379fdd98782SYitzhak Mandelbaum struct T : public S { 380fdd98782SYitzhak Mandelbaum int bad; 381fdd98782SYitzhak Mandelbaum }; 382fdd98782SYitzhak Mandelbaum int g() { 383fdd98782SYitzhak Mandelbaum T t; 384fdd98782SYitzhak Mandelbaum return t.S::good; 385fdd98782SYitzhak Mandelbaum } 386fdd98782SYitzhak Mandelbaum )cc"; 387fdd98782SYitzhak Mandelbaum 388fdd98782SYitzhak Mandelbaum StringRef E = "expr"; 389adcd0268SBenjamin Kramer testRule(makeRule(memberExpr().bind(E), 390adcd0268SBenjamin Kramer changeTo(member(std::string(E)), cat("good"))), 391fdd98782SYitzhak Mandelbaum Input, Expected); 392fdd98782SYitzhak Mandelbaum } 393fdd98782SYitzhak Mandelbaum 394fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMemberMultiToken) { 395fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 396fdd98782SYitzhak Mandelbaum struct Y { 397fdd98782SYitzhak Mandelbaum int operator*(); 398fdd98782SYitzhak Mandelbaum int good(); 399fdd98782SYitzhak Mandelbaum template <typename T> void foo(T t); 400fdd98782SYitzhak Mandelbaum }; 401fdd98782SYitzhak Mandelbaum int neutral(int x) { 402fdd98782SYitzhak Mandelbaum Y y; 403fdd98782SYitzhak Mandelbaum y.template foo<int>(3); 404fdd98782SYitzhak Mandelbaum return y.operator *(); 405fdd98782SYitzhak Mandelbaum } 406fdd98782SYitzhak Mandelbaum )cc"; 407fdd98782SYitzhak Mandelbaum std::string Expected = R"cc( 408fdd98782SYitzhak Mandelbaum struct Y { 409fdd98782SYitzhak Mandelbaum int operator*(); 410fdd98782SYitzhak Mandelbaum int good(); 411fdd98782SYitzhak Mandelbaum template <typename T> void foo(T t); 412fdd98782SYitzhak Mandelbaum }; 413fdd98782SYitzhak Mandelbaum int neutral(int x) { 414fdd98782SYitzhak Mandelbaum Y y; 415fdd98782SYitzhak Mandelbaum y.template good<int>(3); 416fdd98782SYitzhak Mandelbaum return y.good(); 417fdd98782SYitzhak Mandelbaum } 418fdd98782SYitzhak Mandelbaum )cc"; 419fdd98782SYitzhak Mandelbaum 420fdd98782SYitzhak Mandelbaum StringRef MemExpr = "member"; 421fa1552e8SYitzhak Mandelbaum testRule(makeRule(memberExpr().bind(MemExpr), 422adcd0268SBenjamin Kramer changeTo(member(std::string(MemExpr)), cat("good"))), 423fa1552e8SYitzhak Mandelbaum Input, Expected); 424fa1552e8SYitzhak Mandelbaum } 425fa1552e8SYitzhak Mandelbaum 426cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, NoEdits) { 427cf428778SYitzhak Mandelbaum using transformer::noEdits; 428cf428778SYitzhak Mandelbaum std::string Input = "int f(int x) { return x; }"; 429cf428778SYitzhak Mandelbaum testRule(makeRule(returnStmt().bind("return"), noEdits()), Input, Input); 430cf428778SYitzhak Mandelbaum } 431cf428778SYitzhak Mandelbaum 4326f8f5cb7SYitzhak Mandelbaum TEST_F(TransformerTest, NoopEdit) { 4336f8f5cb7SYitzhak Mandelbaum using transformer::node; 4346f8f5cb7SYitzhak Mandelbaum using transformer::noopEdit; 4356f8f5cb7SYitzhak Mandelbaum std::string Input = "int f(int x) { return x; }"; 4366f8f5cb7SYitzhak Mandelbaum testRule(makeRule(returnStmt().bind("return"), noopEdit(node("return"))), 4376f8f5cb7SYitzhak Mandelbaum Input, Input); 4386f8f5cb7SYitzhak Mandelbaum } 4396f8f5cb7SYitzhak Mandelbaum 440cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, IfBound2Args) { 441cf428778SYitzhak Mandelbaum using transformer::ifBound; 442cf428778SYitzhak Mandelbaum std::string Input = "int f(int x) { return x; }"; 443cf428778SYitzhak Mandelbaum std::string Expected = "int f(int x) { CHANGE; }"; 444cf428778SYitzhak Mandelbaum testRule(makeRule(returnStmt().bind("return"), 445cf428778SYitzhak Mandelbaum ifBound("return", changeTo(cat("CHANGE;")))), 446cf428778SYitzhak Mandelbaum Input, Expected); 447cf428778SYitzhak Mandelbaum } 448cf428778SYitzhak Mandelbaum 449cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, IfBound3Args) { 450cf428778SYitzhak Mandelbaum using transformer::ifBound; 451cf428778SYitzhak Mandelbaum std::string Input = "int f(int x) { return x; }"; 452cf428778SYitzhak Mandelbaum std::string Expected = "int f(int x) { CHANGE; }"; 453cf428778SYitzhak Mandelbaum testRule(makeRule(returnStmt().bind("return"), 454cf428778SYitzhak Mandelbaum ifBound("nothing", changeTo(cat("ERROR")), 455cf428778SYitzhak Mandelbaum changeTo(cat("CHANGE;")))), 456cf428778SYitzhak Mandelbaum Input, Expected); 457cf428778SYitzhak Mandelbaum } 458cf428778SYitzhak Mandelbaum 459cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, ShrinkTo) { 460cf428778SYitzhak Mandelbaum using transformer::shrinkTo; 461cf428778SYitzhak Mandelbaum std::string Input = "int f(int x) { return x; }"; 462cf428778SYitzhak Mandelbaum std::string Expected = "return x;"; 463cf428778SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasDescendant(returnStmt().bind("return"))) 464cf428778SYitzhak Mandelbaum .bind("function"), 465cf428778SYitzhak Mandelbaum shrinkTo(node("function"), node("return"))), 466cf428778SYitzhak Mandelbaum Input, Expected); 467cf428778SYitzhak Mandelbaum } 468cf428778SYitzhak Mandelbaum 469c332a984SYitzhak Mandelbaum // Rewrite various Stmts inside a Decl. 470c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsDeclChangeStmt) { 471c332a984SYitzhak Mandelbaum std::string Input = 472c332a984SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 473c332a984SYitzhak Mandelbaum std::string Expected = 474c332a984SYitzhak Mandelbaum "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 475c332a984SYitzhak Mandelbaum auto InlineX = 476c332a984SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 477c332a984SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasName("f")).bind("fun"), 478c332a984SYitzhak Mandelbaum rewriteDescendants("fun", InlineX)), 479c332a984SYitzhak Mandelbaum Input, Expected); 480c332a984SYitzhak Mandelbaum } 481c332a984SYitzhak Mandelbaum 482c332a984SYitzhak Mandelbaum // Rewrite various TypeLocs inside a Decl. 483c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsDeclChangeTypeLoc) { 484c332a984SYitzhak Mandelbaum std::string Input = "int f(int *x) { return *x; }"; 485c332a984SYitzhak Mandelbaum std::string Expected = "char f(char *x) { return *x; }"; 486c332a984SYitzhak Mandelbaum auto IntToChar = makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))), 487c332a984SYitzhak Mandelbaum changeTo(cat("char"))); 488c332a984SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasName("f")).bind("fun"), 489c332a984SYitzhak Mandelbaum rewriteDescendants("fun", IntToChar)), 490c332a984SYitzhak Mandelbaum Input, Expected); 491c332a984SYitzhak Mandelbaum } 492c332a984SYitzhak Mandelbaum 493c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsStmt) { 494c332a984SYitzhak Mandelbaum // Add an unrelated definition to the header that also has a variable named 495c332a984SYitzhak Mandelbaum // "x", to test that the rewrite is limited to the scope we intend. 496c332a984SYitzhak Mandelbaum appendToHeader(R"cc(int g(int x) { return x; })cc"); 497c332a984SYitzhak Mandelbaum std::string Input = 498c332a984SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 499c332a984SYitzhak Mandelbaum std::string Expected = 500c332a984SYitzhak Mandelbaum "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 501c332a984SYitzhak Mandelbaum auto InlineX = 502c332a984SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 503c332a984SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))), 504c332a984SYitzhak Mandelbaum rewriteDescendants("body", InlineX)), 505c332a984SYitzhak Mandelbaum Input, Expected); 506c332a984SYitzhak Mandelbaum } 507c332a984SYitzhak Mandelbaum 508c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsStmtWithAdditionalChange) { 509c332a984SYitzhak Mandelbaum std::string Input = 510c332a984SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 511c332a984SYitzhak Mandelbaum std::string Expected = 512c332a984SYitzhak Mandelbaum "int newName(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 513c332a984SYitzhak Mandelbaum auto InlineX = 514c332a984SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 515c332a984SYitzhak Mandelbaum testRule( 516c332a984SYitzhak Mandelbaum makeRule( 517c332a984SYitzhak Mandelbaum functionDecl(hasName("f"), hasBody(stmt().bind("body"))).bind("f"), 518c332a984SYitzhak Mandelbaum flatten(changeTo(name("f"), cat("newName")), 519c332a984SYitzhak Mandelbaum rewriteDescendants("body", InlineX))), 520c332a984SYitzhak Mandelbaum Input, Expected); 521c332a984SYitzhak Mandelbaum } 522c332a984SYitzhak Mandelbaum 523c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypeLoc) { 524c332a984SYitzhak Mandelbaum std::string Input = "int f(int *x) { return *x; }"; 525c332a984SYitzhak Mandelbaum std::string Expected = "int f(char *x) { return *x; }"; 526c332a984SYitzhak Mandelbaum auto IntToChar = 527c332a984SYitzhak Mandelbaum makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"), 528c332a984SYitzhak Mandelbaum changeTo(cat("char"))); 529c332a984SYitzhak Mandelbaum testRule( 530c332a984SYitzhak Mandelbaum makeRule(functionDecl(hasName("f"), 531c332a984SYitzhak Mandelbaum hasParameter(0, varDecl(hasTypeLoc( 532c332a984SYitzhak Mandelbaum typeLoc().bind("parmType"))))), 533c332a984SYitzhak Mandelbaum rewriteDescendants("parmType", IntToChar)), 534c332a984SYitzhak Mandelbaum Input, Expected); 535c332a984SYitzhak Mandelbaum } 536c332a984SYitzhak Mandelbaum 537c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsReferToParentBinding) { 538c332a984SYitzhak Mandelbaum std::string Input = 539c332a984SYitzhak Mandelbaum "int f(int p) { int y = p; { int z = p * p; } return p; }"; 540c332a984SYitzhak Mandelbaum std::string Expected = 541c332a984SYitzhak Mandelbaum "int f(int p) { int y = 3; { int z = 3 * 3; } return 3; }"; 542c332a984SYitzhak Mandelbaum std::string VarId = "var"; 543c332a984SYitzhak Mandelbaum auto InlineVar = makeRule(declRefExpr(to(varDecl(equalsBoundNode(VarId)))), 544c332a984SYitzhak Mandelbaum changeTo(cat("3"))); 545c332a984SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasName("f"), 546c332a984SYitzhak Mandelbaum hasParameter(0, varDecl().bind(VarId))) 547c332a984SYitzhak Mandelbaum .bind("fun"), 548c332a984SYitzhak Mandelbaum rewriteDescendants("fun", InlineVar)), 549c332a984SYitzhak Mandelbaum Input, Expected); 550c332a984SYitzhak Mandelbaum } 551c332a984SYitzhak Mandelbaum 552c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsUnboundNode) { 553c332a984SYitzhak Mandelbaum std::string Input = 554c332a984SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 555c332a984SYitzhak Mandelbaum auto InlineX = 556c332a984SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 557c332a984SYitzhak Mandelbaum Transformer T(makeRule(functionDecl(hasName("f")), 558c332a984SYitzhak Mandelbaum rewriteDescendants("UNBOUND", InlineX)), 559c332a984SYitzhak Mandelbaum consumer()); 560c332a984SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 561c332a984SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 562c332a984SYitzhak Mandelbaum EXPECT_THAT(Changes, IsEmpty()); 563c332a984SYitzhak Mandelbaum EXPECT_EQ(ErrorCount, 1); 564c332a984SYitzhak Mandelbaum } 565c332a984SYitzhak Mandelbaum 566c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsInvalidNodeType) { 567c332a984SYitzhak Mandelbaum std::string Input = 568c332a984SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 569c332a984SYitzhak Mandelbaum auto IntToChar = 570c332a984SYitzhak Mandelbaum makeRule(qualType(isInteger(), builtinType()), changeTo(cat("char"))); 571c332a984SYitzhak Mandelbaum Transformer T( 572c332a984SYitzhak Mandelbaum makeRule(functionDecl( 573c332a984SYitzhak Mandelbaum hasName("f"), 574c332a984SYitzhak Mandelbaum hasParameter(0, varDecl(hasType(qualType().bind("type"))))), 575c332a984SYitzhak Mandelbaum rewriteDescendants("type", IntToChar)), 576c332a984SYitzhak Mandelbaum consumer()); 577c332a984SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 578c332a984SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 579c332a984SYitzhak Mandelbaum EXPECT_THAT(Changes, IsEmpty()); 580c332a984SYitzhak Mandelbaum EXPECT_EQ(ErrorCount, 1); 581c332a984SYitzhak Mandelbaum } 582c332a984SYitzhak Mandelbaum 583d4f39031SYitzhak Mandelbaum // 584d4f39031SYitzhak Mandelbaum // We include one test per typed overload. We don't test extensively since that 585d4f39031SYitzhak Mandelbaum // is already covered by the tests above. 586d4f39031SYitzhak Mandelbaum // 587d4f39031SYitzhak Mandelbaum 588d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedStmt) { 589d4f39031SYitzhak Mandelbaum // Add an unrelated definition to the header that also has a variable named 590d4f39031SYitzhak Mandelbaum // "x", to test that the rewrite is limited to the scope we intend. 591d4f39031SYitzhak Mandelbaum appendToHeader(R"cc(int g(int x) { return x; })cc"); 592d4f39031SYitzhak Mandelbaum std::string Input = 593d4f39031SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 594d4f39031SYitzhak Mandelbaum std::string Expected = 595d4f39031SYitzhak Mandelbaum "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 596d4f39031SYitzhak Mandelbaum auto InlineX = 597d4f39031SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 598d4f39031SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))), 599d4f39031SYitzhak Mandelbaum [&InlineX](const MatchFinder::MatchResult &R) { 600d4f39031SYitzhak Mandelbaum const auto *Node = R.Nodes.getNodeAs<Stmt>("body"); 601d4f39031SYitzhak Mandelbaum assert(Node != nullptr && "body must be bound"); 602d4f39031SYitzhak Mandelbaum return transformer::detail::rewriteDescendants( 603d4f39031SYitzhak Mandelbaum *Node, InlineX, R); 604d4f39031SYitzhak Mandelbaum }), 605d4f39031SYitzhak Mandelbaum Input, Expected); 606d4f39031SYitzhak Mandelbaum } 607d4f39031SYitzhak Mandelbaum 608d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedDecl) { 609d4f39031SYitzhak Mandelbaum std::string Input = 610d4f39031SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 611d4f39031SYitzhak Mandelbaum std::string Expected = 612d4f39031SYitzhak Mandelbaum "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 613d4f39031SYitzhak Mandelbaum auto InlineX = 614d4f39031SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 615d4f39031SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasName("f")).bind("fun"), 616d4f39031SYitzhak Mandelbaum [&InlineX](const MatchFinder::MatchResult &R) { 617d4f39031SYitzhak Mandelbaum const auto *Node = R.Nodes.getNodeAs<Decl>("fun"); 618d4f39031SYitzhak Mandelbaum assert(Node != nullptr && "fun must be bound"); 619d4f39031SYitzhak Mandelbaum return transformer::detail::rewriteDescendants( 620d4f39031SYitzhak Mandelbaum *Node, InlineX, R); 621d4f39031SYitzhak Mandelbaum }), 622d4f39031SYitzhak Mandelbaum Input, Expected); 623d4f39031SYitzhak Mandelbaum } 624d4f39031SYitzhak Mandelbaum 625d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedTypeLoc) { 626d4f39031SYitzhak Mandelbaum std::string Input = "int f(int *x) { return *x; }"; 627d4f39031SYitzhak Mandelbaum std::string Expected = "int f(char *x) { return *x; }"; 628d4f39031SYitzhak Mandelbaum auto IntToChar = 629d4f39031SYitzhak Mandelbaum makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"), 630d4f39031SYitzhak Mandelbaum changeTo(cat("char"))); 631d4f39031SYitzhak Mandelbaum testRule( 632d4f39031SYitzhak Mandelbaum makeRule( 633d4f39031SYitzhak Mandelbaum functionDecl( 634d4f39031SYitzhak Mandelbaum hasName("f"), 635d4f39031SYitzhak Mandelbaum hasParameter(0, varDecl(hasTypeLoc(typeLoc().bind("parmType"))))), 636d4f39031SYitzhak Mandelbaum [&IntToChar](const MatchFinder::MatchResult &R) { 637d4f39031SYitzhak Mandelbaum const auto *Node = R.Nodes.getNodeAs<TypeLoc>("parmType"); 638d4f39031SYitzhak Mandelbaum assert(Node != nullptr && "parmType must be bound"); 639d4f39031SYitzhak Mandelbaum return transformer::detail::rewriteDescendants(*Node, IntToChar, R); 640d4f39031SYitzhak Mandelbaum }), 641d4f39031SYitzhak Mandelbaum Input, Expected); 642d4f39031SYitzhak Mandelbaum } 643d4f39031SYitzhak Mandelbaum 644d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedDynTyped) { 645d4f39031SYitzhak Mandelbaum // Add an unrelated definition to the header that also has a variable named 646d4f39031SYitzhak Mandelbaum // "x", to test that the rewrite is limited to the scope we intend. 647d4f39031SYitzhak Mandelbaum appendToHeader(R"cc(int g(int x) { return x; })cc"); 648d4f39031SYitzhak Mandelbaum std::string Input = 649d4f39031SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 650d4f39031SYitzhak Mandelbaum std::string Expected = 651d4f39031SYitzhak Mandelbaum "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 652d4f39031SYitzhak Mandelbaum auto InlineX = 653d4f39031SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 654d4f39031SYitzhak Mandelbaum testRule( 655d4f39031SYitzhak Mandelbaum makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))), 656d4f39031SYitzhak Mandelbaum [&InlineX](const MatchFinder::MatchResult &R) { 657d4f39031SYitzhak Mandelbaum auto It = R.Nodes.getMap().find("body"); 658d4f39031SYitzhak Mandelbaum assert(It != R.Nodes.getMap().end() && "body must be bound"); 659d4f39031SYitzhak Mandelbaum return transformer::detail::rewriteDescendants(It->second, 660d4f39031SYitzhak Mandelbaum InlineX, R); 661d4f39031SYitzhak Mandelbaum }), 662d4f39031SYitzhak Mandelbaum Input, Expected); 663d4f39031SYitzhak Mandelbaum } 664d4f39031SYitzhak Mandelbaum 6652e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, InsertBeforeEdit) { 6662e4a628cSYitzhak Mandelbaum std::string Input = R"cc( 6672e4a628cSYitzhak Mandelbaum int f() { 6682e4a628cSYitzhak Mandelbaum return 7; 6692e4a628cSYitzhak Mandelbaum } 6702e4a628cSYitzhak Mandelbaum )cc"; 6712e4a628cSYitzhak Mandelbaum std::string Expected = R"cc( 6722e4a628cSYitzhak Mandelbaum int f() { 6732e4a628cSYitzhak Mandelbaum int y = 3; 6742e4a628cSYitzhak Mandelbaum return 7; 6752e4a628cSYitzhak Mandelbaum } 6762e4a628cSYitzhak Mandelbaum )cc"; 6772e4a628cSYitzhak Mandelbaum 6782e4a628cSYitzhak Mandelbaum StringRef Ret = "return"; 679adcd0268SBenjamin Kramer testRule( 680adcd0268SBenjamin Kramer makeRule(returnStmt().bind(Ret), 681adcd0268SBenjamin Kramer insertBefore(statement(std::string(Ret)), cat("int y = 3;"))), 6822e4a628cSYitzhak Mandelbaum Input, Expected); 6832e4a628cSYitzhak Mandelbaum } 6842e4a628cSYitzhak Mandelbaum 6852e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, InsertAfterEdit) { 6862e4a628cSYitzhak Mandelbaum std::string Input = R"cc( 6872e4a628cSYitzhak Mandelbaum int f() { 6882e4a628cSYitzhak Mandelbaum int x = 5; 6892e4a628cSYitzhak Mandelbaum return 7; 6902e4a628cSYitzhak Mandelbaum } 6912e4a628cSYitzhak Mandelbaum )cc"; 6922e4a628cSYitzhak Mandelbaum std::string Expected = R"cc( 6932e4a628cSYitzhak Mandelbaum int f() { 6942e4a628cSYitzhak Mandelbaum int x = 5; 6952e4a628cSYitzhak Mandelbaum int y = 3; 6962e4a628cSYitzhak Mandelbaum return 7; 6972e4a628cSYitzhak Mandelbaum } 6982e4a628cSYitzhak Mandelbaum )cc"; 6992e4a628cSYitzhak Mandelbaum 7002e4a628cSYitzhak Mandelbaum StringRef Decl = "decl"; 701adcd0268SBenjamin Kramer testRule( 702adcd0268SBenjamin Kramer makeRule(declStmt().bind(Decl), 703adcd0268SBenjamin Kramer insertAfter(statement(std::string(Decl)), cat("int y = 3;"))), 7042e4a628cSYitzhak Mandelbaum Input, Expected); 7052e4a628cSYitzhak Mandelbaum } 7062e4a628cSYitzhak Mandelbaum 7072e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, RemoveEdit) { 7082e4a628cSYitzhak Mandelbaum std::string Input = R"cc( 7092e4a628cSYitzhak Mandelbaum int f() { 7102e4a628cSYitzhak Mandelbaum int x = 5; 7112e4a628cSYitzhak Mandelbaum return 7; 7122e4a628cSYitzhak Mandelbaum } 7132e4a628cSYitzhak Mandelbaum )cc"; 7142e4a628cSYitzhak Mandelbaum std::string Expected = R"cc( 7152e4a628cSYitzhak Mandelbaum int f() { 7162e4a628cSYitzhak Mandelbaum return 7; 7172e4a628cSYitzhak Mandelbaum } 7182e4a628cSYitzhak Mandelbaum )cc"; 7192e4a628cSYitzhak Mandelbaum 7202e4a628cSYitzhak Mandelbaum StringRef Decl = "decl"; 721adcd0268SBenjamin Kramer testRule( 722adcd0268SBenjamin Kramer makeRule(declStmt().bind(Decl), remove(statement(std::string(Decl)))), 723adcd0268SBenjamin Kramer Input, Expected); 7242e4a628cSYitzhak Mandelbaum } 7252e4a628cSYitzhak Mandelbaum 7269945bd59SAndy Soffer TEST_F(TransformerTest, WithMetadata) { 727e5b3202bSAndy Soffer auto makeMetadata = [](const MatchFinder::MatchResult &R) -> llvm::Any { 728e5b3202bSAndy Soffer int N = 729e5b3202bSAndy Soffer R.Nodes.getNodeAs<IntegerLiteral>("int")->getValue().getLimitedValue(); 730e5b3202bSAndy Soffer return N; 731e5b3202bSAndy Soffer }; 732e5b3202bSAndy Soffer 7339945bd59SAndy Soffer std::string Input = R"cc( 7349945bd59SAndy Soffer int f() { 7359945bd59SAndy Soffer int x = 5; 7369945bd59SAndy Soffer return 7; 7379945bd59SAndy Soffer } 7389945bd59SAndy Soffer )cc"; 7399945bd59SAndy Soffer 7409945bd59SAndy Soffer Transformer T( 741e5b3202bSAndy Soffer makeRule( 742e5b3202bSAndy Soffer declStmt(containsDeclaration(0, varDecl(hasInitializer( 743e5b3202bSAndy Soffer integerLiteral().bind("int"))))) 744e5b3202bSAndy Soffer .bind("decl"), 745e5b3202bSAndy Soffer withMetadata(remove(statement(std::string("decl"))), makeMetadata)), 7469945bd59SAndy Soffer consumer()); 7479945bd59SAndy Soffer T.registerMatchers(&MatchFinder); 7489945bd59SAndy Soffer auto Factory = newFrontendActionFactory(&MatchFinder); 7499945bd59SAndy Soffer EXPECT_TRUE(runToolOnCodeWithArgs( 7509945bd59SAndy Soffer Factory->create(), Input, std::vector<std::string>(), "input.cc", 7519945bd59SAndy Soffer "clang-tool", std::make_shared<PCHContainerOperations>(), {})); 7529945bd59SAndy Soffer ASSERT_EQ(Changes.size(), 1u); 7539945bd59SAndy Soffer const llvm::Any &Metadata = Changes[0].getMetadata(); 7549945bd59SAndy Soffer ASSERT_TRUE(llvm::any_isa<int>(Metadata)); 755e5b3202bSAndy Soffer EXPECT_THAT(llvm::any_cast<int>(Metadata), 5); 7569945bd59SAndy Soffer } 7579945bd59SAndy Soffer 758fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, MultiChange) { 759fa1552e8SYitzhak Mandelbaum std::string Input = R"cc( 760fa1552e8SYitzhak Mandelbaum void foo() { 761fa1552e8SYitzhak Mandelbaum if (10 > 1.0) 762fa1552e8SYitzhak Mandelbaum log(1) << "oh no!"; 763fa1552e8SYitzhak Mandelbaum else 764fa1552e8SYitzhak Mandelbaum log(0) << "ok"; 765fa1552e8SYitzhak Mandelbaum } 766fa1552e8SYitzhak Mandelbaum )cc"; 767fa1552e8SYitzhak Mandelbaum std::string Expected = R"( 768fa1552e8SYitzhak Mandelbaum void foo() { 769fa1552e8SYitzhak Mandelbaum if (true) { /* then */ } 770fa1552e8SYitzhak Mandelbaum else { /* else */ } 771fa1552e8SYitzhak Mandelbaum } 772fa1552e8SYitzhak Mandelbaum )"; 773fa1552e8SYitzhak Mandelbaum 774fa1552e8SYitzhak Mandelbaum StringRef C = "C", T = "T", E = "E"; 775adcd0268SBenjamin Kramer testRule( 776adcd0268SBenjamin Kramer makeRule(ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)), 777adcd0268SBenjamin Kramer hasElse(stmt().bind(E))), 778adcd0268SBenjamin Kramer {changeTo(node(std::string(C)), cat("true")), 779adcd0268SBenjamin Kramer changeTo(statement(std::string(T)), cat("{ /* then */ }")), 780adcd0268SBenjamin Kramer changeTo(statement(std::string(E)), cat("{ /* else */ }"))}), 781fdd98782SYitzhak Mandelbaum Input, Expected); 782fdd98782SYitzhak Mandelbaum } 783fdd98782SYitzhak Mandelbaum 784cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, EditList) { 785cf428778SYitzhak Mandelbaum using clang::transformer::editList; 786cf428778SYitzhak Mandelbaum std::string Input = R"cc( 787cf428778SYitzhak Mandelbaum void foo() { 788cf428778SYitzhak Mandelbaum if (10 > 1.0) 789cf428778SYitzhak Mandelbaum log(1) << "oh no!"; 790cf428778SYitzhak Mandelbaum else 791cf428778SYitzhak Mandelbaum log(0) << "ok"; 792cf428778SYitzhak Mandelbaum } 793cf428778SYitzhak Mandelbaum )cc"; 794cf428778SYitzhak Mandelbaum std::string Expected = R"( 795cf428778SYitzhak Mandelbaum void foo() { 796cf428778SYitzhak Mandelbaum if (true) { /* then */ } 797cf428778SYitzhak Mandelbaum else { /* else */ } 798cf428778SYitzhak Mandelbaum } 799cf428778SYitzhak Mandelbaum )"; 800cf428778SYitzhak Mandelbaum 801cf428778SYitzhak Mandelbaum StringRef C = "C", T = "T", E = "E"; 802cf428778SYitzhak Mandelbaum testRule(makeRule(ifStmt(hasCondition(expr().bind(C)), 803cf428778SYitzhak Mandelbaum hasThen(stmt().bind(T)), hasElse(stmt().bind(E))), 804cf428778SYitzhak Mandelbaum editList({changeTo(node(std::string(C)), cat("true")), 805cf428778SYitzhak Mandelbaum changeTo(statement(std::string(T)), 806cf428778SYitzhak Mandelbaum cat("{ /* then */ }")), 807cf428778SYitzhak Mandelbaum changeTo(statement(std::string(E)), 808cf428778SYitzhak Mandelbaum cat("{ /* else */ }"))})), 809cf428778SYitzhak Mandelbaum Input, Expected); 810cf428778SYitzhak Mandelbaum } 811cf428778SYitzhak Mandelbaum 812cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, Flatten) { 813cf428778SYitzhak Mandelbaum using clang::transformer::editList; 814cf428778SYitzhak Mandelbaum std::string Input = R"cc( 815cf428778SYitzhak Mandelbaum void foo() { 816cf428778SYitzhak Mandelbaum if (10 > 1.0) 817cf428778SYitzhak Mandelbaum log(1) << "oh no!"; 818cf428778SYitzhak Mandelbaum else 819cf428778SYitzhak Mandelbaum log(0) << "ok"; 820cf428778SYitzhak Mandelbaum } 821cf428778SYitzhak Mandelbaum )cc"; 822cf428778SYitzhak Mandelbaum std::string Expected = R"( 823cf428778SYitzhak Mandelbaum void foo() { 824cf428778SYitzhak Mandelbaum if (true) { /* then */ } 825cf428778SYitzhak Mandelbaum else { /* else */ } 826cf428778SYitzhak Mandelbaum } 827cf428778SYitzhak Mandelbaum )"; 828cf428778SYitzhak Mandelbaum 829cf428778SYitzhak Mandelbaum StringRef C = "C", T = "T", E = "E"; 830cf428778SYitzhak Mandelbaum testRule( 831cf428778SYitzhak Mandelbaum makeRule( 832cf428778SYitzhak Mandelbaum ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)), 833cf428778SYitzhak Mandelbaum hasElse(stmt().bind(E))), 834cf428778SYitzhak Mandelbaum flatten(changeTo(node(std::string(C)), cat("true")), 835cf428778SYitzhak Mandelbaum changeTo(statement(std::string(T)), cat("{ /* then */ }")), 836cf428778SYitzhak Mandelbaum changeTo(statement(std::string(E)), cat("{ /* else */ }")))), 837cf428778SYitzhak Mandelbaum Input, Expected); 838cf428778SYitzhak Mandelbaum } 839cf428778SYitzhak Mandelbaum 840cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, FlattenWithMixedArgs) { 841cf428778SYitzhak Mandelbaum using clang::transformer::editList; 842cf428778SYitzhak Mandelbaum std::string Input = R"cc( 843cf428778SYitzhak Mandelbaum void foo() { 844cf428778SYitzhak Mandelbaum if (10 > 1.0) 845cf428778SYitzhak Mandelbaum log(1) << "oh no!"; 846cf428778SYitzhak Mandelbaum else 847cf428778SYitzhak Mandelbaum log(0) << "ok"; 848cf428778SYitzhak Mandelbaum } 849cf428778SYitzhak Mandelbaum )cc"; 850cf428778SYitzhak Mandelbaum std::string Expected = R"( 851cf428778SYitzhak Mandelbaum void foo() { 852cf428778SYitzhak Mandelbaum if (true) { /* then */ } 853cf428778SYitzhak Mandelbaum else { /* else */ } 854cf428778SYitzhak Mandelbaum } 855cf428778SYitzhak Mandelbaum )"; 856cf428778SYitzhak Mandelbaum 857cf428778SYitzhak Mandelbaum StringRef C = "C", T = "T", E = "E"; 858cf428778SYitzhak Mandelbaum testRule(makeRule(ifStmt(hasCondition(expr().bind(C)), 859cf428778SYitzhak Mandelbaum hasThen(stmt().bind(T)), hasElse(stmt().bind(E))), 860cf428778SYitzhak Mandelbaum flatten(changeTo(node(std::string(C)), cat("true")), 861cf428778SYitzhak Mandelbaum edit(changeTo(statement(std::string(T)), 862cf428778SYitzhak Mandelbaum cat("{ /* then */ }"))), 863cf428778SYitzhak Mandelbaum editList({changeTo(statement(std::string(E)), 864cf428778SYitzhak Mandelbaum cat("{ /* else */ }"))}))), 865cf428778SYitzhak Mandelbaum Input, Expected); 866cf428778SYitzhak Mandelbaum } 867cf428778SYitzhak Mandelbaum 8688369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleUnrelated) { 8698369a9beSYitzhak Mandelbaum StringRef Flag = "flag"; 8708369a9beSYitzhak Mandelbaum RewriteRule FlagRule = makeRule( 8718369a9beSYitzhak Mandelbaum cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( 8728369a9beSYitzhak Mandelbaum hasName("proto::ProtoCommandLineFlag")))) 8738369a9beSYitzhak Mandelbaum .bind(Flag)), 8748369a9beSYitzhak Mandelbaum unless(callee(cxxMethodDecl(hasName("GetProto"))))), 875adcd0268SBenjamin Kramer changeTo(node(std::string(Flag)), cat("PROTO"))); 8768369a9beSYitzhak Mandelbaum 8778369a9beSYitzhak Mandelbaum std::string Input = R"cc( 8788369a9beSYitzhak Mandelbaum proto::ProtoCommandLineFlag flag; 8798369a9beSYitzhak Mandelbaum int x = flag.foo(); 8808369a9beSYitzhak Mandelbaum int y = flag.GetProto().foo(); 8818369a9beSYitzhak Mandelbaum int f(string s) { return strlen(s.c_str()); } 8828369a9beSYitzhak Mandelbaum )cc"; 8838369a9beSYitzhak Mandelbaum std::string Expected = R"cc( 8848369a9beSYitzhak Mandelbaum proto::ProtoCommandLineFlag flag; 8858369a9beSYitzhak Mandelbaum int x = PROTO.foo(); 8868369a9beSYitzhak Mandelbaum int y = flag.GetProto().foo(); 8878369a9beSYitzhak Mandelbaum int f(string s) { return REPLACED; } 8888369a9beSYitzhak Mandelbaum )cc"; 8898369a9beSYitzhak Mandelbaum 8908369a9beSYitzhak Mandelbaum testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected); 8918369a9beSYitzhak Mandelbaum } 8928369a9beSYitzhak Mandelbaum 8938369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleRelated) { 8948369a9beSYitzhak Mandelbaum std::string Input = R"cc( 89542b957aaSYitzhak Mandelbaum void f1(); 89642b957aaSYitzhak Mandelbaum void f2(); 89742b957aaSYitzhak Mandelbaum void call_f1() { f1(); } 89842b957aaSYitzhak Mandelbaum void call_f2() { f2(); } 8998369a9beSYitzhak Mandelbaum )cc"; 9008369a9beSYitzhak Mandelbaum std::string Expected = R"cc( 90142b957aaSYitzhak Mandelbaum void f1(); 90242b957aaSYitzhak Mandelbaum void f2(); 90342b957aaSYitzhak Mandelbaum void call_f1() { REPLACE_F1; } 90442b957aaSYitzhak Mandelbaum void call_f2() { REPLACE_F1_OR_F2; } 9058369a9beSYitzhak Mandelbaum )cc"; 9068369a9beSYitzhak Mandelbaum 90742b957aaSYitzhak Mandelbaum RewriteRule ReplaceF1 = 90842b957aaSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasName("f1")))), 9099f97480cSYitzhak Mandelbaum changeTo(cat("REPLACE_F1"))); 91042b957aaSYitzhak Mandelbaum RewriteRule ReplaceF1OrF2 = 91142b957aaSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 9129f97480cSYitzhak Mandelbaum changeTo(cat("REPLACE_F1_OR_F2"))); 91342b957aaSYitzhak Mandelbaum testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected); 9148369a9beSYitzhak Mandelbaum } 9158369a9beSYitzhak Mandelbaum 91642b957aaSYitzhak Mandelbaum // Change the order of the rules to get a different result. When `ReplaceF1OrF2` 91742b957aaSYitzhak Mandelbaum // comes first, it applies for both uses, so `ReplaceF1` never applies. 9188369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleRelatedSwapped) { 9198369a9beSYitzhak Mandelbaum std::string Input = R"cc( 92042b957aaSYitzhak Mandelbaum void f1(); 92142b957aaSYitzhak Mandelbaum void f2(); 92242b957aaSYitzhak Mandelbaum void call_f1() { f1(); } 92342b957aaSYitzhak Mandelbaum void call_f2() { f2(); } 9248369a9beSYitzhak Mandelbaum )cc"; 9258369a9beSYitzhak Mandelbaum std::string Expected = R"cc( 92642b957aaSYitzhak Mandelbaum void f1(); 92742b957aaSYitzhak Mandelbaum void f2(); 92842b957aaSYitzhak Mandelbaum void call_f1() { REPLACE_F1_OR_F2; } 92942b957aaSYitzhak Mandelbaum void call_f2() { REPLACE_F1_OR_F2; } 9308369a9beSYitzhak Mandelbaum )cc"; 9318369a9beSYitzhak Mandelbaum 93242b957aaSYitzhak Mandelbaum RewriteRule ReplaceF1 = 93342b957aaSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasName("f1")))), 9349f97480cSYitzhak Mandelbaum changeTo(cat("REPLACE_F1"))); 93542b957aaSYitzhak Mandelbaum RewriteRule ReplaceF1OrF2 = 93642b957aaSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 9379f97480cSYitzhak Mandelbaum changeTo(cat("REPLACE_F1_OR_F2"))); 93842b957aaSYitzhak Mandelbaum testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected); 93942b957aaSYitzhak Mandelbaum } 94042b957aaSYitzhak Mandelbaum 94142b957aaSYitzhak Mandelbaum // Verify that a set of rules whose matchers have different base kinds works 94242b957aaSYitzhak Mandelbaum // properly, including that `applyFirst` produces multiple matchers. We test 94342b957aaSYitzhak Mandelbaum // two different kinds of rules: Expr and Decl. We place the Decl rule in the 94442b957aaSYitzhak Mandelbaum // middle to test that `buildMatchers` works even when the kinds aren't grouped 94542b957aaSYitzhak Mandelbaum // together. 94642b957aaSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleMultipleKinds) { 94742b957aaSYitzhak Mandelbaum std::string Input = R"cc( 94842b957aaSYitzhak Mandelbaum void f1(); 94942b957aaSYitzhak Mandelbaum void f2(); 95042b957aaSYitzhak Mandelbaum void call_f1() { f1(); } 95142b957aaSYitzhak Mandelbaum void call_f2() { f2(); } 95242b957aaSYitzhak Mandelbaum )cc"; 95342b957aaSYitzhak Mandelbaum std::string Expected = R"cc( 95442b957aaSYitzhak Mandelbaum void f1(); 95542b957aaSYitzhak Mandelbaum void DECL_RULE(); 95642b957aaSYitzhak Mandelbaum void call_f1() { REPLACE_F1; } 95742b957aaSYitzhak Mandelbaum void call_f2() { REPLACE_F1_OR_F2; } 95842b957aaSYitzhak Mandelbaum )cc"; 95942b957aaSYitzhak Mandelbaum 96042b957aaSYitzhak Mandelbaum RewriteRule ReplaceF1 = 96142b957aaSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasName("f1")))), 9629f97480cSYitzhak Mandelbaum changeTo(cat("REPLACE_F1"))); 96342b957aaSYitzhak Mandelbaum RewriteRule ReplaceF1OrF2 = 96442b957aaSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 9659f97480cSYitzhak Mandelbaum changeTo(cat("REPLACE_F1_OR_F2"))); 96642b957aaSYitzhak Mandelbaum RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"), 9679f97480cSYitzhak Mandelbaum changeTo(name("fun"), cat("DECL_RULE"))); 96842b957aaSYitzhak Mandelbaum 96942b957aaSYitzhak Mandelbaum RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2}); 9708bb47cd8SYitzhak Mandelbaum EXPECT_EQ(transformer::detail::buildMatchers(Rule).size(), 2UL); 97142b957aaSYitzhak Mandelbaum testRule(Rule, Input, Expected); 9728369a9beSYitzhak Mandelbaum } 9738369a9beSYitzhak Mandelbaum 974ce5780b8SYitzhak Mandelbaum // Verifies that a rule with a top-level matcher for an implicit node (like 9756f0a3711SYitzhak Mandelbaum // `implicitCastExpr`) works correctly -- the implicit nodes are not skipped. 976ce5780b8SYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleImplicitMatched) { 977ce5780b8SYitzhak Mandelbaum std::string Input = R"cc( 978ce5780b8SYitzhak Mandelbaum void f1(); 979ce5780b8SYitzhak Mandelbaum int f2(); 980ce5780b8SYitzhak Mandelbaum void call_f1() { f1(); } 981ce5780b8SYitzhak Mandelbaum float call_f2() { return f2(); } 982ce5780b8SYitzhak Mandelbaum )cc"; 983ce5780b8SYitzhak Mandelbaum std::string Expected = R"cc( 984ce5780b8SYitzhak Mandelbaum void f1(); 985ce5780b8SYitzhak Mandelbaum int f2(); 986ce5780b8SYitzhak Mandelbaum void call_f1() { REPLACE_F1; } 987ce5780b8SYitzhak Mandelbaum float call_f2() { return REPLACE_F2; } 988ce5780b8SYitzhak Mandelbaum )cc"; 989ce5780b8SYitzhak Mandelbaum 9906f0a3711SYitzhak Mandelbaum RewriteRule ReplaceF1 = 9916f0a3711SYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasName("f1")))), 992ce5780b8SYitzhak Mandelbaum changeTo(cat("REPLACE_F1"))); 993ce5780b8SYitzhak Mandelbaum RewriteRule ReplaceF2 = 9946f0a3711SYitzhak Mandelbaum makeRule(implicitCastExpr(hasSourceExpression(callExpr())), 995ce5780b8SYitzhak Mandelbaum changeTo(cat("REPLACE_F2"))); 996ce5780b8SYitzhak Mandelbaum testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected); 997ce5780b8SYitzhak Mandelbaum } 998ce5780b8SYitzhak Mandelbaum 999fdd98782SYitzhak Mandelbaum // 1000fdd98782SYitzhak Mandelbaum // Negative tests (where we expect no transformation to occur). 1001fdd98782SYitzhak Mandelbaum // 1002fdd98782SYitzhak Mandelbaum 1003fa1552e8SYitzhak Mandelbaum // Tests for a conflict in edits from a single match for a rule. 1004aecc59c5SYitzhak Mandelbaum TEST_F(TransformerTest, TextGeneratorFailure) { 1005aecc59c5SYitzhak Mandelbaum std::string Input = "int conflictOneRule() { return 3 + 7; }"; 1006aecc59c5SYitzhak Mandelbaum // Try to change the whole binary-operator expression AND one its operands: 1007aecc59c5SYitzhak Mandelbaum StringRef O = "O"; 1008489449c2SYitzhak Mandelbaum class AlwaysFail : public transformer::MatchComputation<std::string> { 1009489449c2SYitzhak Mandelbaum llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &, 1010489449c2SYitzhak Mandelbaum std::string *) const override { 1011aecc59c5SYitzhak Mandelbaum return llvm::createStringError(llvm::errc::invalid_argument, "ERROR"); 1012489449c2SYitzhak Mandelbaum } 1013489449c2SYitzhak Mandelbaum std::string toString() const override { return "AlwaysFail"; } 1014aecc59c5SYitzhak Mandelbaum }; 1015adcd0268SBenjamin Kramer Transformer T( 1016adcd0268SBenjamin Kramer makeRule(binaryOperator().bind(O), 1017adcd0268SBenjamin Kramer changeTo(node(std::string(O)), std::make_shared<AlwaysFail>())), 1018aecc59c5SYitzhak Mandelbaum consumer()); 1019aecc59c5SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 1020aecc59c5SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 1021aecc59c5SYitzhak Mandelbaum EXPECT_THAT(Changes, IsEmpty()); 1022aecc59c5SYitzhak Mandelbaum EXPECT_EQ(ErrorCount, 1); 1023aecc59c5SYitzhak Mandelbaum } 1024aecc59c5SYitzhak Mandelbaum 1025aecc59c5SYitzhak Mandelbaum // Tests for a conflict in edits from a single match for a rule. 1026fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, OverlappingEditsInRule) { 1027fa1552e8SYitzhak Mandelbaum std::string Input = "int conflictOneRule() { return 3 + 7; }"; 1028fa1552e8SYitzhak Mandelbaum // Try to change the whole binary-operator expression AND one its operands: 1029fa1552e8SYitzhak Mandelbaum StringRef O = "O", L = "L"; 10303ec50e29SYitzhak Mandelbaum Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O), 1031adcd0268SBenjamin Kramer {changeTo(node(std::string(O)), cat("DELETE_OP")), 1032adcd0268SBenjamin Kramer changeTo(node(std::string(L)), cat("DELETE_LHS"))}), 1033aecc59c5SYitzhak Mandelbaum consumer()); 1034fa1552e8SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 1035aecc59c5SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 1036aecc59c5SYitzhak Mandelbaum EXPECT_THAT(Changes, IsEmpty()); 1037aecc59c5SYitzhak Mandelbaum EXPECT_EQ(ErrorCount, 1); 1038fa1552e8SYitzhak Mandelbaum } 1039fa1552e8SYitzhak Mandelbaum 1040fa1552e8SYitzhak Mandelbaum // Tests for a conflict in edits across multiple matches (of the same rule). 1041fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, OverlappingEditsMultipleMatches) { 1042fa1552e8SYitzhak Mandelbaum std::string Input = "int conflictOneRule() { return -7; }"; 1043fa1552e8SYitzhak Mandelbaum // Try to change the whole binary-operator expression AND one its operands: 1044fa1552e8SYitzhak Mandelbaum StringRef E = "E"; 1045adcd0268SBenjamin Kramer Transformer T(makeRule(expr().bind(E), 1046adcd0268SBenjamin Kramer changeTo(node(std::string(E)), cat("DELETE_EXPR"))), 1047aecc59c5SYitzhak Mandelbaum consumer()); 1048fa1552e8SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 1049fa1552e8SYitzhak Mandelbaum // The rewrite process fails because the changes conflict with each other... 1050fa1552e8SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 1051aecc59c5SYitzhak Mandelbaum // ... but two changes were produced. 1052aecc59c5SYitzhak Mandelbaum EXPECT_EQ(Changes.size(), 2u); 1053aecc59c5SYitzhak Mandelbaum EXPECT_EQ(ErrorCount, 0); 1054fa1552e8SYitzhak Mandelbaum } 1055fa1552e8SYitzhak Mandelbaum 1056fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, ErrorOccurredMatchSkipped) { 1057fa1552e8SYitzhak Mandelbaum // Syntax error in the function body: 1058fa1552e8SYitzhak Mandelbaum std::string Input = "void errorOccurred() { 3 }"; 1059aecc59c5SYitzhak Mandelbaum Transformer T(makeRule(functionDecl(hasName("errorOccurred")), 10609f97480cSYitzhak Mandelbaum changeTo(cat("DELETED;"))), 1061aecc59c5SYitzhak Mandelbaum consumer()); 1062fa1552e8SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 1063fa1552e8SYitzhak Mandelbaum // The rewrite process itself fails... 1064fa1552e8SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 1065aecc59c5SYitzhak Mandelbaum // ... and no changes or errors are produced in the process. 1066aecc59c5SYitzhak Mandelbaum EXPECT_THAT(Changes, IsEmpty()); 1067aecc59c5SYitzhak Mandelbaum EXPECT_EQ(ErrorCount, 0); 1068fa1552e8SYitzhak Mandelbaum } 1069fa1552e8SYitzhak Mandelbaum 107053df3bebSStephen Kelly TEST_F(TransformerTest, TemplateInstantiation) { 107153df3bebSStephen Kelly 107253df3bebSStephen Kelly std::string NonTemplatesInput = R"cpp( 107353df3bebSStephen Kelly struct S { 107453df3bebSStephen Kelly int m_i; 107553df3bebSStephen Kelly }; 107653df3bebSStephen Kelly )cpp"; 107753df3bebSStephen Kelly std::string NonTemplatesExpected = R"cpp( 107853df3bebSStephen Kelly struct S { 107953df3bebSStephen Kelly safe_int m_i; 108053df3bebSStephen Kelly }; 108153df3bebSStephen Kelly )cpp"; 108253df3bebSStephen Kelly 108353df3bebSStephen Kelly std::string TemplatesInput = R"cpp( 108453df3bebSStephen Kelly template<typename T> 108553df3bebSStephen Kelly struct TemplStruct { 108653df3bebSStephen Kelly TemplStruct() {} 108753df3bebSStephen Kelly ~TemplStruct() {} 108853df3bebSStephen Kelly 108953df3bebSStephen Kelly private: 109053df3bebSStephen Kelly T m_t; 109153df3bebSStephen Kelly }; 109253df3bebSStephen Kelly 109353df3bebSStephen Kelly void instantiate() 109453df3bebSStephen Kelly { 109553df3bebSStephen Kelly TemplStruct<int> ti; 109653df3bebSStephen Kelly } 109753df3bebSStephen Kelly )cpp"; 109853df3bebSStephen Kelly 109953df3bebSStephen Kelly auto MatchedField = fieldDecl(hasType(asString("int"))).bind("theField"); 110053df3bebSStephen Kelly 110153df3bebSStephen Kelly // Changes the 'int' in 'S', but not the 'T' in 'TemplStruct': 110253df3bebSStephen Kelly testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedField), 110353df3bebSStephen Kelly changeTo(cat("safe_int ", name("theField")))), 110453df3bebSStephen Kelly NonTemplatesInput + TemplatesInput, 110553df3bebSStephen Kelly NonTemplatesExpected + TemplatesInput); 110653df3bebSStephen Kelly 110753df3bebSStephen Kelly // In AsIs mode, template instantiations are modified, which is 110853df3bebSStephen Kelly // often not desired: 110953df3bebSStephen Kelly 111053df3bebSStephen Kelly std::string IncorrectTemplatesExpected = R"cpp( 111153df3bebSStephen Kelly template<typename T> 111253df3bebSStephen Kelly struct TemplStruct { 111353df3bebSStephen Kelly TemplStruct() {} 111453df3bebSStephen Kelly ~TemplStruct() {} 111553df3bebSStephen Kelly 111653df3bebSStephen Kelly private: 111753df3bebSStephen Kelly safe_int m_t; 111853df3bebSStephen Kelly }; 111953df3bebSStephen Kelly 112053df3bebSStephen Kelly void instantiate() 112153df3bebSStephen Kelly { 112253df3bebSStephen Kelly TemplStruct<int> ti; 112353df3bebSStephen Kelly } 112453df3bebSStephen Kelly )cpp"; 112553df3bebSStephen Kelly 112653df3bebSStephen Kelly // Changes the 'int' in 'S', and (incorrectly) the 'T' in 'TemplStruct': 112753df3bebSStephen Kelly testRule(makeRule(traverse(TK_AsIs, MatchedField), 112853df3bebSStephen Kelly changeTo(cat("safe_int ", name("theField")))), 112953df3bebSStephen Kelly 113053df3bebSStephen Kelly NonTemplatesInput + TemplatesInput, 113153df3bebSStephen Kelly NonTemplatesExpected + IncorrectTemplatesExpected); 113253df3bebSStephen Kelly } 113353df3bebSStephen Kelly 11343f1ab737SYitzhak Mandelbaum // Transformation of macro source text when the change encompasses the entirety 11353f1ab737SYitzhak Mandelbaum // of the expanded text. 11363f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, SimpleMacro) { 1137fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 11383f1ab737SYitzhak Mandelbaum #define ZERO 0 11393f1ab737SYitzhak Mandelbaum int f(string s) { return ZERO; } 11403f1ab737SYitzhak Mandelbaum )cc"; 11413f1ab737SYitzhak Mandelbaum std::string Expected = R"cc( 11423f1ab737SYitzhak Mandelbaum #define ZERO 0 11433f1ab737SYitzhak Mandelbaum int f(string s) { return 999; } 11443f1ab737SYitzhak Mandelbaum )cc"; 11453f1ab737SYitzhak Mandelbaum 11463f1ab737SYitzhak Mandelbaum StringRef zero = "zero"; 11473f1ab737SYitzhak Mandelbaum RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 1148adcd0268SBenjamin Kramer changeTo(node(std::string(zero)), cat("999"))); 11493f1ab737SYitzhak Mandelbaum testRule(R, Input, Expected); 1150fdd98782SYitzhak Mandelbaum } 1151fdd98782SYitzhak Mandelbaum 11523f1ab737SYitzhak Mandelbaum // Transformation of macro source text when the change encompasses the entirety 11533f1ab737SYitzhak Mandelbaum // of the expanded text, for the case of function-style macros. 11543f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, FunctionMacro) { 11553f1ab737SYitzhak Mandelbaum std::string Input = R"cc( 11563f1ab737SYitzhak Mandelbaum #define MACRO(str) strlen((str).c_str()) 11573f1ab737SYitzhak Mandelbaum int f(string s) { return MACRO(s); } 11583f1ab737SYitzhak Mandelbaum )cc"; 11593f1ab737SYitzhak Mandelbaum std::string Expected = R"cc( 11603f1ab737SYitzhak Mandelbaum #define MACRO(str) strlen((str).c_str()) 11613f1ab737SYitzhak Mandelbaum int f(string s) { return REPLACED; } 11623f1ab737SYitzhak Mandelbaum )cc"; 11633f1ab737SYitzhak Mandelbaum 11643f1ab737SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Expected); 11653f1ab737SYitzhak Mandelbaum } 11663f1ab737SYitzhak Mandelbaum 11673f1ab737SYitzhak Mandelbaum // Tests that expressions in macro arguments can be rewritten. 11683f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, MacroArg) { 11693f1ab737SYitzhak Mandelbaum std::string Input = R"cc( 11703f1ab737SYitzhak Mandelbaum #define PLUS(e) e + 1 11713f1ab737SYitzhak Mandelbaum int f(string s) { return PLUS(strlen(s.c_str())); } 11723f1ab737SYitzhak Mandelbaum )cc"; 11733f1ab737SYitzhak Mandelbaum std::string Expected = R"cc( 11743f1ab737SYitzhak Mandelbaum #define PLUS(e) e + 1 11753f1ab737SYitzhak Mandelbaum int f(string s) { return PLUS(REPLACED); } 11763f1ab737SYitzhak Mandelbaum )cc"; 11773f1ab737SYitzhak Mandelbaum 11783f1ab737SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Expected); 11793f1ab737SYitzhak Mandelbaum } 11803f1ab737SYitzhak Mandelbaum 11813f1ab737SYitzhak Mandelbaum // Tests that expressions in macro arguments can be rewritten, even when the 11823f1ab737SYitzhak Mandelbaum // macro call occurs inside another macro's definition. 11833f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, MacroArgInMacroDef) { 1184fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 1185fdd98782SYitzhak Mandelbaum #define NESTED(e) e 1186fdd98782SYitzhak Mandelbaum #define MACRO(str) NESTED(strlen((str).c_str())) 11873f1ab737SYitzhak Mandelbaum int f(string s) { return MACRO(s); } 11883f1ab737SYitzhak Mandelbaum )cc"; 11893f1ab737SYitzhak Mandelbaum std::string Expected = R"cc( 11903f1ab737SYitzhak Mandelbaum #define NESTED(e) e 11913f1ab737SYitzhak Mandelbaum #define MACRO(str) NESTED(strlen((str).c_str())) 11923f1ab737SYitzhak Mandelbaum int f(string s) { return REPLACED; } 11933f1ab737SYitzhak Mandelbaum )cc"; 11943f1ab737SYitzhak Mandelbaum 11953f1ab737SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Expected); 11963f1ab737SYitzhak Mandelbaum } 11973f1ab737SYitzhak Mandelbaum 11983f1ab737SYitzhak Mandelbaum // Tests the corner case of the identity macro, specifically that it is 11993f1ab737SYitzhak Mandelbaum // discarded in the rewrite rather than preserved (like PLUS is preserved in the 12003f1ab737SYitzhak Mandelbaum // previous test). This behavior is of dubious value (and marked with a FIXME 12013f1ab737SYitzhak Mandelbaum // in the code), but we test it to verify (and demonstrate) how this case is 12023f1ab737SYitzhak Mandelbaum // handled. 12033f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, IdentityMacro) { 12043f1ab737SYitzhak Mandelbaum std::string Input = R"cc( 12053f1ab737SYitzhak Mandelbaum #define ID(e) e 12063f1ab737SYitzhak Mandelbaum int f(string s) { return ID(strlen(s.c_str())); } 12073f1ab737SYitzhak Mandelbaum )cc"; 12083f1ab737SYitzhak Mandelbaum std::string Expected = R"cc( 12093f1ab737SYitzhak Mandelbaum #define ID(e) e 12103f1ab737SYitzhak Mandelbaum int f(string s) { return REPLACED; } 12113f1ab737SYitzhak Mandelbaum )cc"; 12123f1ab737SYitzhak Mandelbaum 12133f1ab737SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Expected); 12143f1ab737SYitzhak Mandelbaum } 12153f1ab737SYitzhak Mandelbaum 1216db24ef50SYitzhak Mandelbaum // Tests that two changes in a single macro expansion do not lead to conflicts 1217db24ef50SYitzhak Mandelbaum // in applying the changes. 1218db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) { 1219db24ef50SYitzhak Mandelbaum std::string Input = R"cc( 1220db24ef50SYitzhak Mandelbaum #define PLUS(a,b) (a) + (b) 1221db24ef50SYitzhak Mandelbaum int f() { return PLUS(3, 4); } 1222db24ef50SYitzhak Mandelbaum )cc"; 1223db24ef50SYitzhak Mandelbaum std::string Expected = R"cc( 1224db24ef50SYitzhak Mandelbaum #define PLUS(a,b) (a) + (b) 1225db24ef50SYitzhak Mandelbaum int f() { return PLUS(LIT, LIT); } 1226db24ef50SYitzhak Mandelbaum )cc"; 1227db24ef50SYitzhak Mandelbaum 12289f97480cSYitzhak Mandelbaum testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected); 1229db24ef50SYitzhak Mandelbaum } 1230db24ef50SYitzhak Mandelbaum 1231db24ef50SYitzhak Mandelbaum // Tests case where the rule's match spans both source from the macro and its 1232db24ef50SYitzhak Mandelbaum // arg, with the begin location (the "anchor") being the arg. 1233db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) { 1234db24ef50SYitzhak Mandelbaum std::string Input = R"cc( 1235db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) a + 1 1236db24ef50SYitzhak Mandelbaum int f() { return PLUS_ONE(3); } 1237db24ef50SYitzhak Mandelbaum )cc"; 1238db24ef50SYitzhak Mandelbaum std::string Expected = R"cc( 1239db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) a + 1 1240db24ef50SYitzhak Mandelbaum int f() { return PLUS_ONE(LIT); } 1241db24ef50SYitzhak Mandelbaum )cc"; 1242db24ef50SYitzhak Mandelbaum 1243db24ef50SYitzhak Mandelbaum StringRef E = "expr"; 1244db24ef50SYitzhak Mandelbaum testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))), 1245adcd0268SBenjamin Kramer changeTo(node(std::string(E)), cat("LIT"))), 1246db24ef50SYitzhak Mandelbaum Input, Expected); 1247db24ef50SYitzhak Mandelbaum } 1248db24ef50SYitzhak Mandelbaum 1249db24ef50SYitzhak Mandelbaum // Tests case where the rule's match spans both source from the macro and its 1250db24ef50SYitzhak Mandelbaum // arg, with the begin location (the "anchor") being inside the macro. 1251db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) { 1252db24ef50SYitzhak Mandelbaum std::string Input = R"cc( 1253db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) 1 + a 1254db24ef50SYitzhak Mandelbaum int f() { return PLUS_ONE(3); } 1255db24ef50SYitzhak Mandelbaum )cc"; 1256db24ef50SYitzhak Mandelbaum std::string Expected = R"cc( 1257db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) 1 + a 1258db24ef50SYitzhak Mandelbaum int f() { return PLUS_ONE(LIT); } 1259db24ef50SYitzhak Mandelbaum )cc"; 1260db24ef50SYitzhak Mandelbaum 1261db24ef50SYitzhak Mandelbaum StringRef E = "expr"; 1262db24ef50SYitzhak Mandelbaum testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))), 1263adcd0268SBenjamin Kramer changeTo(node(std::string(E)), cat("LIT"))), 1264db24ef50SYitzhak Mandelbaum Input, Expected); 1265db24ef50SYitzhak Mandelbaum } 1266db24ef50SYitzhak Mandelbaum 12673f1ab737SYitzhak Mandelbaum // No rewrite is applied when the changed text does not encompass the entirety 12683f1ab737SYitzhak Mandelbaum // of the expanded text. That is, the edit would have to be applied to the 12693f1ab737SYitzhak Mandelbaum // macro's definition to succeed and editing the expansion point would not 12703f1ab737SYitzhak Mandelbaum // suffice. 12713f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) { 12723f1ab737SYitzhak Mandelbaum std::string Input = R"cc( 12733f1ab737SYitzhak Mandelbaum #define ZERO_PLUS 0 + 3 12743f1ab737SYitzhak Mandelbaum int f(string s) { return ZERO_PLUS; })cc"; 12753f1ab737SYitzhak Mandelbaum 12763f1ab737SYitzhak Mandelbaum StringRef zero = "zero"; 12773f1ab737SYitzhak Mandelbaum RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 1278adcd0268SBenjamin Kramer changeTo(node(std::string(zero)), cat("0"))); 12793f1ab737SYitzhak Mandelbaum testRule(R, Input, Input); 12803f1ab737SYitzhak Mandelbaum } 12813f1ab737SYitzhak Mandelbaum 12823f1ab737SYitzhak Mandelbaum // This test handles the corner case where a macro expands within another macro 12833f1ab737SYitzhak Mandelbaum // to matching code, but that code is an argument to the nested macro call. A 12843f1ab737SYitzhak Mandelbaum // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get 12853f1ab737SYitzhak Mandelbaum // this wrong, and transform the code. 12863f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) { 12873f1ab737SYitzhak Mandelbaum std::string Input = R"cc( 12883f1ab737SYitzhak Mandelbaum #define NESTED(e) e 12893f1ab737SYitzhak Mandelbaum #define MACRO(str) 1 + NESTED(strlen((str).c_str())) 12903f1ab737SYitzhak Mandelbaum int f(string s) { return MACRO(s); } 12913f1ab737SYitzhak Mandelbaum )cc"; 12923f1ab737SYitzhak Mandelbaum 1293fdd98782SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Input); 1294fdd98782SYitzhak Mandelbaum } 129542b957aaSYitzhak Mandelbaum 129642b957aaSYitzhak Mandelbaum #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST 129742b957aaSYitzhak Mandelbaum // Verifies that `Type` and `QualType` are not allowed as top-level matchers in 129842b957aaSYitzhak Mandelbaum // rules. 129942b957aaSYitzhak Mandelbaum TEST(TransformerDeathTest, OrderedRuleTypes) { 13009f97480cSYitzhak Mandelbaum RewriteRule QualTypeRule = makeRule(qualType(), changeTo(cat("Q"))); 13018bb47cd8SYitzhak Mandelbaum EXPECT_DEATH(transformer::detail::buildMatchers(QualTypeRule), 130242b957aaSYitzhak Mandelbaum "Matcher must be.*node matcher"); 130342b957aaSYitzhak Mandelbaum 13049f97480cSYitzhak Mandelbaum RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T"))); 13058bb47cd8SYitzhak Mandelbaum EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule), 130642b957aaSYitzhak Mandelbaum "Matcher must be.*node matcher"); 130742b957aaSYitzhak Mandelbaum } 130842b957aaSYitzhak Mandelbaum #endif 1309ff2743bfSYitzhak Mandelbaum 1310ff2743bfSYitzhak Mandelbaum // Edits are able to span multiple files; in this case, a header and an 1311ff2743bfSYitzhak Mandelbaum // implementation file. 1312ff2743bfSYitzhak Mandelbaum TEST_F(TransformerTest, MultipleFiles) { 1313ff2743bfSYitzhak Mandelbaum std::string Header = R"cc(void RemoveThisFunction();)cc"; 1314ff2743bfSYitzhak Mandelbaum std::string Source = R"cc(#include "input.h" 1315ff2743bfSYitzhak Mandelbaum void RemoveThisFunction();)cc"; 1316ff2743bfSYitzhak Mandelbaum Transformer T( 1317ff2743bfSYitzhak Mandelbaum makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))), 1318ff2743bfSYitzhak Mandelbaum consumer()); 1319ff2743bfSYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 1320ff2743bfSYitzhak Mandelbaum auto Factory = newFrontendActionFactory(&MatchFinder); 1321ff2743bfSYitzhak Mandelbaum EXPECT_TRUE(runToolOnCodeWithArgs( 1322ff2743bfSYitzhak Mandelbaum Factory->create(), Source, std::vector<std::string>(), "input.cc", 1323ff2743bfSYitzhak Mandelbaum "clang-tool", std::make_shared<PCHContainerOperations>(), 1324ff2743bfSYitzhak Mandelbaum {{"input.h", Header}})); 1325ff2743bfSYitzhak Mandelbaum 1326ff2743bfSYitzhak Mandelbaum std::sort(Changes.begin(), Changes.end(), 1327ff2743bfSYitzhak Mandelbaum [](const AtomicChange &L, const AtomicChange &R) { 1328ff2743bfSYitzhak Mandelbaum return L.getFilePath() < R.getFilePath(); 1329ff2743bfSYitzhak Mandelbaum }); 1330ff2743bfSYitzhak Mandelbaum 1331ff2743bfSYitzhak Mandelbaum ASSERT_EQ(Changes[0].getFilePath(), "./input.h"); 1332ff2743bfSYitzhak Mandelbaum EXPECT_THAT(Changes[0].getInsertedHeaders(), IsEmpty()); 1333ff2743bfSYitzhak Mandelbaum EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty()); 1334ff2743bfSYitzhak Mandelbaum llvm::Expected<std::string> UpdatedCode = 1335ff2743bfSYitzhak Mandelbaum clang::tooling::applyAllReplacements(Header, 1336ff2743bfSYitzhak Mandelbaum Changes[0].getReplacements()); 1337ff2743bfSYitzhak Mandelbaum ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1338ff2743bfSYitzhak Mandelbaum << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1339ff2743bfSYitzhak Mandelbaum EXPECT_EQ(format(*UpdatedCode), format(R"cc(;)cc")); 1340ff2743bfSYitzhak Mandelbaum 1341ff2743bfSYitzhak Mandelbaum ASSERT_EQ(Changes[1].getFilePath(), "input.cc"); 1342ff2743bfSYitzhak Mandelbaum EXPECT_THAT(Changes[1].getInsertedHeaders(), IsEmpty()); 1343ff2743bfSYitzhak Mandelbaum EXPECT_THAT(Changes[1].getRemovedHeaders(), IsEmpty()); 1344ff2743bfSYitzhak Mandelbaum UpdatedCode = clang::tooling::applyAllReplacements( 1345ff2743bfSYitzhak Mandelbaum Source, Changes[1].getReplacements()); 1346ff2743bfSYitzhak Mandelbaum ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1347ff2743bfSYitzhak Mandelbaum << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1348ff2743bfSYitzhak Mandelbaum EXPECT_EQ(format(*UpdatedCode), format(R"cc(#include "input.h" 1349ff2743bfSYitzhak Mandelbaum ;)cc")); 1350ff2743bfSYitzhak Mandelbaum } 1351d8c1f43dSYitzhak Mandelbaum 1352d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeMultipleFiles) { 1353d8c1f43dSYitzhak Mandelbaum std::string Header = R"cc(void RemoveThisFunction();)cc"; 1354d8c1f43dSYitzhak Mandelbaum std::string Source = R"cc(#include "input.h" 1355d8c1f43dSYitzhak Mandelbaum void Foo() {RemoveThisFunction();})cc"; 1356d8c1f43dSYitzhak Mandelbaum Transformer T( 1357d8c1f43dSYitzhak Mandelbaum makeRule(callExpr(callee( 1358d8c1f43dSYitzhak Mandelbaum functionDecl(hasName("RemoveThisFunction")).bind("fun"))), 1359d8c1f43dSYitzhak Mandelbaum addInclude(node("fun"), "header.h")), 1360d8c1f43dSYitzhak Mandelbaum consumer()); 1361d8c1f43dSYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 1362d8c1f43dSYitzhak Mandelbaum auto Factory = newFrontendActionFactory(&MatchFinder); 1363d8c1f43dSYitzhak Mandelbaum EXPECT_TRUE(runToolOnCodeWithArgs( 1364d8c1f43dSYitzhak Mandelbaum Factory->create(), Source, std::vector<std::string>(), "input.cc", 1365d8c1f43dSYitzhak Mandelbaum "clang-tool", std::make_shared<PCHContainerOperations>(), 1366d8c1f43dSYitzhak Mandelbaum {{"input.h", Header}})); 1367d8c1f43dSYitzhak Mandelbaum 1368d8c1f43dSYitzhak Mandelbaum ASSERT_EQ(Changes.size(), 1U); 1369d8c1f43dSYitzhak Mandelbaum ASSERT_EQ(Changes[0].getFilePath(), "./input.h"); 1370d8c1f43dSYitzhak Mandelbaum EXPECT_THAT(Changes[0].getInsertedHeaders(), ElementsAre("header.h")); 1371d8c1f43dSYitzhak Mandelbaum EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty()); 1372d8c1f43dSYitzhak Mandelbaum llvm::Expected<std::string> UpdatedCode = 1373d8c1f43dSYitzhak Mandelbaum clang::tooling::applyAllReplacements(Header, 1374d8c1f43dSYitzhak Mandelbaum Changes[0].getReplacements()); 1375d8c1f43dSYitzhak Mandelbaum ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1376d8c1f43dSYitzhak Mandelbaum << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1377d8c1f43dSYitzhak Mandelbaum EXPECT_EQ(format(*UpdatedCode), format(Header)); 1378d8c1f43dSYitzhak Mandelbaum } 1379fdd98782SYitzhak Mandelbaum } // namespace 1380