xref: /llvm-project/clang/unittests/Format/CleanupTest.cpp (revision 1c58208d899285318c89e069268145c85ec33368)
1 //===- unittest/Format/CleanupTest.cpp - Code cleanup unit tests ----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/Format/Format.h"
10 
11 #include "../Tooling/ReplacementTest.h"
12 #include "clang/Tooling/Core/Replacement.h"
13 
14 #include "gtest/gtest.h"
15 
16 using clang::tooling::ReplacementTest;
17 using clang::tooling::toReplacements;
18 
19 namespace clang {
20 namespace format {
21 namespace {
22 
23 class CleanupTest : public testing::Test {
24 protected:
cleanup(StringRef Code,const std::vector<tooling::Range> & Ranges,const FormatStyle & Style=getLLVMStyle ())25   std::string cleanup(StringRef Code, const std::vector<tooling::Range> &Ranges,
26                       const FormatStyle &Style = getLLVMStyle()) {
27     tooling::Replacements Replaces = format::cleanup(Style, Code, Ranges);
28 
29     auto Result = applyAllReplacements(Code, Replaces);
30     EXPECT_TRUE(static_cast<bool>(Result));
31     return *Result;
32   }
33 
34   // Returns code after cleanup around \p Offsets.
cleanupAroundOffsets(ArrayRef<unsigned> Offsets,StringRef Code,const FormatStyle & Style=getLLVMStyle ())35   std::string cleanupAroundOffsets(ArrayRef<unsigned> Offsets, StringRef Code,
36                                    const FormatStyle &Style = getLLVMStyle()) {
37     std::vector<tooling::Range> Ranges;
38     for (auto Offset : Offsets)
39       Ranges.push_back(tooling::Range(Offset, 0));
40     return cleanup(Code, Ranges, Style);
41   }
42 };
43 
TEST_F(CleanupTest,DeleteEmptyNamespaces)44 TEST_F(CleanupTest, DeleteEmptyNamespaces) {
45   std::string Code = "namespace A {\n"
46                      "namespace B {\n"
47                      "} // namespace B\n"
48                      "} // namespace A\n\n"
49                      "namespace C {\n"
50                      "namespace D { int i; }\n"
51                      "inline namespace E { namespace { } }\n"
52                      "}";
53   std::string Expected = "\n\n\n\n\nnamespace C {\n"
54                          "namespace D { int i; }\n   \n"
55                          "}";
56   EXPECT_EQ(Expected, cleanupAroundOffsets({28, 91, 132}, Code));
57 }
58 
TEST_F(CleanupTest,NamespaceWithSyntaxError)59 TEST_F(CleanupTest, NamespaceWithSyntaxError) {
60   std::string Code = "namespace A {\n"
61                      "namespace B {\n" // missing r_brace
62                      "} // namespace A\n\n"
63                      "namespace C {\n"
64                      "namespace D int i; }\n"
65                      "inline namespace E { namespace { } }\n"
66                      "}";
67   std::string Expected = "namespace A {\n"
68                          "\n\n\nnamespace C {\n"
69                          "namespace D int i; }\n   \n"
70                          "}";
71   std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
72   EXPECT_EQ(Expected, cleanup(Code, Ranges));
73 }
74 
TEST_F(CleanupTest,EmptyNamespaceNotAffected)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   EXPECT_EQ(Expected, cleanupAroundOffsets({14}, Code));
84 }
85 
TEST_F(CleanupTest,EmptyNamespaceWithCommentsNoBreakBeforeBrace)86 TEST_F(CleanupTest, EmptyNamespaceWithCommentsNoBreakBeforeBrace) {
87   std::string Code = "namespace A {\n"
88                      "namespace B {\n"
89                      "// Yo\n"
90                      "} // namespace B\n"
91                      "} // namespace A\n"
92                      "namespace C { // Yo\n"
93                      "}";
94   std::string Expected = "\n\n\n\n\n\n";
95   std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
96   std::string Result = cleanup(Code, Ranges);
97   EXPECT_EQ(Expected, Result);
98 }
99 
TEST_F(CleanupTest,EmptyNamespaceWithCommentsBreakBeforeBrace)100 TEST_F(CleanupTest, EmptyNamespaceWithCommentsBreakBeforeBrace) {
101   std::string Code = "namespace A\n"
102                      "/* Yo */ {\n"
103                      "namespace B\n"
104                      "{\n"
105                      "// Yo\n"
106                      "} // namespace B\n"
107                      "} // namespace A\n"
108                      "namespace C\n"
109                      "{ // Yo\n"
110                      "}\n";
111   std::string Expected = "\n\n\n\n\n\n\n\n\n\n";
112   std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
113   FormatStyle Style = getLLVMStyle();
114   Style.BraceWrapping.AfterNamespace = true;
115   std::string Result = cleanup(Code, Ranges, Style);
116   EXPECT_EQ(Expected, Result);
117 }
118 
TEST_F(CleanupTest,EmptyNamespaceAroundConditionalCompilation)119 TEST_F(CleanupTest, EmptyNamespaceAroundConditionalCompilation) {
120   std::string Code = "#ifdef A\n"
121                      "int a;\n"
122                      "int b;\n"
123                      "#else\n"
124                      "#endif\n"
125                      "namespace {}";
126   std::string Expected = "#ifdef A\n"
127                          "int a;\n"
128                          "int b;\n"
129                          "#else\n"
130                          "#endif\n";
131   std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
132   FormatStyle Style = getLLVMStyle();
133   std::string Result = cleanup(Code, Ranges, Style);
134   EXPECT_EQ(Expected, Result);
135 }
136 
TEST_F(CleanupTest,CtorInitializationSimpleRedundantComma)137 TEST_F(CleanupTest, CtorInitializationSimpleRedundantComma) {
138   std::string Code = "class A {\nA() : , {} };";
139   std::string Expected = "class A {\nA()  {} };";
140   EXPECT_EQ(Expected, cleanupAroundOffsets({17, 19}, Code));
141 
142   Code = "class A {\nA() : x(1), {} };";
143   Expected = "class A {\nA() : x(1) {} };";
144   EXPECT_EQ(Expected, cleanupAroundOffsets({23}, Code));
145 
146   Code = "class A {\nA() :,,,,{} };";
147   Expected = "class A {\nA() {} };";
148   EXPECT_EQ(Expected, cleanupAroundOffsets({15}, Code));
149 }
150 
151 // regression test for bug 39310
TEST_F(CleanupTest,CtorInitializationSimpleRedundantCommaInFunctionTryBlock)152 TEST_F(CleanupTest, CtorInitializationSimpleRedundantCommaInFunctionTryBlock) {
153   std::string Code = "class A {\nA() try : , {} };";
154   std::string Expected = "class A {\nA() try  {} };";
155   EXPECT_EQ(Expected, cleanupAroundOffsets({21, 23}, Code));
156 
157   Code = "class A {\nA() try : x(1), {} };";
158   Expected = "class A {\nA() try : x(1) {} };";
159   EXPECT_EQ(Expected, cleanupAroundOffsets({27}, Code));
160 
161   Code = "class A {\nA() try :,,,,{} };";
162   Expected = "class A {\nA() try {} };";
163   EXPECT_EQ(Expected, cleanupAroundOffsets({19}, Code));
164 
165   Code = "class A {\nA() try : x(1),,, {} };";
166   Expected = "class A {\nA() try : x(1) {} };";
167   EXPECT_EQ(Expected, cleanupAroundOffsets({27}, Code));
168 
169   // Do not remove every comma following a colon as it simply doesn't make
170   // sense in some situations.
171   Code = "try : , {}";
172   Expected = "try : , {}";
173   EXPECT_EQ(Expected, cleanupAroundOffsets({8}, Code));
174 }
175 
TEST_F(CleanupTest,CtorInitializationSimpleRedundantColon)176 TEST_F(CleanupTest, CtorInitializationSimpleRedundantColon) {
177   std::string Code = "class A {\nA() : =default; };";
178   std::string Expected = "class A {\nA()  =default; };";
179   EXPECT_EQ(Expected, cleanupAroundOffsets({15}, Code));
180 
181   Code = "class A {\nA() : , =default; };";
182   Expected = "class A {\nA()  =default; };";
183   EXPECT_EQ(Expected, cleanupAroundOffsets({15}, Code));
184 }
185 
TEST_F(CleanupTest,ListRedundantComma)186 TEST_F(CleanupTest, ListRedundantComma) {
187   std::string Code = "void f() { std::vector<int> v = {1,2,,,3,{4,5}}; }";
188   std::string Expected = "void f() { std::vector<int> v = {1,2,3,{4,5}}; }";
189   EXPECT_EQ(Expected, cleanupAroundOffsets({40}, Code));
190 
191   Code = "int main() { f(1,,2,3,,4);}";
192   Expected = "int main() { f(1,2,3,4);}";
193   EXPECT_EQ(Expected, cleanupAroundOffsets({17, 22}, Code));
194 }
195 
TEST_F(CleanupTest,NoCleanupsForJavaScript)196 TEST_F(CleanupTest, NoCleanupsForJavaScript) {
197   std::string Code = "function f() { var x = [a, b, , c]; }";
198   std::string Expected = "function f() { var x = [a, b, , c]; }";
199   const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript);
200 
201   EXPECT_EQ(Expected, cleanupAroundOffsets({30}, Code, Style));
202 }
203 
TEST_F(CleanupTest,TrailingCommaInParens)204 TEST_F(CleanupTest, TrailingCommaInParens) {
205   std::string Code = "int main() { f(,1,,2,3,f(1,2,),4,,);}";
206   std::string Expected = "int main() { f(1,2,3,f(1,2),4);}";
207   EXPECT_EQ(Expected, cleanupAroundOffsets({15, 18, 29, 33}, Code));
208 
209   // Lambda contents are also checked for trailing commas.
210   Code = "int main() { [](){f(,1,,2,3,f(1,2,),4,,);}();}";
211   Expected = "int main() { [](){f(1,2,3,f(1,2),4);}();}";
212   EXPECT_EQ(Expected, cleanupAroundOffsets({20, 23, 34, 38}, Code));
213 }
214 
TEST_F(CleanupTest,TrailingCommaInBraces)215 TEST_F(CleanupTest, TrailingCommaInBraces) {
216   // Trailing comma is allowed in brace list.
217   // If there was trailing comma in the original code, then trailing comma is
218   // preserved. In this example, element between the last two commas is deleted
219   // causing the second-last comma to be redundant.
220   std::string Code = "void f() { std::vector<int> v = {1,2,3,,}; }";
221   std::string Expected = "void f() { std::vector<int> v = {1,2,3,}; }";
222   EXPECT_EQ(Expected, cleanupAroundOffsets({39}, Code));
223 
224   // If there was no trailing comma in the original code, then trailing comma
225   // introduced by replacements should be cleaned up. In this example, the
226   // element after the last comma is deleted causing the last comma to be
227   // redundant.
228   Code = "void f() { std::vector<int> v = {1,2,3,}; }";
229   // FIXME: redundant trailing comma should be removed.
230   Expected = "void f() { std::vector<int> v = {1,2,3,}; }";
231   EXPECT_EQ(Expected, cleanupAroundOffsets({39}, Code));
232 
233   // Still no trailing comma in the original code, but two elements are deleted,
234   // which makes it seems like there was trailing comma.
235   Code = "void f() { std::vector<int> v = {1, 2, 3, , }; }";
236   // FIXME: redundant trailing comma should also be removed.
237   Expected = "void f() { std::vector<int> v = {1, 2, 3,  }; }";
238   EXPECT_EQ(Expected, cleanupAroundOffsets({42, 44}, Code));
239 }
240 
TEST_F(CleanupTest,CtorInitializationBracesInParens)241 TEST_F(CleanupTest, CtorInitializationBracesInParens) {
242   std::string Code = "class A {\nA() : x({1}),, {} };";
243   std::string Expected = "class A {\nA() : x({1}) {} };";
244   EXPECT_EQ(Expected, cleanupAroundOffsets({24, 26}, Code));
245 }
246 
TEST_F(CleanupTest,RedundantCommaNotInAffectedRanges)247 TEST_F(CleanupTest, RedundantCommaNotInAffectedRanges) {
248   std::string Code =
249       "class A {\nA() : x({1}), /* comment */, { int x = 0; } };";
250   std::string Expected =
251       "class A {\nA() : x({1}), /* comment */, { int x = 0; } };";
252   // Set the affected range to be "int x = 0", which does not intercept the
253   // constructor initialization list.
254   std::vector<tooling::Range> Ranges(1, tooling::Range(42, 9));
255   std::string Result = cleanup(Code, Ranges);
256   EXPECT_EQ(Expected, Result);
257 
258   Code = "class A {\nA() : x(1), {} };";
259   Expected = "class A {\nA() : x(1), {} };";
260   // No range. Fixer should do nothing.
261   Ranges.clear();
262   Result = cleanup(Code, Ranges);
263   EXPECT_EQ(Expected, Result);
264 }
265 
TEST_F(CleanupTest,RemoveCommentsAroundDeleteCode)266 TEST_F(CleanupTest, RemoveCommentsAroundDeleteCode) {
267   std::string Code =
268       "class A {\nA() : x({1}), /* comment */, /* comment */ {} };";
269   std::string Expected = "class A {\nA() : x({1}) {} };";
270   EXPECT_EQ(Expected, cleanupAroundOffsets({25, 40}, Code));
271 
272   Code = "class A {\nA() : x({1}), // comment\n {} };";
273   Expected = "class A {\nA() : x({1})\n {} };";
274   EXPECT_EQ(Expected, cleanupAroundOffsets({25}, Code));
275 
276   Code = "class A {\nA() : x({1}), // comment\n , y(1),{} };";
277   Expected = "class A {\nA() : x({1}),  y(1){} };";
278   EXPECT_EQ(Expected, cleanupAroundOffsets({38}, Code));
279 
280   Code = "class A {\nA() : x({1}), \n/* comment */, y(1),{} };";
281   Expected = "class A {\nA() : x({1}), \n y(1){} };";
282   EXPECT_EQ(Expected, cleanupAroundOffsets({40}, Code));
283 
284   Code = "class A {\nA() : , // comment\n y(1),{} };";
285   Expected = "class A {\nA() :  // comment\n y(1){} };";
286   EXPECT_EQ(Expected, cleanupAroundOffsets({17}, Code));
287 
288   Code = "class A {\nA() // comment\n : ,,{} };";
289   Expected = "class A {\nA() // comment\n {} };";
290   EXPECT_EQ(Expected, cleanupAroundOffsets({30}, Code));
291 
292   Code = "class A {\nA() // comment\n : ,,=default; };";
293   Expected = "class A {\nA() // comment\n =default; };";
294   EXPECT_EQ(Expected, cleanupAroundOffsets({30}, Code));
295 }
296 
TEST_F(CleanupTest,CtorInitializerInNamespace)297 TEST_F(CleanupTest, CtorInitializerInNamespace) {
298   std::string Code = "namespace A {\n"
299                      "namespace B {\n" // missing r_brace
300                      "} // namespace A\n\n"
301                      "namespace C {\n"
302                      "class A { A() : x(0),, {} };\n"
303                      "inline namespace E { namespace { } }\n"
304                      "}";
305   std::string Expected = "namespace A {\n"
306                          "\n\n\nnamespace C {\n"
307                          "class A { A() : x(0) {} };\n   \n"
308                          "}";
309   std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
310   std::string Result = cleanup(Code, Ranges);
311   EXPECT_EQ(Expected, Result);
312 }
313 
314 class CleanUpReplacementsTest : public ReplacementTest {
315 protected:
createReplacement(unsigned Offset,unsigned Length,StringRef Text)316   tooling::Replacement createReplacement(unsigned Offset, unsigned Length,
317                                          StringRef Text) {
318     return tooling::Replacement(FileName, Offset, Length, Text);
319   }
320 
createInsertion(StringRef IncludeDirective)321   tooling::Replacement createInsertion(StringRef IncludeDirective) {
322     return createReplacement(UINT_MAX, 0, IncludeDirective);
323   }
324 
createDeletion(StringRef HeaderName)325   tooling::Replacement createDeletion(StringRef HeaderName) {
326     return createReplacement(UINT_MAX, 1, HeaderName);
327   }
328 
apply(StringRef Code,const tooling::Replacements & Replaces)329   inline std::string apply(StringRef Code,
330                            const tooling::Replacements &Replaces) {
331     auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style);
332     EXPECT_TRUE(static_cast<bool>(CleanReplaces))
333         << toString(CleanReplaces.takeError()) << "\n";
334     auto Result = applyAllReplacements(Code, *CleanReplaces);
335     EXPECT_TRUE(static_cast<bool>(Result));
336     return *Result;
337   }
338 
formatAndApply(StringRef Code,const tooling::Replacements & Replaces)339   inline std::string formatAndApply(StringRef Code,
340                                     const tooling::Replacements &Replaces) {
341     auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style);
342     EXPECT_TRUE(static_cast<bool>(CleanReplaces))
343         << toString(CleanReplaces.takeError()) << "\n";
344     auto FormattedReplaces = formatReplacements(Code, *CleanReplaces, Style);
345     EXPECT_TRUE(static_cast<bool>(FormattedReplaces))
346         << toString(FormattedReplaces.takeError()) << "\n";
347     auto Result = applyAllReplacements(Code, *FormattedReplaces);
348     EXPECT_TRUE(static_cast<bool>(Result));
349     return *Result;
350   }
351 
getOffset(StringRef Code,int Line,int Column)352   int getOffset(StringRef Code, int Line, int Column) {
353     RewriterTestContext Context;
354     FileID ID = Context.createInMemoryFile(FileName, Code);
355     auto DecomposedLocation =
356         Context.Sources.getDecomposedLoc(Context.getLocation(ID, Line, Column));
357     return DecomposedLocation.second;
358   }
359 
360   const std::string FileName = "fix.cpp";
361   FormatStyle Style = getLLVMStyle();
362 };
363 
TEST_F(CleanUpReplacementsTest,FixOnlyAffectedCodeAfterReplacements)364 TEST_F(CleanUpReplacementsTest, FixOnlyAffectedCodeAfterReplacements) {
365   std::string Code = "namespace A {\n"
366                      "namespace B {\n"
367                      "  int x;\n"
368                      "} // namespace B\n"
369                      "} // namespace A\n"
370                      "\n"
371                      "namespace C {\n"
372                      "namespace D { int i; }\n"
373                      "inline namespace E { namespace { int y; } }\n"
374                      "int x=     0;"
375                      "}";
376   std::string Expected = "\n\nnamespace C {\n"
377                          "namespace D { int i; }\n\n"
378                          "int x=     0;"
379                          "}";
380   tooling::Replacements Replaces =
381       toReplacements({createReplacement(getOffset(Code, 3, 3), 6, ""),
382                       createReplacement(getOffset(Code, 9, 34), 6, "")});
383 
384   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
385 }
386 
TEST_F(CleanUpReplacementsTest,InsertMultipleIncludesLLVMStyle)387 TEST_F(CleanUpReplacementsTest, InsertMultipleIncludesLLVMStyle) {
388   std::string Code = "#include \"x/fix.h\"\n"
389                      "#include \"a.h\"\n"
390                      "#include \"b.h\"\n"
391                      "#include \"z.h\"\n"
392                      "#include \"clang/Format/Format.h\"\n"
393                      "#include <memory>\n";
394   std::string Expected = "#include \"x/fix.h\"\n"
395                          "#include \"a.h\"\n"
396                          "#include \"b.h\"\n"
397                          "#include \"new/new.h\"\n"
398                          "#include \"z.h\"\n"
399                          "#include \"clang/Format/Format.h\"\n"
400                          "#include <list>\n"
401                          "#include <memory>\n";
402   tooling::Replacements Replaces =
403       toReplacements({createInsertion("#include <list>"),
404                       createInsertion("#include \"new/new.h\"")});
405   EXPECT_EQ(Expected, apply(Code, Replaces));
406 }
407 
TEST_F(CleanUpReplacementsTest,InsertMultipleIncludesGoogleStyle)408 TEST_F(CleanUpReplacementsTest, InsertMultipleIncludesGoogleStyle) {
409   std::string Code = "#include \"x/fix.h\"\n"
410                      "\n"
411                      "#include <vector>\n"
412                      "\n"
413                      "#include \"y/a.h\"\n"
414                      "#include \"z/b.h\"\n";
415   std::string Expected = "#include \"x/fix.h\"\n"
416                          "\n"
417                          "#include <list>\n"
418                          "#include <vector>\n"
419                          "\n"
420                          "#include \"x/x.h\"\n"
421                          "#include \"y/a.h\"\n"
422                          "#include \"z/b.h\"\n";
423   tooling::Replacements Replaces =
424       toReplacements({createInsertion("#include <list>"),
425                       createInsertion("#include \"x/x.h\"")});
426   Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
427   EXPECT_EQ(Expected, apply(Code, Replaces));
428 }
429 
TEST_F(CleanUpReplacementsTest,InsertMultipleNewHeadersAndSortLLVM)430 TEST_F(CleanUpReplacementsTest, InsertMultipleNewHeadersAndSortLLVM) {
431   std::string Code = "\nint x;";
432   std::string Expected = "\n#include \"fix.h\"\n"
433                          "#include \"a.h\"\n"
434                          "#include \"b.h\"\n"
435                          "#include \"c.h\"\n"
436                          "#include <list>\n"
437                          "#include <vector>\n"
438                          "int x;";
439   tooling::Replacements Replaces = toReplacements(
440       {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""),
441        createInsertion("#include \"b.h\""),
442        createInsertion("#include <vector>"), createInsertion("#include <list>"),
443        createInsertion("#include \"fix.h\"")});
444   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
445 }
446 
TEST_F(CleanUpReplacementsTest,InsertMultipleNewHeadersAndSortGoogle)447 TEST_F(CleanUpReplacementsTest, InsertMultipleNewHeadersAndSortGoogle) {
448   std::string Code = "\nint x;";
449   std::string Expected = "\n#include \"fix.h\"\n"
450                          "\n"
451                          "#include <list>\n"
452                          "#include <vector>\n"
453                          "\n"
454                          "#include \"a.h\"\n"
455                          "#include \"b.h\"\n"
456                          "#include \"c.h\"\n"
457                          "int x;";
458   tooling::Replacements Replaces = toReplacements(
459       {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""),
460        createInsertion("#include \"b.h\""),
461        createInsertion("#include <vector>"), createInsertion("#include <list>"),
462        createInsertion("#include \"fix.h\"")});
463   Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
464   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
465 }
466 
TEST_F(CleanUpReplacementsTest,NoNewLineAtTheEndOfCodeMultipleInsertions)467 TEST_F(CleanUpReplacementsTest, NoNewLineAtTheEndOfCodeMultipleInsertions) {
468   std::string Code = "#include <map>";
469   // FIXME: a better behavior is to only append on newline to Code, but this
470   // case should be rare in practice.
471   std::string Expected =
472       "#include <map>\n#include <string>\n\n#include <vector>\n";
473   tooling::Replacements Replaces =
474       toReplacements({createInsertion("#include <string>"),
475                       createInsertion("#include <vector>")});
476   EXPECT_EQ(Expected, apply(Code, Replaces));
477 }
478 
TEST_F(CleanUpReplacementsTest,FormatCorrectLineWhenHeadersAreInserted)479 TEST_F(CleanUpReplacementsTest, FormatCorrectLineWhenHeadersAreInserted) {
480   std::string Code = "\n"
481                      "int x;\n"
482                      "int    a;\n"
483                      "int    a;\n"
484                      "int    a;";
485 
486   std::string Expected = "\n#include \"x.h\"\n"
487                          "#include \"y.h\"\n"
488                          "#include \"clang/x/x.h\"\n"
489                          "#include <list>\n"
490                          "#include <vector>\n"
491                          "int x;\n"
492                          "int    a;\n"
493                          "int b;\n"
494                          "int    a;";
495   tooling::Replacements Replaces = toReplacements(
496       {createReplacement(getOffset(Code, 4, 8), 1, "b"),
497        createInsertion("#include <vector>"), createInsertion("#include <list>"),
498        createInsertion("#include \"clang/x/x.h\""),
499        createInsertion("#include \"y.h\""),
500        createInsertion("#include \"x.h\"")});
501   EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
502 }
503 
TEST_F(CleanUpReplacementsTest,SimpleDeleteIncludes)504 TEST_F(CleanUpReplacementsTest, SimpleDeleteIncludes) {
505   std::string Code = "#include \"abc.h\"\n"
506                      "#include \"xyz.h\" // comment\n"
507                      "#include \"xyz\"\n"
508                      "int x;\n";
509   std::string Expected = "#include \"xyz\"\n"
510                          "int x;\n";
511   tooling::Replacements Replaces =
512       toReplacements({createDeletion("abc.h"), createDeletion("xyz.h")});
513   EXPECT_EQ(Expected, apply(Code, Replaces));
514 }
515 
TEST_F(CleanUpReplacementsTest,InsertionAndDeleteHeader)516 TEST_F(CleanUpReplacementsTest, InsertionAndDeleteHeader) {
517   std::string Code = "#include \"a.h\"\n"
518                      "\n"
519                      "#include <vector>\n";
520   std::string Expected = "#include \"a.h\"\n"
521                          "\n"
522                          "#include <map>\n";
523   tooling::Replacements Replaces = toReplacements(
524       {createDeletion("<vector>"), createInsertion("#include <map>")});
525   EXPECT_EQ(Expected, apply(Code, Replaces));
526 }
527 
528 } // end namespace
529 } // end namespace format
530 } // end namespace clang
531