blob: 6fbb328732dac922018f65ead8d6961b672e496b [file] [log] [blame]
Manuel Klimek3f001342012-05-23 16:29:20 +00001//===- unittest/Tooling/RefactoringTest.cpp - Refactoring unit tests ------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Eric Liu40ef2fb2016-08-01 10:16:37 +000010#include "ReplacementTest.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000011#include "RewriterTestContext.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000012#include "clang/AST/ASTConsumer.h"
Chandler Carruth320d9662012-12-04 09:45:34 +000013#include "clang/AST/ASTContext.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000014#include "clang/AST/DeclCXX.h"
15#include "clang/AST/DeclGroup.h"
16#include "clang/AST/RecursiveASTVisitor.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000017#include "clang/Basic/Diagnostic.h"
Douglas Gregor275e8832012-10-23 22:55:10 +000018#include "clang/Basic/DiagnosticOptions.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000019#include "clang/Basic/FileManager.h"
20#include "clang/Basic/LangOptions.h"
21#include "clang/Basic/SourceManager.h"
Eric Liu4c1ef97a2016-03-29 16:31:53 +000022#include "clang/Format/Format.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000023#include "clang/Frontend/CompilerInstance.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000024#include "clang/Frontend/FrontendAction.h"
25#include "clang/Frontend/TextDiagnosticPrinter.h"
Ted Kremenekcdf81492012-09-01 05:09:24 +000026#include "clang/Rewrite/Core/Rewriter.h"
Chandler Carruth320d9662012-12-04 09:45:34 +000027#include "clang/Tooling/Refactoring.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000028#include "clang/Tooling/Tooling.h"
29#include "llvm/ADT/SmallString.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000030#include "gtest/gtest.h"
31
32namespace clang {
33namespace tooling {
34
Manuel Klimek3f001342012-05-23 16:29:20 +000035TEST_F(ReplacementTest, CanDeleteAllText) {
36 FileID ID = Context.createInMemoryFile("input.cpp", "text");
37 SourceLocation Location = Context.getLocation(ID, 1, 1);
38 Replacement Replace(createReplacement(Location, 4, ""));
39 EXPECT_TRUE(Replace.apply(Context.Rewrite));
40 EXPECT_EQ("", Context.getRewrittenText(ID));
41}
42
43TEST_F(ReplacementTest, CanDeleteAllTextInTextWithNewlines) {
44 FileID ID = Context.createInMemoryFile("input.cpp", "line1\nline2\nline3");
45 SourceLocation Location = Context.getLocation(ID, 1, 1);
46 Replacement Replace(createReplacement(Location, 17, ""));
47 EXPECT_TRUE(Replace.apply(Context.Rewrite));
48 EXPECT_EQ("", Context.getRewrittenText(ID));
49}
50
51TEST_F(ReplacementTest, CanAddText) {
52 FileID ID = Context.createInMemoryFile("input.cpp", "");
53 SourceLocation Location = Context.getLocation(ID, 1, 1);
54 Replacement Replace(createReplacement(Location, 0, "result"));
55 EXPECT_TRUE(Replace.apply(Context.Rewrite));
56 EXPECT_EQ("result", Context.getRewrittenText(ID));
57}
58
59TEST_F(ReplacementTest, CanReplaceTextAtPosition) {
60 FileID ID = Context.createInMemoryFile("input.cpp",
61 "line1\nline2\nline3\nline4");
62 SourceLocation Location = Context.getLocation(ID, 2, 3);
63 Replacement Replace(createReplacement(Location, 12, "x"));
64 EXPECT_TRUE(Replace.apply(Context.Rewrite));
65 EXPECT_EQ("line1\nlixne4", Context.getRewrittenText(ID));
66}
67
68TEST_F(ReplacementTest, CanReplaceTextAtPositionMultipleTimes) {
69 FileID ID = Context.createInMemoryFile("input.cpp",
70 "line1\nline2\nline3\nline4");
71 SourceLocation Location1 = Context.getLocation(ID, 2, 3);
72 Replacement Replace1(createReplacement(Location1, 12, "x\ny\n"));
73 EXPECT_TRUE(Replace1.apply(Context.Rewrite));
74 EXPECT_EQ("line1\nlix\ny\nne4", Context.getRewrittenText(ID));
75
76 // Since the original source has not been modified, the (4, 4) points to the
77 // 'e' in the original content.
78 SourceLocation Location2 = Context.getLocation(ID, 4, 4);
79 Replacement Replace2(createReplacement(Location2, 1, "f"));
80 EXPECT_TRUE(Replace2.apply(Context.Rewrite));
81 EXPECT_EQ("line1\nlix\ny\nnf4", Context.getRewrittenText(ID));
82}
83
84TEST_F(ReplacementTest, ApplyFailsForNonExistentLocation) {
85 Replacement Replace("nonexistent-file.cpp", 0, 1, "");
86 EXPECT_FALSE(Replace.apply(Context.Rewrite));
87}
88
89TEST_F(ReplacementTest, CanRetrivePath) {
90 Replacement Replace("/path/to/file.cpp", 0, 1, "");
91 EXPECT_EQ("/path/to/file.cpp", Replace.getFilePath());
92}
93
94TEST_F(ReplacementTest, ReturnsInvalidPath) {
95 Replacement Replace1(Context.Sources, SourceLocation(), 0, "");
96 EXPECT_TRUE(Replace1.getFilePath().empty());
97
98 Replacement Replace2;
99 EXPECT_TRUE(Replace2.getFilePath().empty());
100}
101
Eric Liu40ef2fb2016-08-01 10:16:37 +0000102TEST_F(ReplacementTest, FailAddReplacements) {
103 Replacements Replaces;
104 auto Err = Replaces.add(Replacement("x.cc", 0, 10, "3"));
105 EXPECT_TRUE(!Err);
106 llvm::consumeError(std::move(Err));
107 Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
108 EXPECT_TRUE((bool)Err);
109 llvm::consumeError(std::move(Err));
110 Err = Replaces.add(Replacement("x.cc", 2, 2, ""));
111 EXPECT_TRUE((bool)Err);
112 llvm::consumeError(std::move(Err));
113 Err = Replaces.add(Replacement("y.cc", 20, 2, ""));
114 EXPECT_TRUE((bool)Err);
115 llvm::consumeError(std::move(Err));
116}
117
Manuel Klimek3f001342012-05-23 16:29:20 +0000118TEST_F(ReplacementTest, CanApplyReplacements) {
119 FileID ID = Context.createInMemoryFile("input.cpp",
120 "line1\nline2\nline3\nline4");
Eric Liu40ef2fb2016-08-01 10:16:37 +0000121 Replacements Replaces =
122 toReplacements({Replacement(Context.Sources,
123 Context.getLocation(ID, 2, 1), 5, "replaced"),
124 Replacement(Context.Sources,
125 Context.getLocation(ID, 3, 1), 5, "other")});
Edwin Vane349e1c12013-08-13 17:38:19 +0000126 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
127 EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
128}
129
Manuel Klimek3f001342012-05-23 16:29:20 +0000130TEST_F(ReplacementTest, SkipsDuplicateReplacements) {
131 FileID ID = Context.createInMemoryFile("input.cpp",
132 "line1\nline2\nline3\nline4");
Eric Liu40ef2fb2016-08-01 10:16:37 +0000133 auto Replaces = toReplacements({Replacement(
134 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
135
136 auto Err = Replaces.add(Replacement(
137 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced"));
138 EXPECT_TRUE((bool)Err);
139 llvm::consumeError(std::move(Err));
140
141 Err = Replaces.add(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
142 5, "replaced"));
143 EXPECT_TRUE((bool)Err);
144 llvm::consumeError(std::move(Err));
145
Manuel Klimek3f001342012-05-23 16:29:20 +0000146 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
147 EXPECT_EQ("line1\nreplaced\nline3\nline4", Context.getRewrittenText(ID));
148}
149
Eric Liu40ef2fb2016-08-01 10:16:37 +0000150TEST_F(ReplacementTest, InvalidSourceLocationFailsApplyAll) {
151 Replacements Replaces =
152 toReplacements({Replacement(Context.Sources, SourceLocation(), 5, "2")});
153
Manuel Klimek3f001342012-05-23 16:29:20 +0000154 EXPECT_FALSE(applyAllReplacements(Replaces, Context.Rewrite));
Manuel Klimek3f001342012-05-23 16:29:20 +0000155}
156
Eric Liu4c1ef97a2016-03-29 16:31:53 +0000157TEST_F(ReplacementTest, MultipleFilesReplaceAndFormat) {
158 // Column limit is 20.
159 std::string Code1 = "Long *a =\n"
160 " new Long();\n"
161 "long x = 1;";
162 std::string Expected1 = "auto a = new Long();\n"
163 "long x =\n"
164 " 12345678901;";
165 std::string Code2 = "int x = 123;\n"
166 "int y = 0;";
167 std::string Expected2 = "int x =\n"
168 " 1234567890123;\n"
169 "int y = 10;";
Eric Liu40ef2fb2016-08-01 10:16:37 +0000170 StringRef File1 = "format_1.cpp";
171 StringRef File2 = "format_2.cpp";
172 FileID ID1 = Context.createInMemoryFile(File1, Code1);
173 FileID ID2 = Context.createInMemoryFile(File2, Code2);
Eric Liu4c1ef97a2016-03-29 16:31:53 +0000174
Eric Liu4c1ef97a2016-03-29 16:31:53 +0000175 // Scrambled the order of replacements.
Eric Liu40ef2fb2016-08-01 10:16:37 +0000176 std::map<std::string, Replacements> FileToReplaces;
177 FileToReplaces[File1] = toReplacements(
178 {tooling::Replacement(Context.Sources, Context.getLocation(ID1, 1, 1), 6,
179 "auto "),
180 tooling::Replacement(Context.Sources, Context.getLocation(ID1, 3, 10), 1,
181 "12345678901")});
182 FileToReplaces[File2] = toReplacements(
183 {tooling::Replacement(Context.Sources, Context.getLocation(ID2, 1, 12), 0,
184 "4567890123"),
185 tooling::Replacement(Context.Sources, Context.getLocation(ID2, 2, 9), 1,
186 "10")});
187 EXPECT_TRUE(
188 formatAndApplyAllReplacements(FileToReplaces, Context.Rewrite,
189 "{BasedOnStyle: LLVM, ColumnLimit: 20}"));
Eric Liu4c1ef97a2016-03-29 16:31:53 +0000190 EXPECT_EQ(Expected1, Context.getRewrittenText(ID1));
191 EXPECT_EQ(Expected2, Context.getRewrittenText(ID2));
192}
193
Daniel Jasper2a250b82013-05-21 12:21:39 +0000194TEST(ShiftedCodePositionTest, FindsNewCodePosition) {
Eric Liu40ef2fb2016-08-01 10:16:37 +0000195 Replacements Replaces =
196 toReplacements({Replacement("", 0, 1, ""), Replacement("", 4, 3, " ")});
Daniel Jasper2a250b82013-05-21 12:21:39 +0000197 // Assume ' int i;' is turned into 'int i;' and cursor is located at '|'.
Eric Liu40ef2fb2016-08-01 10:16:37 +0000198 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0)); // |int i;
199 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(1)); // |nt i;
200 EXPECT_EQ(1u, Replaces.getShiftedCodePosition(2)); // i|t i;
201 EXPECT_EQ(2u, Replaces.getShiftedCodePosition(3)); // in| i;
202 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(4)); // int| i;
203 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(5)); // int | i;
204 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(6)); // int |i;
205 EXPECT_EQ(4u, Replaces.getShiftedCodePosition(7)); // int |;
206 EXPECT_EQ(5u, Replaces.getShiftedCodePosition(8)); // int i|
Edwin Vane18e503c2013-08-27 15:44:26 +0000207}
208
Daniel Jasper2a250b82013-05-21 12:21:39 +0000209TEST(ShiftedCodePositionTest, FindsNewCodePositionWithInserts) {
Eric Liu40ef2fb2016-08-01 10:16:37 +0000210 Replacements Replaces = toReplacements({Replacement("", 4, 0, "\"\n\"")});
Daniel Jasper2a250b82013-05-21 12:21:39 +0000211 // Assume '"12345678"' is turned into '"1234"\n"5678"'.
Eric Liu40ef2fb2016-08-01 10:16:37 +0000212 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(3)); // "123|5678"
213 EXPECT_EQ(7u, Replaces.getShiftedCodePosition(4)); // "1234|678"
214 EXPECT_EQ(8u, Replaces.getShiftedCodePosition(5)); // "12345|78"
Daniel Jasper3fed9452015-11-23 08:33:48 +0000215}
216
217TEST(ShiftedCodePositionTest, FindsNewCodePositionInReplacedText) {
Daniel Jasper3fed9452015-11-23 08:33:48 +0000218 // Replace the first four characters with "abcd".
Eric Liu40ef2fb2016-08-01 10:16:37 +0000219 auto Replaces = toReplacements({Replacement("", 0, 4, "abcd")});
Daniel Jasper3fed9452015-11-23 08:33:48 +0000220 for (unsigned i = 0; i < 3; ++i)
Eric Liu40ef2fb2016-08-01 10:16:37 +0000221 EXPECT_EQ(i, Replaces.getShiftedCodePosition(i));
222}
223
224TEST(ShiftedCodePositionTest, NoReplacementText) {
225 Replacements Replaces = toReplacements({Replacement("", 0, 42, "")});
226 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0));
227 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(39));
228 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(45));
229 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(42));
Daniel Jasper2a250b82013-05-21 12:21:39 +0000230}
231
Manuel Klimek3f001342012-05-23 16:29:20 +0000232class FlushRewrittenFilesTest : public ::testing::Test {
Rafael Espindola641c6a12013-06-26 15:01:50 +0000233public:
234 FlushRewrittenFilesTest() {}
Manuel Klimek3f001342012-05-23 16:29:20 +0000235
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000236 ~FlushRewrittenFilesTest() override {
Rafael Espindola641c6a12013-06-26 15:01:50 +0000237 for (llvm::StringMap<std::string>::iterator I = TemporaryFiles.begin(),
238 E = TemporaryFiles.end();
239 I != E; ++I) {
240 llvm::StringRef Name = I->second;
Rafael Espindolac0809172014-06-12 14:02:15 +0000241 std::error_code EC = llvm::sys::fs::remove(Name);
Rafael Espindola641c6a12013-06-26 15:01:50 +0000242 (void)EC;
243 assert(!EC);
244 }
Manuel Klimek3f001342012-05-23 16:29:20 +0000245 }
246
247 FileID createFile(llvm::StringRef Name, llvm::StringRef Content) {
Rafael Espindola641c6a12013-06-26 15:01:50 +0000248 SmallString<1024> Path;
249 int FD;
Rafael Espindolac0809172014-06-12 14:02:15 +0000250 std::error_code EC = llvm::sys::fs::createTemporaryFile(Name, "", FD, Path);
Rafael Espindola641c6a12013-06-26 15:01:50 +0000251 assert(!EC);
252 (void)EC;
253
254 llvm::raw_fd_ostream OutStream(FD, true);
Manuel Klimek3f001342012-05-23 16:29:20 +0000255 OutStream << Content;
256 OutStream.close();
257 const FileEntry *File = Context.Files.getFile(Path);
Craig Topper416fa342014-06-08 08:38:12 +0000258 assert(File != nullptr);
Rafael Espindola641c6a12013-06-26 15:01:50 +0000259
David Blaikie13156b62014-11-19 03:06:06 +0000260 StringRef Found =
261 TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second;
Rafael Espindola641c6a12013-06-26 15:01:50 +0000262 assert(Found == Path);
263 (void)Found;
Manuel Klimek3f001342012-05-23 16:29:20 +0000264 return Context.Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
265 }
266
267 std::string getFileContentFromDisk(llvm::StringRef Name) {
Rafael Espindola641c6a12013-06-26 15:01:50 +0000268 std::string Path = TemporaryFiles.lookup(Name);
269 assert(!Path.empty());
Manuel Klimek3f001342012-05-23 16:29:20 +0000270 // We need to read directly from the FileManager without relaying through
271 // a FileEntry, as otherwise we'd read through an already opened file
272 // descriptor, which might not see the changes made.
273 // FIXME: Figure out whether there is a way to get the SourceManger to
274 // reopen the file.
Benjamin Kramera8857962014-10-26 22:44:13 +0000275 auto FileBuffer = Context.Files.getBufferForFile(Path);
276 return (*FileBuffer)->getBuffer();
Manuel Klimek3f001342012-05-23 16:29:20 +0000277 }
278
Rafael Espindola641c6a12013-06-26 15:01:50 +0000279 llvm::StringMap<std::string> TemporaryFiles;
Manuel Klimek3f001342012-05-23 16:29:20 +0000280 RewriterTestContext Context;
281};
282
283TEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) {
284 FileID ID = createFile("input.cpp", "line1\nline2\nline3\nline4");
Eric Liu40ef2fb2016-08-01 10:16:37 +0000285 Replacements Replaces = toReplacements({Replacement(
286 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
Manuel Klimek3f001342012-05-23 16:29:20 +0000287 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
288 EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles());
289 EXPECT_EQ("line1\nreplaced\nline3\nline4",
290 getFileContentFromDisk("input.cpp"));
291}
292
293namespace {
294template <typename T>
295class TestVisitor : public clang::RecursiveASTVisitor<T> {
296public:
297 bool runOver(StringRef Code) {
298 return runToolOnCode(new TestAction(this), Code);
299 }
300
301protected:
302 clang::SourceManager *SM;
Manuel Klimek94a89232015-06-03 13:10:41 +0000303 clang::ASTContext *Context;
Manuel Klimek3f001342012-05-23 16:29:20 +0000304
305private:
306 class FindConsumer : public clang::ASTConsumer {
307 public:
308 FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}
309
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000310 void HandleTranslationUnit(clang::ASTContext &Context) override {
Manuel Klimek3f001342012-05-23 16:29:20 +0000311 Visitor->TraverseDecl(Context.getTranslationUnitDecl());
312 }
313
314 private:
315 TestVisitor *Visitor;
316 };
317
318 class TestAction : public clang::ASTFrontendAction {
319 public:
320 TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
321
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000322 std::unique_ptr<clang::ASTConsumer>
David Blaikie6beb6aa2014-08-10 19:56:51 +0000323 CreateASTConsumer(clang::CompilerInstance &compiler,
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000324 llvm::StringRef dummy) override {
Manuel Klimek3f001342012-05-23 16:29:20 +0000325 Visitor->SM = &compiler.getSourceManager();
Manuel Klimek94a89232015-06-03 13:10:41 +0000326 Visitor->Context = &compiler.getASTContext();
Manuel Klimek3f001342012-05-23 16:29:20 +0000327 /// TestConsumer will be deleted by the framework calling us.
David Blaikie6beb6aa2014-08-10 19:56:51 +0000328 return llvm::make_unique<FindConsumer>(Visitor);
Manuel Klimek3f001342012-05-23 16:29:20 +0000329 }
330
331 private:
332 TestVisitor *Visitor;
333 };
334};
335} // end namespace
336
337void expectReplacementAt(const Replacement &Replace,
338 StringRef File, unsigned Offset, unsigned Length) {
339 ASSERT_TRUE(Replace.isApplicable());
340 EXPECT_EQ(File, Replace.getFilePath());
341 EXPECT_EQ(Offset, Replace.getOffset());
342 EXPECT_EQ(Length, Replace.getLength());
343}
344
345class ClassDeclXVisitor : public TestVisitor<ClassDeclXVisitor> {
346public:
347 bool VisitCXXRecordDecl(CXXRecordDecl *Record) {
348 if (Record->getName() == "X") {
349 Replace = Replacement(*SM, Record, "");
350 }
351 return true;
352 }
353 Replacement Replace;
354};
355
356TEST(Replacement, CanBeConstructedFromNode) {
357 ClassDeclXVisitor ClassDeclX;
358 EXPECT_TRUE(ClassDeclX.runOver(" class X;"));
359 expectReplacementAt(ClassDeclX.Replace, "input.cc", 5, 7);
360}
361
362TEST(Replacement, ReplacesAtSpellingLocation) {
363 ClassDeclXVisitor ClassDeclX;
364 EXPECT_TRUE(ClassDeclX.runOver("#define A(Y) Y\nA(class X);"));
365 expectReplacementAt(ClassDeclX.Replace, "input.cc", 17, 7);
366}
367
368class CallToFVisitor : public TestVisitor<CallToFVisitor> {
369public:
370 bool VisitCallExpr(CallExpr *Call) {
371 if (Call->getDirectCallee()->getName() == "F") {
372 Replace = Replacement(*SM, Call, "");
373 }
374 return true;
375 }
376 Replacement Replace;
377};
378
379TEST(Replacement, FunctionCall) {
380 CallToFVisitor CallToF;
381 EXPECT_TRUE(CallToF.runOver("void F(); void G() { F(); }"));
382 expectReplacementAt(CallToF.Replace, "input.cc", 21, 3);
383}
384
385TEST(Replacement, TemplatedFunctionCall) {
386 CallToFVisitor CallToF;
387 EXPECT_TRUE(CallToF.runOver(
388 "template <typename T> void F(); void G() { F<int>(); }"));
389 expectReplacementAt(CallToF.Replace, "input.cc", 43, 8);
390}
391
Manuel Klimek94a89232015-06-03 13:10:41 +0000392class NestedNameSpecifierAVisitor
393 : public TestVisitor<NestedNameSpecifierAVisitor> {
394public:
395 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) {
396 if (NNSLoc.getNestedNameSpecifier()) {
397 if (const NamespaceDecl* NS = NNSLoc.getNestedNameSpecifier()->getAsNamespace()) {
398 if (NS->getName() == "a") {
399 Replace = Replacement(*SM, &NNSLoc, "", Context->getLangOpts());
400 }
401 }
402 }
403 return TestVisitor<NestedNameSpecifierAVisitor>::TraverseNestedNameSpecifierLoc(
404 NNSLoc);
405 }
406 Replacement Replace;
407};
408
409TEST(Replacement, ColonColon) {
410 NestedNameSpecifierAVisitor VisitNNSA;
411 EXPECT_TRUE(VisitNNSA.runOver("namespace a { void f() { ::a::f(); } }"));
412 expectReplacementAt(VisitNNSA.Replace, "input.cc", 25, 5);
413}
414
Manuel Klimekdce23472013-07-19 12:12:36 +0000415TEST(Range, overlaps) {
416 EXPECT_TRUE(Range(10, 10).overlapsWith(Range(0, 11)));
417 EXPECT_TRUE(Range(0, 11).overlapsWith(Range(10, 10)));
418 EXPECT_FALSE(Range(10, 10).overlapsWith(Range(0, 10)));
419 EXPECT_FALSE(Range(0, 10).overlapsWith(Range(10, 10)));
420 EXPECT_TRUE(Range(0, 10).overlapsWith(Range(2, 6)));
Edwin Vanec5148482013-08-13 18:11:16 +0000421 EXPECT_TRUE(Range(2, 6).overlapsWith(Range(0, 10)));
Manuel Klimekdce23472013-07-19 12:12:36 +0000422}
423
424TEST(Range, contains) {
425 EXPECT_TRUE(Range(0, 10).contains(Range(0, 10)));
426 EXPECT_TRUE(Range(0, 10).contains(Range(2, 6)));
427 EXPECT_FALSE(Range(2, 6).contains(Range(0, 10)));
428 EXPECT_FALSE(Range(0, 10).contains(Range(0, 11)));
429}
430
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000431TEST(Range, CalculateRangesOfReplacements) {
432 // Before: aaaabbbbbbz
433 // After : bbbbbbzzzzzzoooooooooooooooo
Eric Liu40ef2fb2016-08-01 10:16:37 +0000434 Replacements Replaces = toReplacements(
435 {Replacement("foo", 0, 4, ""), Replacement("foo", 10, 1, "zzzzzz"),
436 Replacement("foo", 11, 0, "oooooooooooooooo")});
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000437
Eric Liu40ef2fb2016-08-01 10:16:37 +0000438 std::vector<Range> Ranges = Replaces.getAffectedRanges();
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000439
Eric Liu8b636db2016-06-21 17:56:31 +0000440 EXPECT_EQ(2ul, Ranges.size());
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000441 EXPECT_TRUE(Ranges[0].getOffset() == 0);
442 EXPECT_TRUE(Ranges[0].getLength() == 0);
443 EXPECT_TRUE(Ranges[1].getOffset() == 6);
Eric Liu8b636db2016-06-21 17:56:31 +0000444 EXPECT_TRUE(Ranges[1].getLength() == 22);
445}
446
447TEST(Range, RangesAfterReplacements) {
448 std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000449 Replacements Replaces = toReplacements({Replacement("foo", 0, 2, "1234")});
Eric Liu8b636db2016-06-21 17:56:31 +0000450 std::vector<Range> Expected = {Range(0, 4), Range(7, 2), Range(12, 5)};
451 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
452}
453
454TEST(Range, RangesBeforeReplacements) {
455 std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000456 Replacements Replaces = toReplacements({Replacement("foo", 20, 2, "1234")});
Eric Liu8b636db2016-06-21 17:56:31 +0000457 std::vector<Range> Expected = {Range(5, 2), Range(10, 5), Range(20, 4)};
458 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
459}
460
461TEST(Range, NotAffectedByReplacements) {
462 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000463 Replacements Replaces = toReplacements({Replacement("foo", 3, 2, "12"),
464 Replacement("foo", 12, 2, "12"),
465 Replacement("foo", 20, 5, "")});
Eric Liu8b636db2016-06-21 17:56:31 +0000466 std::vector<Range> Expected = {Range(0, 2), Range(3, 4), Range(10, 5),
467 Range(20, 0)};
468 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
469}
470
471TEST(Range, RangesWithNonOverlappingReplacements) {
472 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000473 Replacements Replaces = toReplacements({Replacement("foo", 3, 1, ""),
474 Replacement("foo", 6, 1, "123"),
475 Replacement("foo", 20, 2, "12345")});
Eric Liu8b636db2016-06-21 17:56:31 +0000476 std::vector<Range> Expected = {Range(0, 2), Range(3, 0), Range(4, 4),
477 Range(11, 5), Range(21, 5)};
478 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
479}
480
481TEST(Range, RangesWithOverlappingReplacements) {
482 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5),
483 Range(30, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000484 Replacements Replaces = toReplacements(
485 {Replacement("foo", 1, 3, ""), Replacement("foo", 6, 1, "123"),
486 Replacement("foo", 13, 3, "1"), Replacement("foo", 25, 15, "")});
Eric Liu8b636db2016-06-21 17:56:31 +0000487 std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(12, 5),
488 Range(22, 0)};
489 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
490}
491
492TEST(Range, MergeIntoOneRange) {
493 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000494 Replacements Replaces =
495 toReplacements({Replacement("foo", 1, 15, "1234567890")});
Eric Liu8b636db2016-06-21 17:56:31 +0000496 std::vector<Range> Expected = {Range(0, 15)};
497 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
498}
499
500TEST(Range, ReplacementsStartingAtRangeOffsets) {
501 std::vector<Range> Ranges = {Range(0, 2), Range(5, 5), Range(15, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000502 Replacements Replaces = toReplacements(
503 {Replacement("foo", 0, 2, "12"), Replacement("foo", 5, 1, "123"),
504 Replacement("foo", 7, 4, "12345"), Replacement("foo", 15, 10, "12")});
Eric Liu8b636db2016-06-21 17:56:31 +0000505 std::vector<Range> Expected = {Range(0, 2), Range(5, 9), Range(18, 2)};
506 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
507}
508
509TEST(Range, ReplacementsEndingAtRangeEnds) {
510 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000511 Replacements Replaces = toReplacements(
512 {Replacement("foo", 6, 1, "123"), Replacement("foo", 17, 3, "12")});
Eric Liu8b636db2016-06-21 17:56:31 +0000513 std::vector<Range> Expected = {Range(0, 2), Range(5, 4), Range(17, 4)};
514 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
515}
516
517TEST(Range, AjacentReplacements) {
518 std::vector<Range> Ranges = {Range(0, 0), Range(15, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000519 Replacements Replaces = toReplacements(
520 {Replacement("foo", 1, 2, "123"), Replacement("foo", 12, 3, "1234")});
Eric Liu8b636db2016-06-21 17:56:31 +0000521 std::vector<Range> Expected = {Range(0, 0), Range(1, 3), Range(13, 9)};
522 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
523}
524
525TEST(Range, MergeRangesAfterReplacements) {
526 std::vector<Range> Ranges = {Range(8, 0), Range(5, 2), Range(9, 0), Range(0, 1)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000527 Replacements Replaces = toReplacements({Replacement("foo", 1, 3, ""),
528 Replacement("foo", 7, 0, "12"),
529 Replacement("foo", 9, 2, "")});
530 std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(7, 0),
531 Range(8, 0)};
Eric Liu8b636db2016-06-21 17:56:31 +0000532 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000533}
534
Eric Liu40ef2fb2016-08-01 10:16:37 +0000535TEST(Range, ConflictingRangesBeforeReplacements) {
536 std::vector<Range> Ranges = {Range(8, 3), Range(5, 4), Range(9, 1)};
537 Replacements Replaces = toReplacements({Replacement("foo", 1, 3, "")});
538 std::vector<Range> Expected = {Range(1, 0), Range(2, 6)};
539 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
Edwin Vane938f6882013-08-08 13:31:14 +0000540}
541
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000542class MergeReplacementsTest : public ::testing::Test {
543protected:
544 void mergeAndTestRewrite(StringRef Code, StringRef Intermediate,
545 StringRef Result, const Replacements &First,
546 const Replacements &Second) {
547 // These are mainly to verify the test itself and make it easier to read.
Eric Liu4f8d9942016-07-11 13:53:12 +0000548 auto AfterFirst = applyAllReplacements(Code, First);
549 EXPECT_TRUE(static_cast<bool>(AfterFirst));
550 auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
551 EXPECT_TRUE(static_cast<bool>(InSequenceRewrite));
552 EXPECT_EQ(Intermediate, *AfterFirst);
553 EXPECT_EQ(Result, *InSequenceRewrite);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000554
Eric Liu40ef2fb2016-08-01 10:16:37 +0000555 tooling::Replacements Merged = First.merge(Second);
Eric Liu4f8d9942016-07-11 13:53:12 +0000556 auto MergedRewrite = applyAllReplacements(Code, Merged);
557 EXPECT_TRUE(static_cast<bool>(MergedRewrite));
558 EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
559 if (*InSequenceRewrite != *MergedRewrite)
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000560 for (tooling::Replacement M : Merged)
561 llvm::errs() << M.getOffset() << " " << M.getLength() << " "
562 << M.getReplacementText() << "\n";
563 }
564 void mergeAndTestRewrite(StringRef Code, const Replacements &First,
565 const Replacements &Second) {
Eric Liu4f8d9942016-07-11 13:53:12 +0000566 auto AfterFirst = applyAllReplacements(Code, First);
567 EXPECT_TRUE(static_cast<bool>(AfterFirst));
568 auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
Eric Liu40ef2fb2016-08-01 10:16:37 +0000569 tooling::Replacements Merged = First.merge(Second);
Eric Liu4f8d9942016-07-11 13:53:12 +0000570 auto MergedRewrite = applyAllReplacements(Code, Merged);
571 EXPECT_TRUE(static_cast<bool>(MergedRewrite));
572 EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
573 if (*InSequenceRewrite != *MergedRewrite)
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000574 for (tooling::Replacement M : Merged)
575 llvm::errs() << M.getOffset() << " " << M.getLength() << " "
576 << M.getReplacementText() << "\n";
577 }
578};
579
580TEST_F(MergeReplacementsTest, Offsets) {
581 mergeAndTestRewrite("aaa", "aabab", "cacabab",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000582 toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
583 toReplacements({{"", 0, 0, "c"}, {"", 1, 0, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000584 mergeAndTestRewrite("aaa", "babaa", "babacac",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000585 toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "b"}}),
586 toReplacements({{"", 4, 0, "c"}, {"", 5, 0, "c"}}));
587 mergeAndTestRewrite("aaaa", "aaa", "aac", toReplacements({{"", 1, 1, ""}}),
588 toReplacements({{"", 2, 1, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000589
590 mergeAndTestRewrite("aa", "bbabba", "bbabcba",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000591 toReplacements({{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}),
592 toReplacements({{"", 4, 0, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000593}
594
595TEST_F(MergeReplacementsTest, Concatenations) {
596 // Basic concatenations. It is important to merge these into a single
597 // replacement to ensure the correct order.
Eric Liu40ef2fb2016-08-01 10:16:37 +0000598 {
599 auto First = toReplacements({{"", 0, 0, "a"}});
600 auto Second = toReplacements({{"", 1, 0, "b"}});
601 EXPECT_EQ(toReplacements({{"", 0, 0, "ab"}}), First.merge(Second));
602 }
603 {
604 auto First = toReplacements({{"", 0, 0, "a"}});
605 auto Second = toReplacements({{"", 0, 0, "b"}});
606 EXPECT_EQ(toReplacements({{"", 0, 0, "ba"}}), First.merge(Second));
607 }
608 mergeAndTestRewrite("", "a", "ab", toReplacements({{"", 0, 0, "a"}}),
609 toReplacements({{"", 1, 0, "b"}}));
610 mergeAndTestRewrite("", "a", "ba", toReplacements({{"", 0, 0, "a"}}),
611 toReplacements({{"", 0, 0, "b"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000612}
613
614TEST_F(MergeReplacementsTest, NotChangingLengths) {
Eric Liu40ef2fb2016-08-01 10:16:37 +0000615 mergeAndTestRewrite("aaaa", "abba", "acca",
616 toReplacements({{"", 1, 2, "bb"}}),
617 toReplacements({{"", 1, 2, "cc"}}));
618 mergeAndTestRewrite("aaaa", "abba", "abcc",
619 toReplacements({{"", 1, 2, "bb"}}),
620 toReplacements({{"", 2, 2, "cc"}}));
621 mergeAndTestRewrite("aaaa", "abba", "ccba",
622 toReplacements({{"", 1, 2, "bb"}}),
623 toReplacements({{"", 0, 2, "cc"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000624 mergeAndTestRewrite("aaaaaa", "abbdda", "abccda",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000625 toReplacements({{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}),
626 toReplacements({{"", 2, 2, "cc"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000627}
628
629TEST_F(MergeReplacementsTest, OverlappingRanges) {
630 mergeAndTestRewrite("aaa", "bbd", "bcbcd",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000631 toReplacements({{"", 0, 1, "bb"}, {"", 1, 2, "d"}}),
632 toReplacements({{"", 1, 0, "c"}, {"", 2, 0, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000633
Eric Liu40ef2fb2016-08-01 10:16:37 +0000634 mergeAndTestRewrite("aaaa", "aabbaa", "acccca",
635 toReplacements({{"", 2, 0, "bb"}}),
636 toReplacements({{"", 1, 4, "cccc"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000637 mergeAndTestRewrite("aaaa", "aababa", "acccca",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000638 toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
639 toReplacements({{"", 1, 4, "cccc"}}));
640 mergeAndTestRewrite("aaaaaa", "abbbba", "abba",
641 toReplacements({{"", 1, 4, "bbbb"}}),
642 toReplacements({{"", 2, 2, ""}}));
643 mergeAndTestRewrite("aaaa", "aa", "cc",
644 toReplacements({{"", 1, 1, ""}, {"", 2, 1, ""}}),
645 toReplacements({{"", 0, 2, "cc"}}));
646 mergeAndTestRewrite("aa", "abbba", "abcbcba",
647 toReplacements({{"", 1, 0, "bbb"}}),
648 toReplacements({{"", 2, 0, "c"}, {"", 3, 0, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000649
Eric Liu40ef2fb2016-08-01 10:16:37 +0000650 mergeAndTestRewrite(
651 "aaa", "abbab", "ccdd",
652 toReplacements({{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}}),
653 toReplacements({{"", 0, 2, "cc"}, {"", 2, 3, "dd"}}));
654 mergeAndTestRewrite(
655 "aa", "babbab", "ccdd",
656 toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}}),
657 toReplacements({{"", 0, 3, "cc"}, {"", 3, 3, "dd"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000658}
659
Manuel Klimek3f001342012-05-23 16:29:20 +0000660} // end namespace tooling
661} // end namespace clang