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