1 //===- unittest/Tooling/RefactoringTest.cpp - Refactoring unit tests ------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "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/RecursiveASTVisitor.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.h"
28 #include "clang/Tooling/Tooling.h"
29 #include "llvm/ADT/SmallString.h"
30 #include "gtest/gtest.h"
31 
32 namespace clang {
33 namespace tooling {
34 
35 TEST_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 
43 TEST_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 
51 TEST_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 
59 TEST_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 
68 TEST_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 
84 TEST_F(ReplacementTest, ApplyFailsForNonExistentLocation) {
85   Replacement Replace("nonexistent-file.cpp", 0, 1, "");
86   EXPECT_FALSE(Replace.apply(Context.Rewrite));
87 }
88 
89 TEST_F(ReplacementTest, CanRetrivePath) {
90   Replacement Replace("/path/to/file.cpp", 0, 1, "");
91   EXPECT_EQ("/path/to/file.cpp", Replace.getFilePath());
92 }
93 
94 TEST_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 
102 TEST_F(ReplacementTest, FailAddReplacements) {
103   Replacements Replaces;
104   Replacement Deletion("x.cc", 0, 10, "3");
105   auto Err = Replaces.add(Deletion);
106   EXPECT_TRUE(!Err);
107   llvm::consumeError(std::move(Err));
108   Err = Replaces.add(Replacement("x.cc", 0, 2, "a"));
109   EXPECT_TRUE((bool)Err);
110   llvm::consumeError(std::move(Err));
111   Err = Replaces.add(Replacement("x.cc", 2, 2, "a"));
112   EXPECT_TRUE((bool)Err);
113   llvm::consumeError(std::move(Err));
114   Err = Replaces.add(Replacement("y.cc", 20, 2, ""));
115   EXPECT_TRUE((bool)Err);
116   llvm::consumeError(std::move(Err));
117   EXPECT_EQ(1u, Replaces.size());
118   EXPECT_EQ(Deletion, *Replaces.begin());
119 }
120 
121 TEST_F(ReplacementTest, DeletionInReplacements) {
122   Replacements Replaces;
123   Replacement R("x.cc", 0, 10, "3");
124   auto Err = Replaces.add(R);
125   EXPECT_TRUE(!Err);
126   llvm::consumeError(std::move(Err));
127   Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
128   EXPECT_TRUE(!Err);
129   llvm::consumeError(std::move(Err));
130   Err = Replaces.add(Replacement("x.cc", 2, 2, ""));
131   EXPECT_TRUE(!Err);
132   llvm::consumeError(std::move(Err));
133   EXPECT_EQ(1u, Replaces.size());
134   EXPECT_EQ(R, *Replaces.begin());
135 }
136 
137 TEST_F(ReplacementTest, OverlappingReplacements) {
138   Replacements Replaces;
139   auto Err = Replaces.add(Replacement("x.cc", 0, 3, "345"));
140   EXPECT_TRUE(!Err);
141   llvm::consumeError(std::move(Err));
142   Err = Replaces.add(Replacement("x.cc", 2, 3, "543"));
143   EXPECT_TRUE(!Err);
144   llvm::consumeError(std::move(Err));
145 
146   EXPECT_EQ(1u, Replaces.size());
147   EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin());
148 
149   Err = Replaces.add(Replacement("x.cc", 2, 1, "5"));
150   EXPECT_TRUE(!Err);
151   llvm::consumeError(std::move(Err));
152   EXPECT_EQ(1u, Replaces.size());
153   EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin());
154 }
155 
156 TEST_F(ReplacementTest, AddAdjacentInsertionAndReplacement) {
157   Replacements Replaces;
158   // Test adding an insertion at the offset of an existing replacement.
159   auto Err = Replaces.add(Replacement("x.cc", 10, 3, "replace"));
160   EXPECT_TRUE(!Err);
161   llvm::consumeError(std::move(Err));
162   Err = Replaces.add(Replacement("x.cc", 10, 0, "insert"));
163   EXPECT_TRUE(!Err);
164   llvm::consumeError(std::move(Err));
165   EXPECT_EQ(Replaces.size(), 2u);
166 
167   Replaces.clear();
168   // Test overlap with an existing insertion.
169   Err = Replaces.add(Replacement("x.cc", 10, 0, "insert"));
170   EXPECT_TRUE(!Err);
171   llvm::consumeError(std::move(Err));
172   Err = Replaces.add(Replacement("x.cc", 10, 3, "replace"));
173   EXPECT_TRUE(!Err);
174   llvm::consumeError(std::move(Err));
175   EXPECT_EQ(Replaces.size(), 2u);
176 }
177 
178 TEST_F(ReplacementTest, MergeNewDeletions) {
179   Replacements Replaces;
180   Replacement ContainingReplacement("x.cc", 0, 10, "");
181   auto Err = Replaces.add(ContainingReplacement);
182   EXPECT_TRUE(!Err);
183   llvm::consumeError(std::move(Err));
184 
185   Err = Replaces.add(Replacement("x.cc", 5, 3, ""));
186   EXPECT_TRUE(!Err);
187   llvm::consumeError(std::move(Err));
188 
189   Err = Replaces.add(Replacement("x.cc", 0, 10, ""));
190   EXPECT_TRUE(!Err);
191   llvm::consumeError(std::move(Err));
192 
193   Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
194   EXPECT_TRUE(!Err);
195   llvm::consumeError(std::move(Err));
196 
197   EXPECT_EQ(1u, Replaces.size());
198   EXPECT_EQ(*Replaces.begin(), ContainingReplacement);
199 }
200 
201 TEST_F(ReplacementTest, MergeOverlappingButNotAdjacentReplacement) {
202   Replacements Replaces;
203   auto Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
204   EXPECT_TRUE(!Err);
205   llvm::consumeError(std::move(Err));
206 
207   Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
208   EXPECT_TRUE(!Err);
209   llvm::consumeError(std::move(Err));
210 
211   Replacement After = Replacement("x.cc", 10, 5, "");
212   Err = Replaces.add(After);
213   EXPECT_TRUE(!Err);
214   llvm::consumeError(std::move(Err));
215 
216   Replacement ContainingReplacement("x.cc", 0, 10, "");
217   Err = Replaces.add(ContainingReplacement);
218   EXPECT_TRUE(!Err);
219   llvm::consumeError(std::move(Err));
220 
221   EXPECT_EQ(2u, Replaces.size());
222   EXPECT_EQ(*Replaces.begin(), ContainingReplacement);
223   EXPECT_EQ(*(++Replaces.begin()), After);
224 }
225 
226 TEST_F(ReplacementTest, InsertionBeforeMergedDeletions) {
227   Replacements Replaces;
228 
229   Replacement Insertion("x.cc", 0, 0, "123");
230   auto Err = Replaces.add(Insertion);
231   EXPECT_TRUE(!Err);
232   llvm::consumeError(std::move(Err));
233 
234   Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
235   EXPECT_TRUE(!Err);
236   llvm::consumeError(std::move(Err));
237 
238   Replacement Deletion("x.cc", 0, 10, "");
239   Err = Replaces.add(Deletion);
240   EXPECT_TRUE(!Err);
241   llvm::consumeError(std::move(Err));
242 
243   EXPECT_EQ(2u, Replaces.size());
244   EXPECT_EQ(*Replaces.begin(), Insertion);
245   EXPECT_EQ(*(++Replaces.begin()), Deletion);
246 }
247 
248 TEST_F(ReplacementTest, MergeOverlappingDeletions) {
249   Replacements Replaces;
250   auto Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
251   EXPECT_TRUE(!Err);
252   llvm::consumeError(std::move(Err));
253 
254   Err = Replaces.add(Replacement("x.cc", 0, 5, ""));
255   EXPECT_TRUE(!Err);
256   llvm::consumeError(std::move(Err));
257 
258   EXPECT_EQ(1u, Replaces.size());
259   EXPECT_EQ(Replacement("x.cc", 0, 5, ""), *Replaces.begin());
260 
261   Err = Replaces.add(Replacement("x.cc", 1, 5, ""));
262   EXPECT_TRUE(!Err);
263   llvm::consumeError(std::move(Err));
264   EXPECT_EQ(1u, Replaces.size());
265   EXPECT_EQ(Replacement("x.cc", 0, 6, ""), *Replaces.begin());
266 }
267 
268 TEST_F(ReplacementTest, FailedMergeExistingDeletions) {
269   Replacements Replaces;
270   Replacement First("x.cc", 0, 2, "");
271   auto Err = Replaces.add(First);
272   EXPECT_TRUE(!Err);
273   llvm::consumeError(std::move(Err));
274 
275   Replacement Second("x.cc", 5, 5, "");
276   Err = Replaces.add(Second);
277   EXPECT_TRUE(!Err);
278   llvm::consumeError(std::move(Err));
279 
280   Err = Replaces.add(Replacement("x.cc", 1, 10, ""));
281   EXPECT_TRUE(!Err);
282   llvm::consumeError(std::move(Err));
283 
284   EXPECT_EQ(1u, Replaces.size());
285   EXPECT_EQ(Replacement("x.cc", 0, 11, ""), *Replaces.begin());
286 }
287 
288 TEST_F(ReplacementTest, FailAddRegression) {
289   Replacements Replaces;
290   // Create two replacements, where the second one is an insertion of the empty
291   // string exactly at the end of the first one.
292   auto Err = Replaces.add(Replacement("x.cc", 0, 10, "1"));
293   EXPECT_TRUE(!Err);
294   llvm::consumeError(std::move(Err));
295   Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
296   EXPECT_TRUE(!Err);
297   llvm::consumeError(std::move(Err));
298 
299   // Make sure we find the overlap with the first entry when inserting a
300   // replacement that ends exactly at the seam of the existing replacements.
301   Err = Replaces.add(Replacement("x.cc", 5, 5, "fail"));
302   EXPECT_TRUE((bool)Err);
303   llvm::consumeError(std::move(Err));
304 
305   Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
306   EXPECT_TRUE(!Err);
307   llvm::consumeError(std::move(Err));
308 }
309 
310 TEST_F(ReplacementTest, InsertAtOffsetOfReplacement) {
311   Replacements Replaces;
312   auto Err = Replaces.add(Replacement("x.cc", 10, 2, ""));
313   EXPECT_TRUE(!Err);
314   llvm::consumeError(std::move(Err));
315   Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
316   EXPECT_TRUE(!Err);
317   llvm::consumeError(std::move(Err));
318   EXPECT_EQ(Replaces.size(), 2u);
319 
320   Replaces.clear();
321   Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
322   EXPECT_TRUE(!Err);
323   llvm::consumeError(std::move(Err));
324   Err = Replaces.add(Replacement("x.cc", 10, 2, ""));
325   EXPECT_TRUE(!Err);
326   llvm::consumeError(std::move(Err));
327   EXPECT_EQ(Replaces.size(), 2u);
328 }
329 
330 TEST_F(ReplacementTest, AddInsertAtOtherInsertWhenOderIndependent) {
331   Replacements Replaces;
332   auto Err = Replaces.add(Replacement("x.cc", 10, 0, "a"));
333   EXPECT_TRUE(!Err);
334   llvm::consumeError(std::move(Err));
335   Err = Replaces.add(Replacement("x.cc", 10, 0, "b"));
336   EXPECT_TRUE((bool)Err);
337   llvm::consumeError(std::move(Err));
338 
339   Replaces.clear();
340   Err = Replaces.add(Replacement("x.cc", 10, 0, "a"));
341   EXPECT_TRUE(!Err);
342   llvm::consumeError(std::move(Err));
343   Err = Replaces.add(Replacement("x.cc", 10, 0, "aa"));
344   EXPECT_TRUE(!Err);
345   llvm::consumeError(std::move(Err));
346   EXPECT_EQ(1u, Replaces.size());
347   EXPECT_EQ(Replacement("x.cc", 10, 0, "aaa"), *Replaces.begin());
348 
349   Replaces.clear();
350   Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
351   EXPECT_TRUE(!Err);
352   llvm::consumeError(std::move(Err));
353   Err = Replaces.add(Replacement("x.cc", 10, 3, ""));
354   EXPECT_TRUE(!Err);
355   llvm::consumeError(std::move(Err));
356   Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
357   EXPECT_TRUE(!Err);
358   llvm::consumeError(std::move(Err));
359   EXPECT_EQ(2u, Replaces.size());
360   EXPECT_EQ(Replacement("x.cc", 10, 0, ""), *Replaces.begin());
361   EXPECT_EQ(Replacement("x.cc", 10, 3, ""), *std::next(Replaces.begin()));
362 }
363 
364 TEST_F(ReplacementTest, InsertBetweenAdjacentReplacements) {
365   Replacements Replaces;
366   auto Err = Replaces.add(Replacement("x.cc", 10, 5, "a"));
367   EXPECT_TRUE(!Err);
368   llvm::consumeError(std::move(Err));
369   Err = Replaces.add(Replacement("x.cc", 8, 2, "a"));
370   EXPECT_TRUE(!Err);
371   llvm::consumeError(std::move(Err));
372   Err = Replaces.add(Replacement("x.cc", 10, 0, "b"));
373   EXPECT_TRUE(!Err);
374   llvm::consumeError(std::move(Err));
375 }
376 
377 TEST_F(ReplacementTest, CanApplyReplacements) {
378   FileID ID = Context.createInMemoryFile("input.cpp",
379                                          "line1\nline2\nline3\nline4");
380   Replacements Replaces =
381       toReplacements({Replacement(Context.Sources,
382                                   Context.getLocation(ID, 2, 1), 5, "replaced"),
383                       Replacement(Context.Sources,
384                                   Context.getLocation(ID, 3, 1), 5, "other")});
385   EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
386   EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
387 }
388 
389 // Verifies that replacement/deletion is applied before insertion at the same
390 // offset.
391 TEST_F(ReplacementTest, InsertAndDelete) {
392   FileID ID = Context.createInMemoryFile("input.cpp",
393                                          "line1\nline2\nline3\nline4");
394   Replacements Replaces = toReplacements(
395       {Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 6, ""),
396        Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 0,
397                    "other\n")});
398   EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
399   EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID));
400 }
401 
402 TEST_F(ReplacementTest, AdjacentReplacements) {
403   FileID ID = Context.createInMemoryFile("input.cpp",
404                                          "ab");
405   Replacements Replaces = toReplacements(
406       {Replacement(Context.Sources, Context.getLocation(ID, 1, 1), 1, "x"),
407        Replacement(Context.Sources, Context.getLocation(ID, 1, 2), 1, "y")});
408   EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
409   EXPECT_EQ("xy", Context.getRewrittenText(ID));
410 }
411 
412 TEST_F(ReplacementTest, AddDuplicateReplacements) {
413   FileID ID = Context.createInMemoryFile("input.cpp",
414                                          "line1\nline2\nline3\nline4");
415   auto Replaces = toReplacements({Replacement(
416       Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
417 
418   auto Err = Replaces.add(Replacement(
419       Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced"));
420   EXPECT_TRUE(!Err);
421   llvm::consumeError(std::move(Err));
422 
423   Err = Replaces.add(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
424                                  5, "replaced"));
425   EXPECT_TRUE(!Err);
426   llvm::consumeError(std::move(Err));
427 
428   EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
429   EXPECT_EQ("line1\nreplaced\nline3\nline4", Context.getRewrittenText(ID));
430 }
431 
432 TEST_F(ReplacementTest, FailOrderDependentReplacements) {
433   FileID ID = Context.createInMemoryFile("input.cpp",
434                                          "line1\nline2\nline3\nline4");
435   auto Replaces = toReplacements({Replacement(
436       Context.Sources, Context.getLocation(ID, 2, 1), 5, "other")});
437 
438   auto Err = Replaces.add(Replacement(
439       Context.Sources, Context.getLocation(ID, 2, 1), 5, "rehto"));
440   EXPECT_TRUE((bool)Err);
441   llvm::consumeError(std::move(Err));
442 
443   EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
444   EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID));
445 }
446 
447 TEST_F(ReplacementTest, InvalidSourceLocationFailsApplyAll) {
448   Replacements Replaces =
449       toReplacements({Replacement(Context.Sources, SourceLocation(), 5, "2")});
450 
451   EXPECT_FALSE(applyAllReplacements(Replaces, Context.Rewrite));
452 }
453 
454 TEST_F(ReplacementTest, MultipleFilesReplaceAndFormat) {
455   // Column limit is 20.
456   std::string Code1 = "Long *a =\n"
457                       "    new Long();\n"
458                       "long x = 1;";
459   std::string Expected1 = "auto a = new Long();\n"
460                           "long x =\n"
461                           "    12345678901;";
462   std::string Code2 = "int x = 123;\n"
463                       "int y = 0;";
464   std::string Expected2 = "int x =\n"
465                           "    1234567890123;\n"
466                           "int y = 10;";
467   StringRef File1 = "format_1.cpp";
468   StringRef File2 = "format_2.cpp";
469   FileID ID1 = Context.createInMemoryFile(File1, Code1);
470   FileID ID2 = Context.createInMemoryFile(File2, Code2);
471 
472   // Scrambled the order of replacements.
473   std::map<std::string, Replacements> FileToReplaces;
474   FileToReplaces[File1] = toReplacements(
475       {tooling::Replacement(Context.Sources, Context.getLocation(ID1, 1, 1), 6,
476                             "auto "),
477        tooling::Replacement(Context.Sources, Context.getLocation(ID1, 3, 10), 1,
478                             "12345678901")});
479   FileToReplaces[File2] = toReplacements(
480       {tooling::Replacement(Context.Sources, Context.getLocation(ID2, 1, 12), 0,
481                             "4567890123"),
482        tooling::Replacement(Context.Sources, Context.getLocation(ID2, 2, 9), 1,
483                             "10")});
484   EXPECT_TRUE(
485       formatAndApplyAllReplacements(FileToReplaces, Context.Rewrite,
486                                     "{BasedOnStyle: LLVM, ColumnLimit: 20}"));
487   EXPECT_EQ(Expected1, Context.getRewrittenText(ID1));
488   EXPECT_EQ(Expected2, Context.getRewrittenText(ID2));
489 }
490 
491 TEST(ShiftedCodePositionTest, FindsNewCodePosition) {
492   Replacements Replaces =
493       toReplacements({Replacement("", 0, 1, ""), Replacement("", 4, 3, " ")});
494   // Assume ' int   i;' is turned into 'int i;' and cursor is located at '|'.
495   EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0)); // |int   i;
496   EXPECT_EQ(0u, Replaces.getShiftedCodePosition(1)); //  |nt   i;
497   EXPECT_EQ(1u, Replaces.getShiftedCodePosition(2)); //  i|t   i;
498   EXPECT_EQ(2u, Replaces.getShiftedCodePosition(3)); //  in|   i;
499   EXPECT_EQ(3u, Replaces.getShiftedCodePosition(4)); //  int|  i;
500   EXPECT_EQ(3u, Replaces.getShiftedCodePosition(5)); //  int | i;
501   EXPECT_EQ(3u, Replaces.getShiftedCodePosition(6)); //  int  |i;
502   EXPECT_EQ(4u, Replaces.getShiftedCodePosition(7)); //  int   |;
503   EXPECT_EQ(5u, Replaces.getShiftedCodePosition(8)); //  int   i|
504 }
505 
506 TEST(ShiftedCodePositionTest, FindsNewCodePositionWithInserts) {
507   Replacements Replaces = toReplacements({Replacement("", 4, 0, "\"\n\"")});
508   // Assume '"12345678"' is turned into '"1234"\n"5678"'.
509   EXPECT_EQ(3u, Replaces.getShiftedCodePosition(3)); // "123|5678"
510   EXPECT_EQ(7u, Replaces.getShiftedCodePosition(4)); // "1234|678"
511   EXPECT_EQ(8u, Replaces.getShiftedCodePosition(5)); // "12345|78"
512 }
513 
514 TEST(ShiftedCodePositionTest, FindsNewCodePositionInReplacedText) {
515   // Replace the first four characters with "abcd".
516   auto Replaces = toReplacements({Replacement("", 0, 4, "abcd")});
517   for (unsigned i = 0; i < 3; ++i)
518     EXPECT_EQ(i, Replaces.getShiftedCodePosition(i));
519 }
520 
521 TEST(ShiftedCodePositionTest, NoReplacementText) {
522   Replacements Replaces = toReplacements({Replacement("", 0, 42, "")});
523   EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0));
524   EXPECT_EQ(0u, Replaces.getShiftedCodePosition(39));
525   EXPECT_EQ(3u, Replaces.getShiftedCodePosition(45));
526   EXPECT_EQ(0u, Replaces.getShiftedCodePosition(42));
527 }
528 
529 class FlushRewrittenFilesTest : public ::testing::Test {
530 public:
531    FlushRewrittenFilesTest() {}
532 
533    ~FlushRewrittenFilesTest() override {
534     for (llvm::StringMap<std::string>::iterator I = TemporaryFiles.begin(),
535                                                 E = TemporaryFiles.end();
536          I != E; ++I) {
537       llvm::StringRef Name = I->second;
538       std::error_code EC = llvm::sys::fs::remove(Name);
539       (void)EC;
540       assert(!EC);
541     }
542   }
543 
544   FileID createFile(llvm::StringRef Name, llvm::StringRef Content) {
545     SmallString<1024> Path;
546     int FD;
547     std::error_code EC = llvm::sys::fs::createTemporaryFile(Name, "", FD, Path);
548     assert(!EC);
549     (void)EC;
550 
551     llvm::raw_fd_ostream OutStream(FD, true);
552     OutStream << Content;
553     OutStream.close();
554     const FileEntry *File = Context.Files.getFile(Path);
555     assert(File != nullptr);
556 
557     StringRef Found =
558         TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second;
559     assert(Found == Path);
560     (void)Found;
561     return Context.Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
562   }
563 
564   std::string getFileContentFromDisk(llvm::StringRef Name) {
565     std::string Path = TemporaryFiles.lookup(Name);
566     assert(!Path.empty());
567     // We need to read directly from the FileManager without relaying through
568     // a FileEntry, as otherwise we'd read through an already opened file
569     // descriptor, which might not see the changes made.
570     // FIXME: Figure out whether there is a way to get the SourceManger to
571     // reopen the file.
572     auto FileBuffer = Context.Files.getBufferForFile(Path);
573     return (*FileBuffer)->getBuffer();
574   }
575 
576   llvm::StringMap<std::string> TemporaryFiles;
577   RewriterTestContext Context;
578 };
579 
580 TEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) {
581   FileID ID = createFile("input.cpp", "line1\nline2\nline3\nline4");
582   Replacements Replaces = toReplacements({Replacement(
583       Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
584   EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
585   EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles());
586   EXPECT_EQ("line1\nreplaced\nline3\nline4",
587             getFileContentFromDisk("input.cpp"));
588 }
589 
590 namespace {
591 template <typename T>
592 class TestVisitor : public clang::RecursiveASTVisitor<T> {
593 public:
594   bool runOver(StringRef Code) {
595     return runToolOnCode(new TestAction(this), Code);
596   }
597 
598 protected:
599   clang::SourceManager *SM;
600   clang::ASTContext *Context;
601 
602 private:
603   class FindConsumer : public clang::ASTConsumer {
604   public:
605     FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}
606 
607     void HandleTranslationUnit(clang::ASTContext &Context) override {
608       Visitor->TraverseDecl(Context.getTranslationUnitDecl());
609     }
610 
611   private:
612     TestVisitor *Visitor;
613   };
614 
615   class TestAction : public clang::ASTFrontendAction {
616   public:
617     TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
618 
619     std::unique_ptr<clang::ASTConsumer>
620     CreateASTConsumer(clang::CompilerInstance &compiler,
621                       llvm::StringRef dummy) override {
622       Visitor->SM = &compiler.getSourceManager();
623       Visitor->Context = &compiler.getASTContext();
624       /// TestConsumer will be deleted by the framework calling us.
625       return llvm::make_unique<FindConsumer>(Visitor);
626     }
627 
628   private:
629     TestVisitor *Visitor;
630   };
631 };
632 } // end namespace
633 
634 void expectReplacementAt(const Replacement &Replace,
635                          StringRef File, unsigned Offset, unsigned Length) {
636   ASSERT_TRUE(Replace.isApplicable());
637   EXPECT_EQ(File, Replace.getFilePath());
638   EXPECT_EQ(Offset, Replace.getOffset());
639   EXPECT_EQ(Length, Replace.getLength());
640 }
641 
642 class ClassDeclXVisitor : public TestVisitor<ClassDeclXVisitor> {
643 public:
644   bool VisitCXXRecordDecl(CXXRecordDecl *Record) {
645     if (Record->getName() == "X") {
646       Replace = Replacement(*SM, Record, "");
647     }
648     return true;
649   }
650   Replacement Replace;
651 };
652 
653 TEST(Replacement, CanBeConstructedFromNode) {
654   ClassDeclXVisitor ClassDeclX;
655   EXPECT_TRUE(ClassDeclX.runOver("     class X;"));
656   expectReplacementAt(ClassDeclX.Replace, "input.cc", 5, 7);
657 }
658 
659 TEST(Replacement, ReplacesAtSpellingLocation) {
660   ClassDeclXVisitor ClassDeclX;
661   EXPECT_TRUE(ClassDeclX.runOver("#define A(Y) Y\nA(class X);"));
662   expectReplacementAt(ClassDeclX.Replace, "input.cc", 17, 7);
663 }
664 
665 class CallToFVisitor : public TestVisitor<CallToFVisitor> {
666 public:
667   bool VisitCallExpr(CallExpr *Call) {
668     if (Call->getDirectCallee()->getName() == "F") {
669       Replace = Replacement(*SM, Call, "");
670     }
671     return true;
672   }
673   Replacement Replace;
674 };
675 
676 TEST(Replacement, FunctionCall) {
677   CallToFVisitor CallToF;
678   EXPECT_TRUE(CallToF.runOver("void F(); void G() { F(); }"));
679   expectReplacementAt(CallToF.Replace, "input.cc", 21, 3);
680 }
681 
682 TEST(Replacement, TemplatedFunctionCall) {
683   CallToFVisitor CallToF;
684   EXPECT_TRUE(CallToF.runOver(
685         "template <typename T> void F(); void G() { F<int>(); }"));
686   expectReplacementAt(CallToF.Replace, "input.cc", 43, 8);
687 }
688 
689 class NestedNameSpecifierAVisitor
690     : public TestVisitor<NestedNameSpecifierAVisitor> {
691 public:
692   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) {
693     if (NNSLoc.getNestedNameSpecifier()) {
694       if (const NamespaceDecl* NS = NNSLoc.getNestedNameSpecifier()->getAsNamespace()) {
695         if (NS->getName() == "a") {
696           Replace = Replacement(*SM, &NNSLoc, "", Context->getLangOpts());
697         }
698       }
699     }
700     return TestVisitor<NestedNameSpecifierAVisitor>::TraverseNestedNameSpecifierLoc(
701         NNSLoc);
702   }
703   Replacement Replace;
704 };
705 
706 TEST(Replacement, ColonColon) {
707   NestedNameSpecifierAVisitor VisitNNSA;
708   EXPECT_TRUE(VisitNNSA.runOver("namespace a { void f() { ::a::f(); } }"));
709   expectReplacementAt(VisitNNSA.Replace, "input.cc", 25, 5);
710 }
711 
712 TEST(Range, overlaps) {
713   EXPECT_TRUE(Range(10, 10).overlapsWith(Range(0, 11)));
714   EXPECT_TRUE(Range(0, 11).overlapsWith(Range(10, 10)));
715   EXPECT_FALSE(Range(10, 10).overlapsWith(Range(0, 10)));
716   EXPECT_FALSE(Range(0, 10).overlapsWith(Range(10, 10)));
717   EXPECT_TRUE(Range(0, 10).overlapsWith(Range(2, 6)));
718   EXPECT_TRUE(Range(2, 6).overlapsWith(Range(0, 10)));
719 }
720 
721 TEST(Range, contains) {
722   EXPECT_TRUE(Range(0, 10).contains(Range(0, 10)));
723   EXPECT_TRUE(Range(0, 10).contains(Range(2, 6)));
724   EXPECT_FALSE(Range(2, 6).contains(Range(0, 10)));
725   EXPECT_FALSE(Range(0, 10).contains(Range(0, 11)));
726 }
727 
728 TEST(Range, CalculateRangesOfReplacements) {
729   // Before: aaaabbbbbbz
730   // After : bbbbbbzzzzzzoooooooooooooooo
731   Replacements Replaces = toReplacements(
732       {Replacement("foo", 0, 4, ""), Replacement("foo", 10, 1, "zzzzzz"),
733        Replacement("foo", 11, 0, "oooooooooooooooo")});
734 
735   std::vector<Range> Ranges = Replaces.getAffectedRanges();
736 
737   EXPECT_EQ(2ul, Ranges.size());
738   EXPECT_TRUE(Ranges[0].getOffset() == 0);
739   EXPECT_TRUE(Ranges[0].getLength() == 0);
740   EXPECT_TRUE(Ranges[1].getOffset() == 6);
741   EXPECT_TRUE(Ranges[1].getLength() == 22);
742 }
743 
744 TEST(Range, CalculateRangesOfInsertionAroundReplacement) {
745   Replacements Replaces = toReplacements(
746       {Replacement("foo", 0, 2, ""), Replacement("foo", 0, 0, "ba")});
747 
748   std::vector<Range> Ranges = Replaces.getAffectedRanges();
749 
750   EXPECT_EQ(1ul, Ranges.size());
751   EXPECT_EQ(0u, Ranges[0].getOffset());
752   EXPECT_EQ(2u, Ranges[0].getLength());
753 }
754 
755 TEST(Range, RangesAfterEmptyReplacements) {
756   std::vector<Range> Ranges = {Range(5, 6), Range(10, 5)};
757   Replacements Replaces;
758   std::vector<Range> Expected = {Range(5, 10)};
759   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
760 }
761 
762 TEST(Range, RangesAfterReplacements) {
763   std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
764   Replacements Replaces = toReplacements({Replacement("foo", 0, 2, "1234")});
765   std::vector<Range> Expected = {Range(0, 4), Range(7, 2), Range(12, 5)};
766   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
767 }
768 
769 TEST(Range, RangesBeforeReplacements) {
770   std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
771   Replacements Replaces = toReplacements({Replacement("foo", 20, 2, "1234")});
772   std::vector<Range> Expected = {Range(5, 2), Range(10, 5), Range(20, 4)};
773   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
774 }
775 
776 TEST(Range, NotAffectedByReplacements) {
777   std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
778   Replacements Replaces = toReplacements({Replacement("foo", 3, 2, "12"),
779                                           Replacement("foo", 12, 2, "12"),
780                                           Replacement("foo", 20, 5, "")});
781   std::vector<Range> Expected = {Range(0, 2), Range(3, 4), Range(10, 5),
782                                  Range(20, 0)};
783   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
784 }
785 
786 TEST(Range, RangesWithNonOverlappingReplacements) {
787   std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
788   Replacements Replaces = toReplacements({Replacement("foo", 3, 1, ""),
789                                           Replacement("foo", 6, 1, "123"),
790                                           Replacement("foo", 20, 2, "12345")});
791   std::vector<Range> Expected = {Range(0, 2), Range(3, 0), Range(4, 4),
792                                  Range(11, 5), Range(21, 5)};
793   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
794 }
795 
796 TEST(Range, RangesWithOverlappingReplacements) {
797   std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5),
798                                Range(30, 5)};
799   Replacements Replaces = toReplacements(
800       {Replacement("foo", 1, 3, ""), Replacement("foo", 6, 1, "123"),
801        Replacement("foo", 13, 3, "1"), Replacement("foo", 25, 15, "")});
802   std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(12, 5),
803                                  Range(22, 0)};
804   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
805 }
806 
807 TEST(Range, MergeIntoOneRange) {
808   std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
809   Replacements Replaces =
810       toReplacements({Replacement("foo", 1, 15, "1234567890")});
811   std::vector<Range> Expected = {Range(0, 15)};
812   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
813 }
814 
815 TEST(Range, ReplacementsStartingAtRangeOffsets) {
816   std::vector<Range> Ranges = {Range(0, 2), Range(5, 5), Range(15, 5)};
817   Replacements Replaces = toReplacements(
818       {Replacement("foo", 0, 2, "12"), Replacement("foo", 5, 1, "123"),
819        Replacement("foo", 7, 4, "12345"), Replacement("foo", 15, 10, "12")});
820   std::vector<Range> Expected = {Range(0, 2), Range(5, 9), Range(18, 2)};
821   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
822 }
823 
824 TEST(Range, ReplacementsEndingAtRangeEnds) {
825   std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
826   Replacements Replaces = toReplacements(
827       {Replacement("foo", 6, 1, "123"), Replacement("foo", 17, 3, "12")});
828   std::vector<Range> Expected = {Range(0, 2), Range(5, 4), Range(17, 4)};
829   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
830 }
831 
832 TEST(Range, AjacentReplacements) {
833   std::vector<Range> Ranges = {Range(0, 0), Range(15, 5)};
834   Replacements Replaces = toReplacements(
835       {Replacement("foo", 1, 2, "123"), Replacement("foo", 12, 3, "1234")});
836   std::vector<Range> Expected = {Range(0, 0), Range(1, 3), Range(13, 9)};
837   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
838 }
839 
840 TEST(Range, MergeRangesAfterReplacements) {
841   std::vector<Range> Ranges = {Range(8, 0), Range(5, 2), Range(9, 0), Range(0, 1)};
842   Replacements Replaces = toReplacements({Replacement("foo", 1, 3, ""),
843                                           Replacement("foo", 7, 0, "12"),
844                                           Replacement("foo", 9, 2, "")});
845   std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(7, 0),
846                                  Range(8, 0)};
847   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
848 }
849 
850 TEST(Range, ConflictingRangesBeforeReplacements) {
851   std::vector<Range> Ranges = {Range(8, 3), Range(5, 4), Range(9, 1)};
852   Replacements Replaces = toReplacements({Replacement("foo", 1, 3, "")});
853   std::vector<Range> Expected = {Range(1, 0), Range(2, 6)};
854   EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
855 }
856 
857 class MergeReplacementsTest : public ::testing::Test {
858 protected:
859   void mergeAndTestRewrite(StringRef Code, StringRef Intermediate,
860                            StringRef Result, const Replacements &First,
861                            const Replacements &Second) {
862     // These are mainly to verify the test itself and make it easier to read.
863     auto AfterFirst = applyAllReplacements(Code, First);
864     EXPECT_TRUE(static_cast<bool>(AfterFirst));
865     auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
866     EXPECT_TRUE(static_cast<bool>(InSequenceRewrite));
867     EXPECT_EQ(Intermediate, *AfterFirst);
868     EXPECT_EQ(Result, *InSequenceRewrite);
869 
870     tooling::Replacements Merged = First.merge(Second);
871     auto MergedRewrite = applyAllReplacements(Code, Merged);
872     EXPECT_TRUE(static_cast<bool>(MergedRewrite));
873     EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
874     if (*InSequenceRewrite != *MergedRewrite)
875       for (tooling::Replacement M : Merged)
876         llvm::errs() << M.getOffset() << " " << M.getLength() << " "
877                      << M.getReplacementText() << "\n";
878   }
879   void mergeAndTestRewrite(StringRef Code, const Replacements &First,
880                            const Replacements &Second) {
881     auto AfterFirst = applyAllReplacements(Code, First);
882     EXPECT_TRUE(static_cast<bool>(AfterFirst));
883     auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
884     tooling::Replacements Merged = First.merge(Second);
885     auto MergedRewrite = applyAllReplacements(Code, Merged);
886     EXPECT_TRUE(static_cast<bool>(MergedRewrite));
887     EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
888     if (*InSequenceRewrite != *MergedRewrite)
889       for (tooling::Replacement M : Merged)
890         llvm::errs() << M.getOffset() << " " << M.getLength() << " "
891                      << M.getReplacementText() << "\n";
892   }
893 };
894 
895 TEST_F(MergeReplacementsTest, Offsets) {
896   mergeAndTestRewrite("aaa", "aabab", "cacabab",
897                       toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
898                       toReplacements({{"", 0, 0, "c"}, {"", 1, 0, "c"}}));
899   mergeAndTestRewrite("aaa", "babaa", "babacac",
900                       toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "b"}}),
901                       toReplacements({{"", 4, 0, "c"}, {"", 5, 0, "c"}}));
902   mergeAndTestRewrite("aaaa", "aaa", "aac", toReplacements({{"", 1, 1, ""}}),
903                       toReplacements({{"", 2, 1, "c"}}));
904 
905   mergeAndTestRewrite("aa", "bbabba", "bbabcba",
906                       toReplacements({{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}),
907                       toReplacements({{"", 4, 0, "c"}}));
908 }
909 
910 TEST_F(MergeReplacementsTest, Concatenations) {
911   // Basic concatenations. It is important to merge these into a single
912   // replacement to ensure the correct order.
913   {
914     auto First = toReplacements({{"", 0, 0, "a"}});
915     auto Second = toReplacements({{"", 1, 0, "b"}});
916     EXPECT_EQ(toReplacements({{"", 0, 0, "ab"}}), First.merge(Second));
917   }
918   {
919     auto First = toReplacements({{"", 0, 0, "a"}});
920     auto Second = toReplacements({{"", 0, 0, "b"}});
921     EXPECT_EQ(toReplacements({{"", 0, 0, "ba"}}), First.merge(Second));
922   }
923   mergeAndTestRewrite("", "a", "ab", toReplacements({{"", 0, 0, "a"}}),
924                       toReplacements({{"", 1, 0, "b"}}));
925   mergeAndTestRewrite("", "a", "ba", toReplacements({{"", 0, 0, "a"}}),
926                       toReplacements({{"", 0, 0, "b"}}));
927 }
928 
929 TEST_F(MergeReplacementsTest, NotChangingLengths) {
930   mergeAndTestRewrite("aaaa", "abba", "acca",
931                       toReplacements({{"", 1, 2, "bb"}}),
932                       toReplacements({{"", 1, 2, "cc"}}));
933   mergeAndTestRewrite("aaaa", "abba", "abcc",
934                       toReplacements({{"", 1, 2, "bb"}}),
935                       toReplacements({{"", 2, 2, "cc"}}));
936   mergeAndTestRewrite("aaaa", "abba", "ccba",
937                       toReplacements({{"", 1, 2, "bb"}}),
938                       toReplacements({{"", 0, 2, "cc"}}));
939   mergeAndTestRewrite("aaaaaa", "abbdda", "abccda",
940                       toReplacements({{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}),
941                       toReplacements({{"", 2, 2, "cc"}}));
942 }
943 
944 TEST_F(MergeReplacementsTest, OverlappingRanges) {
945   mergeAndTestRewrite("aaa", "bbd", "bcbcd",
946                       toReplacements({{"", 0, 1, "bb"}, {"", 1, 2, "d"}}),
947                       toReplacements({{"", 1, 0, "c"}, {"", 2, 0, "c"}}));
948 
949   mergeAndTestRewrite("aaaa", "aabbaa", "acccca",
950                       toReplacements({{"", 2, 0, "bb"}}),
951                       toReplacements({{"", 1, 4, "cccc"}}));
952   mergeAndTestRewrite("aaaa", "aababa", "acccca",
953                       toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
954                       toReplacements({{"", 1, 4, "cccc"}}));
955   mergeAndTestRewrite("aaaaaa", "abbbba", "abba",
956                       toReplacements({{"", 1, 4, "bbbb"}}),
957                       toReplacements({{"", 2, 2, ""}}));
958   mergeAndTestRewrite("aaaa", "aa", "cc",
959                       toReplacements({{"", 1, 1, ""}, {"", 2, 1, ""}}),
960                       toReplacements({{"", 0, 2, "cc"}}));
961   mergeAndTestRewrite("aa", "abbba", "abcbcba",
962                       toReplacements({{"", 1, 0, "bbb"}}),
963                       toReplacements({{"", 2, 0, "c"}, {"", 3, 0, "c"}}));
964 
965   mergeAndTestRewrite(
966       "aaa", "abbab", "ccdd",
967       toReplacements({{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}}),
968       toReplacements({{"", 0, 2, "cc"}, {"", 2, 3, "dd"}}));
969   mergeAndTestRewrite(
970       "aa", "babbab", "ccdd",
971       toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}}),
972       toReplacements({{"", 0, 3, "cc"}, {"", 3, 3, "dd"}}));
973 }
974 
975 TEST(DeduplicateByFileTest, LeaveLeadingDotDot) {
976   std::map<std::string, Replacements> FileToReplaces;
977 #if !defined(LLVM_ON_WIN32)
978   FileToReplaces["../../a/b/.././c.h"] = Replacements();
979   FileToReplaces["../../a/c.h"] = Replacements();
980 #else
981   FileToReplaces["..\\..\\a\\b\\..\\.\\c.h"] = Replacements();
982   FileToReplaces["..\\..\\a\\c.h"] = Replacements();
983 #endif
984   FileToReplaces = groupReplacementsByFile(FileToReplaces);
985   EXPECT_EQ(1u, FileToReplaces.size());
986 #if !defined(LLVM_ON_WIN32)
987   EXPECT_EQ("../../a/c.h", FileToReplaces.begin()->first);
988 #else
989   EXPECT_EQ("..\\..\\a\\c.h", FileToReplaces.begin()->first);
990 #endif
991 }
992 
993 TEST(DeduplicateByFileTest, RemoveDotSlash) {
994   std::map<std::string, Replacements> FileToReplaces;
995 #if !defined(LLVM_ON_WIN32)
996   FileToReplaces["./a/b/.././c.h"] = Replacements();
997   FileToReplaces["a/c.h"] = Replacements();
998 #else
999   FileToReplaces[".\\a\\b\\..\\.\\c.h"] = Replacements();
1000   FileToReplaces["a\\c.h"] = Replacements();
1001 #endif
1002   FileToReplaces = groupReplacementsByFile(FileToReplaces);
1003   EXPECT_EQ(1u, FileToReplaces.size());
1004 #if !defined(LLVM_ON_WIN32)
1005   EXPECT_EQ("a/c.h", FileToReplaces.begin()->first);
1006 #else
1007   EXPECT_EQ("a\\c.h", FileToReplaces.begin()->first);
1008 #endif
1009 }
1010 
1011 } // end namespace tooling
1012 } // end namespace clang
1013