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) { 12996ed6793SFangrui Song Transformers.push_back( 13096ed6793SFangrui Song std::make_unique<Transformer>(std::move(Rule), consumer())); 13196ed6793SFangrui Song Transformers.back()->registerMatchers(&MatchFinder); 132fdd98782SYitzhak Mandelbaum compareSnippets(Expected, rewrite(Input)); 133fdd98782SYitzhak Mandelbaum } 134fdd98782SYitzhak Mandelbaum 135246b428fSStephen Kelly template <typename R> void testRuleFailure(R Rule, StringRef Input) { 136246b428fSStephen Kelly Transformers.push_back( 137246b428fSStephen Kelly std::make_unique<Transformer>(std::move(Rule), consumer())); 138246b428fSStephen Kelly Transformers.back()->registerMatchers(&MatchFinder); 139246b428fSStephen Kelly ASSERT_FALSE(rewrite(Input)) << "Expected failure to rewrite code"; 140246b428fSStephen Kelly } 141246b428fSStephen Kelly 14296ed6793SFangrui Song // Transformers are referenced by MatchFinder. 14396ed6793SFangrui Song std::vector<std::unique_ptr<Transformer>> Transformers; 144fdd98782SYitzhak Mandelbaum clang::ast_matchers::MatchFinder MatchFinder; 145aecc59c5SYitzhak Mandelbaum // Records whether any errors occurred in individual changes. 146aecc59c5SYitzhak Mandelbaum int ErrorCount = 0; 147fdd98782SYitzhak Mandelbaum AtomicChanges Changes; 148fdd98782SYitzhak Mandelbaum 149fdd98782SYitzhak Mandelbaum private: 150fdd98782SYitzhak Mandelbaum FileContentMappings FileContents = {{"header.h", ""}}; 151fdd98782SYitzhak Mandelbaum }; 152fdd98782SYitzhak Mandelbaum 153fdd98782SYitzhak Mandelbaum class TransformerTest : public ClangRefactoringTestBase { 154fdd98782SYitzhak Mandelbaum protected: 155fdd98782SYitzhak Mandelbaum TransformerTest() { appendToHeader(KHeaderContents); } 156fdd98782SYitzhak Mandelbaum }; 157fdd98782SYitzhak Mandelbaum 1583f1ab737SYitzhak Mandelbaum // Given string s, change strlen($s.c_str()) to REPLACED. 159fdd98782SYitzhak Mandelbaum static RewriteRule ruleStrlenSize() { 160fdd98782SYitzhak Mandelbaum StringRef StringExpr = "strexpr"; 161fdd98782SYitzhak Mandelbaum auto StringType = namedDecl(hasAnyName("::basic_string", "::string")); 162fa1552e8SYitzhak Mandelbaum auto R = makeRule( 163fa1552e8SYitzhak Mandelbaum callExpr(callee(functionDecl(hasName("strlen"))), 164fdd98782SYitzhak Mandelbaum hasArgument(0, cxxMemberCallExpr( 165fdd98782SYitzhak Mandelbaum on(expr(hasType(isOrPointsTo(StringType))) 166fdd98782SYitzhak Mandelbaum .bind(StringExpr)), 167fa1552e8SYitzhak Mandelbaum callee(cxxMethodDecl(hasName("c_str")))))), 1689f97480cSYitzhak Mandelbaum changeTo(cat("REPLACED")), cat("Use size() method directly on string.")); 169fa1552e8SYitzhak Mandelbaum return R; 170fdd98782SYitzhak Mandelbaum } 171fdd98782SYitzhak Mandelbaum 172fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, StrlenSize) { 173fdd98782SYitzhak Mandelbaum std::string Input = "int f(string s) { return strlen(s.c_str()); }"; 174fdd98782SYitzhak Mandelbaum std::string Expected = "int f(string s) { return REPLACED; }"; 175fdd98782SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Expected); 176fdd98782SYitzhak Mandelbaum } 177fdd98782SYitzhak Mandelbaum 178fdd98782SYitzhak Mandelbaum // Tests that no change is applied when a match is not expected. 179fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NoMatch) { 180fdd98782SYitzhak Mandelbaum std::string Input = "int f(string s) { return s.size(); }"; 181fdd98782SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Input); 182fdd98782SYitzhak Mandelbaum } 183fdd98782SYitzhak Mandelbaum 184fdd98782SYitzhak Mandelbaum // Tests replacing an expression. 185fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, Flag) { 186fdd98782SYitzhak Mandelbaum StringRef Flag = "flag"; 187fa1552e8SYitzhak Mandelbaum RewriteRule Rule = makeRule( 188fa1552e8SYitzhak Mandelbaum cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( 189fa1552e8SYitzhak Mandelbaum hasName("proto::ProtoCommandLineFlag")))) 190fdd98782SYitzhak Mandelbaum .bind(Flag)), 191fa1552e8SYitzhak Mandelbaum unless(callee(cxxMethodDecl(hasName("GetProto"))))), 192adcd0268SBenjamin Kramer changeTo(node(std::string(Flag)), cat("EXPR"))); 193fdd98782SYitzhak Mandelbaum 194fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 195fdd98782SYitzhak Mandelbaum proto::ProtoCommandLineFlag flag; 196fdd98782SYitzhak Mandelbaum int x = flag.foo(); 197fdd98782SYitzhak Mandelbaum int y = flag.GetProto().foo(); 198fdd98782SYitzhak Mandelbaum )cc"; 199fdd98782SYitzhak Mandelbaum std::string Expected = R"cc( 200fdd98782SYitzhak Mandelbaum proto::ProtoCommandLineFlag flag; 201fdd98782SYitzhak Mandelbaum int x = EXPR.foo(); 202fdd98782SYitzhak Mandelbaum int y = flag.GetProto().foo(); 203fdd98782SYitzhak Mandelbaum )cc"; 204fdd98782SYitzhak Mandelbaum 205fdd98782SYitzhak Mandelbaum testRule(std::move(Rule), Input, Expected); 206fdd98782SYitzhak Mandelbaum } 207fdd98782SYitzhak Mandelbaum 208727bdcb2SYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeQuoted) { 209d8c1f43dSYitzhak Mandelbaum RewriteRule Rule = 210d8c1f43dSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasName("f")))), 211d8c1f43dSYitzhak Mandelbaum {addInclude("clang/OtherLib.h"), changeTo(cat("other()"))}); 212d8c1f43dSYitzhak Mandelbaum 213d8c1f43dSYitzhak Mandelbaum std::string Input = R"cc( 214d8c1f43dSYitzhak Mandelbaum int f(int x); 215d8c1f43dSYitzhak Mandelbaum int h(int x) { return f(x); } 216d8c1f43dSYitzhak Mandelbaum )cc"; 217d8c1f43dSYitzhak Mandelbaum std::string Expected = R"cc(#include "clang/OtherLib.h" 218d8c1f43dSYitzhak Mandelbaum 219d8c1f43dSYitzhak Mandelbaum int f(int x); 220d8c1f43dSYitzhak Mandelbaum int h(int x) { return other(); } 221d8c1f43dSYitzhak Mandelbaum )cc"; 222d8c1f43dSYitzhak Mandelbaum 223d8c1f43dSYitzhak Mandelbaum testRule(Rule, Input, Expected); 224d8c1f43dSYitzhak Mandelbaum } 225d8c1f43dSYitzhak Mandelbaum 226d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeAngled) { 227d8c1f43dSYitzhak Mandelbaum RewriteRule Rule = makeRule( 228d8c1f43dSYitzhak Mandelbaum callExpr(callee(functionDecl(hasName("f")))), 229d8c1f43dSYitzhak Mandelbaum {addInclude("clang/OtherLib.h", transformer::IncludeFormat::Angled), 230d8c1f43dSYitzhak Mandelbaum changeTo(cat("other()"))}); 231d8c1f43dSYitzhak Mandelbaum 232d8c1f43dSYitzhak Mandelbaum std::string Input = R"cc( 233d8c1f43dSYitzhak Mandelbaum int f(int x); 234d8c1f43dSYitzhak Mandelbaum int h(int x) { return f(x); } 235d8c1f43dSYitzhak Mandelbaum )cc"; 236d8c1f43dSYitzhak Mandelbaum std::string Expected = R"cc(#include <clang/OtherLib.h> 237d8c1f43dSYitzhak Mandelbaum 238d8c1f43dSYitzhak Mandelbaum int f(int x); 239d8c1f43dSYitzhak Mandelbaum int h(int x) { return other(); } 240d8c1f43dSYitzhak Mandelbaum )cc"; 241d8c1f43dSYitzhak Mandelbaum 242d8c1f43dSYitzhak Mandelbaum testRule(Rule, Input, Expected); 243d8c1f43dSYitzhak Mandelbaum } 244d8c1f43dSYitzhak Mandelbaum 245d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeQuotedForRule) { 246727bdcb2SYitzhak Mandelbaum RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))), 2479f97480cSYitzhak Mandelbaum changeTo(cat("other()"))); 248727bdcb2SYitzhak Mandelbaum addInclude(Rule, "clang/OtherLib.h"); 249727bdcb2SYitzhak Mandelbaum 250727bdcb2SYitzhak Mandelbaum std::string Input = R"cc( 251727bdcb2SYitzhak Mandelbaum int f(int x); 252727bdcb2SYitzhak Mandelbaum int h(int x) { return f(x); } 253727bdcb2SYitzhak Mandelbaum )cc"; 254727bdcb2SYitzhak Mandelbaum std::string Expected = R"cc(#include "clang/OtherLib.h" 255727bdcb2SYitzhak Mandelbaum 256727bdcb2SYitzhak Mandelbaum int f(int x); 257727bdcb2SYitzhak Mandelbaum int h(int x) { return other(); } 258727bdcb2SYitzhak Mandelbaum )cc"; 259727bdcb2SYitzhak Mandelbaum 260727bdcb2SYitzhak Mandelbaum testRule(Rule, Input, Expected); 261727bdcb2SYitzhak Mandelbaum } 262727bdcb2SYitzhak Mandelbaum 263d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeAngledForRule) { 264727bdcb2SYitzhak Mandelbaum RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))), 2659f97480cSYitzhak Mandelbaum changeTo(cat("other()"))); 2668bb47cd8SYitzhak Mandelbaum addInclude(Rule, "clang/OtherLib.h", transformer::IncludeFormat::Angled); 267727bdcb2SYitzhak Mandelbaum 268727bdcb2SYitzhak Mandelbaum std::string Input = R"cc( 269727bdcb2SYitzhak Mandelbaum int f(int x); 270727bdcb2SYitzhak Mandelbaum int h(int x) { return f(x); } 271727bdcb2SYitzhak Mandelbaum )cc"; 272727bdcb2SYitzhak Mandelbaum std::string Expected = R"cc(#include <clang/OtherLib.h> 273727bdcb2SYitzhak Mandelbaum 274727bdcb2SYitzhak Mandelbaum int f(int x); 275727bdcb2SYitzhak Mandelbaum int h(int x) { return other(); } 276727bdcb2SYitzhak Mandelbaum )cc"; 277727bdcb2SYitzhak Mandelbaum 278727bdcb2SYitzhak Mandelbaum testRule(Rule, Input, Expected); 279727bdcb2SYitzhak Mandelbaum } 280727bdcb2SYitzhak Mandelbaum 281fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameNamedDecl) { 282fdd98782SYitzhak Mandelbaum StringRef Fun = "fun"; 2833ec50e29SYitzhak Mandelbaum RewriteRule Rule = makeRule(functionDecl(hasName("bad")).bind(Fun), 284adcd0268SBenjamin Kramer changeTo(name(std::string(Fun)), cat("good"))); 285fdd98782SYitzhak Mandelbaum 286fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 287fdd98782SYitzhak Mandelbaum int bad(int x); 288fdd98782SYitzhak Mandelbaum int bad(int x) { return x * x; } 289fdd98782SYitzhak Mandelbaum )cc"; 290fdd98782SYitzhak Mandelbaum std::string Expected = R"cc( 291fdd98782SYitzhak Mandelbaum int good(int x); 292fdd98782SYitzhak Mandelbaum int good(int x) { return x * x; } 293fdd98782SYitzhak Mandelbaum )cc"; 294fdd98782SYitzhak Mandelbaum 295fdd98782SYitzhak Mandelbaum testRule(Rule, Input, Expected); 296fdd98782SYitzhak Mandelbaum } 297fdd98782SYitzhak Mandelbaum 298fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameDeclRef) { 299fdd98782SYitzhak Mandelbaum std::string Input = 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 bad<int>(x) * x; } 305fdd98782SYitzhak Mandelbaum )cc"; 306fdd98782SYitzhak Mandelbaum std::string Expected = R"cc( 307fdd98782SYitzhak Mandelbaum template <typename T> 308fdd98782SYitzhak Mandelbaum T bad(T x) { 309fdd98782SYitzhak Mandelbaum return x; 310fdd98782SYitzhak Mandelbaum } 311fdd98782SYitzhak Mandelbaum int neutral(int x) { return good<int>(x) * x; } 312fdd98782SYitzhak Mandelbaum )cc"; 313fdd98782SYitzhak Mandelbaum 314fdd98782SYitzhak Mandelbaum StringRef Ref = "ref"; 315fa1552e8SYitzhak Mandelbaum testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref), 316adcd0268SBenjamin Kramer changeTo(name(std::string(Ref)), cat("good"))), 317fdd98782SYitzhak Mandelbaum Input, Expected); 318fdd98782SYitzhak Mandelbaum } 319fdd98782SYitzhak Mandelbaum 320fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameDeclRefFailure) { 321fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 322fdd98782SYitzhak Mandelbaum struct Y { 323fdd98782SYitzhak Mandelbaum int operator*(); 324fdd98782SYitzhak Mandelbaum }; 325fdd98782SYitzhak Mandelbaum int neutral(int x) { 326fdd98782SYitzhak Mandelbaum Y y; 327fdd98782SYitzhak Mandelbaum int (Y::*ptr)() = &Y::operator*; 328fdd98782SYitzhak Mandelbaum return *y + x; 329fdd98782SYitzhak Mandelbaum } 330fdd98782SYitzhak Mandelbaum )cc"; 331fdd98782SYitzhak Mandelbaum 332fdd98782SYitzhak Mandelbaum StringRef Ref = "ref"; 333a5dadbe1SYitzhak Mandelbaum Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref), 334adcd0268SBenjamin Kramer changeTo(name(std::string(Ref)), cat("good"))), 335a5dadbe1SYitzhak Mandelbaum consumer()); 336a5dadbe1SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 337a5dadbe1SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 338fdd98782SYitzhak Mandelbaum } 339fdd98782SYitzhak Mandelbaum 340fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMember) { 341fdd98782SYitzhak Mandelbaum StringRef E = "expr"; 342fa1552e8SYitzhak Mandelbaum RewriteRule Rule = makeRule(memberExpr(member(hasName("bad"))).bind(E), 343adcd0268SBenjamin Kramer changeTo(member(std::string(E)), cat("good"))); 344fdd98782SYitzhak Mandelbaum 345fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 346fdd98782SYitzhak Mandelbaum struct S { 347fdd98782SYitzhak Mandelbaum int bad; 348fdd98782SYitzhak Mandelbaum }; 349fdd98782SYitzhak Mandelbaum int g() { 350fdd98782SYitzhak Mandelbaum S s; 351fdd98782SYitzhak Mandelbaum return s.bad; 352fdd98782SYitzhak Mandelbaum } 353fdd98782SYitzhak Mandelbaum )cc"; 354fdd98782SYitzhak Mandelbaum std::string Expected = R"cc( 355fdd98782SYitzhak Mandelbaum struct S { 356fdd98782SYitzhak Mandelbaum int bad; 357fdd98782SYitzhak Mandelbaum }; 358fdd98782SYitzhak Mandelbaum int g() { 359fdd98782SYitzhak Mandelbaum S s; 360fdd98782SYitzhak Mandelbaum return s.good; 361fdd98782SYitzhak Mandelbaum } 362fdd98782SYitzhak Mandelbaum )cc"; 363fdd98782SYitzhak Mandelbaum 364fdd98782SYitzhak Mandelbaum testRule(Rule, Input, Expected); 365fdd98782SYitzhak Mandelbaum } 366fdd98782SYitzhak Mandelbaum 367fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMemberQualified) { 368fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 369fdd98782SYitzhak Mandelbaum struct S { 370fdd98782SYitzhak Mandelbaum int bad; 371fdd98782SYitzhak Mandelbaum int good; 372fdd98782SYitzhak Mandelbaum }; 373fdd98782SYitzhak Mandelbaum struct T : public S { 374fdd98782SYitzhak Mandelbaum int bad; 375fdd98782SYitzhak Mandelbaum }; 376fdd98782SYitzhak Mandelbaum int g() { 377fdd98782SYitzhak Mandelbaum T t; 378fdd98782SYitzhak Mandelbaum return t.S::bad; 379fdd98782SYitzhak Mandelbaum } 380fdd98782SYitzhak Mandelbaum )cc"; 381fdd98782SYitzhak Mandelbaum std::string Expected = R"cc( 382fdd98782SYitzhak Mandelbaum struct S { 383fdd98782SYitzhak Mandelbaum int bad; 384fdd98782SYitzhak Mandelbaum int good; 385fdd98782SYitzhak Mandelbaum }; 386fdd98782SYitzhak Mandelbaum struct T : public S { 387fdd98782SYitzhak Mandelbaum int bad; 388fdd98782SYitzhak Mandelbaum }; 389fdd98782SYitzhak Mandelbaum int g() { 390fdd98782SYitzhak Mandelbaum T t; 391fdd98782SYitzhak Mandelbaum return t.S::good; 392fdd98782SYitzhak Mandelbaum } 393fdd98782SYitzhak Mandelbaum )cc"; 394fdd98782SYitzhak Mandelbaum 395fdd98782SYitzhak Mandelbaum StringRef E = "expr"; 396adcd0268SBenjamin Kramer testRule(makeRule(memberExpr().bind(E), 397adcd0268SBenjamin Kramer changeTo(member(std::string(E)), cat("good"))), 398fdd98782SYitzhak Mandelbaum Input, Expected); 399fdd98782SYitzhak Mandelbaum } 400fdd98782SYitzhak Mandelbaum 401fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMemberMultiToken) { 402fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 403fdd98782SYitzhak Mandelbaum struct Y { 404fdd98782SYitzhak Mandelbaum int operator*(); 405fdd98782SYitzhak Mandelbaum int good(); 406fdd98782SYitzhak Mandelbaum template <typename T> void foo(T t); 407fdd98782SYitzhak Mandelbaum }; 408fdd98782SYitzhak Mandelbaum int neutral(int x) { 409fdd98782SYitzhak Mandelbaum Y y; 410fdd98782SYitzhak Mandelbaum y.template foo<int>(3); 411fdd98782SYitzhak Mandelbaum return y.operator *(); 412fdd98782SYitzhak Mandelbaum } 413fdd98782SYitzhak Mandelbaum )cc"; 414fdd98782SYitzhak Mandelbaum std::string Expected = R"cc( 415fdd98782SYitzhak Mandelbaum struct Y { 416fdd98782SYitzhak Mandelbaum int operator*(); 417fdd98782SYitzhak Mandelbaum int good(); 418fdd98782SYitzhak Mandelbaum template <typename T> void foo(T t); 419fdd98782SYitzhak Mandelbaum }; 420fdd98782SYitzhak Mandelbaum int neutral(int x) { 421fdd98782SYitzhak Mandelbaum Y y; 422fdd98782SYitzhak Mandelbaum y.template good<int>(3); 423fdd98782SYitzhak Mandelbaum return y.good(); 424fdd98782SYitzhak Mandelbaum } 425fdd98782SYitzhak Mandelbaum )cc"; 426fdd98782SYitzhak Mandelbaum 427fdd98782SYitzhak Mandelbaum StringRef MemExpr = "member"; 428fa1552e8SYitzhak Mandelbaum testRule(makeRule(memberExpr().bind(MemExpr), 429adcd0268SBenjamin Kramer changeTo(member(std::string(MemExpr)), cat("good"))), 430fa1552e8SYitzhak Mandelbaum Input, Expected); 431fa1552e8SYitzhak Mandelbaum } 432fa1552e8SYitzhak Mandelbaum 433cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, NoEdits) { 434cf428778SYitzhak Mandelbaum using transformer::noEdits; 435cf428778SYitzhak Mandelbaum std::string Input = "int f(int x) { return x; }"; 436cf428778SYitzhak Mandelbaum testRule(makeRule(returnStmt().bind("return"), noEdits()), Input, Input); 437cf428778SYitzhak Mandelbaum } 438cf428778SYitzhak Mandelbaum 4396f8f5cb7SYitzhak Mandelbaum TEST_F(TransformerTest, NoopEdit) { 4406f8f5cb7SYitzhak Mandelbaum using transformer::node; 4416f8f5cb7SYitzhak Mandelbaum using transformer::noopEdit; 4426f8f5cb7SYitzhak Mandelbaum std::string Input = "int f(int x) { return x; }"; 4436f8f5cb7SYitzhak Mandelbaum testRule(makeRule(returnStmt().bind("return"), noopEdit(node("return"))), 4446f8f5cb7SYitzhak Mandelbaum Input, Input); 4456f8f5cb7SYitzhak Mandelbaum } 4466f8f5cb7SYitzhak Mandelbaum 447cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, IfBound2Args) { 448cf428778SYitzhak Mandelbaum using transformer::ifBound; 449cf428778SYitzhak Mandelbaum std::string Input = "int f(int x) { return x; }"; 450cf428778SYitzhak Mandelbaum std::string Expected = "int f(int x) { CHANGE; }"; 451cf428778SYitzhak Mandelbaum testRule(makeRule(returnStmt().bind("return"), 452cf428778SYitzhak Mandelbaum ifBound("return", changeTo(cat("CHANGE;")))), 453cf428778SYitzhak Mandelbaum Input, Expected); 454cf428778SYitzhak Mandelbaum } 455cf428778SYitzhak Mandelbaum 456cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, IfBound3Args) { 457cf428778SYitzhak Mandelbaum using transformer::ifBound; 458cf428778SYitzhak Mandelbaum std::string Input = "int f(int x) { return x; }"; 459cf428778SYitzhak Mandelbaum std::string Expected = "int f(int x) { CHANGE; }"; 460cf428778SYitzhak Mandelbaum testRule(makeRule(returnStmt().bind("return"), 461cf428778SYitzhak Mandelbaum ifBound("nothing", changeTo(cat("ERROR")), 462cf428778SYitzhak Mandelbaum changeTo(cat("CHANGE;")))), 463cf428778SYitzhak Mandelbaum Input, Expected); 464cf428778SYitzhak Mandelbaum } 465cf428778SYitzhak Mandelbaum 466cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, ShrinkTo) { 467cf428778SYitzhak Mandelbaum using transformer::shrinkTo; 468cf428778SYitzhak Mandelbaum std::string Input = "int f(int x) { return x; }"; 469cf428778SYitzhak Mandelbaum std::string Expected = "return x;"; 470cf428778SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasDescendant(returnStmt().bind("return"))) 471cf428778SYitzhak Mandelbaum .bind("function"), 472cf428778SYitzhak Mandelbaum shrinkTo(node("function"), node("return"))), 473cf428778SYitzhak Mandelbaum Input, Expected); 474cf428778SYitzhak Mandelbaum } 475cf428778SYitzhak Mandelbaum 476c332a984SYitzhak Mandelbaum // Rewrite various Stmts inside a Decl. 477c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsDeclChangeStmt) { 478c332a984SYitzhak Mandelbaum std::string Input = 479c332a984SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 480c332a984SYitzhak Mandelbaum std::string Expected = 481c332a984SYitzhak Mandelbaum "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 482c332a984SYitzhak Mandelbaum auto InlineX = 483c332a984SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 484c332a984SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasName("f")).bind("fun"), 485c332a984SYitzhak Mandelbaum rewriteDescendants("fun", InlineX)), 486c332a984SYitzhak Mandelbaum Input, Expected); 487c332a984SYitzhak Mandelbaum } 488c332a984SYitzhak Mandelbaum 489c332a984SYitzhak Mandelbaum // Rewrite various TypeLocs inside a Decl. 490c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsDeclChangeTypeLoc) { 491c332a984SYitzhak Mandelbaum std::string Input = "int f(int *x) { return *x; }"; 492c332a984SYitzhak Mandelbaum std::string Expected = "char f(char *x) { return *x; }"; 493c332a984SYitzhak Mandelbaum auto IntToChar = makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))), 494c332a984SYitzhak Mandelbaum changeTo(cat("char"))); 495c332a984SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasName("f")).bind("fun"), 496c332a984SYitzhak Mandelbaum rewriteDescendants("fun", IntToChar)), 497c332a984SYitzhak Mandelbaum Input, Expected); 498c332a984SYitzhak Mandelbaum } 499c332a984SYitzhak Mandelbaum 500c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsStmt) { 501c332a984SYitzhak Mandelbaum // Add an unrelated definition to the header that also has a variable named 502c332a984SYitzhak Mandelbaum // "x", to test that the rewrite is limited to the scope we intend. 503c332a984SYitzhak Mandelbaum appendToHeader(R"cc(int g(int x) { return x; })cc"); 504c332a984SYitzhak Mandelbaum std::string Input = 505c332a984SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 506c332a984SYitzhak Mandelbaum std::string Expected = 507c332a984SYitzhak Mandelbaum "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 508c332a984SYitzhak Mandelbaum auto InlineX = 509c332a984SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 510c332a984SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))), 511c332a984SYitzhak Mandelbaum rewriteDescendants("body", InlineX)), 512c332a984SYitzhak Mandelbaum Input, Expected); 513c332a984SYitzhak Mandelbaum } 514c332a984SYitzhak Mandelbaum 515c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsStmtWithAdditionalChange) { 516c332a984SYitzhak Mandelbaum std::string Input = 517c332a984SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 518c332a984SYitzhak Mandelbaum std::string Expected = 519c332a984SYitzhak Mandelbaum "int newName(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 520c332a984SYitzhak Mandelbaum auto InlineX = 521c332a984SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 522c332a984SYitzhak Mandelbaum testRule( 523c332a984SYitzhak Mandelbaum makeRule( 524c332a984SYitzhak Mandelbaum functionDecl(hasName("f"), hasBody(stmt().bind("body"))).bind("f"), 525c332a984SYitzhak Mandelbaum flatten(changeTo(name("f"), cat("newName")), 526c332a984SYitzhak Mandelbaum rewriteDescendants("body", InlineX))), 527c332a984SYitzhak Mandelbaum Input, Expected); 528c332a984SYitzhak Mandelbaum } 529c332a984SYitzhak Mandelbaum 530c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypeLoc) { 531c332a984SYitzhak Mandelbaum std::string Input = "int f(int *x) { return *x; }"; 532c332a984SYitzhak Mandelbaum std::string Expected = "int f(char *x) { return *x; }"; 533c332a984SYitzhak Mandelbaum auto IntToChar = 534c332a984SYitzhak Mandelbaum makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"), 535c332a984SYitzhak Mandelbaum changeTo(cat("char"))); 536c332a984SYitzhak Mandelbaum testRule( 537c332a984SYitzhak Mandelbaum makeRule(functionDecl(hasName("f"), 538c332a984SYitzhak Mandelbaum hasParameter(0, varDecl(hasTypeLoc( 539c332a984SYitzhak Mandelbaum typeLoc().bind("parmType"))))), 540c332a984SYitzhak Mandelbaum rewriteDescendants("parmType", IntToChar)), 541c332a984SYitzhak Mandelbaum Input, Expected); 542c332a984SYitzhak Mandelbaum } 543c332a984SYitzhak Mandelbaum 544c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsReferToParentBinding) { 545c332a984SYitzhak Mandelbaum std::string Input = 546c332a984SYitzhak Mandelbaum "int f(int p) { int y = p; { int z = p * p; } return p; }"; 547c332a984SYitzhak Mandelbaum std::string Expected = 548c332a984SYitzhak Mandelbaum "int f(int p) { int y = 3; { int z = 3 * 3; } return 3; }"; 549c332a984SYitzhak Mandelbaum std::string VarId = "var"; 550c332a984SYitzhak Mandelbaum auto InlineVar = makeRule(declRefExpr(to(varDecl(equalsBoundNode(VarId)))), 551c332a984SYitzhak Mandelbaum changeTo(cat("3"))); 552c332a984SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasName("f"), 553c332a984SYitzhak Mandelbaum hasParameter(0, varDecl().bind(VarId))) 554c332a984SYitzhak Mandelbaum .bind("fun"), 555c332a984SYitzhak Mandelbaum rewriteDescendants("fun", InlineVar)), 556c332a984SYitzhak Mandelbaum Input, Expected); 557c332a984SYitzhak Mandelbaum } 558c332a984SYitzhak Mandelbaum 559c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsUnboundNode) { 560c332a984SYitzhak Mandelbaum std::string Input = 561c332a984SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 562c332a984SYitzhak Mandelbaum auto InlineX = 563c332a984SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 564c332a984SYitzhak Mandelbaum Transformer T(makeRule(functionDecl(hasName("f")), 565c332a984SYitzhak Mandelbaum rewriteDescendants("UNBOUND", InlineX)), 566c332a984SYitzhak Mandelbaum consumer()); 567c332a984SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 568c332a984SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 569c332a984SYitzhak Mandelbaum EXPECT_THAT(Changes, IsEmpty()); 570c332a984SYitzhak Mandelbaum EXPECT_EQ(ErrorCount, 1); 571c332a984SYitzhak Mandelbaum } 572c332a984SYitzhak Mandelbaum 573c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsInvalidNodeType) { 574c332a984SYitzhak Mandelbaum std::string Input = 575c332a984SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 576c332a984SYitzhak Mandelbaum auto IntToChar = 577c332a984SYitzhak Mandelbaum makeRule(qualType(isInteger(), builtinType()), changeTo(cat("char"))); 578c332a984SYitzhak Mandelbaum Transformer T( 579c332a984SYitzhak Mandelbaum makeRule(functionDecl( 580c332a984SYitzhak Mandelbaum hasName("f"), 581c332a984SYitzhak Mandelbaum hasParameter(0, varDecl(hasType(qualType().bind("type"))))), 582c332a984SYitzhak Mandelbaum rewriteDescendants("type", IntToChar)), 583c332a984SYitzhak Mandelbaum consumer()); 584c332a984SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 585c332a984SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 586c332a984SYitzhak Mandelbaum EXPECT_THAT(Changes, IsEmpty()); 587c332a984SYitzhak Mandelbaum EXPECT_EQ(ErrorCount, 1); 588c332a984SYitzhak Mandelbaum } 589c332a984SYitzhak Mandelbaum 590d4f39031SYitzhak Mandelbaum // 591d4f39031SYitzhak Mandelbaum // We include one test per typed overload. We don't test extensively since that 592d4f39031SYitzhak Mandelbaum // is already covered by the tests above. 593d4f39031SYitzhak Mandelbaum // 594d4f39031SYitzhak Mandelbaum 595d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedStmt) { 596d4f39031SYitzhak Mandelbaum // Add an unrelated definition to the header that also has a variable named 597d4f39031SYitzhak Mandelbaum // "x", to test that the rewrite is limited to the scope we intend. 598d4f39031SYitzhak Mandelbaum appendToHeader(R"cc(int g(int x) { return x; })cc"); 599d4f39031SYitzhak Mandelbaum std::string Input = 600d4f39031SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 601d4f39031SYitzhak Mandelbaum std::string Expected = 602d4f39031SYitzhak Mandelbaum "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 603d4f39031SYitzhak Mandelbaum auto InlineX = 604d4f39031SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 605d4f39031SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))), 606d4f39031SYitzhak Mandelbaum [&InlineX](const MatchFinder::MatchResult &R) { 607d4f39031SYitzhak Mandelbaum const auto *Node = R.Nodes.getNodeAs<Stmt>("body"); 608d4f39031SYitzhak Mandelbaum assert(Node != nullptr && "body must be bound"); 609d4f39031SYitzhak Mandelbaum return transformer::detail::rewriteDescendants( 610d4f39031SYitzhak Mandelbaum *Node, InlineX, R); 611d4f39031SYitzhak Mandelbaum }), 612d4f39031SYitzhak Mandelbaum Input, Expected); 613d4f39031SYitzhak Mandelbaum } 614d4f39031SYitzhak Mandelbaum 615d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedDecl) { 616d4f39031SYitzhak Mandelbaum std::string Input = 617d4f39031SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 618d4f39031SYitzhak Mandelbaum std::string Expected = 619d4f39031SYitzhak Mandelbaum "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 620d4f39031SYitzhak Mandelbaum auto InlineX = 621d4f39031SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 622d4f39031SYitzhak Mandelbaum testRule(makeRule(functionDecl(hasName("f")).bind("fun"), 623d4f39031SYitzhak Mandelbaum [&InlineX](const MatchFinder::MatchResult &R) { 624d4f39031SYitzhak Mandelbaum const auto *Node = R.Nodes.getNodeAs<Decl>("fun"); 625d4f39031SYitzhak Mandelbaum assert(Node != nullptr && "fun must be bound"); 626d4f39031SYitzhak Mandelbaum return transformer::detail::rewriteDescendants( 627d4f39031SYitzhak Mandelbaum *Node, InlineX, R); 628d4f39031SYitzhak Mandelbaum }), 629d4f39031SYitzhak Mandelbaum Input, Expected); 630d4f39031SYitzhak Mandelbaum } 631d4f39031SYitzhak Mandelbaum 632d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedTypeLoc) { 633d4f39031SYitzhak Mandelbaum std::string Input = "int f(int *x) { return *x; }"; 634d4f39031SYitzhak Mandelbaum std::string Expected = "int f(char *x) { return *x; }"; 635d4f39031SYitzhak Mandelbaum auto IntToChar = 636d4f39031SYitzhak Mandelbaum makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"), 637d4f39031SYitzhak Mandelbaum changeTo(cat("char"))); 638d4f39031SYitzhak Mandelbaum testRule( 639d4f39031SYitzhak Mandelbaum makeRule( 640d4f39031SYitzhak Mandelbaum functionDecl( 641d4f39031SYitzhak Mandelbaum hasName("f"), 642d4f39031SYitzhak Mandelbaum hasParameter(0, varDecl(hasTypeLoc(typeLoc().bind("parmType"))))), 643d4f39031SYitzhak Mandelbaum [&IntToChar](const MatchFinder::MatchResult &R) { 644d4f39031SYitzhak Mandelbaum const auto *Node = R.Nodes.getNodeAs<TypeLoc>("parmType"); 645d4f39031SYitzhak Mandelbaum assert(Node != nullptr && "parmType must be bound"); 646d4f39031SYitzhak Mandelbaum return transformer::detail::rewriteDescendants(*Node, IntToChar, R); 647d4f39031SYitzhak Mandelbaum }), 648d4f39031SYitzhak Mandelbaum Input, Expected); 649d4f39031SYitzhak Mandelbaum } 650d4f39031SYitzhak Mandelbaum 651d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedDynTyped) { 652d4f39031SYitzhak Mandelbaum // Add an unrelated definition to the header that also has a variable named 653d4f39031SYitzhak Mandelbaum // "x", to test that the rewrite is limited to the scope we intend. 654d4f39031SYitzhak Mandelbaum appendToHeader(R"cc(int g(int x) { return x; })cc"); 655d4f39031SYitzhak Mandelbaum std::string Input = 656d4f39031SYitzhak Mandelbaum "int f(int x) { int y = x; { int z = x * x; } return x; }"; 657d4f39031SYitzhak Mandelbaum std::string Expected = 658d4f39031SYitzhak Mandelbaum "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 659d4f39031SYitzhak Mandelbaum auto InlineX = 660d4f39031SYitzhak Mandelbaum makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 661d4f39031SYitzhak Mandelbaum testRule( 662d4f39031SYitzhak Mandelbaum makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))), 663d4f39031SYitzhak Mandelbaum [&InlineX](const MatchFinder::MatchResult &R) { 664d4f39031SYitzhak Mandelbaum auto It = R.Nodes.getMap().find("body"); 665d4f39031SYitzhak Mandelbaum assert(It != R.Nodes.getMap().end() && "body must be bound"); 666d4f39031SYitzhak Mandelbaum return transformer::detail::rewriteDescendants(It->second, 667d4f39031SYitzhak Mandelbaum InlineX, R); 668d4f39031SYitzhak Mandelbaum }), 669d4f39031SYitzhak Mandelbaum Input, Expected); 670d4f39031SYitzhak Mandelbaum } 671d4f39031SYitzhak Mandelbaum 6722e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, InsertBeforeEdit) { 6732e4a628cSYitzhak Mandelbaum std::string Input = R"cc( 6742e4a628cSYitzhak Mandelbaum int f() { 6752e4a628cSYitzhak Mandelbaum return 7; 6762e4a628cSYitzhak Mandelbaum } 6772e4a628cSYitzhak Mandelbaum )cc"; 6782e4a628cSYitzhak Mandelbaum std::string Expected = R"cc( 6792e4a628cSYitzhak Mandelbaum int f() { 6802e4a628cSYitzhak Mandelbaum int y = 3; 6812e4a628cSYitzhak Mandelbaum return 7; 6822e4a628cSYitzhak Mandelbaum } 6832e4a628cSYitzhak Mandelbaum )cc"; 6842e4a628cSYitzhak Mandelbaum 6852e4a628cSYitzhak Mandelbaum StringRef Ret = "return"; 686adcd0268SBenjamin Kramer testRule( 687adcd0268SBenjamin Kramer makeRule(returnStmt().bind(Ret), 688adcd0268SBenjamin Kramer insertBefore(statement(std::string(Ret)), cat("int y = 3;"))), 6892e4a628cSYitzhak Mandelbaum Input, Expected); 6902e4a628cSYitzhak Mandelbaum } 6912e4a628cSYitzhak Mandelbaum 6922e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, InsertAfterEdit) { 6932e4a628cSYitzhak Mandelbaum std::string Input = R"cc( 6942e4a628cSYitzhak Mandelbaum int f() { 6952e4a628cSYitzhak Mandelbaum int x = 5; 6962e4a628cSYitzhak Mandelbaum return 7; 6972e4a628cSYitzhak Mandelbaum } 6982e4a628cSYitzhak Mandelbaum )cc"; 6992e4a628cSYitzhak Mandelbaum std::string Expected = R"cc( 7002e4a628cSYitzhak Mandelbaum int f() { 7012e4a628cSYitzhak Mandelbaum int x = 5; 7022e4a628cSYitzhak Mandelbaum int y = 3; 7032e4a628cSYitzhak Mandelbaum return 7; 7042e4a628cSYitzhak Mandelbaum } 7052e4a628cSYitzhak Mandelbaum )cc"; 7062e4a628cSYitzhak Mandelbaum 7072e4a628cSYitzhak Mandelbaum StringRef Decl = "decl"; 708adcd0268SBenjamin Kramer testRule( 709adcd0268SBenjamin Kramer makeRule(declStmt().bind(Decl), 710adcd0268SBenjamin Kramer insertAfter(statement(std::string(Decl)), cat("int y = 3;"))), 7112e4a628cSYitzhak Mandelbaum Input, Expected); 7122e4a628cSYitzhak Mandelbaum } 7132e4a628cSYitzhak Mandelbaum 7142e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, RemoveEdit) { 7152e4a628cSYitzhak Mandelbaum std::string Input = R"cc( 7162e4a628cSYitzhak Mandelbaum int f() { 7172e4a628cSYitzhak Mandelbaum int x = 5; 7182e4a628cSYitzhak Mandelbaum return 7; 7192e4a628cSYitzhak Mandelbaum } 7202e4a628cSYitzhak Mandelbaum )cc"; 7212e4a628cSYitzhak Mandelbaum std::string Expected = R"cc( 7222e4a628cSYitzhak Mandelbaum int f() { 7232e4a628cSYitzhak Mandelbaum return 7; 7242e4a628cSYitzhak Mandelbaum } 7252e4a628cSYitzhak Mandelbaum )cc"; 7262e4a628cSYitzhak Mandelbaum 7272e4a628cSYitzhak Mandelbaum StringRef Decl = "decl"; 728adcd0268SBenjamin Kramer testRule( 729adcd0268SBenjamin Kramer makeRule(declStmt().bind(Decl), remove(statement(std::string(Decl)))), 730adcd0268SBenjamin Kramer Input, Expected); 7312e4a628cSYitzhak Mandelbaum } 7322e4a628cSYitzhak Mandelbaum 7339945bd59SAndy Soffer TEST_F(TransformerTest, WithMetadata) { 734e5b3202bSAndy Soffer auto makeMetadata = [](const MatchFinder::MatchResult &R) -> llvm::Any { 735e5b3202bSAndy Soffer int N = 736e5b3202bSAndy Soffer R.Nodes.getNodeAs<IntegerLiteral>("int")->getValue().getLimitedValue(); 737e5b3202bSAndy Soffer return N; 738e5b3202bSAndy Soffer }; 739e5b3202bSAndy Soffer 7409945bd59SAndy Soffer std::string Input = R"cc( 7419945bd59SAndy Soffer int f() { 7429945bd59SAndy Soffer int x = 5; 7439945bd59SAndy Soffer return 7; 7449945bd59SAndy Soffer } 7459945bd59SAndy Soffer )cc"; 7469945bd59SAndy Soffer 7479945bd59SAndy Soffer Transformer T( 748e5b3202bSAndy Soffer makeRule( 749e5b3202bSAndy Soffer declStmt(containsDeclaration(0, varDecl(hasInitializer( 750e5b3202bSAndy Soffer integerLiteral().bind("int"))))) 751e5b3202bSAndy Soffer .bind("decl"), 752e5b3202bSAndy Soffer withMetadata(remove(statement(std::string("decl"))), makeMetadata)), 7539945bd59SAndy Soffer consumer()); 7549945bd59SAndy Soffer T.registerMatchers(&MatchFinder); 7559945bd59SAndy Soffer auto Factory = newFrontendActionFactory(&MatchFinder); 7569945bd59SAndy Soffer EXPECT_TRUE(runToolOnCodeWithArgs( 7579945bd59SAndy Soffer Factory->create(), Input, std::vector<std::string>(), "input.cc", 7589945bd59SAndy Soffer "clang-tool", std::make_shared<PCHContainerOperations>(), {})); 7599945bd59SAndy Soffer ASSERT_EQ(Changes.size(), 1u); 7609945bd59SAndy Soffer const llvm::Any &Metadata = Changes[0].getMetadata(); 7619945bd59SAndy Soffer ASSERT_TRUE(llvm::any_isa<int>(Metadata)); 762e5b3202bSAndy Soffer EXPECT_THAT(llvm::any_cast<int>(Metadata), 5); 7639945bd59SAndy Soffer } 7649945bd59SAndy Soffer 765fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, MultiChange) { 766fa1552e8SYitzhak Mandelbaum std::string Input = R"cc( 767fa1552e8SYitzhak Mandelbaum void foo() { 768fa1552e8SYitzhak Mandelbaum if (10 > 1.0) 769fa1552e8SYitzhak Mandelbaum log(1) << "oh no!"; 770fa1552e8SYitzhak Mandelbaum else 771fa1552e8SYitzhak Mandelbaum log(0) << "ok"; 772fa1552e8SYitzhak Mandelbaum } 773fa1552e8SYitzhak Mandelbaum )cc"; 774fa1552e8SYitzhak Mandelbaum std::string Expected = R"( 775fa1552e8SYitzhak Mandelbaum void foo() { 776fa1552e8SYitzhak Mandelbaum if (true) { /* then */ } 777fa1552e8SYitzhak Mandelbaum else { /* else */ } 778fa1552e8SYitzhak Mandelbaum } 779fa1552e8SYitzhak Mandelbaum )"; 780fa1552e8SYitzhak Mandelbaum 781fa1552e8SYitzhak Mandelbaum StringRef C = "C", T = "T", E = "E"; 782adcd0268SBenjamin Kramer testRule( 783adcd0268SBenjamin Kramer makeRule(ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)), 784adcd0268SBenjamin Kramer hasElse(stmt().bind(E))), 785adcd0268SBenjamin Kramer {changeTo(node(std::string(C)), cat("true")), 786adcd0268SBenjamin Kramer changeTo(statement(std::string(T)), cat("{ /* then */ }")), 787adcd0268SBenjamin Kramer changeTo(statement(std::string(E)), cat("{ /* else */ }"))}), 788fdd98782SYitzhak Mandelbaum Input, Expected); 789fdd98782SYitzhak Mandelbaum } 790fdd98782SYitzhak Mandelbaum 791cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, EditList) { 792cf428778SYitzhak Mandelbaum using clang::transformer::editList; 793cf428778SYitzhak Mandelbaum std::string Input = R"cc( 794cf428778SYitzhak Mandelbaum void foo() { 795cf428778SYitzhak Mandelbaum if (10 > 1.0) 796cf428778SYitzhak Mandelbaum log(1) << "oh no!"; 797cf428778SYitzhak Mandelbaum else 798cf428778SYitzhak Mandelbaum log(0) << "ok"; 799cf428778SYitzhak Mandelbaum } 800cf428778SYitzhak Mandelbaum )cc"; 801cf428778SYitzhak Mandelbaum std::string Expected = R"( 802cf428778SYitzhak Mandelbaum void foo() { 803cf428778SYitzhak Mandelbaum if (true) { /* then */ } 804cf428778SYitzhak Mandelbaum else { /* else */ } 805cf428778SYitzhak Mandelbaum } 806cf428778SYitzhak Mandelbaum )"; 807cf428778SYitzhak Mandelbaum 808cf428778SYitzhak Mandelbaum StringRef C = "C", T = "T", E = "E"; 809cf428778SYitzhak Mandelbaum testRule(makeRule(ifStmt(hasCondition(expr().bind(C)), 810cf428778SYitzhak Mandelbaum hasThen(stmt().bind(T)), hasElse(stmt().bind(E))), 811cf428778SYitzhak Mandelbaum editList({changeTo(node(std::string(C)), cat("true")), 812cf428778SYitzhak Mandelbaum changeTo(statement(std::string(T)), 813cf428778SYitzhak Mandelbaum cat("{ /* then */ }")), 814cf428778SYitzhak Mandelbaum changeTo(statement(std::string(E)), 815cf428778SYitzhak Mandelbaum cat("{ /* else */ }"))})), 816cf428778SYitzhak Mandelbaum Input, Expected); 817cf428778SYitzhak Mandelbaum } 818cf428778SYitzhak Mandelbaum 819cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, Flatten) { 820cf428778SYitzhak Mandelbaum using clang::transformer::editList; 821cf428778SYitzhak Mandelbaum std::string Input = R"cc( 822cf428778SYitzhak Mandelbaum void foo() { 823cf428778SYitzhak Mandelbaum if (10 > 1.0) 824cf428778SYitzhak Mandelbaum log(1) << "oh no!"; 825cf428778SYitzhak Mandelbaum else 826cf428778SYitzhak Mandelbaum log(0) << "ok"; 827cf428778SYitzhak Mandelbaum } 828cf428778SYitzhak Mandelbaum )cc"; 829cf428778SYitzhak Mandelbaum std::string Expected = R"( 830cf428778SYitzhak Mandelbaum void foo() { 831cf428778SYitzhak Mandelbaum if (true) { /* then */ } 832cf428778SYitzhak Mandelbaum else { /* else */ } 833cf428778SYitzhak Mandelbaum } 834cf428778SYitzhak Mandelbaum )"; 835cf428778SYitzhak Mandelbaum 836cf428778SYitzhak Mandelbaum StringRef C = "C", T = "T", E = "E"; 837cf428778SYitzhak Mandelbaum testRule( 838cf428778SYitzhak Mandelbaum makeRule( 839cf428778SYitzhak Mandelbaum ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)), 840cf428778SYitzhak Mandelbaum hasElse(stmt().bind(E))), 841cf428778SYitzhak Mandelbaum flatten(changeTo(node(std::string(C)), cat("true")), 842cf428778SYitzhak Mandelbaum changeTo(statement(std::string(T)), cat("{ /* then */ }")), 843cf428778SYitzhak Mandelbaum changeTo(statement(std::string(E)), cat("{ /* else */ }")))), 844cf428778SYitzhak Mandelbaum Input, Expected); 845cf428778SYitzhak Mandelbaum } 846cf428778SYitzhak Mandelbaum 847cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, FlattenWithMixedArgs) { 848cf428778SYitzhak Mandelbaum using clang::transformer::editList; 849cf428778SYitzhak Mandelbaum std::string Input = R"cc( 850cf428778SYitzhak Mandelbaum void foo() { 851cf428778SYitzhak Mandelbaum if (10 > 1.0) 852cf428778SYitzhak Mandelbaum log(1) << "oh no!"; 853cf428778SYitzhak Mandelbaum else 854cf428778SYitzhak Mandelbaum log(0) << "ok"; 855cf428778SYitzhak Mandelbaum } 856cf428778SYitzhak Mandelbaum )cc"; 857cf428778SYitzhak Mandelbaum std::string Expected = R"( 858cf428778SYitzhak Mandelbaum void foo() { 859cf428778SYitzhak Mandelbaum if (true) { /* then */ } 860cf428778SYitzhak Mandelbaum else { /* else */ } 861cf428778SYitzhak Mandelbaum } 862cf428778SYitzhak Mandelbaum )"; 863cf428778SYitzhak Mandelbaum 864cf428778SYitzhak Mandelbaum StringRef C = "C", T = "T", E = "E"; 865cf428778SYitzhak Mandelbaum testRule(makeRule(ifStmt(hasCondition(expr().bind(C)), 866cf428778SYitzhak Mandelbaum hasThen(stmt().bind(T)), hasElse(stmt().bind(E))), 867cf428778SYitzhak Mandelbaum flatten(changeTo(node(std::string(C)), cat("true")), 868cf428778SYitzhak Mandelbaum edit(changeTo(statement(std::string(T)), 869cf428778SYitzhak Mandelbaum cat("{ /* then */ }"))), 870cf428778SYitzhak Mandelbaum editList({changeTo(statement(std::string(E)), 871cf428778SYitzhak Mandelbaum cat("{ /* else */ }"))}))), 872cf428778SYitzhak Mandelbaum Input, Expected); 873cf428778SYitzhak Mandelbaum } 874cf428778SYitzhak Mandelbaum 8758369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleUnrelated) { 8768369a9beSYitzhak Mandelbaum StringRef Flag = "flag"; 8778369a9beSYitzhak Mandelbaum RewriteRule FlagRule = makeRule( 8788369a9beSYitzhak Mandelbaum cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( 8798369a9beSYitzhak Mandelbaum hasName("proto::ProtoCommandLineFlag")))) 8808369a9beSYitzhak Mandelbaum .bind(Flag)), 8818369a9beSYitzhak Mandelbaum unless(callee(cxxMethodDecl(hasName("GetProto"))))), 882adcd0268SBenjamin Kramer changeTo(node(std::string(Flag)), cat("PROTO"))); 8838369a9beSYitzhak Mandelbaum 8848369a9beSYitzhak Mandelbaum std::string Input = R"cc( 8858369a9beSYitzhak Mandelbaum proto::ProtoCommandLineFlag flag; 8868369a9beSYitzhak Mandelbaum int x = flag.foo(); 8878369a9beSYitzhak Mandelbaum int y = flag.GetProto().foo(); 8888369a9beSYitzhak Mandelbaum int f(string s) { return strlen(s.c_str()); } 8898369a9beSYitzhak Mandelbaum )cc"; 8908369a9beSYitzhak Mandelbaum std::string Expected = R"cc( 8918369a9beSYitzhak Mandelbaum proto::ProtoCommandLineFlag flag; 8928369a9beSYitzhak Mandelbaum int x = PROTO.foo(); 8938369a9beSYitzhak Mandelbaum int y = flag.GetProto().foo(); 8948369a9beSYitzhak Mandelbaum int f(string s) { return REPLACED; } 8958369a9beSYitzhak Mandelbaum )cc"; 8968369a9beSYitzhak Mandelbaum 8978369a9beSYitzhak Mandelbaum testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected); 8988369a9beSYitzhak Mandelbaum } 8998369a9beSYitzhak Mandelbaum 9008369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleRelated) { 9018369a9beSYitzhak Mandelbaum std::string Input = R"cc( 90242b957aaSYitzhak Mandelbaum void f1(); 90342b957aaSYitzhak Mandelbaum void f2(); 90442b957aaSYitzhak Mandelbaum void call_f1() { f1(); } 90542b957aaSYitzhak Mandelbaum void call_f2() { f2(); } 9068369a9beSYitzhak Mandelbaum )cc"; 9078369a9beSYitzhak Mandelbaum std::string Expected = R"cc( 90842b957aaSYitzhak Mandelbaum void f1(); 90942b957aaSYitzhak Mandelbaum void f2(); 91042b957aaSYitzhak Mandelbaum void call_f1() { REPLACE_F1; } 91142b957aaSYitzhak Mandelbaum void call_f2() { REPLACE_F1_OR_F2; } 9128369a9beSYitzhak Mandelbaum )cc"; 9138369a9beSYitzhak Mandelbaum 91442b957aaSYitzhak Mandelbaum RewriteRule ReplaceF1 = 91542b957aaSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasName("f1")))), 9169f97480cSYitzhak Mandelbaum changeTo(cat("REPLACE_F1"))); 91742b957aaSYitzhak Mandelbaum RewriteRule ReplaceF1OrF2 = 91842b957aaSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 9199f97480cSYitzhak Mandelbaum changeTo(cat("REPLACE_F1_OR_F2"))); 92042b957aaSYitzhak Mandelbaum testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected); 9218369a9beSYitzhak Mandelbaum } 9228369a9beSYitzhak Mandelbaum 92342b957aaSYitzhak Mandelbaum // Change the order of the rules to get a different result. When `ReplaceF1OrF2` 92442b957aaSYitzhak Mandelbaum // comes first, it applies for both uses, so `ReplaceF1` never applies. 9258369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleRelatedSwapped) { 9268369a9beSYitzhak Mandelbaum std::string Input = R"cc( 92742b957aaSYitzhak Mandelbaum void f1(); 92842b957aaSYitzhak Mandelbaum void f2(); 92942b957aaSYitzhak Mandelbaum void call_f1() { f1(); } 93042b957aaSYitzhak Mandelbaum void call_f2() { f2(); } 9318369a9beSYitzhak Mandelbaum )cc"; 9328369a9beSYitzhak Mandelbaum std::string Expected = R"cc( 93342b957aaSYitzhak Mandelbaum void f1(); 93442b957aaSYitzhak Mandelbaum void f2(); 93542b957aaSYitzhak Mandelbaum void call_f1() { REPLACE_F1_OR_F2; } 93642b957aaSYitzhak Mandelbaum void call_f2() { REPLACE_F1_OR_F2; } 9378369a9beSYitzhak Mandelbaum )cc"; 9388369a9beSYitzhak Mandelbaum 93942b957aaSYitzhak Mandelbaum RewriteRule ReplaceF1 = 94042b957aaSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasName("f1")))), 9419f97480cSYitzhak Mandelbaum changeTo(cat("REPLACE_F1"))); 94242b957aaSYitzhak Mandelbaum RewriteRule ReplaceF1OrF2 = 94342b957aaSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 9449f97480cSYitzhak Mandelbaum changeTo(cat("REPLACE_F1_OR_F2"))); 94542b957aaSYitzhak Mandelbaum testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected); 94642b957aaSYitzhak Mandelbaum } 94742b957aaSYitzhak Mandelbaum 94842b957aaSYitzhak Mandelbaum // Verify that a set of rules whose matchers have different base kinds works 94942b957aaSYitzhak Mandelbaum // properly, including that `applyFirst` produces multiple matchers. We test 95042b957aaSYitzhak Mandelbaum // two different kinds of rules: Expr and Decl. We place the Decl rule in the 95142b957aaSYitzhak Mandelbaum // middle to test that `buildMatchers` works even when the kinds aren't grouped 95242b957aaSYitzhak Mandelbaum // together. 95342b957aaSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleMultipleKinds) { 95442b957aaSYitzhak Mandelbaum std::string Input = R"cc( 95542b957aaSYitzhak Mandelbaum void f1(); 95642b957aaSYitzhak Mandelbaum void f2(); 95742b957aaSYitzhak Mandelbaum void call_f1() { f1(); } 95842b957aaSYitzhak Mandelbaum void call_f2() { f2(); } 95942b957aaSYitzhak Mandelbaum )cc"; 96042b957aaSYitzhak Mandelbaum std::string Expected = R"cc( 96142b957aaSYitzhak Mandelbaum void f1(); 96242b957aaSYitzhak Mandelbaum void DECL_RULE(); 96342b957aaSYitzhak Mandelbaum void call_f1() { REPLACE_F1; } 96442b957aaSYitzhak Mandelbaum void call_f2() { REPLACE_F1_OR_F2; } 96542b957aaSYitzhak Mandelbaum )cc"; 96642b957aaSYitzhak Mandelbaum 96742b957aaSYitzhak Mandelbaum RewriteRule ReplaceF1 = 96842b957aaSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasName("f1")))), 9699f97480cSYitzhak Mandelbaum changeTo(cat("REPLACE_F1"))); 97042b957aaSYitzhak Mandelbaum RewriteRule ReplaceF1OrF2 = 97142b957aaSYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 9729f97480cSYitzhak Mandelbaum changeTo(cat("REPLACE_F1_OR_F2"))); 97342b957aaSYitzhak Mandelbaum RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"), 9749f97480cSYitzhak Mandelbaum changeTo(name("fun"), cat("DECL_RULE"))); 97542b957aaSYitzhak Mandelbaum 97642b957aaSYitzhak Mandelbaum RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2}); 9778bb47cd8SYitzhak Mandelbaum EXPECT_EQ(transformer::detail::buildMatchers(Rule).size(), 2UL); 97842b957aaSYitzhak Mandelbaum testRule(Rule, Input, Expected); 9798369a9beSYitzhak Mandelbaum } 9808369a9beSYitzhak Mandelbaum 981ce5780b8SYitzhak Mandelbaum // Verifies that a rule with a top-level matcher for an implicit node (like 9826f0a3711SYitzhak Mandelbaum // `implicitCastExpr`) works correctly -- the implicit nodes are not skipped. 983ce5780b8SYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleImplicitMatched) { 984ce5780b8SYitzhak Mandelbaum std::string Input = R"cc( 985ce5780b8SYitzhak Mandelbaum void f1(); 986ce5780b8SYitzhak Mandelbaum int f2(); 987ce5780b8SYitzhak Mandelbaum void call_f1() { f1(); } 988ce5780b8SYitzhak Mandelbaum float call_f2() { return f2(); } 989ce5780b8SYitzhak Mandelbaum )cc"; 990ce5780b8SYitzhak Mandelbaum std::string Expected = R"cc( 991ce5780b8SYitzhak Mandelbaum void f1(); 992ce5780b8SYitzhak Mandelbaum int f2(); 993ce5780b8SYitzhak Mandelbaum void call_f1() { REPLACE_F1; } 994ce5780b8SYitzhak Mandelbaum float call_f2() { return REPLACE_F2; } 995ce5780b8SYitzhak Mandelbaum )cc"; 996ce5780b8SYitzhak Mandelbaum 9976f0a3711SYitzhak Mandelbaum RewriteRule ReplaceF1 = 9986f0a3711SYitzhak Mandelbaum makeRule(callExpr(callee(functionDecl(hasName("f1")))), 999ce5780b8SYitzhak Mandelbaum changeTo(cat("REPLACE_F1"))); 1000ce5780b8SYitzhak Mandelbaum RewriteRule ReplaceF2 = 10016f0a3711SYitzhak Mandelbaum makeRule(implicitCastExpr(hasSourceExpression(callExpr())), 1002ce5780b8SYitzhak Mandelbaum changeTo(cat("REPLACE_F2"))); 1003ce5780b8SYitzhak Mandelbaum testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected); 1004ce5780b8SYitzhak Mandelbaum } 1005ce5780b8SYitzhak Mandelbaum 1006fdd98782SYitzhak Mandelbaum // 1007fdd98782SYitzhak Mandelbaum // Negative tests (where we expect no transformation to occur). 1008fdd98782SYitzhak Mandelbaum // 1009fdd98782SYitzhak Mandelbaum 1010fa1552e8SYitzhak Mandelbaum // Tests for a conflict in edits from a single match for a rule. 1011aecc59c5SYitzhak Mandelbaum TEST_F(TransformerTest, TextGeneratorFailure) { 1012aecc59c5SYitzhak Mandelbaum std::string Input = "int conflictOneRule() { return 3 + 7; }"; 1013aecc59c5SYitzhak Mandelbaum // Try to change the whole binary-operator expression AND one its operands: 1014aecc59c5SYitzhak Mandelbaum StringRef O = "O"; 1015489449c2SYitzhak Mandelbaum class AlwaysFail : public transformer::MatchComputation<std::string> { 1016489449c2SYitzhak Mandelbaum llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &, 1017489449c2SYitzhak Mandelbaum std::string *) const override { 1018aecc59c5SYitzhak Mandelbaum return llvm::createStringError(llvm::errc::invalid_argument, "ERROR"); 1019489449c2SYitzhak Mandelbaum } 1020489449c2SYitzhak Mandelbaum std::string toString() const override { return "AlwaysFail"; } 1021aecc59c5SYitzhak Mandelbaum }; 1022adcd0268SBenjamin Kramer Transformer T( 1023adcd0268SBenjamin Kramer makeRule(binaryOperator().bind(O), 1024adcd0268SBenjamin Kramer changeTo(node(std::string(O)), std::make_shared<AlwaysFail>())), 1025aecc59c5SYitzhak Mandelbaum consumer()); 1026aecc59c5SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 1027aecc59c5SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 1028aecc59c5SYitzhak Mandelbaum EXPECT_THAT(Changes, IsEmpty()); 1029aecc59c5SYitzhak Mandelbaum EXPECT_EQ(ErrorCount, 1); 1030aecc59c5SYitzhak Mandelbaum } 1031aecc59c5SYitzhak Mandelbaum 1032aecc59c5SYitzhak Mandelbaum // Tests for a conflict in edits from a single match for a rule. 1033fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, OverlappingEditsInRule) { 1034fa1552e8SYitzhak Mandelbaum std::string Input = "int conflictOneRule() { return 3 + 7; }"; 1035fa1552e8SYitzhak Mandelbaum // Try to change the whole binary-operator expression AND one its operands: 1036fa1552e8SYitzhak Mandelbaum StringRef O = "O", L = "L"; 10373ec50e29SYitzhak Mandelbaum Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O), 1038adcd0268SBenjamin Kramer {changeTo(node(std::string(O)), cat("DELETE_OP")), 1039adcd0268SBenjamin Kramer changeTo(node(std::string(L)), cat("DELETE_LHS"))}), 1040aecc59c5SYitzhak Mandelbaum consumer()); 1041fa1552e8SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 1042aecc59c5SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 1043aecc59c5SYitzhak Mandelbaum EXPECT_THAT(Changes, IsEmpty()); 1044aecc59c5SYitzhak Mandelbaum EXPECT_EQ(ErrorCount, 1); 1045fa1552e8SYitzhak Mandelbaum } 1046fa1552e8SYitzhak Mandelbaum 1047fa1552e8SYitzhak Mandelbaum // Tests for a conflict in edits across multiple matches (of the same rule). 1048fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, OverlappingEditsMultipleMatches) { 1049fa1552e8SYitzhak Mandelbaum std::string Input = "int conflictOneRule() { return -7; }"; 1050fa1552e8SYitzhak Mandelbaum // Try to change the whole binary-operator expression AND one its operands: 1051fa1552e8SYitzhak Mandelbaum StringRef E = "E"; 1052adcd0268SBenjamin Kramer Transformer T(makeRule(expr().bind(E), 1053adcd0268SBenjamin Kramer changeTo(node(std::string(E)), cat("DELETE_EXPR"))), 1054aecc59c5SYitzhak Mandelbaum consumer()); 1055fa1552e8SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 1056fa1552e8SYitzhak Mandelbaum // The rewrite process fails because the changes conflict with each other... 1057fa1552e8SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 1058aecc59c5SYitzhak Mandelbaum // ... but two changes were produced. 1059aecc59c5SYitzhak Mandelbaum EXPECT_EQ(Changes.size(), 2u); 1060aecc59c5SYitzhak Mandelbaum EXPECT_EQ(ErrorCount, 0); 1061fa1552e8SYitzhak Mandelbaum } 1062fa1552e8SYitzhak Mandelbaum 1063fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, ErrorOccurredMatchSkipped) { 1064fa1552e8SYitzhak Mandelbaum // Syntax error in the function body: 1065fa1552e8SYitzhak Mandelbaum std::string Input = "void errorOccurred() { 3 }"; 1066aecc59c5SYitzhak Mandelbaum Transformer T(makeRule(functionDecl(hasName("errorOccurred")), 10679f97480cSYitzhak Mandelbaum changeTo(cat("DELETED;"))), 1068aecc59c5SYitzhak Mandelbaum consumer()); 1069fa1552e8SYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 1070fa1552e8SYitzhak Mandelbaum // The rewrite process itself fails... 1071fa1552e8SYitzhak Mandelbaum EXPECT_FALSE(rewrite(Input)); 1072aecc59c5SYitzhak Mandelbaum // ... and no changes or errors are produced in the process. 1073aecc59c5SYitzhak Mandelbaum EXPECT_THAT(Changes, IsEmpty()); 1074aecc59c5SYitzhak Mandelbaum EXPECT_EQ(ErrorCount, 0); 1075fa1552e8SYitzhak Mandelbaum } 1076fa1552e8SYitzhak Mandelbaum 1077246b428fSStephen Kelly TEST_F(TransformerTest, ImplicitNodes_ConstructorDecl) { 1078246b428fSStephen Kelly 1079246b428fSStephen Kelly std::string OtherStructPrefix = R"cpp( 1080246b428fSStephen Kelly struct Other { 1081246b428fSStephen Kelly )cpp"; 1082246b428fSStephen Kelly std::string OtherStructSuffix = "};"; 1083246b428fSStephen Kelly 1084246b428fSStephen Kelly std::string CopyableStructName = "struct Copyable"; 1085246b428fSStephen Kelly std::string BrokenStructName = "struct explicit Copyable"; 1086246b428fSStephen Kelly 1087246b428fSStephen Kelly std::string CodeSuffix = R"cpp( 1088246b428fSStephen Kelly { 1089246b428fSStephen Kelly Other m_i; 1090246b428fSStephen Kelly Copyable(); 1091246b428fSStephen Kelly }; 1092246b428fSStephen Kelly )cpp"; 1093246b428fSStephen Kelly 1094246b428fSStephen Kelly std::string CopyCtor = "Other(const Other&) = default;"; 1095246b428fSStephen Kelly std::string ExplicitCopyCtor = "explicit Other(const Other&) = default;"; 1096246b428fSStephen Kelly std::string BrokenExplicitCopyCtor = 1097246b428fSStephen Kelly "explicit explicit explicit Other(const Other&) = default;"; 1098246b428fSStephen Kelly 1099246b428fSStephen Kelly std::string RewriteInput = OtherStructPrefix + CopyCtor + OtherStructSuffix + 1100246b428fSStephen Kelly CopyableStructName + CodeSuffix; 1101246b428fSStephen Kelly std::string ExpectedRewriteOutput = OtherStructPrefix + ExplicitCopyCtor + 1102246b428fSStephen Kelly OtherStructSuffix + CopyableStructName + 1103246b428fSStephen Kelly CodeSuffix; 1104246b428fSStephen Kelly std::string BrokenRewriteOutput = OtherStructPrefix + BrokenExplicitCopyCtor + 1105246b428fSStephen Kelly OtherStructSuffix + BrokenStructName + 1106246b428fSStephen Kelly CodeSuffix; 1107246b428fSStephen Kelly 1108246b428fSStephen Kelly auto MatchedRecord = 1109246b428fSStephen Kelly cxxConstructorDecl(isCopyConstructor()).bind("copyConstructor"); 1110246b428fSStephen Kelly 1111246b428fSStephen Kelly auto RewriteRule = 1112246b428fSStephen Kelly changeTo(before(node("copyConstructor")), cat("explicit ")); 1113246b428fSStephen Kelly 1114246b428fSStephen Kelly testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord), 1115246b428fSStephen Kelly RewriteRule), 1116246b428fSStephen Kelly RewriteInput, ExpectedRewriteOutput); 1117246b428fSStephen Kelly 1118246b428fSStephen Kelly testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule), 1119246b428fSStephen Kelly RewriteInput, BrokenRewriteOutput); 1120246b428fSStephen Kelly } 1121246b428fSStephen Kelly 1122246b428fSStephen Kelly TEST_F(TransformerTest, ImplicitNodes_RangeFor) { 1123246b428fSStephen Kelly 1124246b428fSStephen Kelly std::string CodePrefix = R"cpp( 1125246b428fSStephen Kelly struct Container 1126246b428fSStephen Kelly { 1127246b428fSStephen Kelly int* begin() const; 1128246b428fSStephen Kelly int* end() const; 1129246b428fSStephen Kelly int* cbegin() const; 1130246b428fSStephen Kelly int* cend() const; 1131246b428fSStephen Kelly }; 1132246b428fSStephen Kelly 1133246b428fSStephen Kelly void foo() 1134246b428fSStephen Kelly { 1135246b428fSStephen Kelly const Container c; 1136246b428fSStephen Kelly )cpp"; 1137246b428fSStephen Kelly 1138246b428fSStephen Kelly std::string BeginCallBefore = " c.begin();"; 1139246b428fSStephen Kelly std::string BeginCallAfter = " c.cbegin();"; 1140246b428fSStephen Kelly 1141246b428fSStephen Kelly std::string ForLoop = "for (auto i : c)"; 1142246b428fSStephen Kelly std::string BrokenForLoop = "for (auto i :.cbegin() c)"; 1143246b428fSStephen Kelly 1144246b428fSStephen Kelly std::string CodeSuffix = R"cpp( 1145246b428fSStephen Kelly { 1146246b428fSStephen Kelly } 1147246b428fSStephen Kelly } 1148246b428fSStephen Kelly )cpp"; 1149246b428fSStephen Kelly 1150246b428fSStephen Kelly std::string RewriteInput = 1151246b428fSStephen Kelly CodePrefix + BeginCallBefore + ForLoop + CodeSuffix; 1152246b428fSStephen Kelly std::string ExpectedRewriteOutput = 1153246b428fSStephen Kelly CodePrefix + BeginCallAfter + ForLoop + CodeSuffix; 1154246b428fSStephen Kelly std::string BrokenRewriteOutput = 1155246b428fSStephen Kelly CodePrefix + BeginCallAfter + BrokenForLoop + CodeSuffix; 1156246b428fSStephen Kelly 1157246b428fSStephen Kelly auto MatchedRecord = 1158246b428fSStephen Kelly cxxMemberCallExpr(on(expr(hasType(qualType(isConstQualified(), 1159246b428fSStephen Kelly hasDeclaration(cxxRecordDecl( 1160246b428fSStephen Kelly hasName("Container")))))) 1161246b428fSStephen Kelly .bind("callTarget")), 1162246b428fSStephen Kelly callee(cxxMethodDecl(hasName("begin")))) 1163246b428fSStephen Kelly .bind("constBeginCall"); 1164246b428fSStephen Kelly 1165246b428fSStephen Kelly auto RewriteRule = 1166246b428fSStephen Kelly changeTo(node("constBeginCall"), cat(name("callTarget"), ".cbegin()")); 1167246b428fSStephen Kelly 1168246b428fSStephen Kelly testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord), 1169246b428fSStephen Kelly RewriteRule), 1170246b428fSStephen Kelly RewriteInput, ExpectedRewriteOutput); 1171246b428fSStephen Kelly 1172246b428fSStephen Kelly testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule), 1173246b428fSStephen Kelly RewriteInput, BrokenRewriteOutput); 1174246b428fSStephen Kelly } 1175246b428fSStephen Kelly 1176246b428fSStephen Kelly TEST_F(TransformerTest, ImplicitNodes_ForStmt) { 1177246b428fSStephen Kelly 1178246b428fSStephen Kelly std::string CodePrefix = R"cpp( 1179246b428fSStephen Kelly struct NonTrivial { 1180246b428fSStephen Kelly NonTrivial() {} 1181246b428fSStephen Kelly NonTrivial(NonTrivial&) {} 1182246b428fSStephen Kelly NonTrivial& operator=(NonTrivial const&) { return *this; } 1183246b428fSStephen Kelly 1184246b428fSStephen Kelly ~NonTrivial() {} 1185246b428fSStephen Kelly }; 1186246b428fSStephen Kelly 1187246b428fSStephen Kelly struct ContainsArray { 1188246b428fSStephen Kelly NonTrivial arr[2]; 1189246b428fSStephen Kelly ContainsArray& operator=(ContainsArray const&) = default; 1190246b428fSStephen Kelly }; 1191246b428fSStephen Kelly 1192246b428fSStephen Kelly void testIt() 1193246b428fSStephen Kelly { 1194246b428fSStephen Kelly ContainsArray ca1; 1195246b428fSStephen Kelly ContainsArray ca2; 1196246b428fSStephen Kelly ca2 = ca1; 1197246b428fSStephen Kelly )cpp"; 1198246b428fSStephen Kelly 1199246b428fSStephen Kelly auto CodeSuffix = "}"; 1200246b428fSStephen Kelly 1201246b428fSStephen Kelly auto LoopBody = R"cpp( 1202246b428fSStephen Kelly { 1203246b428fSStephen Kelly 1204246b428fSStephen Kelly } 1205246b428fSStephen Kelly )cpp"; 1206246b428fSStephen Kelly 1207246b428fSStephen Kelly auto RawLoop = "for (auto i = 0; i != 5; ++i)"; 1208246b428fSStephen Kelly 1209246b428fSStephen Kelly auto RangeLoop = "for (auto i : boost::irange(5))"; 1210246b428fSStephen Kelly 1211246b428fSStephen Kelly // Expect to rewrite the raw loop to the ranged loop. 1212246b428fSStephen Kelly // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs 1213246b428fSStephen Kelly // mode also matches the hidden for loop generated in the copy assignment 1214246b428fSStephen Kelly // operator of ContainsArray. Transformer then fails to transform the code at 1215246b428fSStephen Kelly // all. 1216246b428fSStephen Kelly 1217246b428fSStephen Kelly auto RewriteInput = 1218246b428fSStephen Kelly CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix; 1219246b428fSStephen Kelly 1220246b428fSStephen Kelly auto RewriteOutput = 1221246b428fSStephen Kelly CodePrefix + RangeLoop + LoopBody + RangeLoop + LoopBody + CodeSuffix; 1222246b428fSStephen Kelly { 1223246b428fSStephen Kelly auto MatchedLoop = forStmt( 1224246b428fSStephen Kelly has(declStmt( 1225246b428fSStephen Kelly hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0)))) 1226246b428fSStephen Kelly .bind("loopVar")))), 1227246b428fSStephen Kelly has(binaryOperator(hasOperatorName("!="), 1228246b428fSStephen Kelly hasLHS(ignoringImplicit(declRefExpr( 1229246b428fSStephen Kelly to(varDecl(equalsBoundNode("loopVar")))))), 1230246b428fSStephen Kelly hasRHS(expr().bind("upperBoundExpr")))), 1231246b428fSStephen Kelly has(unaryOperator(hasOperatorName("++"), 1232246b428fSStephen Kelly hasUnaryOperand(declRefExpr( 1233246b428fSStephen Kelly to(varDecl(equalsBoundNode("loopVar")))))) 1234246b428fSStephen Kelly .bind("incrementOp"))); 1235246b428fSStephen Kelly 1236246b428fSStephen Kelly auto RewriteRule = 1237246b428fSStephen Kelly changeTo(transformer::enclose(node("loopVar"), node("incrementOp")), 1238246b428fSStephen Kelly cat("auto ", name("loopVar"), " : boost::irange(", 1239246b428fSStephen Kelly node("upperBoundExpr"), ")")); 1240246b428fSStephen Kelly 1241246b428fSStephen Kelly testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop), 1242246b428fSStephen Kelly RewriteRule), 1243246b428fSStephen Kelly RewriteInput, RewriteOutput); 1244246b428fSStephen Kelly 1245246b428fSStephen Kelly testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule), 1246246b428fSStephen Kelly RewriteInput); 1247246b428fSStephen Kelly } 1248*4cadb66bSStephen Kelly { 1249*4cadb66bSStephen Kelly auto MatchedLoop = forStmt( 1250*4cadb66bSStephen Kelly hasLoopInit(declStmt( 1251*4cadb66bSStephen Kelly hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0)))) 1252*4cadb66bSStephen Kelly .bind("loopVar")))), 1253*4cadb66bSStephen Kelly hasCondition(binaryOperator(hasOperatorName("!="), 1254*4cadb66bSStephen Kelly hasLHS(ignoringImplicit(declRefExpr(to( 1255*4cadb66bSStephen Kelly varDecl(equalsBoundNode("loopVar")))))), 1256*4cadb66bSStephen Kelly hasRHS(expr().bind("upperBoundExpr")))), 1257*4cadb66bSStephen Kelly hasIncrement(unaryOperator(hasOperatorName("++"), 1258*4cadb66bSStephen Kelly hasUnaryOperand(declRefExpr(to( 1259*4cadb66bSStephen Kelly varDecl(equalsBoundNode("loopVar")))))) 1260*4cadb66bSStephen Kelly .bind("incrementOp"))); 1261*4cadb66bSStephen Kelly 1262*4cadb66bSStephen Kelly auto RewriteRule = 1263*4cadb66bSStephen Kelly changeTo(transformer::enclose(node("loopVar"), node("incrementOp")), 1264*4cadb66bSStephen Kelly cat("auto ", name("loopVar"), " : boost::irange(", 1265*4cadb66bSStephen Kelly node("upperBoundExpr"), ")")); 1266*4cadb66bSStephen Kelly 1267*4cadb66bSStephen Kelly testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop), 1268*4cadb66bSStephen Kelly RewriteRule), 1269*4cadb66bSStephen Kelly RewriteInput, RewriteOutput); 1270*4cadb66bSStephen Kelly 1271*4cadb66bSStephen Kelly testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule), 1272*4cadb66bSStephen Kelly RewriteInput); 1273*4cadb66bSStephen Kelly } 1274246b428fSStephen Kelly } 1275246b428fSStephen Kelly 1276a6d15d40SMatt Morehouse TEST_F(TransformerTest, TemplateInstantiation) { 1277a6d15d40SMatt Morehouse 1278a6d15d40SMatt Morehouse std::string NonTemplatesInput = R"cpp( 1279a6d15d40SMatt Morehouse struct S { 1280a6d15d40SMatt Morehouse int m_i; 1281a6d15d40SMatt Morehouse }; 1282a6d15d40SMatt Morehouse )cpp"; 1283a6d15d40SMatt Morehouse std::string NonTemplatesExpected = R"cpp( 1284a6d15d40SMatt Morehouse struct S { 1285a6d15d40SMatt Morehouse safe_int m_i; 1286a6d15d40SMatt Morehouse }; 1287a6d15d40SMatt Morehouse )cpp"; 1288a6d15d40SMatt Morehouse 1289a6d15d40SMatt Morehouse std::string TemplatesInput = R"cpp( 1290a6d15d40SMatt Morehouse template<typename T> 1291a6d15d40SMatt Morehouse struct TemplStruct { 1292a6d15d40SMatt Morehouse TemplStruct() {} 1293a6d15d40SMatt Morehouse ~TemplStruct() {} 1294a6d15d40SMatt Morehouse 1295a6d15d40SMatt Morehouse private: 1296a6d15d40SMatt Morehouse T m_t; 1297a6d15d40SMatt Morehouse }; 1298a6d15d40SMatt Morehouse 1299a6d15d40SMatt Morehouse void instantiate() 1300a6d15d40SMatt Morehouse { 1301a6d15d40SMatt Morehouse TemplStruct<int> ti; 1302a6d15d40SMatt Morehouse } 1303a6d15d40SMatt Morehouse )cpp"; 1304a6d15d40SMatt Morehouse 1305a6d15d40SMatt Morehouse auto MatchedField = fieldDecl(hasType(asString("int"))).bind("theField"); 1306a6d15d40SMatt Morehouse 1307a6d15d40SMatt Morehouse // Changes the 'int' in 'S', but not the 'T' in 'TemplStruct': 1308a6d15d40SMatt Morehouse testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedField), 1309a6d15d40SMatt Morehouse changeTo(cat("safe_int ", name("theField")))), 1310a6d15d40SMatt Morehouse NonTemplatesInput + TemplatesInput, 1311a6d15d40SMatt Morehouse NonTemplatesExpected + TemplatesInput); 1312a6d15d40SMatt Morehouse 1313a6d15d40SMatt Morehouse // In AsIs mode, template instantiations are modified, which is 1314a6d15d40SMatt Morehouse // often not desired: 1315a6d15d40SMatt Morehouse 1316a6d15d40SMatt Morehouse std::string IncorrectTemplatesExpected = R"cpp( 1317a6d15d40SMatt Morehouse template<typename T> 1318a6d15d40SMatt Morehouse struct TemplStruct { 1319a6d15d40SMatt Morehouse TemplStruct() {} 1320a6d15d40SMatt Morehouse ~TemplStruct() {} 1321a6d15d40SMatt Morehouse 1322a6d15d40SMatt Morehouse private: 1323a6d15d40SMatt Morehouse safe_int m_t; 1324a6d15d40SMatt Morehouse }; 1325a6d15d40SMatt Morehouse 1326a6d15d40SMatt Morehouse void instantiate() 1327a6d15d40SMatt Morehouse { 1328a6d15d40SMatt Morehouse TemplStruct<int> ti; 1329a6d15d40SMatt Morehouse } 1330a6d15d40SMatt Morehouse )cpp"; 1331a6d15d40SMatt Morehouse 1332a6d15d40SMatt Morehouse // Changes the 'int' in 'S', and (incorrectly) the 'T' in 'TemplStruct': 1333a6d15d40SMatt Morehouse testRule(makeRule(traverse(TK_AsIs, MatchedField), 1334a6d15d40SMatt Morehouse changeTo(cat("safe_int ", name("theField")))), 1335a6d15d40SMatt Morehouse 1336a6d15d40SMatt Morehouse NonTemplatesInput + TemplatesInput, 1337a6d15d40SMatt Morehouse NonTemplatesExpected + IncorrectTemplatesExpected); 1338a6d15d40SMatt Morehouse } 1339a6d15d40SMatt Morehouse 13403f1ab737SYitzhak Mandelbaum // Transformation of macro source text when the change encompasses the entirety 13413f1ab737SYitzhak Mandelbaum // of the expanded text. 13423f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, SimpleMacro) { 1343fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 13443f1ab737SYitzhak Mandelbaum #define ZERO 0 13453f1ab737SYitzhak Mandelbaum int f(string s) { return ZERO; } 13463f1ab737SYitzhak Mandelbaum )cc"; 13473f1ab737SYitzhak Mandelbaum std::string Expected = R"cc( 13483f1ab737SYitzhak Mandelbaum #define ZERO 0 13493f1ab737SYitzhak Mandelbaum int f(string s) { return 999; } 13503f1ab737SYitzhak Mandelbaum )cc"; 13513f1ab737SYitzhak Mandelbaum 13523f1ab737SYitzhak Mandelbaum StringRef zero = "zero"; 13533f1ab737SYitzhak Mandelbaum RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 1354adcd0268SBenjamin Kramer changeTo(node(std::string(zero)), cat("999"))); 13553f1ab737SYitzhak Mandelbaum testRule(R, Input, Expected); 1356fdd98782SYitzhak Mandelbaum } 1357fdd98782SYitzhak Mandelbaum 13583f1ab737SYitzhak Mandelbaum // Transformation of macro source text when the change encompasses the entirety 13593f1ab737SYitzhak Mandelbaum // of the expanded text, for the case of function-style macros. 13603f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, FunctionMacro) { 13613f1ab737SYitzhak Mandelbaum std::string Input = R"cc( 13623f1ab737SYitzhak Mandelbaum #define MACRO(str) strlen((str).c_str()) 13633f1ab737SYitzhak Mandelbaum int f(string s) { return MACRO(s); } 13643f1ab737SYitzhak Mandelbaum )cc"; 13653f1ab737SYitzhak Mandelbaum std::string Expected = R"cc( 13663f1ab737SYitzhak Mandelbaum #define MACRO(str) strlen((str).c_str()) 13673f1ab737SYitzhak Mandelbaum int f(string s) { return REPLACED; } 13683f1ab737SYitzhak Mandelbaum )cc"; 13693f1ab737SYitzhak Mandelbaum 13703f1ab737SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Expected); 13713f1ab737SYitzhak Mandelbaum } 13723f1ab737SYitzhak Mandelbaum 13733f1ab737SYitzhak Mandelbaum // Tests that expressions in macro arguments can be rewritten. 13743f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, MacroArg) { 13753f1ab737SYitzhak Mandelbaum std::string Input = R"cc( 13763f1ab737SYitzhak Mandelbaum #define PLUS(e) e + 1 13773f1ab737SYitzhak Mandelbaum int f(string s) { return PLUS(strlen(s.c_str())); } 13783f1ab737SYitzhak Mandelbaum )cc"; 13793f1ab737SYitzhak Mandelbaum std::string Expected = R"cc( 13803f1ab737SYitzhak Mandelbaum #define PLUS(e) e + 1 13813f1ab737SYitzhak Mandelbaum int f(string s) { return PLUS(REPLACED); } 13823f1ab737SYitzhak Mandelbaum )cc"; 13833f1ab737SYitzhak Mandelbaum 13843f1ab737SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Expected); 13853f1ab737SYitzhak Mandelbaum } 13863f1ab737SYitzhak Mandelbaum 13873f1ab737SYitzhak Mandelbaum // Tests that expressions in macro arguments can be rewritten, even when the 13883f1ab737SYitzhak Mandelbaum // macro call occurs inside another macro's definition. 13893f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, MacroArgInMacroDef) { 1390fdd98782SYitzhak Mandelbaum std::string Input = R"cc( 1391fdd98782SYitzhak Mandelbaum #define NESTED(e) e 1392fdd98782SYitzhak Mandelbaum #define MACRO(str) NESTED(strlen((str).c_str())) 13933f1ab737SYitzhak Mandelbaum int f(string s) { return MACRO(s); } 13943f1ab737SYitzhak Mandelbaum )cc"; 13953f1ab737SYitzhak Mandelbaum std::string Expected = R"cc( 13963f1ab737SYitzhak Mandelbaum #define NESTED(e) e 13973f1ab737SYitzhak Mandelbaum #define MACRO(str) NESTED(strlen((str).c_str())) 13983f1ab737SYitzhak Mandelbaum int f(string s) { return REPLACED; } 13993f1ab737SYitzhak Mandelbaum )cc"; 14003f1ab737SYitzhak Mandelbaum 14013f1ab737SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Expected); 14023f1ab737SYitzhak Mandelbaum } 14033f1ab737SYitzhak Mandelbaum 14043f1ab737SYitzhak Mandelbaum // Tests the corner case of the identity macro, specifically that it is 14053f1ab737SYitzhak Mandelbaum // discarded in the rewrite rather than preserved (like PLUS is preserved in the 14063f1ab737SYitzhak Mandelbaum // previous test). This behavior is of dubious value (and marked with a FIXME 14073f1ab737SYitzhak Mandelbaum // in the code), but we test it to verify (and demonstrate) how this case is 14083f1ab737SYitzhak Mandelbaum // handled. 14093f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, IdentityMacro) { 14103f1ab737SYitzhak Mandelbaum std::string Input = R"cc( 14113f1ab737SYitzhak Mandelbaum #define ID(e) e 14123f1ab737SYitzhak Mandelbaum int f(string s) { return ID(strlen(s.c_str())); } 14133f1ab737SYitzhak Mandelbaum )cc"; 14143f1ab737SYitzhak Mandelbaum std::string Expected = R"cc( 14153f1ab737SYitzhak Mandelbaum #define ID(e) e 14163f1ab737SYitzhak Mandelbaum int f(string s) { return REPLACED; } 14173f1ab737SYitzhak Mandelbaum )cc"; 14183f1ab737SYitzhak Mandelbaum 14193f1ab737SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Expected); 14203f1ab737SYitzhak Mandelbaum } 14213f1ab737SYitzhak Mandelbaum 1422db24ef50SYitzhak Mandelbaum // Tests that two changes in a single macro expansion do not lead to conflicts 1423db24ef50SYitzhak Mandelbaum // in applying the changes. 1424db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) { 1425db24ef50SYitzhak Mandelbaum std::string Input = R"cc( 1426db24ef50SYitzhak Mandelbaum #define PLUS(a,b) (a) + (b) 1427db24ef50SYitzhak Mandelbaum int f() { return PLUS(3, 4); } 1428db24ef50SYitzhak Mandelbaum )cc"; 1429db24ef50SYitzhak Mandelbaum std::string Expected = R"cc( 1430db24ef50SYitzhak Mandelbaum #define PLUS(a,b) (a) + (b) 1431db24ef50SYitzhak Mandelbaum int f() { return PLUS(LIT, LIT); } 1432db24ef50SYitzhak Mandelbaum )cc"; 1433db24ef50SYitzhak Mandelbaum 14349f97480cSYitzhak Mandelbaum testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected); 1435db24ef50SYitzhak Mandelbaum } 1436db24ef50SYitzhak Mandelbaum 1437db24ef50SYitzhak Mandelbaum // Tests case where the rule's match spans both source from the macro and its 1438db24ef50SYitzhak Mandelbaum // arg, with the begin location (the "anchor") being the arg. 1439db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) { 1440db24ef50SYitzhak Mandelbaum std::string Input = R"cc( 1441db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) a + 1 1442db24ef50SYitzhak Mandelbaum int f() { return PLUS_ONE(3); } 1443db24ef50SYitzhak Mandelbaum )cc"; 1444db24ef50SYitzhak Mandelbaum std::string Expected = R"cc( 1445db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) a + 1 1446db24ef50SYitzhak Mandelbaum int f() { return PLUS_ONE(LIT); } 1447db24ef50SYitzhak Mandelbaum )cc"; 1448db24ef50SYitzhak Mandelbaum 1449db24ef50SYitzhak Mandelbaum StringRef E = "expr"; 1450db24ef50SYitzhak Mandelbaum testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))), 1451adcd0268SBenjamin Kramer changeTo(node(std::string(E)), cat("LIT"))), 1452db24ef50SYitzhak Mandelbaum Input, Expected); 1453db24ef50SYitzhak Mandelbaum } 1454db24ef50SYitzhak Mandelbaum 1455db24ef50SYitzhak Mandelbaum // Tests case where the rule's match spans both source from the macro and its 1456db24ef50SYitzhak Mandelbaum // arg, with the begin location (the "anchor") being inside the macro. 1457db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) { 1458db24ef50SYitzhak Mandelbaum std::string Input = R"cc( 1459db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) 1 + a 1460db24ef50SYitzhak Mandelbaum int f() { return PLUS_ONE(3); } 1461db24ef50SYitzhak Mandelbaum )cc"; 1462db24ef50SYitzhak Mandelbaum std::string Expected = R"cc( 1463db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) 1 + a 1464db24ef50SYitzhak Mandelbaum int f() { return PLUS_ONE(LIT); } 1465db24ef50SYitzhak Mandelbaum )cc"; 1466db24ef50SYitzhak Mandelbaum 1467db24ef50SYitzhak Mandelbaum StringRef E = "expr"; 1468db24ef50SYitzhak Mandelbaum testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))), 1469adcd0268SBenjamin Kramer changeTo(node(std::string(E)), cat("LIT"))), 1470db24ef50SYitzhak Mandelbaum Input, Expected); 1471db24ef50SYitzhak Mandelbaum } 1472db24ef50SYitzhak Mandelbaum 14733f1ab737SYitzhak Mandelbaum // No rewrite is applied when the changed text does not encompass the entirety 14743f1ab737SYitzhak Mandelbaum // of the expanded text. That is, the edit would have to be applied to the 14753f1ab737SYitzhak Mandelbaum // macro's definition to succeed and editing the expansion point would not 14763f1ab737SYitzhak Mandelbaum // suffice. 14773f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) { 14783f1ab737SYitzhak Mandelbaum std::string Input = R"cc( 14793f1ab737SYitzhak Mandelbaum #define ZERO_PLUS 0 + 3 14803f1ab737SYitzhak Mandelbaum int f(string s) { return ZERO_PLUS; })cc"; 14813f1ab737SYitzhak Mandelbaum 14823f1ab737SYitzhak Mandelbaum StringRef zero = "zero"; 14833f1ab737SYitzhak Mandelbaum RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 1484adcd0268SBenjamin Kramer changeTo(node(std::string(zero)), cat("0"))); 14853f1ab737SYitzhak Mandelbaum testRule(R, Input, Input); 14863f1ab737SYitzhak Mandelbaum } 14873f1ab737SYitzhak Mandelbaum 14883f1ab737SYitzhak Mandelbaum // This test handles the corner case where a macro expands within another macro 14893f1ab737SYitzhak Mandelbaum // to matching code, but that code is an argument to the nested macro call. A 14903f1ab737SYitzhak Mandelbaum // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get 14913f1ab737SYitzhak Mandelbaum // this wrong, and transform the code. 14923f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) { 14933f1ab737SYitzhak Mandelbaum std::string Input = R"cc( 14943f1ab737SYitzhak Mandelbaum #define NESTED(e) e 14953f1ab737SYitzhak Mandelbaum #define MACRO(str) 1 + NESTED(strlen((str).c_str())) 14963f1ab737SYitzhak Mandelbaum int f(string s) { return MACRO(s); } 14973f1ab737SYitzhak Mandelbaum )cc"; 14983f1ab737SYitzhak Mandelbaum 1499fdd98782SYitzhak Mandelbaum testRule(ruleStrlenSize(), Input, Input); 1500fdd98782SYitzhak Mandelbaum } 150142b957aaSYitzhak Mandelbaum 150242b957aaSYitzhak Mandelbaum #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST 150342b957aaSYitzhak Mandelbaum // Verifies that `Type` and `QualType` are not allowed as top-level matchers in 150442b957aaSYitzhak Mandelbaum // rules. 150542b957aaSYitzhak Mandelbaum TEST(TransformerDeathTest, OrderedRuleTypes) { 15069f97480cSYitzhak Mandelbaum RewriteRule QualTypeRule = makeRule(qualType(), changeTo(cat("Q"))); 15078bb47cd8SYitzhak Mandelbaum EXPECT_DEATH(transformer::detail::buildMatchers(QualTypeRule), 150842b957aaSYitzhak Mandelbaum "Matcher must be.*node matcher"); 150942b957aaSYitzhak Mandelbaum 15109f97480cSYitzhak Mandelbaum RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T"))); 15118bb47cd8SYitzhak Mandelbaum EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule), 151242b957aaSYitzhak Mandelbaum "Matcher must be.*node matcher"); 151342b957aaSYitzhak Mandelbaum } 151442b957aaSYitzhak Mandelbaum #endif 1515ff2743bfSYitzhak Mandelbaum 1516ff2743bfSYitzhak Mandelbaum // Edits are able to span multiple files; in this case, a header and an 1517ff2743bfSYitzhak Mandelbaum // implementation file. 1518ff2743bfSYitzhak Mandelbaum TEST_F(TransformerTest, MultipleFiles) { 1519ff2743bfSYitzhak Mandelbaum std::string Header = R"cc(void RemoveThisFunction();)cc"; 1520ff2743bfSYitzhak Mandelbaum std::string Source = R"cc(#include "input.h" 1521ff2743bfSYitzhak Mandelbaum void RemoveThisFunction();)cc"; 1522ff2743bfSYitzhak Mandelbaum Transformer T( 1523ff2743bfSYitzhak Mandelbaum makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))), 1524ff2743bfSYitzhak Mandelbaum consumer()); 1525ff2743bfSYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 1526ff2743bfSYitzhak Mandelbaum auto Factory = newFrontendActionFactory(&MatchFinder); 1527ff2743bfSYitzhak Mandelbaum EXPECT_TRUE(runToolOnCodeWithArgs( 1528ff2743bfSYitzhak Mandelbaum Factory->create(), Source, std::vector<std::string>(), "input.cc", 1529ff2743bfSYitzhak Mandelbaum "clang-tool", std::make_shared<PCHContainerOperations>(), 1530ff2743bfSYitzhak Mandelbaum {{"input.h", Header}})); 1531ff2743bfSYitzhak Mandelbaum 1532ff2743bfSYitzhak Mandelbaum std::sort(Changes.begin(), Changes.end(), 1533ff2743bfSYitzhak Mandelbaum [](const AtomicChange &L, const AtomicChange &R) { 1534ff2743bfSYitzhak Mandelbaum return L.getFilePath() < R.getFilePath(); 1535ff2743bfSYitzhak Mandelbaum }); 1536ff2743bfSYitzhak Mandelbaum 1537ff2743bfSYitzhak Mandelbaum ASSERT_EQ(Changes[0].getFilePath(), "./input.h"); 1538ff2743bfSYitzhak Mandelbaum EXPECT_THAT(Changes[0].getInsertedHeaders(), IsEmpty()); 1539ff2743bfSYitzhak Mandelbaum EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty()); 1540ff2743bfSYitzhak Mandelbaum llvm::Expected<std::string> UpdatedCode = 1541ff2743bfSYitzhak Mandelbaum clang::tooling::applyAllReplacements(Header, 1542ff2743bfSYitzhak Mandelbaum Changes[0].getReplacements()); 1543ff2743bfSYitzhak Mandelbaum ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1544ff2743bfSYitzhak Mandelbaum << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1545ff2743bfSYitzhak Mandelbaum EXPECT_EQ(format(*UpdatedCode), format(R"cc(;)cc")); 1546ff2743bfSYitzhak Mandelbaum 1547ff2743bfSYitzhak Mandelbaum ASSERT_EQ(Changes[1].getFilePath(), "input.cc"); 1548ff2743bfSYitzhak Mandelbaum EXPECT_THAT(Changes[1].getInsertedHeaders(), IsEmpty()); 1549ff2743bfSYitzhak Mandelbaum EXPECT_THAT(Changes[1].getRemovedHeaders(), IsEmpty()); 1550ff2743bfSYitzhak Mandelbaum UpdatedCode = clang::tooling::applyAllReplacements( 1551ff2743bfSYitzhak Mandelbaum Source, Changes[1].getReplacements()); 1552ff2743bfSYitzhak Mandelbaum ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1553ff2743bfSYitzhak Mandelbaum << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1554ff2743bfSYitzhak Mandelbaum EXPECT_EQ(format(*UpdatedCode), format(R"cc(#include "input.h" 1555ff2743bfSYitzhak Mandelbaum ;)cc")); 1556ff2743bfSYitzhak Mandelbaum } 1557d8c1f43dSYitzhak Mandelbaum 1558d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeMultipleFiles) { 1559d8c1f43dSYitzhak Mandelbaum std::string Header = R"cc(void RemoveThisFunction();)cc"; 1560d8c1f43dSYitzhak Mandelbaum std::string Source = R"cc(#include "input.h" 1561d8c1f43dSYitzhak Mandelbaum void Foo() {RemoveThisFunction();})cc"; 1562d8c1f43dSYitzhak Mandelbaum Transformer T( 1563d8c1f43dSYitzhak Mandelbaum makeRule(callExpr(callee( 1564d8c1f43dSYitzhak Mandelbaum functionDecl(hasName("RemoveThisFunction")).bind("fun"))), 1565d8c1f43dSYitzhak Mandelbaum addInclude(node("fun"), "header.h")), 1566d8c1f43dSYitzhak Mandelbaum consumer()); 1567d8c1f43dSYitzhak Mandelbaum T.registerMatchers(&MatchFinder); 1568d8c1f43dSYitzhak Mandelbaum auto Factory = newFrontendActionFactory(&MatchFinder); 1569d8c1f43dSYitzhak Mandelbaum EXPECT_TRUE(runToolOnCodeWithArgs( 1570d8c1f43dSYitzhak Mandelbaum Factory->create(), Source, std::vector<std::string>(), "input.cc", 1571d8c1f43dSYitzhak Mandelbaum "clang-tool", std::make_shared<PCHContainerOperations>(), 1572d8c1f43dSYitzhak Mandelbaum {{"input.h", Header}})); 1573d8c1f43dSYitzhak Mandelbaum 1574d8c1f43dSYitzhak Mandelbaum ASSERT_EQ(Changes.size(), 1U); 1575d8c1f43dSYitzhak Mandelbaum ASSERT_EQ(Changes[0].getFilePath(), "./input.h"); 1576d8c1f43dSYitzhak Mandelbaum EXPECT_THAT(Changes[0].getInsertedHeaders(), ElementsAre("header.h")); 1577d8c1f43dSYitzhak Mandelbaum EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty()); 1578d8c1f43dSYitzhak Mandelbaum llvm::Expected<std::string> UpdatedCode = 1579d8c1f43dSYitzhak Mandelbaum clang::tooling::applyAllReplacements(Header, 1580d8c1f43dSYitzhak Mandelbaum Changes[0].getReplacements()); 1581d8c1f43dSYitzhak Mandelbaum ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1582d8c1f43dSYitzhak Mandelbaum << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1583d8c1f43dSYitzhak Mandelbaum EXPECT_EQ(format(*UpdatedCode), format(Header)); 1584d8c1f43dSYitzhak Mandelbaum } 1585fdd98782SYitzhak Mandelbaum } // namespace 1586