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