1 //===---- IncludeInserterTest.cpp - clang-tidy ----------------------------===//
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-tidy/utils/IncludeInserter.h"
10 #include "clang/Lex/Preprocessor.h"
11 #include "clang/Frontend/CompilerInstance.h"
12 #include "ClangTidyTest.h"
13 #include "gtest/gtest.h"
14 
15 // FIXME: Canonicalize paths correctly on windows.
16 // Currently, adding virtual files will canonicalize the paths before
17 // storing the virtual entries.
18 // When resolving virtual entries in the FileManager, the paths (for
19 // example coming from a #include directive) are not canonicalized
20 // to native paths; thus, the virtual file is not found.
21 // This needs to be fixed in the FileManager before we can make
22 // clang-tidy tests work.
23 #if !defined(_WIN32)
24 
25 namespace clang {
26 namespace tidy {
27 namespace {
28 
29 class IncludeInserterCheckBase : public ClangTidyCheck {
30 public:
IncludeInserterCheckBase(StringRef CheckName,ClangTidyContext * Context,utils::IncludeSorter::IncludeStyle Style=utils::IncludeSorter::IS_Google)31   IncludeInserterCheckBase(StringRef CheckName, ClangTidyContext *Context,
32                            utils::IncludeSorter::IncludeStyle Style =
33                                utils::IncludeSorter::IS_Google)
34       : ClangTidyCheck(CheckName, Context), Inserter(Style) {}
35 
registerPPCallbacks(const SourceManager & SM,Preprocessor * PP,Preprocessor * ModuleExpanderPP)36   void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
37                            Preprocessor *ModuleExpanderPP) override {
38     Inserter.registerPreprocessor(PP);
39   }
40 
registerMatchers(ast_matchers::MatchFinder * Finder)41   void registerMatchers(ast_matchers::MatchFinder *Finder) override {
42     Finder->addMatcher(ast_matchers::declStmt().bind("stmt"), this);
43   }
44 
check(const ast_matchers::MatchFinder::MatchResult & Result)45   void check(const ast_matchers::MatchFinder::MatchResult &Result) override {
46     auto Diag = diag(Result.Nodes.getNodeAs<DeclStmt>("stmt")->getBeginLoc(),
47                      "foo, bar");
48     for (StringRef Header : headersToInclude()) {
49       Diag << Inserter.createMainFileIncludeInsertion(Header);
50     }
51   }
52 
53   virtual std::vector<StringRef> headersToInclude() const = 0;
54 
55   utils::IncludeInserter Inserter;
56 };
57 
58 class NonSystemHeaderInserterCheck : public IncludeInserterCheckBase {
59 public:
NonSystemHeaderInserterCheck(StringRef CheckName,ClangTidyContext * Context)60   NonSystemHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
61       : IncludeInserterCheckBase(CheckName, Context) {}
62 
headersToInclude() const63   std::vector<StringRef> headersToInclude() const override {
64     return {"path/to/header.h"};
65   }
66 };
67 
68 class EarlyInAlphabetHeaderInserterCheck : public IncludeInserterCheckBase {
69 public:
EarlyInAlphabetHeaderInserterCheck(StringRef CheckName,ClangTidyContext * Context)70   EarlyInAlphabetHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
71       : IncludeInserterCheckBase(CheckName, Context) {}
72 
headersToInclude() const73   std::vector<StringRef> headersToInclude() const override {
74     return {"a/header.h"};
75   }
76 };
77 
78 class MultipleHeaderInserterCheck : public IncludeInserterCheckBase {
79 public:
MultipleHeaderInserterCheck(StringRef CheckName,ClangTidyContext * Context)80   MultipleHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
81       : IncludeInserterCheckBase(CheckName, Context) {}
82 
headersToInclude() const83   std::vector<StringRef> headersToInclude() const override {
84     return {"path/to/header.h", "path/to/header2.h", "path/to/header.h"};
85   }
86 };
87 
88 class CSystemIncludeInserterCheck : public IncludeInserterCheckBase {
89 public:
CSystemIncludeInserterCheck(StringRef CheckName,ClangTidyContext * Context)90   CSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
91       : IncludeInserterCheckBase(CheckName, Context) {}
92 
headersToInclude() const93   std::vector<StringRef> headersToInclude() const override {
94     return {"<stdlib.h>"};
95   }
96 };
97 
98 class CXXSystemIncludeInserterCheck : public IncludeInserterCheckBase {
99 public:
CXXSystemIncludeInserterCheck(StringRef CheckName,ClangTidyContext * Context)100   CXXSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
101       : IncludeInserterCheckBase(CheckName, Context) {}
102 
headersToInclude() const103   std::vector<StringRef> headersToInclude() const override { return {"<set>"}; }
104 };
105 
106 class InvalidIncludeInserterCheck : public IncludeInserterCheckBase {
107 public:
InvalidIncludeInserterCheck(StringRef CheckName,ClangTidyContext * Context)108   InvalidIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
109       : IncludeInserterCheckBase(CheckName, Context) {}
110 
headersToInclude() const111   std::vector<StringRef> headersToInclude() const override {
112     return {"a.h", "<stdlib.h", "cstdlib>", "b.h", "<c.h>", "<d>"};
113   }
114 };
115 
116 class ObjCEarlyInAlphabetHeaderInserterCheck : public IncludeInserterCheckBase {
117 public:
ObjCEarlyInAlphabetHeaderInserterCheck(StringRef CheckName,ClangTidyContext * Context)118   ObjCEarlyInAlphabetHeaderInserterCheck(StringRef CheckName,
119                                          ClangTidyContext *Context)
120       : IncludeInserterCheckBase(CheckName, Context,
121                                  utils::IncludeSorter::IS_Google_ObjC) {}
122 
headersToInclude() const123   std::vector<StringRef> headersToInclude() const override {
124     return {"a/header.h"};
125   }
126 };
127 
128 class ObjCCategoryHeaderInserterCheck : public IncludeInserterCheckBase {
129 public:
ObjCCategoryHeaderInserterCheck(StringRef CheckName,ClangTidyContext * Context)130   ObjCCategoryHeaderInserterCheck(StringRef CheckName,
131                                   ClangTidyContext *Context)
132       : IncludeInserterCheckBase(CheckName, Context,
133                                  utils::IncludeSorter::IS_Google_ObjC) {}
134 
headersToInclude() const135   std::vector<StringRef> headersToInclude() const override {
136     return {"top_level_test_header+foo.h"};
137   }
138 };
139 
140 class ObjCGeneratedHeaderInserterCheck : public IncludeInserterCheckBase {
141 public:
ObjCGeneratedHeaderInserterCheck(StringRef CheckName,ClangTidyContext * Context)142   ObjCGeneratedHeaderInserterCheck(StringRef CheckName,
143                                    ClangTidyContext *Context)
144       : IncludeInserterCheckBase(CheckName, Context,
145                                  utils::IncludeSorter::IS_Google_ObjC) {}
146 
headersToInclude() const147   std::vector<StringRef> headersToInclude() const override {
148     return {"clang_tidy/tests/generated_file.proto.h"};
149   }
150 };
151 
152 template <typename Check>
runCheckOnCode(StringRef Code,StringRef Filename)153 std::string runCheckOnCode(StringRef Code, StringRef Filename) {
154   std::vector<ClangTidyError> Errors;
155   return test::runCheckOnCode<Check>(Code, &Errors, Filename, None,
156                                      ClangTidyOptions(),
157                                      {// Main file include
158                                       {"clang_tidy/tests/"
159                                        "insert_includes_test_header.h",
160                                        "\n"},
161                                       // Top-level main file include +
162                                       // category.
163                                       {"top_level_test_header.h", "\n"},
164                                       {"top_level_test_header+foo.h", "\n"},
165                                       // ObjC category.
166                                       {"clang_tidy/tests/"
167                                        "insert_includes_test_header+foo.h",
168                                        "\n"},
169                                       // Non system headers
170                                       {"a/header.h", "\n"},
171                                       {"path/to/a/header.h", "\n"},
172                                       {"path/to/z/header.h", "\n"},
173                                       {"path/to/header.h", "\n"},
174                                       {"path/to/header2.h", "\n"},
175                                       // Generated headers
176                                       {"clang_tidy/tests/"
177                                        "generated_file.proto.h",
178                                        "\n"},
179                                       // Fake system headers.
180                                       {"stdlib.h", "\n"},
181                                       {"unistd.h", "\n"},
182                                       {"list", "\n"},
183                                       {"map", "\n"},
184                                       {"set", "\n"},
185                                       {"vector", "\n"}});
186 }
187 
TEST(IncludeInserterTest,InsertAfterLastNonSystemInclude)188 TEST(IncludeInserterTest, InsertAfterLastNonSystemInclude) {
189   const char *PreCode = R"(
190 #include "clang_tidy/tests/insert_includes_test_header.h"
191 
192 #include <list>
193 #include <map>
194 
195 #include "path/to/a/header.h"
196 
197 void foo() {
198   int a = 0;
199 })";
200   const char *PostCode = R"(
201 #include "clang_tidy/tests/insert_includes_test_header.h"
202 
203 #include <list>
204 #include <map>
205 
206 #include "path/to/a/header.h"
207 #include "path/to/header.h"
208 
209 void foo() {
210   int a = 0;
211 })";
212 
213   EXPECT_EQ(PostCode,
214             runCheckOnCode<NonSystemHeaderInserterCheck>(
215                 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc"));
216 }
217 
TEST(IncludeInserterTest,InsertMultipleIncludesAndDeduplicate)218 TEST(IncludeInserterTest, InsertMultipleIncludesAndDeduplicate) {
219   const char *PreCode = R"(
220 #include "clang_tidy/tests/insert_includes_test_header.h"
221 
222 #include <list>
223 #include <map>
224 
225 #include "path/to/a/header.h"
226 
227 void foo() {
228   int a = 0;
229 })";
230   const char *PostCode = R"(
231 #include "clang_tidy/tests/insert_includes_test_header.h"
232 
233 #include <list>
234 #include <map>
235 
236 #include "path/to/a/header.h"
237 #include "path/to/header.h"
238 #include "path/to/header2.h"
239 
240 void foo() {
241   int a = 0;
242 })";
243 
244   EXPECT_EQ(PostCode,
245             runCheckOnCode<MultipleHeaderInserterCheck>(
246                 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc"));
247 }
248 
TEST(IncludeInserterTest,InsertBeforeFirstNonSystemInclude)249 TEST(IncludeInserterTest, InsertBeforeFirstNonSystemInclude) {
250   const char *PreCode = R"(
251 #include "clang_tidy/tests/insert_includes_test_header.h"
252 
253 #include <list>
254 #include <map>
255 
256 #include "path/to/z/header.h"
257 
258 void foo() {
259   int a = 0;
260 })";
261   const char *PostCode = R"(
262 #include "clang_tidy/tests/insert_includes_test_header.h"
263 
264 #include <list>
265 #include <map>
266 
267 #include "path/to/header.h"
268 #include "path/to/z/header.h"
269 
270 void foo() {
271   int a = 0;
272 })";
273 
274   EXPECT_EQ(PostCode,
275             runCheckOnCode<NonSystemHeaderInserterCheck>(
276                 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc"));
277 }
278 
TEST(IncludeInserterTest,InsertBetweenNonSystemIncludes)279 TEST(IncludeInserterTest, InsertBetweenNonSystemIncludes) {
280   const char *PreCode = R"(
281 #include "clang_tidy/tests/insert_includes_test_header.h"
282 
283 #include <list>
284 #include <map>
285 
286 #include "path/to/a/header.h"
287 #include "path/to/z/header.h"
288 
289 void foo() {
290   int a = 0;
291 })";
292   const char *PostCode = R"(
293 #include "clang_tidy/tests/insert_includes_test_header.h"
294 
295 #include <list>
296 #include <map>
297 
298 #include "path/to/a/header.h"
299 #include "path/to/header.h"
300 #include "path/to/z/header.h"
301 
302 void foo() {
303   int a = 0;
304 })";
305 
306   EXPECT_EQ(PostCode,
307             runCheckOnCode<NonSystemHeaderInserterCheck>(
308                 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc"));
309 }
310 
TEST(IncludeInserterTest,NonSystemIncludeAlreadyIncluded)311 TEST(IncludeInserterTest, NonSystemIncludeAlreadyIncluded) {
312   const char *PreCode = R"(
313 #include "clang_tidy/tests/insert_includes_test_header.h"
314 
315 #include <list>
316 #include <map>
317 
318 #include "path/to/a/header.h"
319 #include "path/to/header.h"
320 #include "path/to/z/header.h"
321 
322 void foo() {
323   int a = 0;
324 })";
325   EXPECT_EQ(PreCode,
326             runCheckOnCode<NonSystemHeaderInserterCheck>(
327                 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc"));
328 }
329 
TEST(IncludeInserterTest,InsertNonSystemIncludeAfterLastCXXSystemInclude)330 TEST(IncludeInserterTest, InsertNonSystemIncludeAfterLastCXXSystemInclude) {
331   const char *PreCode = R"(
332 #include "clang_tidy/tests/insert_includes_test_header.h"
333 
334 #include <list>
335 #include <map>
336 
337 void foo() {
338   int a = 0;
339 })";
340   const char *PostCode = R"(
341 #include "clang_tidy/tests/insert_includes_test_header.h"
342 
343 #include <list>
344 #include <map>
345 
346 #include "path/to/header.h"
347 
348 void foo() {
349   int a = 0;
350 })";
351 
352   EXPECT_EQ(PostCode,
353             runCheckOnCode<NonSystemHeaderInserterCheck>(
354                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
355 }
356 
TEST(IncludeInserterTest,InsertNonSystemIncludeAfterMainFileInclude)357 TEST(IncludeInserterTest, InsertNonSystemIncludeAfterMainFileInclude) {
358   const char *PreCode = R"(
359 #include "clang_tidy/tests/insert_includes_test_header.h"
360 
361 void foo() {
362   int a = 0;
363 })";
364   const char *PostCode = R"(
365 #include "clang_tidy/tests/insert_includes_test_header.h"
366 
367 #include "path/to/header.h"
368 
369 void foo() {
370   int a = 0;
371 })";
372 
373   EXPECT_EQ(PostCode,
374             runCheckOnCode<NonSystemHeaderInserterCheck>(
375                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
376 }
377 
TEST(IncludeInserterTest,InsertCXXSystemIncludeAfterLastCXXSystemInclude)378 TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterLastCXXSystemInclude) {
379   const char *PreCode = R"(
380 #include "clang_tidy/tests/insert_includes_test_header.h"
381 
382 #include <list>
383 #include <map>
384 
385 #include "path/to/a/header.h"
386 
387 void foo() {
388   int a = 0;
389 })";
390   const char *PostCode = R"(
391 #include "clang_tidy/tests/insert_includes_test_header.h"
392 
393 #include <list>
394 #include <map>
395 #include <set>
396 
397 #include "path/to/a/header.h"
398 
399 void foo() {
400   int a = 0;
401 })";
402 
403   EXPECT_EQ(PostCode,
404             runCheckOnCode<CXXSystemIncludeInserterCheck>(
405                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
406 }
407 
TEST(IncludeInserterTest,InsertCXXSystemIncludeBeforeFirstCXXSystemInclude)408 TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeFirstCXXSystemInclude) {
409   const char *PreCode = R"(
410 #include "clang_tidy/tests/insert_includes_test_header.h"
411 
412 #include <vector>
413 
414 #include "path/to/a/header.h"
415 
416 void foo() {
417   int a = 0;
418 })";
419   const char *PostCode = R"(
420 #include "clang_tidy/tests/insert_includes_test_header.h"
421 
422 #include <set>
423 #include <vector>
424 
425 #include "path/to/a/header.h"
426 
427 void foo() {
428   int a = 0;
429 })";
430 
431   EXPECT_EQ(PostCode,
432             runCheckOnCode<CXXSystemIncludeInserterCheck>(
433                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
434 }
435 
TEST(IncludeInserterTest,InsertCXXSystemIncludeBetweenCXXSystemIncludes)436 TEST(IncludeInserterTest, InsertCXXSystemIncludeBetweenCXXSystemIncludes) {
437   const char *PreCode = R"(
438 #include "clang_tidy/tests/insert_includes_test_header.h"
439 
440 #include <map>
441 #include <vector>
442 
443 #include "path/to/a/header.h"
444 
445 void foo() {
446   int a = 0;
447 })";
448   const char *PostCode = R"(
449 #include "clang_tidy/tests/insert_includes_test_header.h"
450 
451 #include <map>
452 #include <set>
453 #include <vector>
454 
455 #include "path/to/a/header.h"
456 
457 void foo() {
458   int a = 0;
459 })";
460 
461   EXPECT_EQ(PostCode,
462             runCheckOnCode<CXXSystemIncludeInserterCheck>(
463                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
464 }
465 
TEST(IncludeInserterTest,InsertCXXSystemIncludeAfterMainFileInclude)466 TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterMainFileInclude) {
467   const char *PreCode = R"(
468 #include "clang_tidy/tests/insert_includes_test_header.h"
469 
470 #include "path/to/a/header.h"
471 
472 void foo() {
473   int a = 0;
474 })";
475   const char *PostCode = R"(
476 #include "clang_tidy/tests/insert_includes_test_header.h"
477 
478 #include <set>
479 
480 #include "path/to/a/header.h"
481 
482 void foo() {
483   int a = 0;
484 })";
485 
486   EXPECT_EQ(PostCode,
487             runCheckOnCode<CXXSystemIncludeInserterCheck>(
488                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
489 }
490 
TEST(IncludeInserterTest,InsertCXXSystemIncludeAfterCSystemInclude)491 TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterCSystemInclude) {
492   const char *PreCode = R"(
493 #include "clang_tidy/tests/insert_includes_test_header.h"
494 
495 #include <stdlib.h>
496 
497 #include "path/to/a/header.h"
498 
499 void foo() {
500   int a = 0;
501 })";
502   const char *PostCode = R"(
503 #include "clang_tidy/tests/insert_includes_test_header.h"
504 
505 #include <stdlib.h>
506 
507 #include <set>
508 
509 #include "path/to/a/header.h"
510 
511 void foo() {
512   int a = 0;
513 })";
514 
515   EXPECT_EQ(PostCode,
516             runCheckOnCode<CXXSystemIncludeInserterCheck>(
517                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
518 }
519 
TEST(IncludeInserterTest,InsertCXXSystemIncludeBeforeNonSystemInclude)520 TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeNonSystemInclude) {
521   const char *PreCode = R"(
522 #include "path/to/a/header.h"
523 
524 void foo() {
525   int a = 0;
526 })";
527   const char *PostCode = R"(
528 #include <set>
529 
530 #include "path/to/a/header.h"
531 
532 void foo() {
533   int a = 0;
534 })";
535 
536   EXPECT_EQ(
537       PostCode,
538       runCheckOnCode<CXXSystemIncludeInserterCheck>(
539           PreCode, "repo/clang_tidy/tests/insert_includes_test_header.cc"));
540 }
541 
TEST(IncludeInserterTest,InsertCSystemIncludeBeforeCXXSystemInclude)542 TEST(IncludeInserterTest, InsertCSystemIncludeBeforeCXXSystemInclude) {
543   const char *PreCode = R"(
544 #include <set>
545 
546 #include "path/to/a/header.h"
547 
548 void foo() {
549   int a = 0;
550 })";
551   const char *PostCode = R"(
552 #include <stdlib.h>
553 
554 #include <set>
555 
556 #include "path/to/a/header.h"
557 
558 void foo() {
559   int a = 0;
560 })";
561 
562   EXPECT_EQ(
563       PostCode,
564       runCheckOnCode<CSystemIncludeInserterCheck>(
565           PreCode, "repo/clang_tidy/tests/insert_includes_test_header.cc"));
566 }
567 
TEST(IncludeInserterTest,InsertIncludeIfThereWasNoneBefore)568 TEST(IncludeInserterTest, InsertIncludeIfThereWasNoneBefore) {
569   const char *PreCode = R"(
570 void foo() {
571   int a = 0;
572 })";
573   const char *PostCode = R"(#include <set>
574 
575 
576 void foo() {
577   int a = 0;
578 })";
579 
580   EXPECT_EQ(
581       PostCode,
582       runCheckOnCode<CXXSystemIncludeInserterCheck>(
583           PreCode, "repo/clang_tidy/tests/insert_includes_test_header.cc"));
584 }
585 
TEST(IncludeInserterTest,DontInsertDuplicateIncludeEvenIfMiscategorized)586 TEST(IncludeInserterTest, DontInsertDuplicateIncludeEvenIfMiscategorized) {
587   const char *PreCode = R"(
588 #include "clang_tidy/tests/insert_includes_test_header.h"
589 
590 #include <map>
591 #include <set>
592 #include <vector>
593 
594 #include "a/header.h"
595 #include "path/to/a/header.h"
596 #include "path/to/header.h"
597 
598 void foo() {
599   int a = 0;
600 })";
601 
602   const char *PostCode = R"(
603 #include "clang_tidy/tests/insert_includes_test_header.h"
604 
605 #include <map>
606 #include <set>
607 #include <vector>
608 
609 #include "a/header.h"
610 #include "path/to/a/header.h"
611 #include "path/to/header.h"
612 
613 void foo() {
614   int a = 0;
615 })";
616 
617   EXPECT_EQ(PostCode, runCheckOnCode<EarlyInAlphabetHeaderInserterCheck>(
618                           PreCode, "workspace_folder/clang_tidy/tests/"
619                                    "insert_includes_test_header.cc"));
620 }
621 
TEST(IncludeInserterTest,HandleOrderInSubdirectory)622 TEST(IncludeInserterTest, HandleOrderInSubdirectory) {
623   const char *PreCode = R"(
624 #include "clang_tidy/tests/insert_includes_test_header.h"
625 
626 #include <map>
627 #include <set>
628 #include <vector>
629 
630 #include "path/to/a/header.h"
631 #include "path/to/header.h"
632 
633 void foo() {
634   int a = 0;
635 })";
636 
637   const char *PostCode = R"(
638 #include "clang_tidy/tests/insert_includes_test_header.h"
639 
640 #include <map>
641 #include <set>
642 #include <vector>
643 
644 #include "a/header.h"
645 #include "path/to/a/header.h"
646 #include "path/to/header.h"
647 
648 void foo() {
649   int a = 0;
650 })";
651 
652   EXPECT_EQ(PostCode, runCheckOnCode<EarlyInAlphabetHeaderInserterCheck>(
653                           PreCode, "workspace_folder/clang_tidy/tests/"
654                                    "insert_includes_test_header.cc"));
655 }
656 
TEST(IncludeInserterTest,InvalidHeaderName)657 TEST(IncludeInserterTest, InvalidHeaderName) {
658   const char *PreCode = R"(
659 #include "clang_tidy/tests/insert_includes_test_header.h"
660 
661 #include <list>
662 #include <map>
663 
664 #include "path/to/a/header.h"
665 
666 void foo() {
667   int a = 0;
668 })";
669   const char *PostCode = R"(
670 #include "clang_tidy/tests/insert_includes_test_header.h"
671 
672 #include <c.h>
673 
674 #include <d>
675 #include <list>
676 #include <map>
677 
678 #include "a.h"
679 #include "b.h"
680 #include "path/to/a/header.h"
681 
682 void foo() {
683   int a = 0;
684 })";
685 
686   EXPECT_EQ(PostCode,
687             runCheckOnCode<InvalidIncludeInserterCheck>(
688                 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
689 }
690 
TEST(IncludeInserterTest,InsertHeaderObjectiveC)691 TEST(IncludeInserterTest, InsertHeaderObjectiveC) {
692   const char *PreCode = R"(
693 #import "clang_tidy/tests/insert_includes_test_header.h"
694 
695 void foo() {
696   int a = 0;
697 })";
698   const char *PostCode = R"(
699 #import "clang_tidy/tests/insert_includes_test_header.h"
700 
701 #import "a/header.h"
702 
703 void foo() {
704   int a = 0;
705 })";
706 
707   EXPECT_EQ(
708       PostCode,
709       runCheckOnCode<ObjCEarlyInAlphabetHeaderInserterCheck>(
710           PreCode, "repo/clang_tidy/tests/insert_includes_test_header.mm"));
711 }
712 
TEST(IncludeInserterTest,InsertCategoryHeaderObjectiveC)713 TEST(IncludeInserterTest, InsertCategoryHeaderObjectiveC) {
714   const char *PreCode = R"(
715 #import "top_level_test_header.h"
716 
717 void foo() {
718   int a = 0;
719 })";
720   const char *PostCode = R"(
721 #import "top_level_test_header.h"
722 #import "top_level_test_header+foo.h"
723 
724 void foo() {
725   int a = 0;
726 })";
727 
728   EXPECT_EQ(PostCode, runCheckOnCode<ObjCCategoryHeaderInserterCheck>(
729                           PreCode, "top_level_test_header.mm"));
730 }
731 
TEST(IncludeInserterTest,InsertGeneratedHeaderObjectiveC)732 TEST(IncludeInserterTest, InsertGeneratedHeaderObjectiveC) {
733   const char *PreCode = R"(
734 #import "clang_tidy/tests/insert_includes_test_header.h"
735 
736 #include <list>
737 #include <map>
738 
739 #include "path/to/a/header.h"
740 
741 void foo() {
742   int a = 0;
743 })";
744   const char *PostCode = R"(
745 #import "clang_tidy/tests/insert_includes_test_header.h"
746 
747 #include <list>
748 #include <map>
749 
750 #include "path/to/a/header.h"
751 
752 #import "clang_tidy/tests/generated_file.proto.h"
753 
754 void foo() {
755   int a = 0;
756 })";
757 
758   EXPECT_EQ(
759       PostCode,
760       runCheckOnCode<ObjCGeneratedHeaderInserterCheck>(
761           PreCode, "repo/clang_tidy/tests/insert_includes_test_header.mm"));
762 }
763 
764 } // anonymous namespace
765 } // namespace tidy
766 } // namespace clang
767 
768 #endif
769