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