xref: /llvm-project/clang/unittests/Format/CleanupTest.cpp (revision 40ef2fb363bcd89cb4a88157f5fa97a38d795a1f)
1 //===- unittest/Format/CleanupTest.cpp - Code cleanup 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 "clang/Format/Format.h"
11 
12 #include "../Tooling/ReplacementTest.h"
13 #include "../Tooling/RewriterTestContext.h"
14 #include "clang/Tooling/Core/Replacement.h"
15 
16 #include "gtest/gtest.h"
17 
18 using clang::tooling::ReplacementTest;
19 using clang::tooling::toReplacements;
20 
21 namespace clang {
22 namespace format {
23 namespace {
24 
25 class CleanupTest : public ::testing::Test {
26 protected:
27   std::string cleanup(llvm::StringRef Code,
28                       const std::vector<tooling::Range> &Ranges,
29                       const FormatStyle &Style = getLLVMStyle()) {
30     tooling::Replacements Replaces = format::cleanup(Style, Code, Ranges);
31 
32     auto Result = applyAllReplacements(Code, Replaces);
33     EXPECT_TRUE(static_cast<bool>(Result));
34     return *Result;
35   }
36 };
37 
38 TEST_F(CleanupTest, DeleteEmptyNamespaces) {
39   std::string Code = "namespace A {\n"
40                      "namespace B {\n"
41                      "} // namespace B\n"
42                      "} // namespace A\n\n"
43                      "namespace C {\n"
44                      "namespace D { int i; }\n"
45                      "inline namespace E { namespace { } }\n"
46                      "}";
47   std::string Expected = "\n\n\n\n\nnamespace C {\n"
48                          "namespace D { int i; }\n   \n"
49                          "}";
50   std::vector<tooling::Range> Ranges;
51   Ranges.push_back(tooling::Range(28, 0));
52   Ranges.push_back(tooling::Range(91, 6));
53   Ranges.push_back(tooling::Range(132, 0));
54   std::string Result = cleanup(Code, Ranges);
55   EXPECT_EQ(Expected, Result);
56 }
57 
58 TEST_F(CleanupTest, NamespaceWithSyntaxError) {
59   std::string Code = "namespace A {\n"
60                      "namespace B {\n" // missing r_brace
61                      "} // namespace A\n\n"
62                      "namespace C {\n"
63                      "namespace D int i; }\n"
64                      "inline namespace E { namespace { } }\n"
65                      "}";
66   std::string Expected = "namespace A {\n"
67                          "\n\n\nnamespace C {\n"
68                          "namespace D int i; }\n   \n"
69                          "}";
70   std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
71   std::string Result = cleanup(Code, Ranges);
72   EXPECT_EQ(Expected, Result);
73 }
74 
75 TEST_F(CleanupTest, EmptyNamespaceNotAffected) {
76   std::string Code = "namespace A {\n\n"
77                      "namespace {\n\n}}";
78   // Even though the namespaces are empty, but the inner most empty namespace
79   // block is not affected by the changed ranges.
80   std::string Expected = "namespace A {\n\n"
81                          "namespace {\n\n}}";
82   // Set the changed range to be the second "\n".
83   std::vector<tooling::Range> Ranges(1, tooling::Range(14, 0));
84   std::string Result = cleanup(Code, Ranges);
85   EXPECT_EQ(Expected, Result);
86 }
87 
88 TEST_F(CleanupTest, EmptyNamespaceWithCommentsNoBreakBeforeBrace) {
89   std::string Code = "namespace A {\n"
90                      "namespace B {\n"
91                      "// Yo\n"
92                      "} // namespace B\n"
93                      "} // namespace A\n"
94                      "namespace C { // Yo\n"
95                      "}";
96   std::string Expected = "\n\n\n\n\n\n";
97   std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
98   std::string Result = cleanup(Code, Ranges);
99   EXPECT_EQ(Expected, Result);
100 }
101 
102 TEST_F(CleanupTest, EmptyNamespaceWithCommentsBreakBeforeBrace) {
103   std::string Code = "namespace A\n"
104                      "/* Yo */ {\n"
105                      "namespace B\n"
106                      "{\n"
107                      "// Yo\n"
108                      "} // namespace B\n"
109                      "} // namespace A\n"
110                      "namespace C\n"
111                      "{ // Yo\n"
112                      "}\n";
113   std::string Expected = "\n\n\n\n\n\n\n\n\n\n";
114   std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
115   FormatStyle Style = getLLVMStyle();
116   Style.BraceWrapping.AfterNamespace = true;
117   std::string Result = cleanup(Code, Ranges, Style);
118   EXPECT_EQ(Expected, Result);
119 }
120 
121 TEST_F(CleanupTest, CtorInitializationSimpleRedundantComma) {
122   std::string Code = "class A {\nA() : , {} };";
123   std::string Expected = "class A {\nA()  {} };";
124   std::vector<tooling::Range> Ranges;
125   Ranges.push_back(tooling::Range(17, 0));
126   Ranges.push_back(tooling::Range(19, 0));
127   std::string Result = cleanup(Code, Ranges);
128   EXPECT_EQ(Expected, Result);
129 
130   Code = "class A {\nA() : x(1), {} };";
131   Expected = "class A {\nA() : x(1) {} };";
132   Ranges.clear();
133   Ranges.push_back(tooling::Range(23, 0));
134   Result = cleanup(Code, Ranges);
135   EXPECT_EQ(Expected, Result);
136 
137   Code = "class A {\nA() :,,,,{} };";
138   Expected = "class A {\nA() {} };";
139   Ranges.clear();
140   Ranges.push_back(tooling::Range(15, 0));
141   Result = cleanup(Code, Ranges);
142   EXPECT_EQ(Expected, Result);
143 }
144 
145 TEST_F(CleanupTest, ListSimpleRedundantComma) {
146   std::string Code = "void f() { std::vector<int> v = {1,2,,,3,{4,5}}; }";
147   std::string Expected = "void f() { std::vector<int> v = {1,2,3,{4,5}}; }";
148   std::vector<tooling::Range> Ranges;
149   Ranges.push_back(tooling::Range(40, 0));
150   std::string Result = cleanup(Code, Ranges);
151   EXPECT_EQ(Expected, Result);
152 
153   Code = "int main() { f(1,,2,3,,4);}";
154   Expected = "int main() { f(1,2,3,4);}";
155   Ranges.clear();
156   Ranges.push_back(tooling::Range(17, 0));
157   Ranges.push_back(tooling::Range(22, 0));
158   Result = cleanup(Code, Ranges);
159   EXPECT_EQ(Expected, Result);
160 }
161 
162 TEST_F(CleanupTest, CtorInitializationBracesInParens) {
163   std::string Code = "class A {\nA() : x({1}),, {} };";
164   std::string Expected = "class A {\nA() : x({1}) {} };";
165   std::vector<tooling::Range> Ranges;
166   Ranges.push_back(tooling::Range(24, 0));
167   Ranges.push_back(tooling::Range(26, 0));
168   std::string Result = cleanup(Code, Ranges);
169   EXPECT_EQ(Expected, Result);
170 }
171 
172 TEST_F(CleanupTest, RedundantCommaNotInAffectedRanges) {
173   std::string Code =
174       "class A {\nA() : x({1}), /* comment */, { int x = 0; } };";
175   std::string Expected =
176       "class A {\nA() : x({1}), /* comment */, { int x = 0; } };";
177   // Set the affected range to be "int x = 0", which does not intercept the
178   // constructor initialization list.
179   std::vector<tooling::Range> Ranges(1, tooling::Range(42, 9));
180   std::string Result = cleanup(Code, Ranges);
181   EXPECT_EQ(Expected, Result);
182 
183   Code = "class A {\nA() : x(1), {} };";
184   Expected = "class A {\nA() : x(1), {} };";
185   // No range. Fixer should do nothing.
186   Ranges.clear();
187   Result = cleanup(Code, Ranges);
188   EXPECT_EQ(Expected, Result);
189 }
190 
191 // FIXME: delete comments too.
192 TEST_F(CleanupTest, CtorInitializationCommentAroundCommas) {
193   // Remove redundant commas around comment.
194   std::string Code = "class A {\nA() : x({1}), /* comment */, {} };";
195   std::string Expected = "class A {\nA() : x({1}) /* comment */ {} };";
196   std::vector<tooling::Range> Ranges;
197   Ranges.push_back(tooling::Range(25, 0));
198   Ranges.push_back(tooling::Range(40, 0));
199   std::string Result = cleanup(Code, Ranges);
200   EXPECT_EQ(Expected, Result);
201 
202   // Remove trailing comma and ignore comment.
203   Code = "class A {\nA() : x({1}), // comment\n{} };";
204   Expected = "class A {\nA() : x({1}) // comment\n{} };";
205   Ranges = std::vector<tooling::Range>(1, tooling::Range(25, 0));
206   Result = cleanup(Code, Ranges);
207   EXPECT_EQ(Expected, Result);
208 
209   // Remove trailing comma and ignore comment.
210   Code = "class A {\nA() : x({1}), // comment\n , y(1),{} };";
211   Expected = "class A {\nA() : x({1}), // comment\n  y(1){} };";
212   Ranges = std::vector<tooling::Range>(1, tooling::Range(38, 0));
213   Result = cleanup(Code, Ranges);
214   EXPECT_EQ(Expected, Result);
215 
216   // Remove trailing comma and ignore comment.
217   Code = "class A {\nA() : x({1}), \n/* comment */, y(1),{} };";
218   Expected = "class A {\nA() : x({1}), \n/* comment */ y(1){} };";
219   Ranges = std::vector<tooling::Range>(1, tooling::Range(40, 0));
220   Result = cleanup(Code, Ranges);
221   EXPECT_EQ(Expected, Result);
222 
223   // Remove trailing comma and ignore comment.
224   Code = "class A {\nA() : , // comment\n y(1),{} };";
225   Expected = "class A {\nA() :  // comment\n y(1){} };";
226   Ranges = std::vector<tooling::Range>(1, tooling::Range(17, 0));
227   Result = cleanup(Code, Ranges);
228   EXPECT_EQ(Expected, Result);
229 }
230 
231 TEST_F(CleanupTest, CtorInitializerInNamespace) {
232   std::string Code = "namespace A {\n"
233                      "namespace B {\n" // missing r_brace
234                      "} // namespace A\n\n"
235                      "namespace C {\n"
236                      "class A { A() : x(0),, {} };\n"
237                      "inline namespace E { namespace { } }\n"
238                      "}";
239   std::string Expected = "namespace A {\n"
240                          "\n\n\nnamespace C {\n"
241                          "class A { A() : x(0) {} };\n   \n"
242                          "}";
243   std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
244   std::string Result = cleanup(Code, Ranges);
245   EXPECT_EQ(Expected, Result);
246 }
247 
248 class CleanUpReplacementsTest : public ReplacementTest {
249 protected:
250   tooling::Replacement createReplacement(unsigned Offset, unsigned Length,
251                                          StringRef Text) {
252     return tooling::Replacement(FileName, Offset, Length, Text);
253   }
254 
255   tooling::Replacement createInsertion(StringRef HeaderName) {
256     return createReplacement(UINT_MAX, 0, HeaderName);
257   }
258 
259   inline std::string apply(StringRef Code,
260                            const tooling::Replacements Replaces) {
261     auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style);
262     EXPECT_TRUE(static_cast<bool>(CleanReplaces))
263         << llvm::toString(CleanReplaces.takeError()) << "\n";
264     auto Result = applyAllReplacements(Code, *CleanReplaces);
265     EXPECT_TRUE(static_cast<bool>(Result));
266     return *Result;
267   }
268 
269   inline std::string formatAndApply(StringRef Code,
270                                     const tooling::Replacements Replaces) {
271 
272     auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style);
273     EXPECT_TRUE(static_cast<bool>(CleanReplaces))
274         << llvm::toString(CleanReplaces.takeError()) << "\n";
275     auto FormattedReplaces = formatReplacements(Code, *CleanReplaces, Style);
276     EXPECT_TRUE(static_cast<bool>(FormattedReplaces))
277         << llvm::toString(FormattedReplaces.takeError()) << "\n";
278     auto Result = applyAllReplacements(Code, *FormattedReplaces);
279     EXPECT_TRUE(static_cast<bool>(Result));
280     return *Result;
281   }
282 
283   int getOffset(StringRef Code, int Line, int Column) {
284     RewriterTestContext Context;
285     FileID ID = Context.createInMemoryFile(FileName, Code);
286     auto DecomposedLocation =
287         Context.Sources.getDecomposedLoc(Context.getLocation(ID, Line, Column));
288     return DecomposedLocation.second;
289   }
290 
291   const std::string FileName = "fix.cpp";
292   FormatStyle Style = getLLVMStyle();
293 };
294 
295 TEST_F(CleanUpReplacementsTest, FixOnlyAffectedCodeAfterReplacements) {
296   std::string Code = "namespace A {\n"
297                      "namespace B {\n"
298                      "  int x;\n"
299                      "} // namespace B\n"
300                      "} // namespace A\n"
301                      "\n"
302                      "namespace C {\n"
303                      "namespace D { int i; }\n"
304                      "inline namespace E { namespace { int y; } }\n"
305                      "int x=     0;"
306                      "}";
307   std::string Expected = "\n\nnamespace C {\n"
308                          "namespace D { int i; }\n\n"
309                          "int x=     0;"
310                          "}";
311   tooling::Replacements Replaces =
312       toReplacements({createReplacement(getOffset(Code, 3, 3), 6, ""),
313                       createReplacement(getOffset(Code, 9, 34), 6, "")});
314 
315   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
316 }
317 
318 TEST_F(CleanUpReplacementsTest, NoExistingIncludeWithoutDefine) {
319   std::string Code = "int main() {}";
320   std::string Expected = "#include \"a.h\"\n"
321                          "int main() {}";
322   tooling::Replacements Replaces =
323       toReplacements({createInsertion("#include \"a.h\"")});
324   EXPECT_EQ(Expected, apply(Code, Replaces));
325 }
326 
327 TEST_F(CleanUpReplacementsTest, NoExistingIncludeWithDefine) {
328   std::string Code = "#ifndef A_H\n"
329                      "#define A_H\n"
330                      "class A {};\n"
331                      "#define MMM 123\n"
332                      "#endif";
333   std::string Expected = "#ifndef A_H\n"
334                          "#define A_H\n"
335                          "#include \"b.h\"\n"
336                          "class A {};\n"
337                          "#define MMM 123\n"
338                          "#endif";
339 
340   tooling::Replacements Replaces =
341       toReplacements({createInsertion("#include \"b.h\"")});
342   EXPECT_EQ(Expected, apply(Code, Replaces));
343 }
344 
345 TEST_F(CleanUpReplacementsTest, InsertBeforeCategoryWithLowerPriority) {
346   std::string Code = "#ifndef A_H\n"
347                      "#define A_H\n"
348                      "\n"
349                      "\n"
350                      "\n"
351                      "#include <vector>\n"
352                      "class A {};\n"
353                      "#define MMM 123\n"
354                      "#endif";
355   std::string Expected = "#ifndef A_H\n"
356                          "#define A_H\n"
357                          "\n"
358                          "\n"
359                          "\n"
360                          "#include \"a.h\"\n"
361                          "#include <vector>\n"
362                          "class A {};\n"
363                          "#define MMM 123\n"
364                          "#endif";
365 
366   tooling::Replacements Replaces =
367       toReplacements({createInsertion("#include \"a.h\"")});
368   EXPECT_EQ(Expected, apply(Code, Replaces));
369 }
370 
371 TEST_F(CleanUpReplacementsTest, InsertAfterMainHeader) {
372   std::string Code = "#include \"fix.h\"\n"
373                      "\n"
374                      "int main() {}";
375   std::string Expected = "#include \"fix.h\"\n"
376                          "#include <a>\n"
377                          "\n"
378                          "int main() {}";
379   tooling::Replacements Replaces =
380       toReplacements({createInsertion("#include <a>")});
381   Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
382   EXPECT_EQ(Expected, apply(Code, Replaces));
383 }
384 
385 TEST_F(CleanUpReplacementsTest, InsertBeforeSystemHeaderLLVM) {
386   std::string Code = "#include <memory>\n"
387                      "\n"
388                      "int main() {}";
389   std::string Expected = "#include \"z.h\"\n"
390                          "#include <memory>\n"
391                          "\n"
392                          "int main() {}";
393   tooling::Replacements Replaces =
394       toReplacements({createInsertion("#include \"z.h\"")});
395   EXPECT_EQ(Expected, apply(Code, Replaces));
396 }
397 
398 TEST_F(CleanUpReplacementsTest, InsertAfterSystemHeaderGoogle) {
399   std::string Code = "#include <memory>\n"
400                      "\n"
401                      "int main() {}";
402   std::string Expected = "#include <memory>\n"
403                          "#include \"z.h\"\n"
404                          "\n"
405                          "int main() {}";
406   tooling::Replacements Replaces =
407       toReplacements({createInsertion("#include \"z.h\"")});
408   Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
409   EXPECT_EQ(Expected, apply(Code, Replaces));
410 }
411 
412 TEST_F(CleanUpReplacementsTest, InsertOneIncludeLLVMStyle) {
413   std::string Code = "#include \"x/fix.h\"\n"
414                      "#include \"a.h\"\n"
415                      "#include \"b.h\"\n"
416                      "#include \"clang/Format/Format.h\"\n"
417                      "#include <memory>\n";
418   std::string Expected = "#include \"x/fix.h\"\n"
419                          "#include \"a.h\"\n"
420                          "#include \"b.h\"\n"
421                          "#include \"d.h\"\n"
422                          "#include \"clang/Format/Format.h\"\n"
423                          "#include \"llvm/x/y.h\"\n"
424                          "#include <memory>\n";
425   tooling::Replacements Replaces =
426       toReplacements({createInsertion("#include \"d.h\""),
427                       createInsertion("#include \"llvm/x/y.h\"")});
428   EXPECT_EQ(Expected, apply(Code, Replaces));
429 }
430 
431 TEST_F(CleanUpReplacementsTest, InsertMultipleIncludesLLVMStyle) {
432   std::string Code = "#include \"x/fix.h\"\n"
433                      "#include \"a.h\"\n"
434                      "#include \"b.h\"\n"
435                      "#include \"clang/Format/Format.h\"\n"
436                      "#include <memory>\n";
437   std::string Expected = "#include \"x/fix.h\"\n"
438                          "#include \"a.h\"\n"
439                          "#include \"b.h\"\n"
440                          "#include \"new/new.h\"\n"
441                          "#include \"clang/Format/Format.h\"\n"
442                          "#include <memory>\n"
443                          "#include <list>\n";
444   tooling::Replacements Replaces =
445       toReplacements({createInsertion("#include <list>"),
446                       createInsertion("#include \"new/new.h\"")});
447   EXPECT_EQ(Expected, apply(Code, Replaces));
448 }
449 
450 TEST_F(CleanUpReplacementsTest, InsertNewSystemIncludeGoogleStyle) {
451   std::string Code = "#include \"x/fix.h\"\n"
452                      "\n"
453                      "#include \"y/a.h\"\n"
454                      "#include \"z/b.h\"\n";
455   // FIXME: inserting after the empty line following the main header might be
456   // prefered.
457   std::string Expected = "#include \"x/fix.h\"\n"
458                          "#include <vector>\n"
459                          "\n"
460                          "#include \"y/a.h\"\n"
461                          "#include \"z/b.h\"\n";
462   tooling::Replacements Replaces =
463       toReplacements({createInsertion("#include <vector>")});
464   Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
465   EXPECT_EQ(Expected, apply(Code, Replaces));
466 }
467 
468 TEST_F(CleanUpReplacementsTest, InsertMultipleIncludesGoogleStyle) {
469   std::string Code = "#include \"x/fix.h\"\n"
470                      "\n"
471                      "#include <vector>\n"
472                      "\n"
473                      "#include \"y/a.h\"\n"
474                      "#include \"z/b.h\"\n";
475   std::string Expected = "#include \"x/fix.h\"\n"
476                          "\n"
477                          "#include <vector>\n"
478                          "#include <list>\n"
479                          "\n"
480                          "#include \"y/a.h\"\n"
481                          "#include \"z/b.h\"\n"
482                          "#include \"x/x.h\"\n";
483   tooling::Replacements Replaces =
484       toReplacements({createInsertion("#include <list>"),
485                       createInsertion("#include \"x/x.h\"")});
486   Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
487   EXPECT_EQ(Expected, apply(Code, Replaces));
488 }
489 
490 TEST_F(CleanUpReplacementsTest, InsertMultipleNewHeadersAndSortLLVM) {
491   std::string Code = "\nint x;";
492   std::string Expected = "\n#include \"fix.h\"\n"
493                          "#include \"a.h\"\n"
494                          "#include \"b.h\"\n"
495                          "#include \"c.h\"\n"
496                          "#include <list>\n"
497                          "#include <vector>\n"
498                          "int x;";
499   tooling::Replacements Replaces = toReplacements(
500       {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""),
501        createInsertion("#include \"b.h\""),
502        createInsertion("#include <vector>"), createInsertion("#include <list>"),
503        createInsertion("#include \"fix.h\"")});
504   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
505 }
506 
507 TEST_F(CleanUpReplacementsTest, InsertMultipleNewHeadersAndSortGoogle) {
508   std::string Code = "\nint x;";
509   std::string Expected = "\n#include \"fix.h\"\n"
510                          "#include <list>\n"
511                          "#include <vector>\n"
512                          "#include \"a.h\"\n"
513                          "#include \"b.h\"\n"
514                          "#include \"c.h\"\n"
515                          "int x;";
516   tooling::Replacements Replaces = toReplacements(
517       {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""),
518        createInsertion("#include \"b.h\""),
519        createInsertion("#include <vector>"), createInsertion("#include <list>"),
520        createInsertion("#include \"fix.h\"")});
521   Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
522   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
523 }
524 
525 TEST_F(CleanUpReplacementsTest, FormatCorrectLineWhenHeadersAreInserted) {
526   std::string Code = "\n"
527                      "int x;\n"
528                      "int    a;\n"
529                      "int    a;\n"
530                      "int    a;";
531 
532   std::string Expected = "\n#include \"x.h\"\n"
533                          "#include \"y.h\"\n"
534                          "#include \"clang/x/x.h\"\n"
535                          "#include <list>\n"
536                          "#include <vector>\n"
537                          "int x;\n"
538                          "int    a;\n"
539                          "int b;\n"
540                          "int    a;";
541   tooling::Replacements Replaces = toReplacements(
542       {createReplacement(getOffset(Code, 4, 8), 1, "b"),
543        createInsertion("#include <vector>"), createInsertion("#include <list>"),
544        createInsertion("#include \"clang/x/x.h\""),
545        createInsertion("#include \"y.h\""),
546        createInsertion("#include \"x.h\"")});
547   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
548 }
549 
550 TEST_F(CleanUpReplacementsTest, NotConfusedByDefine) {
551   std::string Code = "void f() {}\n"
552                      "#define A \\\n"
553                      "  int i;";
554   std::string Expected = "#include <vector>\n"
555                          "void f() {}\n"
556                          "#define A \\\n"
557                          "  int i;";
558   tooling::Replacements Replaces =
559       toReplacements({createInsertion("#include <vector>")});
560   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
561 }
562 
563 TEST_F(CleanUpReplacementsTest, SkippedTopComment) {
564   std::string Code = "// comment\n"
565                      "\n"
566                      "   // comment\n";
567   std::string Expected = "// comment\n"
568                          "\n"
569                          "   // comment\n"
570                          "#include <vector>\n";
571   tooling::Replacements Replaces =
572       toReplacements({createInsertion("#include <vector>")});
573   EXPECT_EQ(Expected, apply(Code, Replaces));
574 }
575 
576 TEST_F(CleanUpReplacementsTest, SkippedMixedComments) {
577   std::string Code = "// comment\n"
578                      "// comment \\\n"
579                      " comment continued\n"
580                      "/*\n"
581                      "* comment\n"
582                      "*/\n";
583   std::string Expected = "// comment\n"
584                          "// comment \\\n"
585                          " comment continued\n"
586                          "/*\n"
587                          "* comment\n"
588                          "*/\n"
589                          "#include <vector>\n";
590   tooling::Replacements Replaces =
591       toReplacements({createInsertion("#include <vector>")});
592   EXPECT_EQ(Expected, apply(Code, Replaces));
593 }
594 
595 TEST_F(CleanUpReplacementsTest, MultipleBlockCommentsInOneLine) {
596   std::string Code = "/*\n"
597                      "* comment\n"
598                      "*/ /* comment\n"
599                      "*/\n"
600                      "\n\n"
601                      "/* c1 */ /*c2 */\n";
602   std::string Expected = "/*\n"
603                          "* comment\n"
604                          "*/ /* comment\n"
605                          "*/\n"
606                          "\n\n"
607                          "/* c1 */ /*c2 */\n"
608                          "#include <vector>\n";
609   tooling::Replacements Replaces =
610       toReplacements({createInsertion("#include <vector>")});
611   EXPECT_EQ(Expected, apply(Code, Replaces));
612 }
613 
614 TEST_F(CleanUpReplacementsTest, CodeAfterComments) {
615   std::string Code = "/*\n"
616                      "* comment\n"
617                      "*/ /* comment\n"
618                      "*/\n"
619                      "\n\n"
620                      "/* c1 */ /*c2 */\n"
621                      "\n"
622                      "int x;\n";
623   std::string Expected = "/*\n"
624                          "* comment\n"
625                          "*/ /* comment\n"
626                          "*/\n"
627                          "\n\n"
628                          "/* c1 */ /*c2 */\n"
629                          "\n"
630                          "#include <vector>\n"
631                          "int x;\n";
632   tooling::Replacements Replaces =
633       toReplacements({createInsertion("#include <vector>")});
634   EXPECT_EQ(Expected, apply(Code, Replaces));
635 }
636 
637 TEST_F(CleanUpReplacementsTest, FakeHeaderGuardIfDef) {
638   std::string Code = "// comment \n"
639                      "#ifdef X\n"
640                      "#define X\n";
641   std::string Expected = "// comment \n"
642                          "#include <vector>\n"
643                          "#ifdef X\n"
644                          "#define X\n";
645   tooling::Replacements Replaces =
646       toReplacements({createInsertion("#include <vector>")});
647   EXPECT_EQ(Expected, apply(Code, Replaces));
648 }
649 
650 TEST_F(CleanUpReplacementsTest, RealHeaderGuardAfterComments) {
651   std::string Code = "// comment \n"
652                      "#ifndef X\n"
653                      "#define X\n"
654                      "int x;\n"
655                      "#define Y 1\n";
656   std::string Expected = "// comment \n"
657                          "#ifndef X\n"
658                          "#define X\n"
659                          "#include <vector>\n"
660                          "int x;\n"
661                          "#define Y 1\n";
662   tooling::Replacements Replaces =
663       toReplacements({createInsertion("#include <vector>")});
664   EXPECT_EQ(Expected, apply(Code, Replaces));
665 }
666 
667 TEST_F(CleanUpReplacementsTest, IfNDefWithNoDefine) {
668   std::string Code = "// comment \n"
669                      "#ifndef X\n"
670                      "int x;\n"
671                      "#define Y 1\n";
672   std::string Expected = "// comment \n"
673                          "#include <vector>\n"
674                          "#ifndef X\n"
675                          "int x;\n"
676                          "#define Y 1\n";
677   tooling::Replacements Replaces =
678       toReplacements({createInsertion("#include <vector>")});
679   EXPECT_EQ(Expected, apply(Code, Replaces));
680 }
681 
682 TEST_F(CleanUpReplacementsTest, HeaderGuardWithComment) {
683   std::string Code = "// comment \n"
684                      "#ifndef X // comment\n"
685                      "// comment\n"
686                      "/* comment\n"
687                      "*/\n"
688                      "/* comment */ #define X\n"
689                      "int x;\n"
690                      "#define Y 1\n";
691   std::string Expected = "// comment \n"
692                          "#ifndef X // comment\n"
693                          "// comment\n"
694                          "/* comment\n"
695                          "*/\n"
696                          "/* comment */ #define X\n"
697                          "#include <vector>\n"
698                          "int x;\n"
699                          "#define Y 1\n";
700   tooling::Replacements Replaces =
701       toReplacements({createInsertion("#include <vector>")});
702   EXPECT_EQ(Expected, apply(Code, Replaces));
703 }
704 
705 TEST_F(CleanUpReplacementsTest, EmptyCode) {
706   std::string Code = "";
707   std::string Expected = "#include <vector>\n";
708   tooling::Replacements Replaces =
709       toReplacements({createInsertion("#include <vector>")});
710   EXPECT_EQ(Expected, apply(Code, Replaces));
711 }
712 
713 // FIXME: although this case does not crash, the insertion is wrong. A '\n'
714 // should be inserted between the two #includes.
715 TEST_F(CleanUpReplacementsTest, NoNewLineAtTheEndOfCode) {
716   std::string Code = "#include <map>";
717   std::string Expected = "#include <map>#include <vector>\n";
718   tooling::Replacements Replaces =
719       toReplacements({createInsertion("#include <vector>")});
720   EXPECT_EQ(Expected, apply(Code, Replaces));
721 }
722 
723 TEST_F(CleanUpReplacementsTest, SkipExistingHeaders) {
724   std::string Code = "#include \"a.h\"\n"
725                      "#include <vector>\n";
726   std::string Expected = "#include \"a.h\"\n"
727                          "#include <vector>\n";
728   tooling::Replacements Replaces =
729       toReplacements({createInsertion("#include <vector>"),
730                       createInsertion("#include \"a.h\"")});
731   EXPECT_EQ(Expected, apply(Code, Replaces));
732 }
733 
734 TEST_F(CleanUpReplacementsTest, AddIncludesWithDifferentForms) {
735   std::string Code = "#include \"a.h\"\n"
736                      "#include <vector>\n";
737   // FIXME: this might not be the best behavior.
738   std::string Expected = "#include \"a.h\"\n"
739                          "#include \"vector\"\n"
740                          "#include <vector>\n"
741                          "#include <a.h>\n";
742   tooling::Replacements Replaces =
743       toReplacements({createInsertion("#include \"vector\""),
744                       createInsertion("#include <a.h>")});
745   EXPECT_EQ(Expected, apply(Code, Replaces));
746 }
747 
748 } // end namespace
749 } // end namespace format
750 } // end namespace clang
751