Home | History | Annotate | Download | only in Tooling
      1 //===- unittest/Tooling/RefactoringTest.cpp - Refactoring unit tests ------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "RewriterTestContext.h"
     11 #include "clang/AST/ASTConsumer.h"
     12 #include "clang/AST/ASTContext.h"
     13 #include "clang/AST/DeclCXX.h"
     14 #include "clang/AST/DeclGroup.h"
     15 #include "clang/AST/RecursiveASTVisitor.h"
     16 #include "clang/Basic/Diagnostic.h"
     17 #include "clang/Basic/DiagnosticOptions.h"
     18 #include "clang/Basic/FileManager.h"
     19 #include "clang/Basic/LangOptions.h"
     20 #include "clang/Basic/SourceManager.h"
     21 #include "clang/Format/Format.h"
     22 #include "clang/Frontend/CompilerInstance.h"
     23 #include "clang/Frontend/FrontendAction.h"
     24 #include "clang/Frontend/TextDiagnosticPrinter.h"
     25 #include "clang/Rewrite/Core/Rewriter.h"
     26 #include "clang/Tooling/Refactoring.h"
     27 #include "clang/Tooling/Tooling.h"
     28 #include "llvm/ADT/SmallString.h"
     29 #include "llvm/Support/Path.h"
     30 #include "gtest/gtest.h"
     31 
     32 namespace clang {
     33 namespace tooling {
     34 
     35 class ReplacementTest : public ::testing::Test {
     36  protected:
     37   Replacement createReplacement(SourceLocation Start, unsigned Length,
     38                                 llvm::StringRef ReplacementText) {
     39     return Replacement(Context.Sources, Start, Length, ReplacementText);
     40   }
     41 
     42   RewriterTestContext Context;
     43 };
     44 
     45 TEST_F(ReplacementTest, CanDeleteAllText) {
     46   FileID ID = Context.createInMemoryFile("input.cpp", "text");
     47   SourceLocation Location = Context.getLocation(ID, 1, 1);
     48   Replacement Replace(createReplacement(Location, 4, ""));
     49   EXPECT_TRUE(Replace.apply(Context.Rewrite));
     50   EXPECT_EQ("", Context.getRewrittenText(ID));
     51 }
     52 
     53 TEST_F(ReplacementTest, CanDeleteAllTextInTextWithNewlines) {
     54   FileID ID = Context.createInMemoryFile("input.cpp", "line1\nline2\nline3");
     55   SourceLocation Location = Context.getLocation(ID, 1, 1);
     56   Replacement Replace(createReplacement(Location, 17, ""));
     57   EXPECT_TRUE(Replace.apply(Context.Rewrite));
     58   EXPECT_EQ("", Context.getRewrittenText(ID));
     59 }
     60 
     61 TEST_F(ReplacementTest, CanAddText) {
     62   FileID ID = Context.createInMemoryFile("input.cpp", "");
     63   SourceLocation Location = Context.getLocation(ID, 1, 1);
     64   Replacement Replace(createReplacement(Location, 0, "result"));
     65   EXPECT_TRUE(Replace.apply(Context.Rewrite));
     66   EXPECT_EQ("result", Context.getRewrittenText(ID));
     67 }
     68 
     69 TEST_F(ReplacementTest, CanReplaceTextAtPosition) {
     70   FileID ID = Context.createInMemoryFile("input.cpp",
     71                                          "line1\nline2\nline3\nline4");
     72   SourceLocation Location = Context.getLocation(ID, 2, 3);
     73   Replacement Replace(createReplacement(Location, 12, "x"));
     74   EXPECT_TRUE(Replace.apply(Context.Rewrite));
     75   EXPECT_EQ("line1\nlixne4", Context.getRewrittenText(ID));
     76 }
     77 
     78 TEST_F(ReplacementTest, CanReplaceTextAtPositionMultipleTimes) {
     79   FileID ID = Context.createInMemoryFile("input.cpp",
     80                                          "line1\nline2\nline3\nline4");
     81   SourceLocation Location1 = Context.getLocation(ID, 2, 3);
     82   Replacement Replace1(createReplacement(Location1, 12, "x\ny\n"));
     83   EXPECT_TRUE(Replace1.apply(Context.Rewrite));
     84   EXPECT_EQ("line1\nlix\ny\nne4", Context.getRewrittenText(ID));
     85 
     86   // Since the original source has not been modified, the (4, 4) points to the
     87   // 'e' in the original content.
     88   SourceLocation Location2 = Context.getLocation(ID, 4, 4);
     89   Replacement Replace2(createReplacement(Location2, 1, "f"));
     90   EXPECT_TRUE(Replace2.apply(Context.Rewrite));
     91   EXPECT_EQ("line1\nlix\ny\nnf4", Context.getRewrittenText(ID));
     92 }
     93 
     94 TEST_F(ReplacementTest, ApplyFailsForNonExistentLocation) {
     95   Replacement Replace("nonexistent-file.cpp", 0, 1, "");
     96   EXPECT_FALSE(Replace.apply(Context.Rewrite));
     97 }
     98 
     99 TEST_F(ReplacementTest, CanRetrivePath) {
    100   Replacement Replace("/path/to/file.cpp", 0, 1, "");
    101   EXPECT_EQ("/path/to/file.cpp", Replace.getFilePath());
    102 }
    103 
    104 TEST_F(ReplacementTest, ReturnsInvalidPath) {
    105   Replacement Replace1(Context.Sources, SourceLocation(), 0, "");
    106   EXPECT_TRUE(Replace1.getFilePath().empty());
    107 
    108   Replacement Replace2;
    109   EXPECT_TRUE(Replace2.getFilePath().empty());
    110 }
    111 
    112 TEST_F(ReplacementTest, CanApplyReplacements) {
    113   FileID ID = Context.createInMemoryFile("input.cpp",
    114                                          "line1\nline2\nline3\nline4");
    115   Replacements Replaces;
    116   Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
    117                               5, "replaced"));
    118   Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 3, 1),
    119                               5, "other"));
    120   EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
    121   EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
    122 }
    123 
    124 // FIXME: Remove this test case when Replacements is implemented as std::vector
    125 // instead of std::set. The other ReplacementTest tests will need to be updated
    126 // at that point as well.
    127 TEST_F(ReplacementTest, VectorCanApplyReplacements) {
    128   FileID ID = Context.createInMemoryFile("input.cpp",
    129                                          "line1\nline2\nline3\nline4");
    130   std::vector<Replacement> Replaces;
    131   Replaces.push_back(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
    132                                  5, "replaced"));
    133   Replaces.push_back(
    134       Replacement(Context.Sources, Context.getLocation(ID, 3, 1), 5, "other"));
    135   EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
    136   EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
    137 }
    138 
    139 TEST_F(ReplacementTest, SkipsDuplicateReplacements) {
    140   FileID ID = Context.createInMemoryFile("input.cpp",
    141                                          "line1\nline2\nline3\nline4");
    142   Replacements Replaces;
    143   Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
    144                               5, "replaced"));
    145   Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
    146                               5, "replaced"));
    147   Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
    148                               5, "replaced"));
    149   EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
    150   EXPECT_EQ("line1\nreplaced\nline3\nline4", Context.getRewrittenText(ID));
    151 }
    152 
    153 TEST_F(ReplacementTest, ApplyAllFailsIfOneApplyFails) {
    154   // This test depends on the value of the file name of an invalid source
    155   // location being in the range ]a, z[.
    156   FileID IDa = Context.createInMemoryFile("a.cpp", "text");
    157   FileID IDz = Context.createInMemoryFile("z.cpp", "text");
    158   Replacements Replaces;
    159   Replaces.insert(Replacement(Context.Sources, Context.getLocation(IDa, 1, 1),
    160                               4, "a"));
    161   Replaces.insert(Replacement(Context.Sources, SourceLocation(),
    162                               5, "2"));
    163   Replaces.insert(Replacement(Context.Sources, Context.getLocation(IDz, 1, 1),
    164                               4, "z"));
    165   EXPECT_FALSE(applyAllReplacements(Replaces, Context.Rewrite));
    166   EXPECT_EQ("a", Context.getRewrittenText(IDa));
    167   EXPECT_EQ("z", Context.getRewrittenText(IDz));
    168 }
    169 
    170 TEST_F(ReplacementTest, MultipleFilesReplaceAndFormat) {
    171   // Column limit is 20.
    172   std::string Code1 = "Long *a =\n"
    173                       "    new Long();\n"
    174                       "long x = 1;";
    175   std::string Expected1 = "auto a = new Long();\n"
    176                           "long x =\n"
    177                           "    12345678901;";
    178   std::string Code2 = "int x = 123;\n"
    179                       "int y = 0;";
    180   std::string Expected2 = "int x =\n"
    181                           "    1234567890123;\n"
    182                           "int y = 10;";
    183   FileID ID1 = Context.createInMemoryFile("format_1.cpp", Code1);
    184   FileID ID2 = Context.createInMemoryFile("format_2.cpp", Code2);
    185 
    186   tooling::Replacements Replaces;
    187   // Scrambled the order of replacements.
    188   Replaces.insert(tooling::Replacement(
    189       Context.Sources, Context.getLocation(ID2, 1, 12), 0, "4567890123"));
    190   Replaces.insert(tooling::Replacement(
    191       Context.Sources, Context.getLocation(ID1, 1, 1), 6, "auto "));
    192   Replaces.insert(tooling::Replacement(
    193       Context.Sources, Context.getLocation(ID2, 2, 9), 1, "10"));
    194   Replaces.insert(tooling::Replacement(
    195       Context.Sources, Context.getLocation(ID1, 3, 10), 1, "12345678901"));
    196 
    197   EXPECT_TRUE(formatAndApplyAllReplacements(
    198       Replaces, Context.Rewrite, "{BasedOnStyle: LLVM, ColumnLimit: 20}"));
    199   EXPECT_EQ(Expected1, Context.getRewrittenText(ID1));
    200   EXPECT_EQ(Expected2, Context.getRewrittenText(ID2));
    201 }
    202 
    203 TEST(ShiftedCodePositionTest, FindsNewCodePosition) {
    204   Replacements Replaces;
    205   Replaces.insert(Replacement("", 0, 1, ""));
    206   Replaces.insert(Replacement("", 4, 3, " "));
    207   // Assume ' int   i;' is turned into 'int i;' and cursor is located at '|'.
    208   EXPECT_EQ(0u, shiftedCodePosition(Replaces, 0)); // |int   i;
    209   EXPECT_EQ(0u, shiftedCodePosition(Replaces, 1)); //  |nt   i;
    210   EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); //  i|t   i;
    211   EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); //  in|   i;
    212   EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); //  int|  i;
    213   EXPECT_EQ(3u, shiftedCodePosition(Replaces, 5)); //  int | i;
    214   EXPECT_EQ(3u, shiftedCodePosition(Replaces, 6)); //  int  |i;
    215   EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); //  int   |;
    216   EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); //  int   i|
    217 }
    218 
    219 // FIXME: Remove this test case when Replacements is implemented as std::vector
    220 // instead of std::set. The other ReplacementTest tests will need to be updated
    221 // at that point as well.
    222 TEST(ShiftedCodePositionTest, VectorFindsNewCodePositionWithInserts) {
    223   std::vector<Replacement> Replaces;
    224   Replaces.push_back(Replacement("", 0, 1, ""));
    225   Replaces.push_back(Replacement("", 4, 3, " "));
    226   // Assume ' int   i;' is turned into 'int i;' and cursor is located at '|'.
    227   EXPECT_EQ(0u, shiftedCodePosition(Replaces, 0)); // |int   i;
    228   EXPECT_EQ(0u, shiftedCodePosition(Replaces, 1)); //  |nt   i;
    229   EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); //  i|t   i;
    230   EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); //  in|   i;
    231   EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); //  int|  i;
    232   EXPECT_EQ(3u, shiftedCodePosition(Replaces, 5)); //  int | i;
    233   EXPECT_EQ(3u, shiftedCodePosition(Replaces, 6)); //  int  |i;
    234   EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); //  int   |;
    235   EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); //  int   i|
    236 }
    237 
    238 TEST(ShiftedCodePositionTest, FindsNewCodePositionWithInserts) {
    239   Replacements Replaces;
    240   Replaces.insert(Replacement("", 4, 0, "\"\n\""));
    241   // Assume '"12345678"' is turned into '"1234"\n"5678"'.
    242   EXPECT_EQ(3u, shiftedCodePosition(Replaces, 3)); // "123|5678"
    243   EXPECT_EQ(7u, shiftedCodePosition(Replaces, 4)); // "1234|678"
    244   EXPECT_EQ(8u, shiftedCodePosition(Replaces, 5)); // "12345|78"
    245 }
    246 
    247 TEST(ShiftedCodePositionTest, FindsNewCodePositionInReplacedText) {
    248   Replacements Replaces;
    249   // Replace the first four characters with "abcd".
    250   Replaces.insert(Replacement("", 0, 4, "abcd"));
    251   for (unsigned i = 0; i < 3; ++i)
    252     EXPECT_EQ(i, shiftedCodePosition(Replaces, i));
    253 }
    254 
    255 class FlushRewrittenFilesTest : public ::testing::Test {
    256 public:
    257    FlushRewrittenFilesTest() {}
    258 
    259    ~FlushRewrittenFilesTest() override {
    260     for (llvm::StringMap<std::string>::iterator I = TemporaryFiles.begin(),
    261                                                 E = TemporaryFiles.end();
    262          I != E; ++I) {
    263       llvm::StringRef Name = I->second;
    264       std::error_code EC = llvm::sys::fs::remove(Name);
    265       (void)EC;
    266       assert(!EC);
    267     }
    268   }
    269 
    270   FileID createFile(llvm::StringRef Name, llvm::StringRef Content) {
    271     SmallString<1024> Path;
    272     int FD;
    273     std::error_code EC = llvm::sys::fs::createTemporaryFile(Name, "", FD, Path);
    274     assert(!EC);
    275     (void)EC;
    276 
    277     llvm::raw_fd_ostream OutStream(FD, true);
    278     OutStream << Content;
    279     OutStream.close();
    280     const FileEntry *File = Context.Files.getFile(Path);
    281     assert(File != nullptr);
    282 
    283     StringRef Found =
    284         TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second;
    285     assert(Found == Path);
    286     (void)Found;
    287     return Context.Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
    288   }
    289 
    290   std::string getFileContentFromDisk(llvm::StringRef Name) {
    291     std::string Path = TemporaryFiles.lookup(Name);
    292     assert(!Path.empty());
    293     // We need to read directly from the FileManager without relaying through
    294     // a FileEntry, as otherwise we'd read through an already opened file
    295     // descriptor, which might not see the changes made.
    296     // FIXME: Figure out whether there is a way to get the SourceManger to
    297     // reopen the file.
    298     auto FileBuffer = Context.Files.getBufferForFile(Path);
    299     return (*FileBuffer)->getBuffer();
    300   }
    301 
    302   llvm::StringMap<std::string> TemporaryFiles;
    303   RewriterTestContext Context;
    304 };
    305 
    306 TEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) {
    307   FileID ID = createFile("input.cpp", "line1\nline2\nline3\nline4");
    308   Replacements Replaces;
    309   Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
    310                               5, "replaced"));
    311   EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
    312   EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles());
    313   EXPECT_EQ("line1\nreplaced\nline3\nline4",
    314             getFileContentFromDisk("input.cpp"));
    315 }
    316 
    317 namespace {
    318 template <typename T>
    319 class TestVisitor : public clang::RecursiveASTVisitor<T> {
    320 public:
    321   bool runOver(StringRef Code) {
    322     return runToolOnCode(new TestAction(this), Code);
    323   }
    324 
    325 protected:
    326   clang::SourceManager *SM;
    327   clang::ASTContext *Context;
    328 
    329 private:
    330   class FindConsumer : public clang::ASTConsumer {
    331   public:
    332     FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}
    333 
    334     void HandleTranslationUnit(clang::ASTContext &Context) override {
    335       Visitor->TraverseDecl(Context.getTranslationUnitDecl());
    336     }
    337 
    338   private:
    339     TestVisitor *Visitor;
    340   };
    341 
    342   class TestAction : public clang::ASTFrontendAction {
    343   public:
    344     TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
    345 
    346     std::unique_ptr<clang::ASTConsumer>
    347     CreateASTConsumer(clang::CompilerInstance &compiler,
    348                       llvm::StringRef dummy) override {
    349       Visitor->SM = &compiler.getSourceManager();
    350       Visitor->Context = &compiler.getASTContext();
    351       /// TestConsumer will be deleted by the framework calling us.
    352       return llvm::make_unique<FindConsumer>(Visitor);
    353     }
    354 
    355   private:
    356     TestVisitor *Visitor;
    357   };
    358 };
    359 } // end namespace
    360 
    361 void expectReplacementAt(const Replacement &Replace,
    362                          StringRef File, unsigned Offset, unsigned Length) {
    363   ASSERT_TRUE(Replace.isApplicable());
    364   EXPECT_EQ(File, Replace.getFilePath());
    365   EXPECT_EQ(Offset, Replace.getOffset());
    366   EXPECT_EQ(Length, Replace.getLength());
    367 }
    368 
    369 class ClassDeclXVisitor : public TestVisitor<ClassDeclXVisitor> {
    370 public:
    371   bool VisitCXXRecordDecl(CXXRecordDecl *Record) {
    372     if (Record->getName() == "X") {
    373       Replace = Replacement(*SM, Record, "");
    374     }
    375     return true;
    376   }
    377   Replacement Replace;
    378 };
    379 
    380 TEST(Replacement, CanBeConstructedFromNode) {
    381   ClassDeclXVisitor ClassDeclX;
    382   EXPECT_TRUE(ClassDeclX.runOver("     class X;"));
    383   expectReplacementAt(ClassDeclX.Replace, "input.cc", 5, 7);
    384 }
    385 
    386 TEST(Replacement, ReplacesAtSpellingLocation) {
    387   ClassDeclXVisitor ClassDeclX;
    388   EXPECT_TRUE(ClassDeclX.runOver("#define A(Y) Y\nA(class X);"));
    389   expectReplacementAt(ClassDeclX.Replace, "input.cc", 17, 7);
    390 }
    391 
    392 class CallToFVisitor : public TestVisitor<CallToFVisitor> {
    393 public:
    394   bool VisitCallExpr(CallExpr *Call) {
    395     if (Call->getDirectCallee()->getName() == "F") {
    396       Replace = Replacement(*SM, Call, "");
    397     }
    398     return true;
    399   }
    400   Replacement Replace;
    401 };
    402 
    403 TEST(Replacement, FunctionCall) {
    404   CallToFVisitor CallToF;
    405   EXPECT_TRUE(CallToF.runOver("void F(); void G() { F(); }"));
    406   expectReplacementAt(CallToF.Replace, "input.cc", 21, 3);
    407 }
    408 
    409 TEST(Replacement, TemplatedFunctionCall) {
    410   CallToFVisitor CallToF;
    411   EXPECT_TRUE(CallToF.runOver(
    412         "template <typename T> void F(); void G() { F<int>(); }"));
    413   expectReplacementAt(CallToF.Replace, "input.cc", 43, 8);
    414 }
    415 
    416 class NestedNameSpecifierAVisitor
    417     : public TestVisitor<NestedNameSpecifierAVisitor> {
    418 public:
    419   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) {
    420     if (NNSLoc.getNestedNameSpecifier()) {
    421       if (const NamespaceDecl* NS = NNSLoc.getNestedNameSpecifier()->getAsNamespace()) {
    422         if (NS->getName() == "a") {
    423           Replace = Replacement(*SM, &NNSLoc, "", Context->getLangOpts());
    424         }
    425       }
    426     }
    427     return TestVisitor<NestedNameSpecifierAVisitor>::TraverseNestedNameSpecifierLoc(
    428         NNSLoc);
    429   }
    430   Replacement Replace;
    431 };
    432 
    433 TEST(Replacement, ColonColon) {
    434   NestedNameSpecifierAVisitor VisitNNSA;
    435   EXPECT_TRUE(VisitNNSA.runOver("namespace a { void f() { ::a::f(); } }"));
    436   expectReplacementAt(VisitNNSA.Replace, "input.cc", 25, 5);
    437 }
    438 
    439 TEST(Range, overlaps) {
    440   EXPECT_TRUE(Range(10, 10).overlapsWith(Range(0, 11)));
    441   EXPECT_TRUE(Range(0, 11).overlapsWith(Range(10, 10)));
    442   EXPECT_FALSE(Range(10, 10).overlapsWith(Range(0, 10)));
    443   EXPECT_FALSE(Range(0, 10).overlapsWith(Range(10, 10)));
    444   EXPECT_TRUE(Range(0, 10).overlapsWith(Range(2, 6)));
    445   EXPECT_TRUE(Range(2, 6).overlapsWith(Range(0, 10)));
    446 }
    447 
    448 TEST(Range, contains) {
    449   EXPECT_TRUE(Range(0, 10).contains(Range(0, 10)));
    450   EXPECT_TRUE(Range(0, 10).contains(Range(2, 6)));
    451   EXPECT_FALSE(Range(2, 6).contains(Range(0, 10)));
    452   EXPECT_FALSE(Range(0, 10).contains(Range(0, 11)));
    453 }
    454 
    455 TEST(Range, CalculateRangesOfReplacements) {
    456   // Before: aaaabbbbbbz
    457   // After : bbbbbbzzzzzzoooooooooooooooo
    458   Replacements Replaces;
    459   Replaces.insert(Replacement("foo", 0, 4, ""));
    460   Replaces.insert(Replacement("foo", 10, 1, "zzzzzz"));
    461   Replaces.insert(Replacement("foo", 11, 0, "oooooooooooooooo"));
    462 
    463   std::vector<Range> Ranges = calculateChangedRanges(Replaces);
    464 
    465   EXPECT_EQ(2ul, Ranges.size());
    466   EXPECT_TRUE(Ranges[0].getOffset() == 0);
    467   EXPECT_TRUE(Ranges[0].getLength() == 0);
    468   EXPECT_TRUE(Ranges[1].getOffset() == 6);
    469   EXPECT_TRUE(Ranges[1].getLength() == 22);
    470 }
    471 
    472 TEST(Range, RangesAfterReplacements) {
    473   std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
    474   Replacements Replaces = {Replacement("foo", 0, 2, "1234")};
    475   std::vector<Range> Expected = {Range(0, 4), Range(7, 2), Range(12, 5)};
    476   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
    477 }
    478 
    479 TEST(Range, RangesBeforeReplacements) {
    480   std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
    481   Replacements Replaces = {Replacement("foo", 20, 2, "1234")};
    482   std::vector<Range> Expected = {Range(5, 2), Range(10, 5), Range(20, 4)};
    483   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
    484 }
    485 
    486 TEST(Range, NotAffectedByReplacements) {
    487   std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
    488   Replacements Replaces = {Replacement("foo", 3, 2, "12"),
    489                            Replacement("foo", 12, 2, "12"),
    490                            Replacement("foo", 20, 5, "")};
    491   std::vector<Range> Expected = {Range(0, 2), Range(3, 4), Range(10, 5),
    492                                  Range(20, 0)};
    493   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
    494 }
    495 
    496 TEST(Range, RangesWithNonOverlappingReplacements) {
    497   std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
    498   Replacements Replaces = {Replacement("foo", 3, 1, ""),
    499                            Replacement("foo", 6, 1, "123"),
    500                            Replacement("foo", 20, 2, "12345")};
    501   std::vector<Range> Expected = {Range(0, 2), Range(3, 0), Range(4, 4),
    502                                  Range(11, 5), Range(21, 5)};
    503   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
    504 }
    505 
    506 TEST(Range, RangesWithOverlappingReplacements) {
    507   std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5),
    508                                Range(30, 5)};
    509   Replacements Replaces = {
    510       Replacement("foo", 1, 3, ""), Replacement("foo", 6, 1, "123"),
    511       Replacement("foo", 13, 3, "1"), Replacement("foo", 25, 15, "")};
    512   std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(12, 5),
    513                                  Range(22, 0)};
    514   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
    515 }
    516 
    517 TEST(Range, MergeIntoOneRange) {
    518   std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
    519   Replacements Replaces = {Replacement("foo", 1, 15, "1234567890")};
    520   std::vector<Range> Expected = {Range(0, 15)};
    521   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
    522 }
    523 
    524 TEST(Range, ReplacementsStartingAtRangeOffsets) {
    525   std::vector<Range> Ranges = {Range(0, 2), Range(5, 5), Range(15, 5)};
    526   Replacements Replaces = {
    527       Replacement("foo", 0, 2, "12"), Replacement("foo", 5, 1, "123"),
    528       Replacement("foo", 7, 4, "12345"), Replacement("foo", 15, 10, "12")};
    529   std::vector<Range> Expected = {Range(0, 2), Range(5, 9), Range(18, 2)};
    530   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
    531 }
    532 
    533 TEST(Range, ReplacementsEndingAtRangeEnds) {
    534   std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
    535   Replacements Replaces = {Replacement("foo", 6, 1, "123"),
    536                            Replacement("foo", 17, 3, "12")};
    537   std::vector<Range> Expected = {Range(0, 2), Range(5, 4), Range(17, 4)};
    538   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
    539 }
    540 
    541 TEST(Range, AjacentReplacements) {
    542   std::vector<Range> Ranges = {Range(0, 0), Range(15, 5)};
    543   Replacements Replaces = {Replacement("foo", 1, 2, "123"),
    544                            Replacement("foo", 12, 3, "1234")};
    545   std::vector<Range> Expected = {Range(0, 0), Range(1, 3), Range(13, 9)};
    546   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
    547 }
    548 
    549 TEST(Range, MergeRangesAfterReplacements) {
    550   std::vector<Range> Ranges = {Range(8, 0), Range(5, 2), Range(9, 0), Range(0, 1)};
    551   Replacements Replaces = {Replacement("foo", 1, 3, ""),
    552                            Replacement("foo", 7, 0, "12"), Replacement("foo", 9, 2, "")};
    553   std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(7, 0), Range(8, 0)};
    554   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
    555 }
    556 
    557 TEST(DeduplicateTest, removesDuplicates) {
    558   std::vector<Replacement> Input;
    559   Input.push_back(Replacement("fileA", 50, 0, " foo "));
    560   Input.push_back(Replacement("fileA", 10, 3, " bar "));
    561   Input.push_back(Replacement("fileA", 10, 2, " bar ")); // Length differs
    562   Input.push_back(Replacement("fileA", 9,  3, " bar ")); // Offset differs
    563   Input.push_back(Replacement("fileA", 50, 0, " foo ")); // Duplicate
    564   Input.push_back(Replacement("fileA", 51, 3, " bar "));
    565   Input.push_back(Replacement("fileB", 51, 3, " bar ")); // Filename differs!
    566   Input.push_back(Replacement("fileB", 60, 1, " bar "));
    567   Input.push_back(Replacement("fileA", 60, 2, " bar "));
    568   Input.push_back(Replacement("fileA", 51, 3, " moo ")); // Replacement text
    569                                                          // differs!
    570 
    571   std::vector<Replacement> Expected;
    572   Expected.push_back(Replacement("fileA", 9,  3, " bar "));
    573   Expected.push_back(Replacement("fileA", 10, 2, " bar "));
    574   Expected.push_back(Replacement("fileA", 10, 3, " bar "));
    575   Expected.push_back(Replacement("fileA", 50, 0, " foo "));
    576   Expected.push_back(Replacement("fileA", 51, 3, " bar "));
    577   Expected.push_back(Replacement("fileA", 51, 3, " moo "));
    578   Expected.push_back(Replacement("fileB", 60, 1, " bar "));
    579   Expected.push_back(Replacement("fileA", 60, 2, " bar "));
    580 
    581   std::vector<Range> Conflicts; // Ignored for this test
    582   deduplicate(Input, Conflicts);
    583 
    584   EXPECT_EQ(3U, Conflicts.size());
    585   EXPECT_EQ(Expected, Input);
    586 }
    587 
    588 TEST(DeduplicateTest, detectsConflicts) {
    589   {
    590     std::vector<Replacement> Input;
    591     Input.push_back(Replacement("fileA", 0, 5, " foo "));
    592     Input.push_back(Replacement("fileA", 0, 5, " foo ")); // Duplicate not a
    593                                                           // conflict.
    594     Input.push_back(Replacement("fileA", 2, 6, " bar "));
    595     Input.push_back(Replacement("fileA", 7, 3, " moo "));
    596 
    597     std::vector<Range> Conflicts;
    598     deduplicate(Input, Conflicts);
    599 
    600     // One duplicate is removed and the remaining three items form one
    601     // conflicted range.
    602     ASSERT_EQ(3u, Input.size());
    603     ASSERT_EQ(1u, Conflicts.size());
    604     ASSERT_EQ(0u, Conflicts.front().getOffset());
    605     ASSERT_EQ(3u, Conflicts.front().getLength());
    606   }
    607   {
    608     std::vector<Replacement> Input;
    609 
    610     // Expected sorted order is shown. It is the sorted order to which the
    611     // returned conflict info refers to.
    612     Input.push_back(Replacement("fileA", 0,  5, " foo "));  // 0
    613     Input.push_back(Replacement("fileA", 5,  5, " bar "));  // 1
    614     Input.push_back(Replacement("fileA", 6,  0, " bar "));  // 3
    615     Input.push_back(Replacement("fileA", 5,  5, " moo "));  // 2
    616     Input.push_back(Replacement("fileA", 7,  2, " bar "));  // 4
    617     Input.push_back(Replacement("fileA", 15, 5, " golf ")); // 5
    618     Input.push_back(Replacement("fileA", 16, 5, " bag "));  // 6
    619     Input.push_back(Replacement("fileA", 10, 3, " club ")); // 7
    620 
    621     // #3 is special in that it is completely contained by another conflicting
    622     // Replacement. #4 ensures #3 hasn't messed up the conflicting range size.
    623 
    624     std::vector<Range> Conflicts;
    625     deduplicate(Input, Conflicts);
    626 
    627     // No duplicates
    628     ASSERT_EQ(8u, Input.size());
    629     ASSERT_EQ(2u, Conflicts.size());
    630     ASSERT_EQ(1u, Conflicts[0].getOffset());
    631     ASSERT_EQ(4u, Conflicts[0].getLength());
    632     ASSERT_EQ(6u, Conflicts[1].getOffset());
    633     ASSERT_EQ(2u, Conflicts[1].getLength());
    634   }
    635 }
    636 
    637 class MergeReplacementsTest : public ::testing::Test {
    638 protected:
    639   void mergeAndTestRewrite(StringRef Code, StringRef Intermediate,
    640                            StringRef Result, const Replacements &First,
    641                            const Replacements &Second) {
    642     // These are mainly to verify the test itself and make it easier to read.
    643     auto AfterFirst = applyAllReplacements(Code, First);
    644     EXPECT_TRUE(static_cast<bool>(AfterFirst));
    645     auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
    646     EXPECT_TRUE(static_cast<bool>(InSequenceRewrite));
    647     EXPECT_EQ(Intermediate, *AfterFirst);
    648     EXPECT_EQ(Result, *InSequenceRewrite);
    649 
    650     tooling::Replacements Merged = mergeReplacements(First, Second);
    651     auto MergedRewrite = applyAllReplacements(Code, Merged);
    652     EXPECT_TRUE(static_cast<bool>(MergedRewrite));
    653     EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
    654     if (*InSequenceRewrite != *MergedRewrite)
    655       for (tooling::Replacement M : Merged)
    656         llvm::errs() << M.getOffset() << " " << M.getLength() << " "
    657                      << M.getReplacementText() << "\n";
    658   }
    659   void mergeAndTestRewrite(StringRef Code, const Replacements &First,
    660                            const Replacements &Second) {
    661     auto AfterFirst = applyAllReplacements(Code, First);
    662     EXPECT_TRUE(static_cast<bool>(AfterFirst));
    663     auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
    664     tooling::Replacements Merged = mergeReplacements(First, Second);
    665     auto MergedRewrite = applyAllReplacements(Code, Merged);
    666     EXPECT_TRUE(static_cast<bool>(MergedRewrite));
    667     EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
    668     if (*InSequenceRewrite != *MergedRewrite)
    669       for (tooling::Replacement M : Merged)
    670         llvm::errs() << M.getOffset() << " " << M.getLength() << " "
    671                      << M.getReplacementText() << "\n";
    672   }
    673 };
    674 
    675 TEST_F(MergeReplacementsTest, Offsets) {
    676   mergeAndTestRewrite("aaa", "aabab", "cacabab",
    677                       {{"", 2, 0, "b"}, {"", 3, 0, "b"}},
    678                       {{"", 0, 0, "c"}, {"", 1, 0, "c"}});
    679   mergeAndTestRewrite("aaa", "babaa", "babacac",
    680                       {{"", 0, 0, "b"}, {"", 1, 0, "b"}},
    681                       {{"", 4, 0, "c"}, {"", 5, 0, "c"}});
    682   mergeAndTestRewrite("aaaa", "aaa", "aac", {{"", 1, 1, ""}},
    683                       {{"", 2, 1, "c"}});
    684 
    685   mergeAndTestRewrite("aa", "bbabba", "bbabcba",
    686                       {{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}, {{"", 4, 0, "c"}});
    687 }
    688 
    689 TEST_F(MergeReplacementsTest, Concatenations) {
    690   // Basic concatenations. It is important to merge these into a single
    691   // replacement to ensure the correct order.
    692   EXPECT_EQ((Replacements{{"", 0, 0, "ab"}}),
    693             mergeReplacements({{"", 0, 0, "a"}}, {{"", 1, 0, "b"}}));
    694   EXPECT_EQ((Replacements{{"", 0, 0, "ba"}}),
    695             mergeReplacements({{"", 0, 0, "a"}}, {{"", 0, 0, "b"}}));
    696   mergeAndTestRewrite("", "a", "ab", {{"", 0, 0, "a"}}, {{"", 1, 0, "b"}});
    697   mergeAndTestRewrite("", "a", "ba", {{"", 0, 0, "a"}}, {{"", 0, 0, "b"}});
    698 }
    699 
    700 TEST_F(MergeReplacementsTest, NotChangingLengths) {
    701   mergeAndTestRewrite("aaaa", "abba", "acca", {{"", 1, 2, "bb"}},
    702                       {{"", 1, 2, "cc"}});
    703   mergeAndTestRewrite("aaaa", "abba", "abcc", {{"", 1, 2, "bb"}},
    704                       {{"", 2, 2, "cc"}});
    705   mergeAndTestRewrite("aaaa", "abba", "ccba", {{"", 1, 2, "bb"}},
    706                       {{"", 0, 2, "cc"}});
    707   mergeAndTestRewrite("aaaaaa", "abbdda", "abccda",
    708                       {{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}, {{"", 2, 2, "cc"}});
    709 }
    710 
    711 TEST_F(MergeReplacementsTest, OverlappingRanges) {
    712   mergeAndTestRewrite("aaa", "bbd", "bcbcd",
    713                       {{"", 0, 1, "bb"}, {"", 1, 2, "d"}},
    714                       {{"", 1, 0, "c"}, {"", 2, 0, "c"}});
    715 
    716   mergeAndTestRewrite("aaaa", "aabbaa", "acccca", {{"", 2, 0, "bb"}},
    717                       {{"", 1, 4, "cccc"}});
    718   mergeAndTestRewrite("aaaa", "aababa", "acccca",
    719                       {{"", 2, 0, "b"}, {"", 3, 0, "b"}}, {{"", 1, 4, "cccc"}});
    720   mergeAndTestRewrite("aaaaaa", "abbbba", "abba", {{"", 1, 4, "bbbb"}},
    721                       {{"", 2, 2, ""}});
    722   mergeAndTestRewrite("aaaa", "aa", "cc", {{"", 1, 1, ""}, {"", 2, 1, ""}},
    723                       {{"", 0, 2, "cc"}});
    724   mergeAndTestRewrite("aa", "abbba", "abcbcba", {{"", 1, 0, "bbb"}},
    725                       {{"", 2, 0, "c"}, {"", 3, 0, "c"}});
    726 
    727   mergeAndTestRewrite("aaa", "abbab", "ccdd",
    728                       {{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}},
    729                       {{"", 0, 2, "cc"}, {"", 2, 3, "dd"}});
    730   mergeAndTestRewrite("aa", "babbab", "ccdd",
    731                       {{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}},
    732                       {{"", 0, 3, "cc"}, {"", 3, 3, "dd"}});
    733 }
    734 
    735 } // end namespace tooling
    736 } // end namespace clang
    737