xref: /llvm-project/clang/unittests/Format/CleanupTest.cpp (revision 01426ff875419e939f91d959904baac23075084f)
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 TEST_F(CleanupTest, RemoveCommentsAroundDeleteCode) {
192   std::string Code =
193       "class A {\nA() : x({1}), /* comment */, /* comment */ {} };";
194   std::string Expected = "class A {\nA() : x({1}) {} };";
195   std::vector<tooling::Range> Ranges;
196   Ranges.push_back(tooling::Range(25, 0));
197   Ranges.push_back(tooling::Range(40, 0));
198   std::string Result = cleanup(Code, Ranges);
199   EXPECT_EQ(Expected, Result);
200 
201   Code = "class A {\nA() : x({1}), // comment\n {} };";
202   Expected = "class A {\nA() : x({1})\n {} };";
203   Ranges = std::vector<tooling::Range>(1, tooling::Range(25, 0));
204   Result = cleanup(Code, Ranges);
205   EXPECT_EQ(Expected, Result);
206 
207   Code = "class A {\nA() : x({1}), // comment\n , y(1),{} };";
208   Expected = "class A {\nA() : x({1}),  y(1){} };";
209   Ranges = std::vector<tooling::Range>(1, tooling::Range(38, 0));
210   Result = cleanup(Code, Ranges);
211   EXPECT_EQ(Expected, Result);
212 
213   Code = "class A {\nA() : x({1}), \n/* comment */, y(1),{} };";
214   Expected = "class A {\nA() : x({1}), \n y(1){} };";
215   Ranges = std::vector<tooling::Range>(1, tooling::Range(40, 0));
216   Result = cleanup(Code, Ranges);
217   EXPECT_EQ(Expected, Result);
218 
219   Code = "class A {\nA() : , // comment\n y(1),{} };";
220   Expected = "class A {\nA() :  // comment\n y(1){} };";
221   Ranges = std::vector<tooling::Range>(1, tooling::Range(17, 0));
222   Result = cleanup(Code, Ranges);
223   EXPECT_EQ(Expected, Result);
224 }
225 
226 TEST_F(CleanupTest, CtorInitializerInNamespace) {
227   std::string Code = "namespace A {\n"
228                      "namespace B {\n" // missing r_brace
229                      "} // namespace A\n\n"
230                      "namespace C {\n"
231                      "class A { A() : x(0),, {} };\n"
232                      "inline namespace E { namespace { } }\n"
233                      "}";
234   std::string Expected = "namespace A {\n"
235                          "\n\n\nnamespace C {\n"
236                          "class A { A() : x(0) {} };\n   \n"
237                          "}";
238   std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
239   std::string Result = cleanup(Code, Ranges);
240   EXPECT_EQ(Expected, Result);
241 }
242 
243 class CleanUpReplacementsTest : public ReplacementTest {
244 protected:
245   tooling::Replacement createReplacement(unsigned Offset, unsigned Length,
246                                          StringRef Text) {
247     return tooling::Replacement(FileName, Offset, Length, Text);
248   }
249 
250   tooling::Replacement createInsertion(StringRef HeaderName) {
251     return createReplacement(UINT_MAX, 0, HeaderName);
252   }
253 
254   inline std::string apply(StringRef Code,
255                            const tooling::Replacements Replaces) {
256     auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style);
257     EXPECT_TRUE(static_cast<bool>(CleanReplaces))
258         << llvm::toString(CleanReplaces.takeError()) << "\n";
259     auto Result = applyAllReplacements(Code, *CleanReplaces);
260     EXPECT_TRUE(static_cast<bool>(Result));
261     return *Result;
262   }
263 
264   inline std::string formatAndApply(StringRef Code,
265                                     const tooling::Replacements Replaces) {
266 
267     auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style);
268     EXPECT_TRUE(static_cast<bool>(CleanReplaces))
269         << llvm::toString(CleanReplaces.takeError()) << "\n";
270     auto FormattedReplaces = formatReplacements(Code, *CleanReplaces, Style);
271     EXPECT_TRUE(static_cast<bool>(FormattedReplaces))
272         << llvm::toString(FormattedReplaces.takeError()) << "\n";
273     auto Result = applyAllReplacements(Code, *FormattedReplaces);
274     EXPECT_TRUE(static_cast<bool>(Result));
275     return *Result;
276   }
277 
278   int getOffset(StringRef Code, int Line, int Column) {
279     RewriterTestContext Context;
280     FileID ID = Context.createInMemoryFile(FileName, Code);
281     auto DecomposedLocation =
282         Context.Sources.getDecomposedLoc(Context.getLocation(ID, Line, Column));
283     return DecomposedLocation.second;
284   }
285 
286   const std::string FileName = "fix.cpp";
287   FormatStyle Style = getLLVMStyle();
288 };
289 
290 TEST_F(CleanUpReplacementsTest, FixOnlyAffectedCodeAfterReplacements) {
291   std::string Code = "namespace A {\n"
292                      "namespace B {\n"
293                      "  int x;\n"
294                      "} // namespace B\n"
295                      "} // namespace A\n"
296                      "\n"
297                      "namespace C {\n"
298                      "namespace D { int i; }\n"
299                      "inline namespace E { namespace { int y; } }\n"
300                      "int x=     0;"
301                      "}";
302   std::string Expected = "\n\nnamespace C {\n"
303                          "namespace D { int i; }\n\n"
304                          "int x=     0;"
305                          "}";
306   tooling::Replacements Replaces =
307       toReplacements({createReplacement(getOffset(Code, 3, 3), 6, ""),
308                       createReplacement(getOffset(Code, 9, 34), 6, "")});
309 
310   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
311 }
312 
313 TEST_F(CleanUpReplacementsTest, NoExistingIncludeWithoutDefine) {
314   std::string Code = "int main() {}";
315   std::string Expected = "#include \"a.h\"\n"
316                          "int main() {}";
317   tooling::Replacements Replaces =
318       toReplacements({createInsertion("#include \"a.h\"")});
319   EXPECT_EQ(Expected, apply(Code, Replaces));
320 }
321 
322 TEST_F(CleanUpReplacementsTest, NoExistingIncludeWithDefine) {
323   std::string Code = "#ifndef A_H\n"
324                      "#define A_H\n"
325                      "class A {};\n"
326                      "#define MMM 123\n"
327                      "#endif";
328   std::string Expected = "#ifndef A_H\n"
329                          "#define A_H\n"
330                          "#include \"b.h\"\n"
331                          "class A {};\n"
332                          "#define MMM 123\n"
333                          "#endif";
334 
335   tooling::Replacements Replaces =
336       toReplacements({createInsertion("#include \"b.h\"")});
337   EXPECT_EQ(Expected, apply(Code, Replaces));
338 }
339 
340 TEST_F(CleanUpReplacementsTest, InsertBeforeCategoryWithLowerPriority) {
341   std::string Code = "#ifndef A_H\n"
342                      "#define A_H\n"
343                      "\n"
344                      "\n"
345                      "\n"
346                      "#include <vector>\n"
347                      "class A {};\n"
348                      "#define MMM 123\n"
349                      "#endif";
350   std::string Expected = "#ifndef A_H\n"
351                          "#define A_H\n"
352                          "\n"
353                          "\n"
354                          "\n"
355                          "#include \"a.h\"\n"
356                          "#include <vector>\n"
357                          "class A {};\n"
358                          "#define MMM 123\n"
359                          "#endif";
360 
361   tooling::Replacements Replaces =
362       toReplacements({createInsertion("#include \"a.h\"")});
363   EXPECT_EQ(Expected, apply(Code, Replaces));
364 }
365 
366 TEST_F(CleanUpReplacementsTest, InsertAfterMainHeader) {
367   std::string Code = "#include \"fix.h\"\n"
368                      "\n"
369                      "int main() {}";
370   std::string Expected = "#include \"fix.h\"\n"
371                          "#include <a>\n"
372                          "\n"
373                          "int main() {}";
374   tooling::Replacements Replaces =
375       toReplacements({createInsertion("#include <a>")});
376   Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
377   EXPECT_EQ(Expected, apply(Code, Replaces));
378 }
379 
380 TEST_F(CleanUpReplacementsTest, InsertBeforeSystemHeaderLLVM) {
381   std::string Code = "#include <memory>\n"
382                      "\n"
383                      "int main() {}";
384   std::string Expected = "#include \"z.h\"\n"
385                          "#include <memory>\n"
386                          "\n"
387                          "int main() {}";
388   tooling::Replacements Replaces =
389       toReplacements({createInsertion("#include \"z.h\"")});
390   EXPECT_EQ(Expected, apply(Code, Replaces));
391 }
392 
393 TEST_F(CleanUpReplacementsTest, InsertAfterSystemHeaderGoogle) {
394   std::string Code = "#include <memory>\n"
395                      "\n"
396                      "int main() {}";
397   std::string Expected = "#include <memory>\n"
398                          "#include \"z.h\"\n"
399                          "\n"
400                          "int main() {}";
401   tooling::Replacements Replaces =
402       toReplacements({createInsertion("#include \"z.h\"")});
403   Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
404   EXPECT_EQ(Expected, apply(Code, Replaces));
405 }
406 
407 TEST_F(CleanUpReplacementsTest, InsertOneIncludeLLVMStyle) {
408   std::string Code = "#include \"x/fix.h\"\n"
409                      "#include \"a.h\"\n"
410                      "#include \"b.h\"\n"
411                      "#include \"clang/Format/Format.h\"\n"
412                      "#include <memory>\n";
413   std::string Expected = "#include \"x/fix.h\"\n"
414                          "#include \"a.h\"\n"
415                          "#include \"b.h\"\n"
416                          "#include \"d.h\"\n"
417                          "#include \"clang/Format/Format.h\"\n"
418                          "#include \"llvm/x/y.h\"\n"
419                          "#include <memory>\n";
420   tooling::Replacements Replaces =
421       toReplacements({createInsertion("#include \"d.h\""),
422                       createInsertion("#include \"llvm/x/y.h\"")});
423   EXPECT_EQ(Expected, apply(Code, Replaces));
424 }
425 
426 TEST_F(CleanUpReplacementsTest, InsertMultipleIncludesLLVMStyle) {
427   std::string Code = "#include \"x/fix.h\"\n"
428                      "#include \"a.h\"\n"
429                      "#include \"b.h\"\n"
430                      "#include \"clang/Format/Format.h\"\n"
431                      "#include <memory>\n";
432   std::string Expected = "#include \"x/fix.h\"\n"
433                          "#include \"a.h\"\n"
434                          "#include \"b.h\"\n"
435                          "#include \"new/new.h\"\n"
436                          "#include \"clang/Format/Format.h\"\n"
437                          "#include <memory>\n"
438                          "#include <list>\n";
439   tooling::Replacements Replaces =
440       toReplacements({createInsertion("#include <list>"),
441                       createInsertion("#include \"new/new.h\"")});
442   EXPECT_EQ(Expected, apply(Code, Replaces));
443 }
444 
445 TEST_F(CleanUpReplacementsTest, InsertNewSystemIncludeGoogleStyle) {
446   std::string Code = "#include \"x/fix.h\"\n"
447                      "\n"
448                      "#include \"y/a.h\"\n"
449                      "#include \"z/b.h\"\n";
450   // FIXME: inserting after the empty line following the main header might be
451   // prefered.
452   std::string Expected = "#include \"x/fix.h\"\n"
453                          "#include <vector>\n"
454                          "\n"
455                          "#include \"y/a.h\"\n"
456                          "#include \"z/b.h\"\n";
457   tooling::Replacements Replaces =
458       toReplacements({createInsertion("#include <vector>")});
459   Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
460   EXPECT_EQ(Expected, apply(Code, Replaces));
461 }
462 
463 TEST_F(CleanUpReplacementsTest, InsertMultipleIncludesGoogleStyle) {
464   std::string Code = "#include \"x/fix.h\"\n"
465                      "\n"
466                      "#include <vector>\n"
467                      "\n"
468                      "#include \"y/a.h\"\n"
469                      "#include \"z/b.h\"\n";
470   std::string Expected = "#include \"x/fix.h\"\n"
471                          "\n"
472                          "#include <vector>\n"
473                          "#include <list>\n"
474                          "\n"
475                          "#include \"y/a.h\"\n"
476                          "#include \"z/b.h\"\n"
477                          "#include \"x/x.h\"\n";
478   tooling::Replacements Replaces =
479       toReplacements({createInsertion("#include <list>"),
480                       createInsertion("#include \"x/x.h\"")});
481   Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
482   EXPECT_EQ(Expected, apply(Code, Replaces));
483 }
484 
485 TEST_F(CleanUpReplacementsTest, InsertMultipleNewHeadersAndSortLLVM) {
486   std::string Code = "\nint x;";
487   std::string Expected = "\n#include \"fix.h\"\n"
488                          "#include \"a.h\"\n"
489                          "#include \"b.h\"\n"
490                          "#include \"c.h\"\n"
491                          "#include <list>\n"
492                          "#include <vector>\n"
493                          "int x;";
494   tooling::Replacements Replaces = toReplacements(
495       {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""),
496        createInsertion("#include \"b.h\""),
497        createInsertion("#include <vector>"), createInsertion("#include <list>"),
498        createInsertion("#include \"fix.h\"")});
499   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
500 }
501 
502 TEST_F(CleanUpReplacementsTest, InsertMultipleNewHeadersAndSortGoogle) {
503   std::string Code = "\nint x;";
504   std::string Expected = "\n#include \"fix.h\"\n"
505                          "#include <list>\n"
506                          "#include <vector>\n"
507                          "#include \"a.h\"\n"
508                          "#include \"b.h\"\n"
509                          "#include \"c.h\"\n"
510                          "int x;";
511   tooling::Replacements Replaces = toReplacements(
512       {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""),
513        createInsertion("#include \"b.h\""),
514        createInsertion("#include <vector>"), createInsertion("#include <list>"),
515        createInsertion("#include \"fix.h\"")});
516   Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
517   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
518 }
519 
520 TEST_F(CleanUpReplacementsTest, FormatCorrectLineWhenHeadersAreInserted) {
521   std::string Code = "\n"
522                      "int x;\n"
523                      "int    a;\n"
524                      "int    a;\n"
525                      "int    a;";
526 
527   std::string Expected = "\n#include \"x.h\"\n"
528                          "#include \"y.h\"\n"
529                          "#include \"clang/x/x.h\"\n"
530                          "#include <list>\n"
531                          "#include <vector>\n"
532                          "int x;\n"
533                          "int    a;\n"
534                          "int b;\n"
535                          "int    a;";
536   tooling::Replacements Replaces = toReplacements(
537       {createReplacement(getOffset(Code, 4, 8), 1, "b"),
538        createInsertion("#include <vector>"), createInsertion("#include <list>"),
539        createInsertion("#include \"clang/x/x.h\""),
540        createInsertion("#include \"y.h\""),
541        createInsertion("#include \"x.h\"")});
542   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
543 }
544 
545 TEST_F(CleanUpReplacementsTest, NotConfusedByDefine) {
546   std::string Code = "void f() {}\n"
547                      "#define A \\\n"
548                      "  int i;";
549   std::string Expected = "#include <vector>\n"
550                          "void f() {}\n"
551                          "#define A \\\n"
552                          "  int i;";
553   tooling::Replacements Replaces =
554       toReplacements({createInsertion("#include <vector>")});
555   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
556 }
557 
558 TEST_F(CleanUpReplacementsTest, SkippedTopComment) {
559   std::string Code = "// comment\n"
560                      "\n"
561                      "   // comment\n";
562   std::string Expected = "// comment\n"
563                          "\n"
564                          "   // comment\n"
565                          "#include <vector>\n";
566   tooling::Replacements Replaces =
567       toReplacements({createInsertion("#include <vector>")});
568   EXPECT_EQ(Expected, apply(Code, Replaces));
569 }
570 
571 TEST_F(CleanUpReplacementsTest, SkippedMixedComments) {
572   std::string Code = "// comment\n"
573                      "// comment \\\n"
574                      " comment continued\n"
575                      "/*\n"
576                      "* comment\n"
577                      "*/\n";
578   std::string Expected = "// comment\n"
579                          "// comment \\\n"
580                          " comment continued\n"
581                          "/*\n"
582                          "* comment\n"
583                          "*/\n"
584                          "#include <vector>\n";
585   tooling::Replacements Replaces =
586       toReplacements({createInsertion("#include <vector>")});
587   EXPECT_EQ(Expected, apply(Code, Replaces));
588 }
589 
590 TEST_F(CleanUpReplacementsTest, MultipleBlockCommentsInOneLine) {
591   std::string Code = "/*\n"
592                      "* comment\n"
593                      "*/ /* comment\n"
594                      "*/\n"
595                      "\n\n"
596                      "/* c1 */ /*c2 */\n";
597   std::string Expected = "/*\n"
598                          "* comment\n"
599                          "*/ /* comment\n"
600                          "*/\n"
601                          "\n\n"
602                          "/* c1 */ /*c2 */\n"
603                          "#include <vector>\n";
604   tooling::Replacements Replaces =
605       toReplacements({createInsertion("#include <vector>")});
606   EXPECT_EQ(Expected, apply(Code, Replaces));
607 }
608 
609 TEST_F(CleanUpReplacementsTest, CodeAfterComments) {
610   std::string Code = "/*\n"
611                      "* comment\n"
612                      "*/ /* comment\n"
613                      "*/\n"
614                      "\n\n"
615                      "/* c1 */ /*c2 */\n"
616                      "\n"
617                      "int x;\n";
618   std::string Expected = "/*\n"
619                          "* comment\n"
620                          "*/ /* comment\n"
621                          "*/\n"
622                          "\n\n"
623                          "/* c1 */ /*c2 */\n"
624                          "\n"
625                          "#include <vector>\n"
626                          "int x;\n";
627   tooling::Replacements Replaces =
628       toReplacements({createInsertion("#include <vector>")});
629   EXPECT_EQ(Expected, apply(Code, Replaces));
630 }
631 
632 TEST_F(CleanUpReplacementsTest, FakeHeaderGuardIfDef) {
633   std::string Code = "// comment \n"
634                      "#ifdef X\n"
635                      "#define X\n";
636   std::string Expected = "// comment \n"
637                          "#include <vector>\n"
638                          "#ifdef X\n"
639                          "#define X\n";
640   tooling::Replacements Replaces =
641       toReplacements({createInsertion("#include <vector>")});
642   EXPECT_EQ(Expected, apply(Code, Replaces));
643 }
644 
645 TEST_F(CleanUpReplacementsTest, RealHeaderGuardAfterComments) {
646   std::string Code = "// comment \n"
647                      "#ifndef X\n"
648                      "#define X\n"
649                      "int x;\n"
650                      "#define Y 1\n";
651   std::string Expected = "// comment \n"
652                          "#ifndef X\n"
653                          "#define X\n"
654                          "#include <vector>\n"
655                          "int x;\n"
656                          "#define Y 1\n";
657   tooling::Replacements Replaces =
658       toReplacements({createInsertion("#include <vector>")});
659   EXPECT_EQ(Expected, apply(Code, Replaces));
660 }
661 
662 TEST_F(CleanUpReplacementsTest, IfNDefWithNoDefine) {
663   std::string Code = "// comment \n"
664                      "#ifndef X\n"
665                      "int x;\n"
666                      "#define Y 1\n";
667   std::string Expected = "// comment \n"
668                          "#include <vector>\n"
669                          "#ifndef X\n"
670                          "int x;\n"
671                          "#define Y 1\n";
672   tooling::Replacements Replaces =
673       toReplacements({createInsertion("#include <vector>")});
674   EXPECT_EQ(Expected, apply(Code, Replaces));
675 }
676 
677 TEST_F(CleanUpReplacementsTest, HeaderGuardWithComment) {
678   std::string Code = "// comment \n"
679                      "#ifndef X // comment\n"
680                      "// comment\n"
681                      "/* comment\n"
682                      "*/\n"
683                      "/* comment */ #define X\n"
684                      "int x;\n"
685                      "#define Y 1\n";
686   std::string Expected = "// comment \n"
687                          "#ifndef X // comment\n"
688                          "// comment\n"
689                          "/* comment\n"
690                          "*/\n"
691                          "/* comment */ #define X\n"
692                          "#include <vector>\n"
693                          "int x;\n"
694                          "#define Y 1\n";
695   tooling::Replacements Replaces =
696       toReplacements({createInsertion("#include <vector>")});
697   EXPECT_EQ(Expected, apply(Code, Replaces));
698 }
699 
700 TEST_F(CleanUpReplacementsTest, EmptyCode) {
701   std::string Code = "";
702   std::string Expected = "#include <vector>\n";
703   tooling::Replacements Replaces =
704       toReplacements({createInsertion("#include <vector>")});
705   EXPECT_EQ(Expected, apply(Code, Replaces));
706 }
707 
708 // FIXME: although this case does not crash, the insertion is wrong. A '\n'
709 // should be inserted between the two #includes.
710 TEST_F(CleanUpReplacementsTest, NoNewLineAtTheEndOfCode) {
711   std::string Code = "#include <map>";
712   std::string Expected = "#include <map>#include <vector>\n";
713   tooling::Replacements Replaces =
714       toReplacements({createInsertion("#include <vector>")});
715   EXPECT_EQ(Expected, apply(Code, Replaces));
716 }
717 
718 TEST_F(CleanUpReplacementsTest, SkipExistingHeaders) {
719   std::string Code = "#include \"a.h\"\n"
720                      "#include <vector>\n";
721   std::string Expected = "#include \"a.h\"\n"
722                          "#include <vector>\n";
723   tooling::Replacements Replaces =
724       toReplacements({createInsertion("#include <vector>"),
725                       createInsertion("#include \"a.h\"")});
726   EXPECT_EQ(Expected, apply(Code, Replaces));
727 }
728 
729 TEST_F(CleanUpReplacementsTest, AddIncludesWithDifferentForms) {
730   std::string Code = "#include \"a.h\"\n"
731                      "#include <vector>\n";
732   // FIXME: this might not be the best behavior.
733   std::string Expected = "#include \"a.h\"\n"
734                          "#include \"vector\"\n"
735                          "#include <vector>\n"
736                          "#include <a.h>\n";
737   tooling::Replacements Replaces =
738       toReplacements({createInsertion("#include \"vector\""),
739                       createInsertion("#include <a.h>")});
740   EXPECT_EQ(Expected, apply(Code, Replaces));
741 }
742 
743 } // end namespace
744 } // end namespace format
745 } // end namespace clang
746