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