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