brintos

brintos / llvm-project-archived public Read only

0
0
Text · 64.2 KiB · 171dc6d Raw
1722 lines · cpp
1//===- unittest/Tooling/RefactoringTest.cpp - Refactoring unit tests ------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Tooling/Refactoring.h"10#include "ReplacementTest.h"11#include "RewriterTestContext.h"12#include "clang/AST/ASTConsumer.h"13#include "clang/AST/ASTContext.h"14#include "clang/AST/DeclCXX.h"15#include "clang/AST/DeclGroup.h"16#include "clang/AST/DynamicRecursiveASTVisitor.h"17#include "clang/Basic/Diagnostic.h"18#include "clang/Basic/DiagnosticOptions.h"19#include "clang/Basic/FileManager.h"20#include "clang/Basic/LangOptions.h"21#include "clang/Basic/SourceManager.h"22#include "clang/Format/Format.h"23#include "clang/Frontend/CompilerInstance.h"24#include "clang/Frontend/FrontendAction.h"25#include "clang/Frontend/TextDiagnosticPrinter.h"26#include "clang/Rewrite/Core/Rewriter.h"27#include "clang/Tooling/Refactoring/AtomicChange.h"28#include "clang/Tooling/Tooling.h"29#include "llvm/ADT/SmallString.h"30#include "llvm/Support/VirtualFileSystem.h"31#include "gtest/gtest.h"32#include <optional>33 34namespace clang {35namespace tooling {36 37TEST_F(ReplacementTest, CanDeleteAllText) {38  FileID ID = Context.createInMemoryFile("input.cpp", "text");39  SourceLocation Location = Context.getLocation(ID, 1, 1);40  Replacement Replace(createReplacement(Location, 4, ""));41  EXPECT_TRUE(Replace.apply(Context.Rewrite));42  EXPECT_EQ("", Context.getRewrittenText(ID));43}44 45TEST_F(ReplacementTest, CanDeleteAllTextInTextWithNewlines) {46  FileID ID = Context.createInMemoryFile("input.cpp", "line1\nline2\nline3");47  SourceLocation Location = Context.getLocation(ID, 1, 1);48  Replacement Replace(createReplacement(Location, 17, ""));49  EXPECT_TRUE(Replace.apply(Context.Rewrite));50  EXPECT_EQ("", Context.getRewrittenText(ID));51}52 53TEST_F(ReplacementTest, CanAddText) {54  FileID ID = Context.createInMemoryFile("input.cpp", "");55  SourceLocation Location = Context.getLocation(ID, 1, 1);56  Replacement Replace(createReplacement(Location, 0, "result"));57  EXPECT_TRUE(Replace.apply(Context.Rewrite));58  EXPECT_EQ("result", Context.getRewrittenText(ID));59}60 61TEST_F(ReplacementTest, CanReplaceTextAtPosition) {62  FileID ID = Context.createInMemoryFile("input.cpp",63                                         "line1\nline2\nline3\nline4");64  SourceLocation Location = Context.getLocation(ID, 2, 3);65  Replacement Replace(createReplacement(Location, 12, "x"));66  EXPECT_TRUE(Replace.apply(Context.Rewrite));67  EXPECT_EQ("line1\nlixne4", Context.getRewrittenText(ID));68}69 70TEST_F(ReplacementTest, CanReplaceTextAtPositionMultipleTimes) {71  FileID ID = Context.createInMemoryFile("input.cpp",72                                         "line1\nline2\nline3\nline4");73  SourceLocation Location1 = Context.getLocation(ID, 2, 3);74  Replacement Replace1(createReplacement(Location1, 12, "x\ny\n"));75  EXPECT_TRUE(Replace1.apply(Context.Rewrite));76  EXPECT_EQ("line1\nlix\ny\nne4", Context.getRewrittenText(ID));77 78  // Since the original source has not been modified, the (4, 4) points to the79  // 'e' in the original content.80  SourceLocation Location2 = Context.getLocation(ID, 4, 4);81  Replacement Replace2(createReplacement(Location2, 1, "f"));82  EXPECT_TRUE(Replace2.apply(Context.Rewrite));83  EXPECT_EQ("line1\nlix\ny\nnf4", Context.getRewrittenText(ID));84}85 86TEST_F(ReplacementTest, ApplyFailsForNonExistentLocation) {87  Replacement Replace("nonexistent-file.cpp", 0, 1, "");88  EXPECT_FALSE(Replace.apply(Context.Rewrite));89}90 91TEST_F(ReplacementTest, CanRetrivePath) {92  Replacement Replace("/path/to/file.cpp", 0, 1, "");93  EXPECT_EQ("/path/to/file.cpp", Replace.getFilePath());94}95 96TEST_F(ReplacementTest, ReturnsInvalidPath) {97  Replacement Replace1(Context.Sources, SourceLocation(), 0, "");98  EXPECT_TRUE(Replace1.getFilePath().empty());99 100  Replacement Replace2;101  EXPECT_TRUE(Replace2.getFilePath().empty());102}103 104// Checks that an llvm::Error instance contains a ReplacementError with expected105// error code, expected new replacement, and expected existing replacement.106static bool checkReplacementError(llvm::Error &&Error,107                                  replacement_error ExpectedErr,108                                  std::optional<Replacement> ExpectedExisting,109                                  std::optional<Replacement> ExpectedNew) {110  if (!Error) {111    llvm::errs() << "Error is a success.";112    return false;113  }114  std::string ErrorMessage;115  llvm::raw_string_ostream OS(ErrorMessage);116  llvm::handleAllErrors(std::move(Error), [&](const ReplacementError &RE) {117    llvm::errs() << "Handling error...\n";118    if (ExpectedErr != RE.get())119      OS << "Unexpected error code: " << int(RE.get()) << "\n";120    if (ExpectedExisting != RE.getExistingReplacement()) {121      OS << "Expected Existing != Actual Existing.\n";122      if (ExpectedExisting)123        OS << "Expected existing replacement: " << ExpectedExisting->toString()124           << "\n";125      if (RE.getExistingReplacement())126        OS << "Actual existing replacement: "127           << RE.getExistingReplacement()->toString() << "\n";128    }129    if (ExpectedNew != RE.getNewReplacement()) {130      OS << "Expected New != Actual New.\n";131      if (ExpectedNew)132        OS << "Expected new replacement: " << ExpectedNew->toString() << "\n";133      if (RE.getNewReplacement())134        OS << "Actual new replacement: " << RE.getNewReplacement()->toString()135           << "\n";136    }137  });138  if (ErrorMessage.empty()) return true;139  llvm::errs() << ErrorMessage;140  return false;141}142 143TEST_F(ReplacementTest, FailAddReplacements) {144  Replacements Replaces;145  Replacement Deletion("x.cc", 0, 10, "3");146  auto Err = Replaces.add(Deletion);147  EXPECT_TRUE(!Err);148  llvm::consumeError(std::move(Err));149 150  Replacement OverlappingReplacement("x.cc", 0, 2, "a");151  Err = Replaces.add(OverlappingReplacement);152  EXPECT_TRUE(checkReplacementError(std::move(Err),153                                    replacement_error::overlap_conflict,154                                    Deletion, OverlappingReplacement));155 156  Replacement ContainedReplacement("x.cc", 2, 2, "a");157  Err = Replaces.add(Replacement(ContainedReplacement));158  EXPECT_TRUE(checkReplacementError(std::move(Err),159                                    replacement_error::overlap_conflict,160                                    Deletion, ContainedReplacement));161 162  Replacement WrongPathReplacement("y.cc", 20, 2, "");163  Err = Replaces.add(WrongPathReplacement);164  EXPECT_TRUE(checkReplacementError(std::move(Err),165                                    replacement_error::wrong_file_path,166                                    Deletion, WrongPathReplacement));167 168  EXPECT_EQ(1u, Replaces.size());169  EXPECT_EQ(Deletion, *Replaces.begin());170}171 172TEST_F(ReplacementTest, DeletionInReplacements) {173  Replacements Replaces;174  Replacement R("x.cc", 0, 10, "3");175  auto Err = Replaces.add(R);176  EXPECT_TRUE(!Err);177  llvm::consumeError(std::move(Err));178  Err = Replaces.add(Replacement("x.cc", 0, 2, ""));179  EXPECT_TRUE(!Err);180  llvm::consumeError(std::move(Err));181  Err = Replaces.add(Replacement("x.cc", 2, 2, ""));182  EXPECT_TRUE(!Err);183  llvm::consumeError(std::move(Err));184  EXPECT_EQ(1u, Replaces.size());185  EXPECT_EQ(R, *Replaces.begin());186}187 188TEST_F(ReplacementTest, OverlappingReplacements) {189  Replacements Replaces;190  auto Err = Replaces.add(Replacement("x.cc", 0, 3, "345"));191  EXPECT_TRUE(!Err);192  llvm::consumeError(std::move(Err));193  Err = Replaces.add(Replacement("x.cc", 2, 3, "543"));194  EXPECT_TRUE(!Err);195  llvm::consumeError(std::move(Err));196 197  EXPECT_EQ(1u, Replaces.size());198  EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin());199 200  Err = Replaces.add(Replacement("x.cc", 2, 1, "5"));201  EXPECT_TRUE(!Err);202  llvm::consumeError(std::move(Err));203  EXPECT_EQ(1u, Replaces.size());204  EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin());205}206 207TEST_F(ReplacementTest, AddAdjacentInsertionAndReplacement) {208  Replacements Replaces;209  // Test adding an insertion at the offset of an existing replacement.210  auto Err = Replaces.add(Replacement("x.cc", 10, 3, "replace"));211  EXPECT_TRUE(!Err);212  llvm::consumeError(std::move(Err));213  Err = Replaces.add(Replacement("x.cc", 10, 0, "insert"));214  EXPECT_TRUE(!Err);215  llvm::consumeError(std::move(Err));216  EXPECT_EQ(Replaces.size(), 2u);217 218  Replaces.clear();219  // Test overlap with an existing insertion.220  Err = Replaces.add(Replacement("x.cc", 10, 0, "insert"));221  EXPECT_TRUE(!Err);222  llvm::consumeError(std::move(Err));223  Err = Replaces.add(Replacement("x.cc", 10, 3, "replace"));224  EXPECT_TRUE(!Err);225  llvm::consumeError(std::move(Err));226  EXPECT_EQ(Replaces.size(), 2u);227}228 229TEST_F(ReplacementTest, MergeNewDeletions) {230  Replacements Replaces;231  Replacement ContainingReplacement("x.cc", 0, 10, "");232  auto Err = Replaces.add(ContainingReplacement);233  EXPECT_TRUE(!Err);234  llvm::consumeError(std::move(Err));235 236  Err = Replaces.add(Replacement("x.cc", 5, 3, ""));237  EXPECT_TRUE(!Err);238  llvm::consumeError(std::move(Err));239 240  Err = Replaces.add(Replacement("x.cc", 0, 10, ""));241  EXPECT_TRUE(!Err);242  llvm::consumeError(std::move(Err));243 244  Err = Replaces.add(Replacement("x.cc", 5, 5, ""));245  EXPECT_TRUE(!Err);246  llvm::consumeError(std::move(Err));247 248  EXPECT_EQ(1u, Replaces.size());249  EXPECT_EQ(*Replaces.begin(), ContainingReplacement);250}251 252TEST_F(ReplacementTest, MergeOverlappingButNotAdjacentReplacement) {253  Replacements Replaces;254  auto Err = Replaces.add(Replacement("x.cc", 0, 2, ""));255  EXPECT_TRUE(!Err);256  llvm::consumeError(std::move(Err));257 258  Err = Replaces.add(Replacement("x.cc", 5, 5, ""));259  EXPECT_TRUE(!Err);260  llvm::consumeError(std::move(Err));261 262  Replacement After = Replacement("x.cc", 10, 5, "");263  Err = Replaces.add(After);264  EXPECT_TRUE(!Err);265  llvm::consumeError(std::move(Err));266 267  Replacement ContainingReplacement("x.cc", 0, 10, "");268  Err = Replaces.add(ContainingReplacement);269  EXPECT_TRUE(!Err);270  llvm::consumeError(std::move(Err));271 272  EXPECT_EQ(2u, Replaces.size());273  EXPECT_EQ(*Replaces.begin(), ContainingReplacement);274  EXPECT_EQ(*(++Replaces.begin()), After);275}276 277TEST_F(ReplacementTest, InsertionBeforeMergedDeletions) {278  Replacements Replaces;279 280  Replacement Insertion("x.cc", 0, 0, "123");281  auto Err = Replaces.add(Insertion);282  EXPECT_TRUE(!Err);283  llvm::consumeError(std::move(Err));284 285  Err = Replaces.add(Replacement("x.cc", 5, 5, ""));286  EXPECT_TRUE(!Err);287  llvm::consumeError(std::move(Err));288 289  Replacement Deletion("x.cc", 0, 10, "");290  Err = Replaces.add(Deletion);291  EXPECT_TRUE(!Err);292  llvm::consumeError(std::move(Err));293 294  EXPECT_EQ(2u, Replaces.size());295  EXPECT_EQ(*Replaces.begin(), Insertion);296  EXPECT_EQ(*(++Replaces.begin()), Deletion);297}298 299TEST_F(ReplacementTest, MergeOverlappingDeletions) {300  Replacements Replaces;301  auto Err = Replaces.add(Replacement("x.cc", 0, 2, ""));302  EXPECT_TRUE(!Err);303  llvm::consumeError(std::move(Err));304 305  Err = Replaces.add(Replacement("x.cc", 0, 5, ""));306  EXPECT_TRUE(!Err);307  llvm::consumeError(std::move(Err));308 309  EXPECT_EQ(1u, Replaces.size());310  EXPECT_EQ(Replacement("x.cc", 0, 5, ""), *Replaces.begin());311 312  Err = Replaces.add(Replacement("x.cc", 1, 5, ""));313  EXPECT_TRUE(!Err);314  llvm::consumeError(std::move(Err));315  EXPECT_EQ(1u, Replaces.size());316  EXPECT_EQ(Replacement("x.cc", 0, 6, ""), *Replaces.begin());317}318 319TEST_F(ReplacementTest, FailedMergeExistingDeletions) {320  Replacements Replaces;321  Replacement First("x.cc", 0, 2, "");322  auto Err = Replaces.add(First);323  EXPECT_TRUE(!Err);324  llvm::consumeError(std::move(Err));325 326  Replacement Second("x.cc", 5, 5, "");327  Err = Replaces.add(Second);328  EXPECT_TRUE(!Err);329  llvm::consumeError(std::move(Err));330 331  Err = Replaces.add(Replacement("x.cc", 1, 10, ""));332  EXPECT_TRUE(!Err);333  llvm::consumeError(std::move(Err));334 335  EXPECT_EQ(1u, Replaces.size());336  EXPECT_EQ(Replacement("x.cc", 0, 11, ""), *Replaces.begin());337}338 339TEST_F(ReplacementTest, FailAddRegression) {340  Replacements Replaces;341  // Create two replacements, where the second one is an insertion of the empty342  // string exactly at the end of the first one.343  auto Err = Replaces.add(Replacement("x.cc", 0, 10, "1"));344  EXPECT_TRUE(!Err);345  llvm::consumeError(std::move(Err));346  Err = Replaces.add(Replacement("x.cc", 10, 0, ""));347  EXPECT_TRUE(!Err);348  llvm::consumeError(std::move(Err));349 350  // Make sure we find the overlap with the first entry when inserting a351  // replacement that ends exactly at the seam of the existing replacements.352  Replacement OverlappingReplacement("x.cc", 5, 5, "fail");353  Err = Replaces.add(OverlappingReplacement);354  EXPECT_TRUE(checkReplacementError(std::move(Err),355                                    replacement_error::overlap_conflict,356                                    *Replaces.begin(), OverlappingReplacement));357 358  Err = Replaces.add(Replacement("x.cc", 10, 0, ""));359  EXPECT_TRUE(!Err);360  llvm::consumeError(std::move(Err));361}362 363TEST_F(ReplacementTest, InsertAtOffsetOfReplacement) {364  Replacements Replaces;365  auto Err = Replaces.add(Replacement("x.cc", 10, 2, ""));366  EXPECT_TRUE(!Err);367  llvm::consumeError(std::move(Err));368  Err = Replaces.add(Replacement("x.cc", 10, 0, ""));369  EXPECT_TRUE(!Err);370  llvm::consumeError(std::move(Err));371  EXPECT_EQ(Replaces.size(), 2u);372 373  Replaces.clear();374  Err = Replaces.add(Replacement("x.cc", 10, 0, ""));375  EXPECT_TRUE(!Err);376  llvm::consumeError(std::move(Err));377  Err = Replaces.add(Replacement("x.cc", 10, 2, ""));378  EXPECT_TRUE(!Err);379  llvm::consumeError(std::move(Err));380  EXPECT_EQ(Replaces.size(), 2u);381}382 383TEST_F(ReplacementTest, AddInsertAtOtherInsertWhenOderIndependent) {384  Replacements Replaces;385  auto Err = Replaces.add(Replacement("x.cc", 10, 0, "a"));386  EXPECT_TRUE(!Err);387  llvm::consumeError(std::move(Err));388  Replacement ConflictInsertion("x.cc", 10, 0, "b");389  Err = Replaces.add(ConflictInsertion);390  EXPECT_TRUE(checkReplacementError(std::move(Err),391                                    replacement_error::insert_conflict,392                                    *Replaces.begin(), ConflictInsertion));393 394  Replaces.clear();395  Err = Replaces.add(Replacement("x.cc", 10, 0, "a"));396  EXPECT_TRUE(!Err);397  llvm::consumeError(std::move(Err));398  Err = Replaces.add(Replacement("x.cc", 10, 0, "aa"));399  EXPECT_TRUE(!Err);400  llvm::consumeError(std::move(Err));401  EXPECT_EQ(1u, Replaces.size());402  EXPECT_EQ(Replacement("x.cc", 10, 0, "aaa"), *Replaces.begin());403 404  Replaces.clear();405  Err = Replaces.add(Replacement("x.cc", 10, 0, ""));406  EXPECT_TRUE(!Err);407  llvm::consumeError(std::move(Err));408  Err = Replaces.add(Replacement("x.cc", 10, 3, ""));409  EXPECT_TRUE(!Err);410  llvm::consumeError(std::move(Err));411  Err = Replaces.add(Replacement("x.cc", 10, 0, ""));412  EXPECT_TRUE(!Err);413  llvm::consumeError(std::move(Err));414  EXPECT_EQ(2u, Replaces.size());415  EXPECT_EQ(Replacement("x.cc", 10, 0, ""), *Replaces.begin());416  EXPECT_EQ(Replacement("x.cc", 10, 3, ""), *std::next(Replaces.begin()));417}418 419TEST_F(ReplacementTest, InsertBetweenAdjacentReplacements) {420  Replacements Replaces;421  auto Err = Replaces.add(Replacement("x.cc", 10, 5, "a"));422  EXPECT_TRUE(!Err);423  llvm::consumeError(std::move(Err));424  Err = Replaces.add(Replacement("x.cc", 8, 2, "a"));425  EXPECT_TRUE(!Err);426  llvm::consumeError(std::move(Err));427  Err = Replaces.add(Replacement("x.cc", 10, 0, "b"));428  EXPECT_TRUE(!Err);429  llvm::consumeError(std::move(Err));430}431 432TEST_F(ReplacementTest, CanApplyReplacements) {433  FileID ID = Context.createInMemoryFile("input.cpp",434                                         "line1\nline2\nline3\nline4");435  Replacements Replaces =436      toReplacements({Replacement(Context.Sources,437                                  Context.getLocation(ID, 2, 1), 5, "replaced"),438                      Replacement(Context.Sources,439                                  Context.getLocation(ID, 3, 1), 5, "other")});440  EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));441  EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));442}443 444// Verifies that replacement/deletion is applied before insertion at the same445// offset.446TEST_F(ReplacementTest, InsertAndDelete) {447  FileID ID = Context.createInMemoryFile("input.cpp",448                                         "line1\nline2\nline3\nline4");449  Replacements Replaces = toReplacements(450      {Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 6, ""),451       Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 0,452                   "other\n")});453  EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));454  EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID));455}456 457TEST_F(ReplacementTest, AdjacentReplacements) {458  FileID ID = Context.createInMemoryFile("input.cpp",459                                         "ab");460  Replacements Replaces = toReplacements(461      {Replacement(Context.Sources, Context.getLocation(ID, 1, 1), 1, "x"),462       Replacement(Context.Sources, Context.getLocation(ID, 1, 2), 1, "y")});463  EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));464  EXPECT_EQ("xy", Context.getRewrittenText(ID));465}466 467TEST_F(ReplacementTest, AddDuplicateReplacements) {468  FileID ID = Context.createInMemoryFile("input.cpp",469                                         "line1\nline2\nline3\nline4");470  auto Replaces = toReplacements({Replacement(471      Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});472 473  auto Err = Replaces.add(Replacement(474      Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced"));475  EXPECT_TRUE(!Err);476  llvm::consumeError(std::move(Err));477 478  Err = Replaces.add(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),479                                 5, "replaced"));480  EXPECT_TRUE(!Err);481  llvm::consumeError(std::move(Err));482 483  EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));484  EXPECT_EQ("line1\nreplaced\nline3\nline4", Context.getRewrittenText(ID));485}486 487TEST_F(ReplacementTest, FailOrderDependentReplacements) {488  FileID ID = Context.createInMemoryFile("input.cpp",489                                         "line1\nline2\nline3\nline4");490  auto Replaces = toReplacements({Replacement(491      Context.Sources, Context.getLocation(ID, 2, 1), 5, "other")});492 493  Replacement ConflictReplacement(Context.Sources,494                                  Context.getLocation(ID, 2, 1), 5, "rehto");495  auto Err = Replaces.add(ConflictReplacement);496  EXPECT_TRUE(checkReplacementError(std::move(Err),497                                    replacement_error::overlap_conflict,498                                    *Replaces.begin(), ConflictReplacement));499 500  EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));501  EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID));502}503 504TEST_F(ReplacementTest, InvalidSourceLocationFailsApplyAll) {505  Replacements Replaces =506      toReplacements({Replacement(Context.Sources, SourceLocation(), 5, "2")});507 508  EXPECT_FALSE(applyAllReplacements(Replaces, Context.Rewrite));509}510 511TEST_F(ReplacementTest, MultipleFilesReplaceAndFormat) {512  // Column limit is 20.513  std::string Code1 = "Long *a =\n"514                      "    new Long();\n"515                      "long x = 1;";516  std::string Expected1 = "auto a = new Long();\n"517                          "long x =\n"518                          "    12345678901;";519  std::string Code2 = "int x = 123;\n"520                      "int y = 0;";521  std::string Expected2 = "int x =\n"522                          "    1234567890123;\n"523                          "int y = 10;";524  StringRef File1 = "format_1.cpp";525  StringRef File2 = "format_2.cpp";526  FileID ID1 = Context.createInMemoryFile(File1, Code1);527  FileID ID2 = Context.createInMemoryFile(File2, Code2);528 529  // Scrambled the order of replacements.530  std::map<std::string, Replacements> FileToReplaces;531  FileToReplaces[std::string(File1)] = toReplacements(532      {tooling::Replacement(Context.Sources, Context.getLocation(ID1, 1, 1), 6,533                            "auto "),534       tooling::Replacement(Context.Sources, Context.getLocation(ID1, 3, 10), 1,535                            "12345678901")});536  FileToReplaces[std::string(File2)] = toReplacements(537      {tooling::Replacement(Context.Sources, Context.getLocation(ID2, 1, 12), 0,538                            "4567890123"),539       tooling::Replacement(Context.Sources, Context.getLocation(ID2, 2, 9), 1,540                            "10")});541  EXPECT_TRUE(542      formatAndApplyAllReplacements(FileToReplaces, Context.Rewrite,543                                    "{BasedOnStyle: LLVM, ColumnLimit: 20}"));544  EXPECT_EQ(Expected1, Context.getRewrittenText(ID1));545  EXPECT_EQ(Expected2, Context.getRewrittenText(ID2));546}547 548TEST(ShiftedCodePositionTest, FindsNewCodePosition) {549  Replacements Replaces =550      toReplacements({Replacement("", 0, 1, ""), Replacement("", 4, 3, " ")});551  // Assume ' int   i;' is turned into 'int i;' and cursor is located at '|'.552  EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0)); // |int   i;553  EXPECT_EQ(0u, Replaces.getShiftedCodePosition(1)); //  |nt   i;554  EXPECT_EQ(1u, Replaces.getShiftedCodePosition(2)); //  i|t   i;555  EXPECT_EQ(2u, Replaces.getShiftedCodePosition(3)); //  in|   i;556  EXPECT_EQ(3u, Replaces.getShiftedCodePosition(4)); //  int|  i;557  EXPECT_EQ(3u, Replaces.getShiftedCodePosition(5)); //  int | i;558  EXPECT_EQ(3u, Replaces.getShiftedCodePosition(6)); //  int  |i;559  EXPECT_EQ(4u, Replaces.getShiftedCodePosition(7)); //  int   |;560  EXPECT_EQ(5u, Replaces.getShiftedCodePosition(8)); //  int   i|561}562 563TEST(ShiftedCodePositionTest, FindsNewCodePositionWithInserts) {564  Replacements Replaces = toReplacements({Replacement("", 4, 0, "\"\n\"")});565  // Assume '"12345678"' is turned into '"1234"\n"5678"'.566  EXPECT_EQ(3u, Replaces.getShiftedCodePosition(3)); // "123|5678"567  EXPECT_EQ(7u, Replaces.getShiftedCodePosition(4)); // "1234|678"568  EXPECT_EQ(8u, Replaces.getShiftedCodePosition(5)); // "12345|78"569}570 571TEST(ShiftedCodePositionTest, FindsNewCodePositionInReplacedText) {572  // Replace the first four characters with "abcd".573  auto Replaces = toReplacements({Replacement("", 0, 4, "abcd")});574  for (unsigned i = 0; i < 3; ++i)575    EXPECT_EQ(i, Replaces.getShiftedCodePosition(i));576}577 578TEST(ShiftedCodePositionTest, NoReplacementText) {579  Replacements Replaces = toReplacements({Replacement("", 0, 42, "")});580  EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0));581  EXPECT_EQ(0u, Replaces.getShiftedCodePosition(39));582  EXPECT_EQ(3u, Replaces.getShiftedCodePosition(45));583  EXPECT_EQ(0u, Replaces.getShiftedCodePosition(42));584}585 586class FlushRewrittenFilesTest : public ::testing::Test {587public:588   FlushRewrittenFilesTest() {}589 590   ~FlushRewrittenFilesTest() override {591    for (llvm::StringMap<std::string>::iterator I = TemporaryFiles.begin(),592                                                E = TemporaryFiles.end();593         I != E; ++I) {594      llvm::StringRef Name = I->second;595      std::error_code EC = llvm::sys::fs::remove(Name);596      (void)EC;597      assert(!EC);598    }599  }600 601  FileID createFile(llvm::StringRef Name, llvm::StringRef Content) {602    SmallString<1024> Path;603    int FD;604    std::error_code EC = llvm::sys::fs::createTemporaryFile(Name, "", FD, Path);605    assert(!EC);606    (void)EC;607 608    llvm::raw_fd_ostream OutStream(FD, true);609    OutStream << Content;610    OutStream.close();611    auto File = Context.Files.getOptionalFileRef(Path);612    assert(File);613 614    StringRef Found =615        TemporaryFiles.insert(std::make_pair(Name, std::string(Path.str())))616            .first->second;617    assert(Found == Path);618    (void)Found;619    return Context.Sources.createFileID(*File, SourceLocation(),620                                        SrcMgr::C_User);621  }622 623  std::string getFileContentFromDisk(llvm::StringRef Name) {624    std::string Path = TemporaryFiles.lookup(Name);625    assert(!Path.empty());626    // We need to read directly from the FileManager without relaying through627    // a FileEntry, as otherwise we'd read through an already opened file628    // descriptor, which might not see the changes made.629    // FIXME: Figure out whether there is a way to get the SourceManger to630    // reopen the file.631    auto FileBuffer = Context.Files.getBufferForFile(Path);632    return std::string((*FileBuffer)->getBuffer());633  }634 635  llvm::StringMap<std::string> TemporaryFiles;636  RewriterTestContext Context;637};638 639TEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) {640  FileID ID = createFile("input.cpp", "line1\nline2\nline3\nline4");641  Replacements Replaces = toReplacements({Replacement(642      Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});643  EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));644  EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles());645  EXPECT_EQ("line1\nreplaced\nline3\nline4",646            getFileContentFromDisk("input.cpp"));647}648 649namespace {650class TestVisitor : public DynamicRecursiveASTVisitor {651public:652  bool runOver(StringRef Code) {653    return runToolOnCode(std::make_unique<TestAction>(this), Code);654  }655 656protected:657  clang::SourceManager *SM;658  clang::ASTContext *Context;659 660private:661  class FindConsumer : public clang::ASTConsumer {662  public:663    FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}664 665    void HandleTranslationUnit(clang::ASTContext &Context) override {666      Visitor->TraverseDecl(Context.getTranslationUnitDecl());667    }668 669  private:670    TestVisitor *Visitor;671  };672 673  class TestAction : public clang::ASTFrontendAction {674  public:675    TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}676 677    std::unique_ptr<clang::ASTConsumer>678    CreateASTConsumer(clang::CompilerInstance &compiler,679                      llvm::StringRef dummy) override {680      Visitor->SM = &compiler.getSourceManager();681      Visitor->Context = &compiler.getASTContext();682      /// TestConsumer will be deleted by the framework calling us.683      return std::make_unique<FindConsumer>(Visitor);684    }685 686  private:687    TestVisitor *Visitor;688  };689};690} // end namespace691 692void expectReplacementAt(const Replacement &Replace,693                         StringRef File, unsigned Offset, unsigned Length) {694  ASSERT_TRUE(Replace.isApplicable());695  EXPECT_EQ(File, Replace.getFilePath());696  EXPECT_EQ(Offset, Replace.getOffset());697  EXPECT_EQ(Length, Replace.getLength());698}699 700class ClassDeclXVisitor : public TestVisitor {701public:702  bool VisitCXXRecordDecl(CXXRecordDecl *Record) override {703    if (Record->getName() == "X") {704      Replace = Replacement(*SM, Record, "");705    }706    return true;707  }708  Replacement Replace;709};710 711TEST(Replacement, CanBeConstructedFromNode) {712  ClassDeclXVisitor ClassDeclX;713  EXPECT_TRUE(ClassDeclX.runOver("     class X;"));714  expectReplacementAt(ClassDeclX.Replace, "input.cc", 5, 7);715}716 717TEST(Replacement, ReplacesAtSpellingLocation) {718  ClassDeclXVisitor ClassDeclX;719  EXPECT_TRUE(ClassDeclX.runOver("#define A(Y) Y\nA(class X);"));720  expectReplacementAt(ClassDeclX.Replace, "input.cc", 17, 7);721}722 723class CallToFVisitor : public TestVisitor {724public:725  bool VisitCallExpr(CallExpr *Call) override {726    if (Call->getDirectCallee()->getName() == "F") {727      Replace = Replacement(*SM, Call, "");728    }729    return true;730  }731  Replacement Replace;732};733 734TEST(Replacement, FunctionCall) {735  CallToFVisitor CallToF;736  EXPECT_TRUE(CallToF.runOver("void F(); void G() { F(); }"));737  expectReplacementAt(CallToF.Replace, "input.cc", 21, 3);738}739 740TEST(Replacement, TemplatedFunctionCall) {741  CallToFVisitor CallToF;742  EXPECT_TRUE(CallToF.runOver(743        "template <typename T> void F(); void G() { F<int>(); }"));744  expectReplacementAt(CallToF.Replace, "input.cc", 43, 8);745}746 747class NestedNameSpecifierAVisitor : public TestVisitor {748public:749  bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) override {750    if (NestedNameSpecifier NNS = NNSLoc.getNestedNameSpecifier();751        NNS.getKind() == NestedNameSpecifier::Kind::Namespace) {752      if (const auto *NS =753              dyn_cast<NamespaceDecl>(NNSLoc.getNestedNameSpecifier()754                                          .getAsNamespaceAndPrefix()755                                          .Namespace)) {756        if (NS->getName() == "a") {757          Replace = Replacement(*SM, &NNSLoc, "", Context->getLangOpts());758        }759      }760    }761    return TestVisitor::TraverseNestedNameSpecifierLoc(NNSLoc);762  }763  Replacement Replace;764};765 766TEST(Replacement, ColonColon) {767  NestedNameSpecifierAVisitor VisitNNSA;768  EXPECT_TRUE(VisitNNSA.runOver("namespace a { void f() { ::a::f(); } }"));769  expectReplacementAt(VisitNNSA.Replace, "input.cc", 25, 5);770}771 772TEST(Range, overlaps) {773  EXPECT_TRUE(Range(10, 10).overlapsWith(Range(0, 11)));774  EXPECT_TRUE(Range(0, 11).overlapsWith(Range(10, 10)));775  EXPECT_FALSE(Range(10, 10).overlapsWith(Range(0, 10)));776  EXPECT_FALSE(Range(0, 10).overlapsWith(Range(10, 10)));777  EXPECT_TRUE(Range(0, 10).overlapsWith(Range(2, 6)));778  EXPECT_TRUE(Range(2, 6).overlapsWith(Range(0, 10)));779}780 781TEST(Range, contains) {782  EXPECT_TRUE(Range(0, 10).contains(Range(0, 10)));783  EXPECT_TRUE(Range(0, 10).contains(Range(2, 6)));784  EXPECT_FALSE(Range(2, 6).contains(Range(0, 10)));785  EXPECT_FALSE(Range(0, 10).contains(Range(0, 11)));786}787 788TEST(Range, CalculateRangesOfReplacements) {789  // Before: aaaabbbbbbz790  // After : bbbbbbzzzzzzoooooooooooooooo791  Replacements Replaces = toReplacements(792      {Replacement("foo", 0, 4, ""), Replacement("foo", 10, 1, "zzzzzz"),793       Replacement("foo", 11, 0, "oooooooooooooooo")});794 795  std::vector<Range> Ranges = Replaces.getAffectedRanges();796 797  EXPECT_EQ(2ul, Ranges.size());798  EXPECT_TRUE(Ranges[0].getOffset() == 0);799  EXPECT_TRUE(Ranges[0].getLength() == 0);800  EXPECT_TRUE(Ranges[1].getOffset() == 6);801  EXPECT_TRUE(Ranges[1].getLength() == 22);802}803 804TEST(Range, CalculateRangesOfInsertionAroundReplacement) {805  Replacements Replaces = toReplacements(806      {Replacement("foo", 0, 2, ""), Replacement("foo", 0, 0, "ba")});807 808  std::vector<Range> Ranges = Replaces.getAffectedRanges();809 810  EXPECT_EQ(1ul, Ranges.size());811  EXPECT_EQ(0u, Ranges[0].getOffset());812  EXPECT_EQ(2u, Ranges[0].getLength());813}814 815TEST(Range, RangesAfterEmptyReplacements) {816  std::vector<Range> Ranges = {Range(5, 6), Range(10, 5)};817  Replacements Replaces;818  std::vector<Range> Expected = {Range(5, 10)};819  EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));820}821 822TEST(Range, RangesAfterReplacements) {823  std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};824  Replacements Replaces = toReplacements({Replacement("foo", 0, 2, "1234")});825  std::vector<Range> Expected = {Range(0, 4), Range(7, 2), Range(12, 5)};826  EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));827}828 829TEST(Range, RangesBeforeReplacements) {830  std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};831  Replacements Replaces = toReplacements({Replacement("foo", 20, 2, "1234")});832  std::vector<Range> Expected = {Range(5, 2), Range(10, 5), Range(20, 4)};833  EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));834}835 836TEST(Range, NotAffectedByReplacements) {837  std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};838  Replacements Replaces = toReplacements({Replacement("foo", 3, 2, "12"),839                                          Replacement("foo", 12, 2, "12"),840                                          Replacement("foo", 20, 5, "")});841  std::vector<Range> Expected = {Range(0, 2), Range(3, 4), Range(10, 5),842                                 Range(20, 0)};843  EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));844}845 846TEST(Range, RangesWithNonOverlappingReplacements) {847  std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};848  Replacements Replaces = toReplacements({Replacement("foo", 3, 1, ""),849                                          Replacement("foo", 6, 1, "123"),850                                          Replacement("foo", 20, 2, "12345")});851  std::vector<Range> Expected = {Range(0, 2), Range(3, 0), Range(4, 4),852                                 Range(11, 5), Range(21, 5)};853  EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));854}855 856TEST(Range, RangesWithOverlappingReplacements) {857  std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5),858                               Range(30, 5)};859  Replacements Replaces = toReplacements(860      {Replacement("foo", 1, 3, ""), Replacement("foo", 6, 1, "123"),861       Replacement("foo", 13, 3, "1"), Replacement("foo", 25, 15, "")});862  std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(12, 5),863                                 Range(22, 0)};864  EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));865}866 867TEST(Range, MergeIntoOneRange) {868  std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};869  Replacements Replaces =870      toReplacements({Replacement("foo", 1, 15, "1234567890")});871  std::vector<Range> Expected = {Range(0, 15)};872  EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));873}874 875TEST(Range, ReplacementsStartingAtRangeOffsets) {876  std::vector<Range> Ranges = {Range(0, 2), Range(5, 5), Range(15, 5)};877  Replacements Replaces = toReplacements(878      {Replacement("foo", 0, 2, "12"), Replacement("foo", 5, 1, "123"),879       Replacement("foo", 7, 4, "12345"), Replacement("foo", 15, 10, "12")});880  std::vector<Range> Expected = {Range(0, 2), Range(5, 9), Range(18, 2)};881  EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));882}883 884TEST(Range, ReplacementsEndingAtRangeEnds) {885  std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};886  Replacements Replaces = toReplacements(887      {Replacement("foo", 6, 1, "123"), Replacement("foo", 17, 3, "12")});888  std::vector<Range> Expected = {Range(0, 2), Range(5, 4), Range(17, 4)};889  EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));890}891 892TEST(Range, AjacentReplacements) {893  std::vector<Range> Ranges = {Range(0, 0), Range(15, 5)};894  Replacements Replaces = toReplacements(895      {Replacement("foo", 1, 2, "123"), Replacement("foo", 12, 3, "1234")});896  std::vector<Range> Expected = {Range(0, 0), Range(1, 3), Range(13, 9)};897  EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));898}899 900TEST(Range, MergeRangesAfterReplacements) {901  std::vector<Range> Ranges = {Range(8, 0), Range(5, 2), Range(9, 0), Range(0, 1)};902  Replacements Replaces = toReplacements({Replacement("foo", 1, 3, ""),903                                          Replacement("foo", 7, 0, "12"),904                                          Replacement("foo", 9, 2, "")});905  std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(7, 0),906                                 Range(8, 0)};907  EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));908}909 910TEST(Range, ConflictingRangesBeforeReplacements) {911  std::vector<Range> Ranges = {Range(8, 3), Range(5, 4), Range(9, 1)};912  Replacements Replaces = toReplacements({Replacement("foo", 1, 3, "")});913  std::vector<Range> Expected = {Range(1, 0), Range(2, 6)};914  EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));915}916 917class MergeReplacementsTest : public ::testing::Test {918protected:919  void mergeAndTestRewrite(StringRef Code, StringRef Intermediate,920                           StringRef Result, const Replacements &First,921                           const Replacements &Second) {922    // These are mainly to verify the test itself and make it easier to read.923    auto AfterFirst = applyAllReplacements(Code, First);924    EXPECT_TRUE(static_cast<bool>(AfterFirst));925    auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);926    EXPECT_TRUE(static_cast<bool>(InSequenceRewrite));927    EXPECT_EQ(Intermediate, *AfterFirst);928    EXPECT_EQ(Result, *InSequenceRewrite);929 930    tooling::Replacements Merged = First.merge(Second);931    auto MergedRewrite = applyAllReplacements(Code, Merged);932    EXPECT_TRUE(static_cast<bool>(MergedRewrite));933    EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);934    if (*InSequenceRewrite != *MergedRewrite)935      for (tooling::Replacement M : Merged)936        llvm::errs() << M.getOffset() << " " << M.getLength() << " "937                     << M.getReplacementText() << "\n";938  }939  void mergeAndTestRewrite(StringRef Code, const Replacements &First,940                           const Replacements &Second) {941    auto AfterFirst = applyAllReplacements(Code, First);942    EXPECT_TRUE(static_cast<bool>(AfterFirst));943    auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);944    tooling::Replacements Merged = First.merge(Second);945    auto MergedRewrite = applyAllReplacements(Code, Merged);946    EXPECT_TRUE(static_cast<bool>(MergedRewrite));947    EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);948    if (*InSequenceRewrite != *MergedRewrite)949      for (tooling::Replacement M : Merged)950        llvm::errs() << M.getOffset() << " " << M.getLength() << " "951                     << M.getReplacementText() << "\n";952  }953};954 955TEST_F(MergeReplacementsTest, Offsets) {956  mergeAndTestRewrite("aaa", "aabab", "cacabab",957                      toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),958                      toReplacements({{"", 0, 0, "c"}, {"", 1, 0, "c"}}));959  mergeAndTestRewrite("aaa", "babaa", "babacac",960                      toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "b"}}),961                      toReplacements({{"", 4, 0, "c"}, {"", 5, 0, "c"}}));962  mergeAndTestRewrite("aaaa", "aaa", "aac", toReplacements({{"", 1, 1, ""}}),963                      toReplacements({{"", 2, 1, "c"}}));964 965  mergeAndTestRewrite("aa", "bbabba", "bbabcba",966                      toReplacements({{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}),967                      toReplacements({{"", 4, 0, "c"}}));968}969 970TEST_F(MergeReplacementsTest, Concatenations) {971  // Basic concatenations. It is important to merge these into a single972  // replacement to ensure the correct order.973  {974    auto First = toReplacements({{"", 0, 0, "a"}});975    auto Second = toReplacements({{"", 1, 0, "b"}});976    EXPECT_EQ(toReplacements({{"", 0, 0, "ab"}}), First.merge(Second));977  }978  {979    auto First = toReplacements({{"", 0, 0, "a"}});980    auto Second = toReplacements({{"", 0, 0, "b"}});981    EXPECT_EQ(toReplacements({{"", 0, 0, "ba"}}), First.merge(Second));982  }983  mergeAndTestRewrite("", "a", "ab", toReplacements({{"", 0, 0, "a"}}),984                      toReplacements({{"", 1, 0, "b"}}));985  mergeAndTestRewrite("", "a", "ba", toReplacements({{"", 0, 0, "a"}}),986                      toReplacements({{"", 0, 0, "b"}}));987}988 989TEST_F(MergeReplacementsTest, NotChangingLengths) {990  mergeAndTestRewrite("aaaa", "abba", "acca",991                      toReplacements({{"", 1, 2, "bb"}}),992                      toReplacements({{"", 1, 2, "cc"}}));993  mergeAndTestRewrite("aaaa", "abba", "abcc",994                      toReplacements({{"", 1, 2, "bb"}}),995                      toReplacements({{"", 2, 2, "cc"}}));996  mergeAndTestRewrite("aaaa", "abba", "ccba",997                      toReplacements({{"", 1, 2, "bb"}}),998                      toReplacements({{"", 0, 2, "cc"}}));999  mergeAndTestRewrite("aaaaaa", "abbdda", "abccda",1000                      toReplacements({{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}),1001                      toReplacements({{"", 2, 2, "cc"}}));1002}1003 1004TEST_F(MergeReplacementsTest, OverlappingRanges) {1005  mergeAndTestRewrite("aaa", "bbd", "bcbcd",1006                      toReplacements({{"", 0, 1, "bb"}, {"", 1, 2, "d"}}),1007                      toReplacements({{"", 1, 0, "c"}, {"", 2, 0, "c"}}));1008 1009  mergeAndTestRewrite("aaaa", "aabbaa", "acccca",1010                      toReplacements({{"", 2, 0, "bb"}}),1011                      toReplacements({{"", 1, 4, "cccc"}}));1012  mergeAndTestRewrite("aaaa", "aababa", "acccca",1013                      toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),1014                      toReplacements({{"", 1, 4, "cccc"}}));1015  mergeAndTestRewrite("aaaaaa", "abbbba", "abba",1016                      toReplacements({{"", 1, 4, "bbbb"}}),1017                      toReplacements({{"", 2, 2, ""}}));1018  mergeAndTestRewrite("aaaa", "aa", "cc",1019                      toReplacements({{"", 1, 1, ""}, {"", 2, 1, ""}}),1020                      toReplacements({{"", 0, 2, "cc"}}));1021  mergeAndTestRewrite("aa", "abbba", "abcbcba",1022                      toReplacements({{"", 1, 0, "bbb"}}),1023                      toReplacements({{"", 2, 0, "c"}, {"", 3, 0, "c"}}));1024 1025  mergeAndTestRewrite(1026      "aaa", "abbab", "ccdd",1027      toReplacements({{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}}),1028      toReplacements({{"", 0, 2, "cc"}, {"", 2, 3, "dd"}}));1029  mergeAndTestRewrite(1030      "aa", "babbab", "ccdd",1031      toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}}),1032      toReplacements({{"", 0, 3, "cc"}, {"", 3, 3, "dd"}}));1033}1034 1035static constexpr bool usesWindowsPaths() {1036  return is_style_windows(llvm::sys::path::Style::native);1037}1038 1039TEST(DeduplicateByFileTest, PathsWithDots) {1040  std::map<std::string, Replacements> FileToReplaces;1041  auto VFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();1042  FileManager FileMgr(FileSystemOptions(), VFS);1043  StringRef Path1 = usesWindowsPaths() ? "a\\b\\..\\.\\c.h" : "a/b/.././c.h";1044  StringRef Path2 = usesWindowsPaths() ? "a\\c.h" : "a/c.h";1045  EXPECT_TRUE(VFS->addFile(Path1, 0, llvm::MemoryBuffer::getMemBuffer("")));1046  EXPECT_TRUE(VFS->addFile(Path2, 0, llvm::MemoryBuffer::getMemBuffer("")));1047  FileToReplaces[std::string(Path1)] = Replacements();1048  FileToReplaces[std::string(Path2)] = Replacements();1049  FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces);1050  EXPECT_EQ(1u, FileToReplaces.size());1051  EXPECT_EQ(Path1, FileToReplaces.begin()->first);1052}1053 1054TEST(DeduplicateByFileTest, PathWithDotSlash) {1055  std::map<std::string, Replacements> FileToReplaces;1056  auto VFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();1057  FileManager FileMgr(FileSystemOptions(), VFS);1058  StringRef Path1 = usesWindowsPaths() ? ".\\a\\b\\c.h" : "./a/b/c.h";1059  StringRef Path2 = usesWindowsPaths() ? "a\\b\\c.h" : "a/b/c.h";1060  EXPECT_TRUE(VFS->addFile(Path1, 0, llvm::MemoryBuffer::getMemBuffer("")));1061  EXPECT_TRUE(VFS->addFile(Path2, 0, llvm::MemoryBuffer::getMemBuffer("")));1062  FileToReplaces[std::string(Path1)] = Replacements();1063  FileToReplaces[std::string(Path2)] = Replacements();1064  FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces);1065  EXPECT_EQ(1u, FileToReplaces.size());1066  EXPECT_EQ(Path1, FileToReplaces.begin()->first);1067}1068 1069TEST(DeduplicateByFileTest, NonExistingFilePath) {1070  std::map<std::string, Replacements> FileToReplaces;1071  auto VFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();1072  FileManager FileMgr(FileSystemOptions(), VFS);1073  StringRef Path1 = usesWindowsPaths() ? ".\\a\\b\\c.h" : "./a/b/c.h";1074  StringRef Path2 = usesWindowsPaths() ? "a\\b\\c.h" : "a/b/c.h";1075  FileToReplaces[std::string(Path1)] = Replacements();1076  FileToReplaces[std::string(Path2)] = Replacements();1077  FileToReplaces = groupReplacementsByFile(FileMgr, FileToReplaces);1078  EXPECT_TRUE(FileToReplaces.empty());1079}1080 1081class AtomicChangeTest : public ::testing::Test {1082  protected:1083    void SetUp() override {1084      DefaultFileID = Context.createInMemoryFile("input.cpp", DefaultCode);1085      DefaultLoc = Context.Sources.getLocForStartOfFile(DefaultFileID)1086                       .getLocWithOffset(20);1087      assert(DefaultLoc.isValid() && "Default location must be valid.");1088    }1089 1090    RewriterTestContext Context;1091    std::string DefaultCode = std::string(100, 'a');1092    unsigned DefaultOffset = 20;1093    SourceLocation DefaultLoc;1094    FileID DefaultFileID;1095};1096 1097TEST_F(AtomicChangeTest, AtomicChangeToYAML) {1098  AtomicChange Change(Context.Sources, DefaultLoc);1099  llvm::Error Err =1100      Change.insert(Context.Sources, DefaultLoc, "aa", /*InsertAfter=*/false);1101  ASSERT_TRUE(!Err);1102  Err = Change.insert(Context.Sources, DefaultLoc.getLocWithOffset(10), "bb",1103                    /*InsertAfter=*/false);1104  ASSERT_TRUE(!Err);1105  Change.addHeader("a.h");1106  Change.removeHeader("b.h");1107  std::string YAMLString = Change.toYAMLString();1108 1109  // NOTE: If this test starts to fail for no obvious reason, check whitespace.1110  ASSERT_STREQ("---\n"1111               "Key:             'input.cpp:20'\n"1112               "FilePath:        input.cpp\n"1113               "Error:           ''\n"1114               "InsertedHeaders:\n"1115               "  - a.h\n"1116               "RemovedHeaders:\n"1117               "  - b.h\n"1118               "Replacements:\n"1119               "  - FilePath:        input.cpp\n"1120               "    Offset:          20\n"1121               "    Length:          0\n"1122               "    ReplacementText: aa\n"1123               "  - FilePath:        input.cpp\n"1124               "    Offset:          30\n"1125               "    Length:          0\n"1126               "    ReplacementText: bb\n"1127               "...\n",1128               YAMLString.c_str());1129}1130 1131TEST_F(AtomicChangeTest, YAMLToAtomicChange) {1132  std::string YamlContent = "---\n"1133                            "Key:             'input.cpp:20'\n"1134                            "FilePath:        input.cpp\n"1135                            "Error:           'ok'\n"1136                            "InsertedHeaders:\n"1137                            "  - a.h\n"1138                            "RemovedHeaders:\n"1139                            "  - b.h\n"1140                            "Replacements:\n"1141                            "  - FilePath:        input.cpp\n"1142                            "    Offset:          20\n"1143                            "    Length:          0\n"1144                            "    ReplacementText: aa\n"1145                            "  - FilePath:        input.cpp\n"1146                            "    Offset:          30\n"1147                            "    Length:          0\n"1148                            "    ReplacementText: bb\n"1149                            "...\n";1150  AtomicChange ExpectedChange(Context.Sources, DefaultLoc);1151  llvm::Error Err = ExpectedChange.insert(Context.Sources, DefaultLoc, "aa",1152                                        /*InsertAfter=*/false);1153  ASSERT_TRUE(!Err);1154  Err = ExpectedChange.insert(Context.Sources, DefaultLoc.getLocWithOffset(10),1155                            "bb", /*InsertAfter=*/false);1156  ASSERT_TRUE(!Err);1157 1158  ExpectedChange.addHeader("a.h");1159  ExpectedChange.removeHeader("b.h");1160  ExpectedChange.setError("ok");1161 1162  AtomicChange ActualChange = AtomicChange::convertFromYAML(YamlContent);1163  EXPECT_EQ(ExpectedChange.getKey(), ActualChange.getKey());1164  EXPECT_EQ(ExpectedChange.getFilePath(), ActualChange.getFilePath());1165  EXPECT_EQ(ExpectedChange.getError(), ActualChange.getError());1166  EXPECT_EQ(ExpectedChange.getInsertedHeaders(),1167            ActualChange.getInsertedHeaders());1168  EXPECT_EQ(ExpectedChange.getRemovedHeaders(),1169            ActualChange.getRemovedHeaders());1170  EXPECT_EQ(ExpectedChange.getReplacements().size(),1171            ActualChange.getReplacements().size());1172  EXPECT_EQ(2u, ActualChange.getReplacements().size());1173  EXPECT_EQ(*ExpectedChange.getReplacements().begin(),1174            *ActualChange.getReplacements().begin());1175  EXPECT_EQ(*(++ExpectedChange.getReplacements().begin()),1176            *(++ActualChange.getReplacements().begin()));1177}1178 1179TEST_F(AtomicChangeTest, CheckKeyAndKeyFile) {1180  AtomicChange Change(Context.Sources, DefaultLoc);1181  EXPECT_EQ("input.cpp:20", Change.getKey());1182  EXPECT_EQ("input.cpp", Change.getFilePath());1183}1184 1185TEST_F(AtomicChangeTest, Replace) {1186  AtomicChange Change(Context.Sources, DefaultLoc);1187  llvm::Error Err = Change.replace(Context.Sources, DefaultLoc, 2, "aa");1188  ASSERT_TRUE(!Err);1189  EXPECT_EQ(Change.getReplacements().size(), 1u);1190  EXPECT_EQ(*Change.getReplacements().begin(),1191            Replacement(Context.Sources, DefaultLoc, 2, "aa"));1192 1193  // Add a new replacement that conflicts with the existing one.1194  Err = Change.replace(Context.Sources, DefaultLoc, 3, "ab");1195  EXPECT_TRUE((bool)Err);1196  llvm::consumeError(std::move(Err));1197  EXPECT_EQ(Change.getReplacements().size(), 1u);1198}1199 1200TEST_F(AtomicChangeTest, ReplaceWithRange) {1201  AtomicChange Change(Context.Sources, DefaultLoc);1202  SourceLocation End = DefaultLoc.getLocWithOffset(20);1203  llvm::Error Err = Change.replace(1204      Context.Sources, CharSourceRange::getCharRange(DefaultLoc, End), "aa");1205  ASSERT_TRUE(!Err);1206  EXPECT_EQ(Change.getReplacements().size(), 1u);1207  EXPECT_EQ(*Change.getReplacements().begin(),1208            Replacement(Context.Sources, DefaultLoc, 20, "aa"));1209}1210 1211TEST_F(AtomicChangeTest, InsertBefore) {1212  AtomicChange Change(Context.Sources, DefaultLoc);1213  llvm::Error Err = Change.insert(Context.Sources, DefaultLoc, "aa");1214  ASSERT_TRUE(!Err);1215  EXPECT_EQ(Change.getReplacements().size(), 1u);1216  EXPECT_EQ(*Change.getReplacements().begin(),1217            Replacement(Context.Sources, DefaultLoc, 0, "aa"));1218  Err = Change.insert(Context.Sources, DefaultLoc, "b", /*InsertAfter=*/false);1219  ASSERT_TRUE(!Err);1220  EXPECT_EQ(Change.getReplacements().size(), 1u);1221  EXPECT_EQ(*Change.getReplacements().begin(),1222            Replacement(Context.Sources, DefaultLoc, 0, "baa"));1223}1224 1225TEST_F(AtomicChangeTest, InsertAfter) {1226  AtomicChange Change(Context.Sources, DefaultLoc);1227  llvm::Error Err = Change.insert(Context.Sources, DefaultLoc, "aa");1228  ASSERT_TRUE(!Err);1229  EXPECT_EQ(Change.getReplacements().size(), 1u);1230  EXPECT_EQ(*Change.getReplacements().begin(),1231            Replacement(Context.Sources, DefaultLoc, 0, "aa"));1232  Err = Change.insert(Context.Sources, DefaultLoc, "b");1233  ASSERT_TRUE(!Err);1234  EXPECT_EQ(Change.getReplacements().size(), 1u);1235  EXPECT_EQ(*Change.getReplacements().begin(),1236            Replacement(Context.Sources, DefaultLoc, 0, "aab"));1237}1238 1239TEST_F(AtomicChangeTest, InsertBeforeWithInvalidLocation) {1240  AtomicChange Change(Context.Sources, DefaultLoc);1241  llvm::Error Err =1242      Change.insert(Context.Sources, DefaultLoc, "a", /*InsertAfter=*/false);1243  ASSERT_TRUE(!Err);1244 1245  // Invalid location.1246  Err = Change.insert(Context.Sources, SourceLocation(), "a",1247                    /*InsertAfter=*/false);1248  ASSERT_TRUE((bool)Err);1249  EXPECT_TRUE(checkReplacementError(1250      std::move(Err), replacement_error::wrong_file_path,1251      Replacement(Context.Sources, DefaultLoc, 0, "a"),1252      Replacement(Context.Sources, SourceLocation(), 0, "a")));1253}1254 1255TEST_F(AtomicChangeTest, InsertBeforeToWrongFile) {1256  AtomicChange Change(Context.Sources, DefaultLoc);1257  llvm::Error Err =1258      Change.insert(Context.Sources, DefaultLoc, "a", /*InsertAfter=*/false);1259  ASSERT_TRUE(!Err);1260 1261  // Inserting at a different file.1262  FileID NewID = Context.createInMemoryFile("extra.cpp", DefaultCode);1263  SourceLocation NewLoc = Context.Sources.getLocForStartOfFile(NewID);1264  Err = Change.insert(Context.Sources, NewLoc, "b", /*InsertAfter=*/false);1265  ASSERT_TRUE((bool)Err);1266  EXPECT_TRUE(1267      checkReplacementError(std::move(Err), replacement_error::wrong_file_path,1268                            Replacement(Context.Sources, DefaultLoc, 0, "a"),1269                            Replacement(Context.Sources, NewLoc, 0, "b")));1270}1271 1272TEST_F(AtomicChangeTest, InsertAfterWithInvalidLocation) {1273  AtomicChange Change(Context.Sources, DefaultLoc);1274  llvm::Error Err = Change.insert(Context.Sources, DefaultLoc, "a");1275  ASSERT_TRUE(!Err);1276 1277  // Invalid location.1278  Err = Change.insert(Context.Sources, SourceLocation(), "b");1279  ASSERT_TRUE((bool)Err);1280  EXPECT_TRUE(checkReplacementError(1281      std::move(Err), replacement_error::wrong_file_path,1282      Replacement(Context.Sources, DefaultLoc, 0, "a"),1283      Replacement(Context.Sources, SourceLocation(), 0, "b")));1284}1285 1286TEST_F(AtomicChangeTest, Metadata) {1287  AtomicChange Change(Context.Sources, DefaultLoc, 17);1288  const llvm::Any &Metadata = Change.getMetadata();1289  ASSERT_TRUE(llvm::any_cast<int>(&Metadata));1290  EXPECT_EQ(llvm::any_cast<int>(Metadata), 17);1291}1292 1293TEST_F(AtomicChangeTest, NoMetadata) {1294  AtomicChange Change(Context.Sources, DefaultLoc);1295  EXPECT_FALSE(Change.getMetadata().has_value());1296}1297 1298class ApplyAtomicChangesTest : public ::testing::Test {1299protected:1300  ApplyAtomicChangesTest() : FilePath("file.cc") {1301    Spec.Cleanup = true;1302    Spec.Format = ApplyChangesSpec::kAll;1303    Spec.Style = format::getLLVMStyle();1304  }1305 1306  ~ApplyAtomicChangesTest() override {}1307 1308  void setInput(llvm::StringRef Input) {1309    Code = std::string(Input);1310    FID = Context.createInMemoryFile(FilePath, Code);1311  }1312 1313  SourceLocation getLoc(unsigned Offset) const {1314    return Context.Sources.getLocForStartOfFile(FID).getLocWithOffset(Offset);1315  }1316 1317  AtomicChange replacementToAtomicChange(llvm::StringRef Key, unsigned Offset,1318                                         unsigned Length,1319                                         llvm::StringRef Text) {1320    AtomicChange Change(FilePath, Key);1321    llvm::Error Err =1322        Change.replace(Context.Sources, getLoc(Offset), Length, Text);1323    EXPECT_FALSE(Err);1324    return Change;1325  }1326 1327  std::string rewrite(bool FailureExpected = false) {1328    llvm::Expected<std::string> ChangedCode =1329        applyAtomicChanges(FilePath, Code, Changes, Spec);1330    EXPECT_EQ(FailureExpected, !ChangedCode);1331    if (!ChangedCode) {1332      llvm::errs() << "Failed to apply changes: "1333                   << llvm::toString(ChangedCode.takeError()) << "\n";1334      return "";1335    }1336    return *ChangedCode;1337  }1338 1339  RewriterTestContext Context;1340  FileID FID;1341  ApplyChangesSpec Spec;1342  std::string Code;1343  std::string FilePath;1344  llvm::SmallVector<AtomicChange, 8> Changes;1345};1346 1347TEST_F(ApplyAtomicChangesTest, BasicRefactoring) {1348  setInput("int a;");1349  AtomicChange Change(FilePath, "key1");1350  Changes.push_back(replacementToAtomicChange("key1", 4, 1, "b"));1351  EXPECT_EQ("int b;", rewrite());1352}1353 1354TEST_F(ApplyAtomicChangesTest, SeveralRefactorings) {1355  setInput("int a;\n"1356           "int b;");1357  Changes.push_back(replacementToAtomicChange("key1", 0, 3, "float"));1358  Changes.push_back(replacementToAtomicChange("key2", 4, 1, "f"));1359  Changes.push_back(replacementToAtomicChange("key3", 11, 1, "g"));1360  Changes.push_back(replacementToAtomicChange("key4", 7, 3, "float"));1361  EXPECT_EQ("float f;\n"1362            "float g;",1363            rewrite());1364}1365 1366TEST_F(ApplyAtomicChangesTest, IgnorePathsInRefactorings) {1367  setInput("int a;\n"1368           "int b;");1369  Changes.push_back(replacementToAtomicChange("key1", 4, 1, "aa"));1370 1371  FileID ID = Context.createInMemoryFile("AnotherFile", "12345678912345");1372  Changes.emplace_back("AnotherFile", "key2");1373  auto Err = Changes.back().replace(1374      Context.Sources,1375      Context.Sources.getLocForStartOfFile(ID).getLocWithOffset(11), 1, "bb");1376  ASSERT_TRUE(!Err);1377  EXPECT_EQ("int aa;\n"1378            "int bb;",1379            rewrite());1380}1381 1382TEST_F(ApplyAtomicChangesTest, AppliesDuplicateInsertions) {1383  setInput("int a;");1384  Changes.push_back(replacementToAtomicChange("key1", 5, 0, "b"));1385  Changes.push_back(replacementToAtomicChange("key2", 5, 0, "b"));1386  EXPECT_EQ("int abb;", rewrite());1387}1388 1389TEST_F(ApplyAtomicChangesTest, BailsOnOverlappingRefactorings) {1390  setInput("int a;");1391  Changes.push_back(replacementToAtomicChange("key1", 0, 5, "float f"));1392  Changes.push_back(replacementToAtomicChange("key2", 4, 1, "b"));1393  EXPECT_EQ("", rewrite(/*FailureExpected=*/true));1394}1395 1396TEST_F(ApplyAtomicChangesTest, BasicReformatting) {1397  setInput("int  a;");1398  Changes.push_back(replacementToAtomicChange("key1", 5, 1, "b"));1399  EXPECT_EQ("int b;", rewrite());1400}1401 1402TEST_F(ApplyAtomicChangesTest, OnlyFormatWhenViolateColumnLimits) {1403  Spec.Format = ApplyChangesSpec::kViolations;1404  Spec.Style.ColumnLimit = 8;1405  setInput("int  a;\n"1406           "int    a;\n"1407           "int  aaaaaaaa;\n");1408  Changes.push_back(replacementToAtomicChange("key1", 5, 1, "x"));1409  Changes.push_back(replacementToAtomicChange("key2", 15, 1, "x"));1410  Changes.push_back(replacementToAtomicChange("key3", 23, 8, "xx"));1411  EXPECT_EQ("int  x;\n"1412            "int x;\n"1413            "int  xx;\n",1414            rewrite());1415}1416 1417TEST_F(ApplyAtomicChangesTest, LastLineViolateColumnLimits) {1418  Spec.Format = ApplyChangesSpec::kViolations;1419  Spec.Style.ColumnLimit = 8;1420  setInput("int  a;\n"1421           "int    a;");1422  Changes.push_back(replacementToAtomicChange("key1", 0, 1, "i"));1423  Changes.push_back(replacementToAtomicChange("key2", 15, 2, "y;"));1424  EXPECT_EQ("int  a;\n"1425            "int y;",1426            rewrite());1427}1428 1429TEST_F(ApplyAtomicChangesTest, LastLineWithNewlineViolateColumnLimits) {1430  Spec.Format = ApplyChangesSpec::kViolations;1431  Spec.Style.ColumnLimit = 8;1432  setInput("int  a;\n"1433           "int   a;\n");1434  Changes.push_back(replacementToAtomicChange("key1", 0, 1, "i"));1435  Changes.push_back(replacementToAtomicChange("key2", 14, 3, "y;\n"));1436  EXPECT_EQ("int  a;\n"1437            "int   y;\n",1438            rewrite());1439}1440 1441TEST_F(ApplyAtomicChangesTest, Longer) {1442  setInput("int  a;");1443  Changes.push_back(replacementToAtomicChange("key1", 5, 1, "bbb"));1444  EXPECT_EQ("int bbb;", rewrite());1445}1446 1447TEST_F(ApplyAtomicChangesTest, Shorter) {1448  setInput("int  aaa;");1449  Changes.push_back(replacementToAtomicChange("key1", 5, 3, "b"));1450  EXPECT_EQ("int b;", rewrite());1451}1452 1453TEST_F(ApplyAtomicChangesTest, OnlyFormatChangedLines) {1454  setInput("int  aaa;\n"1455           "int a = b;\n"1456           "int  bbb;");1457  Changes.push_back(replacementToAtomicChange("key1", 14, 1, "b"));1458  EXPECT_EQ("int  aaa;\n"1459            "int b = b;\n"1460            "int  bbb;",1461            rewrite());1462}1463 1464TEST_F(ApplyAtomicChangesTest, DisableFormatting) {1465  Spec.Format = ApplyChangesSpec::kNone;1466  setInput("int  aaa;\n"1467           "int a   = b;\n"1468           "int  bbb;");1469  Changes.push_back(replacementToAtomicChange("key1", 14, 1, "b"));1470  EXPECT_EQ("int  aaa;\n"1471            "int b   = b;\n"1472            "int  bbb;",1473            rewrite());1474}1475 1476TEST_F(ApplyAtomicChangesTest, AdaptsToLocalPointerStyle) {1477  setInput("int *aaa;\n"1478           "int *bbb;");1479  Changes.push_back(replacementToAtomicChange("key1", 0, 0, "int* ccc;\n"));1480  EXPECT_EQ("int *ccc;\n"1481            "int *aaa;\n"1482            "int *bbb;",1483            rewrite());1484}1485 1486TEST_F(ApplyAtomicChangesTest, AcceptsSurroundingFormatting) {1487  setInput("   int  aaa;\n"1488           "   int a = b;\n"1489           "   int  bbb;");1490  Changes.push_back(replacementToAtomicChange("key1", 20, 1, "b"));1491  EXPECT_EQ("   int  aaa;\n"1492            "   int b = b;\n"1493            "   int  bbb;",1494            rewrite());1495}1496 1497TEST_F(ApplyAtomicChangesTest, BailsOutOnConflictingChanges) {1498  setInput("int c;\n"1499           "int f;");1500  // Insertions at the same offset are only allowed in the same AtomicChange.1501  Changes.push_back(replacementToAtomicChange("key1", 0, 0, "int a;\n"));1502  Changes.push_back(replacementToAtomicChange("key2", 0, 0, "int b;\n"));1503  EXPECT_EQ("", rewrite(/*FailureExpected=*/true));1504}1505 1506TEST_F(ApplyAtomicChangesTest, InsertsNewIncludesInRightOrder) {1507  setInput("int a;");1508  Changes.emplace_back(FilePath, "key1");1509  Changes.back().addHeader("b");1510  Changes.back().addHeader("c");1511  Changes.emplace_back(FilePath, "key2");1512  Changes.back().addHeader("a");1513  EXPECT_EQ("#include \"a\"\n"1514            "#include \"b\"\n"1515            "#include \"c\"\n"1516            "int a;",1517            rewrite());1518}1519 1520TEST_F(ApplyAtomicChangesTest, RemoveAndSortIncludes) {1521  setInput("#include \"a\"\n"1522           "#include \"b\"\n"1523           "#include \"c\"\n"1524           "\n"1525           "int a;");1526  Changes.emplace_back(FilePath, "key1");1527  Changes.back().removeHeader("b");1528  EXPECT_EQ("#include \"a\"\n"1529            "#include \"c\"\n"1530            "\n"1531            "int a;",1532            rewrite());1533}1534TEST_F(ApplyAtomicChangesTest, InsertsSystemIncludes) {1535  setInput("#include <asys>\n"1536           "#include <csys>\n"1537           "\n"1538           "#include \"a\"\n"1539           "#include \"c\"\n");1540  Changes.emplace_back(FilePath, "key1");1541  Changes.back().addHeader("<asys>"); // Already exists.1542  Changes.back().addHeader("<b>");1543  Changes.back().addHeader("<d>");1544  Changes.back().addHeader("\"b-already-escaped\"");1545  EXPECT_EQ("#include <asys>\n"1546            "#include <b>\n"1547            "#include <csys>\n"1548            "#include <d>\n"1549            "\n"1550            "#include \"a\"\n"1551            "#include \"b-already-escaped\"\n"1552            "#include \"c\"\n",1553            rewrite());1554}1555 1556TEST_F(ApplyAtomicChangesTest, RemoveSystemIncludes) {1557  setInput("#include <a>\n"1558           "#include <b>\n"1559           "\n"1560           "#include \"c\""1561           "\n"1562           "int a;");1563  Changes.emplace_back(FilePath, "key1");1564  Changes.back().removeHeader("<a>");1565  EXPECT_EQ("#include <b>\n"1566            "\n"1567            "#include \"c\""1568            "\n"1569            "int a;",1570            rewrite());1571}1572 1573TEST_F(ApplyAtomicChangesTest,1574       DoNotFormatFollowingLinesIfSeparatedWithNewline) {1575  setInput("#ifndef __H__\n"1576           "#define __H__\n"1577           "#include \"b\"\n"1578           "\n"1579           "int  a;\n"1580           "int  a;\n"1581           "int  a;\n"1582           "#endif // __H__\n");1583  Changes.push_back(replacementToAtomicChange("key1",1584                                              llvm::StringRef("#ifndef __H__\n"1585                                                              "#define __H__\n"1586                                                              "\n"1587                                                              "#include \"b\"\n"1588                                                              "int  a;\n"1589                                                              "int  ")1590                                                  .size(),1591                                              1, "b"));1592  Changes.back().addHeader("a");1593  EXPECT_EQ("#ifndef __H__\n"1594            "#define __H__\n"1595            "#include \"a\"\n"1596            "#include \"b\"\n"1597            "\n"1598            "int  a;\n"1599            "int b;\n"1600            "int  a;\n"1601            "#endif // __H__\n",1602            rewrite());1603}1604 1605TEST_F(ApplyAtomicChangesTest, FormatsCorrectLineWhenHeaderIsRemoved) {1606  setInput("#include \"a\"\n"1607           "\n"1608           "int  a;\n"1609           "int  a;\n"1610           "int  a;");1611  Changes.push_back(replacementToAtomicChange("key1", 27, 1, "b"));1612  Changes.back().removeHeader("a");1613  EXPECT_EQ("\n"1614            "int  a;\n"1615            "int b;\n"1616            "int  a;",1617            rewrite());1618}1619 1620TEST_F(ApplyAtomicChangesTest, CleansUpCtorInitializers) {1621  setInput("A::A() : a(), b() {}\n"1622           "A::A() : a(), b() {}\n"1623           "A::A() : a(), b() {}\n"1624           "A::A() : a()/**/, b() {}\n"1625           "A::A() : a()  ,// \n"1626           "   /**/    b()    {}");1627  Changes.emplace_back(FilePath, "key1");1628  auto Err = Changes.back().replace(Context.Sources, getLoc(9), 3, "");1629  ASSERT_TRUE(!Err);1630  Err = Changes.back().replace(Context.Sources, getLoc(35), 3, "");1631  ASSERT_TRUE(!Err);1632  Err = Changes.back().replace(Context.Sources, getLoc(51), 3, "");1633  ASSERT_TRUE(!Err);1634  Err = Changes.back().replace(Context.Sources, getLoc(56), 3, "");1635  ASSERT_TRUE(!Err);1636  Err = Changes.back().replace(Context.Sources, getLoc(72), 3, "");1637  ASSERT_TRUE(!Err);1638  Err = Changes.back().replace(Context.Sources, getLoc(97), 3, "");1639  ASSERT_TRUE(!Err);1640  Err = Changes.back().replace(Context.Sources, getLoc(118), 3, "");1641  ASSERT_TRUE(!Err);1642  EXPECT_EQ("A::A() : b() {}\n"1643            "A::A() : a() {}\n"1644            "A::A() {}\n"1645            "A::A() : b() {}\n"1646            "A::A() {}",1647            rewrite());1648}1649 1650TEST_F(ApplyAtomicChangesTest, CleansUpParameterLists) {1651  setInput("void f(int i, float f, string s);\n"1652           "f(1, 2.0f, \"a\");\n"1653           "g(1, 1);");1654  Changes.emplace_back(FilePath, "key1");1655  auto Err = Changes.back().replace(Context.Sources, getLoc(7), 5, "");1656  ASSERT_TRUE(!Err);1657  Err = Changes.back().replace(Context.Sources, getLoc(23), 8, "");1658  ASSERT_TRUE(!Err);1659  Err = Changes.back().replace(Context.Sources, getLoc(36), 1, "");1660  ASSERT_TRUE(!Err);1661  Err = Changes.back().replace(Context.Sources, getLoc(45), 3, "");1662  ASSERT_TRUE(!Err);1663  Err = Changes.back().replace(Context.Sources, getLoc(53), 1, "");1664  ASSERT_TRUE(!Err);1665  Err = Changes.back().replace(Context.Sources, getLoc(56), 1, "");1666  ASSERT_TRUE(!Err);1667  EXPECT_EQ("void f(float f);\n"1668            "f(2.0f);\n"1669            "g();",1670            rewrite());1671}1672 1673TEST_F(ApplyAtomicChangesTest, DisableCleanup) {1674  Spec.Cleanup = false;1675  setInput("void f(int i, float f, string s);\n"1676           "f(1, 2.0f, \"a\");\n"1677           "g(1, 1);");1678  Changes.emplace_back(FilePath, "key1");1679  auto Err = Changes.back().replace(Context.Sources, getLoc(7), 5, "");1680  ASSERT_TRUE(!Err);1681  Err = Changes.back().replace(Context.Sources, getLoc(23), 8, "");1682  ASSERT_TRUE(!Err);1683  Err = Changes.back().replace(Context.Sources, getLoc(36), 1, "");1684  ASSERT_TRUE(!Err);1685  Err = Changes.back().replace(Context.Sources, getLoc(45), 3, "");1686  ASSERT_TRUE(!Err);1687  Err = Changes.back().replace(Context.Sources, getLoc(53), 1, "");1688  ASSERT_TRUE(!Err);1689  Err = Changes.back().replace(Context.Sources, getLoc(56), 1, "");1690  ASSERT_TRUE(!Err);1691  EXPECT_EQ("void f(, float f, );\n"1692            "f(, 2.0f, );\n"1693            "g(, );",1694            rewrite());1695}1696 1697TEST_F(ApplyAtomicChangesTest, EverythingDeleted) {1698  setInput("int a;");1699  Changes.push_back(replacementToAtomicChange("key1", 0, 6, ""));1700  EXPECT_EQ("", rewrite());1701}1702 1703TEST_F(ApplyAtomicChangesTest, DoesNotDeleteInserts) {1704  setInput("int a;\n"1705           "int b;");1706  Changes.emplace_back(FilePath, "key1");1707  auto Err = Changes.back().replace(Context.Sources, getLoc(4), 1, "");1708  ASSERT_TRUE(!Err);1709  Err = Changes.back().replace(Context.Sources, getLoc(4), 0, "b");1710  ASSERT_TRUE(!Err);1711  Err = Changes.back().replace(Context.Sources, getLoc(11), 0, "a");1712  ASSERT_TRUE(!Err);1713  Err = Changes.back().replace(Context.Sources, getLoc(11), 1, "");1714  ASSERT_TRUE(!Err);1715  EXPECT_EQ("int b;\n"1716            "int a;",1717            rewrite());1718}1719 1720} // end namespace tooling1721} // end namespace clang1722