Bump version to 19.1.0git
[llvm-project.git] / clang-tools-extra / unittests / clang-tidy / IncludeInserterTest.cpp
blob71496dd03f9bd8e5871e4c9e7f690304471a392d
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 //===----------------------------------------------------------------------===//
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"
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)
25 namespace clang {
26 namespace tidy {
27 namespace {
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) {}
38 void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
39 Preprocessor *ModuleExpanderPP) override {
40 Inserter.registerPreprocessor(PP);
43 void registerMatchers(ast_matchers::MatchFinder *Finder) override {
44 Finder->addMatcher(ast_matchers::declStmt().bind("stmt"), this);
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);
55 virtual std::vector<StringRef> headersToInclude() const = 0;
57 utils::IncludeInserter Inserter;
60 class NonSystemHeaderInserterCheck : public IncludeInserterCheckBase {
61 public:
62 NonSystemHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
63 : IncludeInserterCheckBase(CheckName, Context) {}
65 std::vector<StringRef> headersToInclude() const override {
66 return {"path/to/header.h"};
70 class EarlyInAlphabetHeaderInserterCheck : public IncludeInserterCheckBase {
71 public:
72 EarlyInAlphabetHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
73 : IncludeInserterCheckBase(CheckName, Context) {}
75 std::vector<StringRef> headersToInclude() const override {
76 return {"a/header.h"};
80 class MultipleHeaderInserterCheck : public IncludeInserterCheckBase {
81 public:
82 MultipleHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
83 : IncludeInserterCheckBase(CheckName, Context) {}
85 std::vector<StringRef> headersToInclude() const override {
86 return {"path/to/header.h", "path/to/header2.h", "path/to/header.h"};
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) {}
98 std::vector<StringRef> headersToInclude() const override {
99 return {"path/to/header.h", "path/to/header2.h", "path/to/header.h"};
103 class CSystemIncludeInserterCheck : public IncludeInserterCheckBase {
104 public:
105 CSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
106 : IncludeInserterCheckBase(CheckName, Context) {}
108 std::vector<StringRef> headersToInclude() const override {
109 return {"<stdlib.h>"};
113 class CXXSystemIncludeInserterCheck : public IncludeInserterCheckBase {
114 public:
115 CXXSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
116 : IncludeInserterCheckBase(CheckName, Context) {}
118 std::vector<StringRef> headersToInclude() const override { return {"<set>"}; }
121 class InvalidIncludeInserterCheck : public IncludeInserterCheckBase {
122 public:
123 InvalidIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
124 : IncludeInserterCheckBase(CheckName, Context) {}
126 std::vector<StringRef> headersToInclude() const override {
127 return {"a.h", "<stdlib.h", "cstdlib>", "b.h", "<c.h>", "<d>"};
131 class ObjCEarlyInAlphabetHeaderInserterCheck : public IncludeInserterCheckBase {
132 public:
133 ObjCEarlyInAlphabetHeaderInserterCheck(StringRef CheckName,
134 ClangTidyContext *Context)
135 : IncludeInserterCheckBase(CheckName, Context,
136 utils::IncludeSorter::IS_Google_ObjC) {}
138 std::vector<StringRef> headersToInclude() const override {
139 return {"a/header.h"};
143 class ObjCCategoryHeaderInserterCheck : public IncludeInserterCheckBase {
144 public:
145 ObjCCategoryHeaderInserterCheck(StringRef CheckName,
146 ClangTidyContext *Context)
147 : IncludeInserterCheckBase(CheckName, Context,
148 utils::IncludeSorter::IS_Google_ObjC) {}
150 std::vector<StringRef> headersToInclude() const override {
151 return {"top_level_test_header+foo.h"};
155 class ObjCGeneratedHeaderInserterCheck : public IncludeInserterCheckBase {
156 public:
157 ObjCGeneratedHeaderInserterCheck(StringRef CheckName,
158 ClangTidyContext *Context)
159 : IncludeInserterCheckBase(CheckName, Context,
160 utils::IncludeSorter::IS_Google_ObjC) {}
162 std::vector<StringRef> headersToInclude() const override {
163 return {"clang_tidy/tests/generated_file.proto.h"};
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, std::nullopt,
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"}});
203 TEST(IncludeInserterTest, InsertAfterLastNonSystemInclude) {
204 const char *PreCode = R"(
205 #include "clang_tidy/tests/insert_includes_test_header.h"
207 #include <list>
208 #include <map>
210 #include "path/to/a/header.h"
212 void foo() {
213 int a = 0;
214 })";
215 const char *PostCode = R"(
216 #include "clang_tidy/tests/insert_includes_test_header.h"
218 #include <list>
219 #include <map>
221 #include "path/to/a/header.h"
222 #include "path/to/header.h"
224 void foo() {
225 int a = 0;
226 })";
228 EXPECT_EQ(PostCode,
229 runCheckOnCode<NonSystemHeaderInserterCheck>(
230 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc"));
233 TEST(IncludeInserterTest, InsertMultipleIncludesAndDeduplicate) {
234 const char *PreCode = R"(
235 #include "clang_tidy/tests/insert_includes_test_header.h"
237 #include <list>
238 #include <map>
240 #include "path/to/a/header.h"
242 void foo() {
243 int a = 0;
244 })";
245 const char *PostCode = R"(
246 #include "clang_tidy/tests/insert_includes_test_header.h"
248 #include <list>
249 #include <map>
251 #include "path/to/a/header.h"
252 #include "path/to/header.h"
253 #include "path/to/header2.h"
255 void foo() {
256 int a = 0;
257 })";
259 EXPECT_EQ(PostCode,
260 runCheckOnCode<MultipleHeaderInserterCheck>(
261 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc"));
264 TEST(IncludeInserterTest, InsertMultipleIncludesNoDeduplicate) {
265 const char *PreCode = R"(
266 #include "clang_tidy/tests/insert_includes_test_header.h"
268 #include <list>
269 #include <map>
271 #include "path/to/a/header.h"
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"
281 #include <list>
282 #include <map>
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"
289 void foo() {
290 int a = 0;
291 })";
292 // clang-format on
294 EXPECT_EQ(PostCode,
295 runCheckOnCode<MultipleHeaderSingleInserterCheck>(
296 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc"));
299 TEST(IncludeInserterTest, InsertBeforeFirstNonSystemInclude) {
300 const char *PreCode = R"(
301 #include "clang_tidy/tests/insert_includes_test_header.h"
303 #include <list>
304 #include <map>
306 #include "path/to/z/header.h"
308 void foo() {
309 int a = 0;
310 })";
311 const char *PostCode = R"(
312 #include "clang_tidy/tests/insert_includes_test_header.h"
314 #include <list>
315 #include <map>
317 #include "path/to/header.h"
318 #include "path/to/z/header.h"
320 void foo() {
321 int a = 0;
322 })";
324 EXPECT_EQ(PostCode,
325 runCheckOnCode<NonSystemHeaderInserterCheck>(
326 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc"));
329 TEST(IncludeInserterTest, InsertBetweenNonSystemIncludes) {
330 const char *PreCode = R"(
331 #include "clang_tidy/tests/insert_includes_test_header.h"
333 #include <list>
334 #include <map>
336 #include "path/to/a/header.h"
337 #include "path/to/z/header.h"
339 void foo() {
340 int a = 0;
341 })";
342 const char *PostCode = R"(
343 #include "clang_tidy/tests/insert_includes_test_header.h"
345 #include <list>
346 #include <map>
348 #include "path/to/a/header.h"
349 #include "path/to/header.h"
350 #include "path/to/z/header.h"
352 void foo() {
353 int a = 0;
354 })";
356 EXPECT_EQ(PostCode,
357 runCheckOnCode<NonSystemHeaderInserterCheck>(
358 PreCode, "clang_tidy/tests/insert_includes_test_input2.cc"));
361 TEST(IncludeInserterTest, NonSystemIncludeAlreadyIncluded) {
362 const char *PreCode = R"(
363 #include "clang_tidy/tests/insert_includes_test_header.h"
365 #include <list>
366 #include <map>
368 #include "path/to/a/header.h"
369 #include "path/to/header.h"
370 #include "path/to/z/header.h"
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"));
380 TEST(IncludeInserterTest, InsertNonSystemIncludeAfterLastCXXSystemInclude) {
381 const char *PreCode = R"(
382 #include "clang_tidy/tests/insert_includes_test_header.h"
384 #include <list>
385 #include <map>
387 void foo() {
388 int a = 0;
389 })";
390 const char *PostCode = R"(
391 #include "clang_tidy/tests/insert_includes_test_header.h"
393 #include <list>
394 #include <map>
396 #include "path/to/header.h"
398 void foo() {
399 int a = 0;
400 })";
402 EXPECT_EQ(PostCode,
403 runCheckOnCode<NonSystemHeaderInserterCheck>(
404 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
407 TEST(IncludeInserterTest, InsertNonSystemIncludeAfterMainFileInclude) {
408 const char *PreCode = R"(
409 #include "clang_tidy/tests/insert_includes_test_header.h"
411 void foo() {
412 int a = 0;
413 })";
414 const char *PostCode = R"(
415 #include "clang_tidy/tests/insert_includes_test_header.h"
417 #include "path/to/header.h"
419 void foo() {
420 int a = 0;
421 })";
423 EXPECT_EQ(PostCode,
424 runCheckOnCode<NonSystemHeaderInserterCheck>(
425 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
428 TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterLastCXXSystemInclude) {
429 const char *PreCode = R"(
430 #include "clang_tidy/tests/insert_includes_test_header.h"
432 #include <list>
433 #include <map>
435 #include "path/to/a/header.h"
437 void foo() {
438 int a = 0;
439 })";
440 const char *PostCode = R"(
441 #include "clang_tidy/tests/insert_includes_test_header.h"
443 #include <list>
444 #include <map>
445 #include <set>
447 #include "path/to/a/header.h"
449 void foo() {
450 int a = 0;
451 })";
453 EXPECT_EQ(PostCode,
454 runCheckOnCode<CXXSystemIncludeInserterCheck>(
455 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
458 TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeFirstCXXSystemInclude) {
459 const char *PreCode = R"(
460 #include "clang_tidy/tests/insert_includes_test_header.h"
462 #include <vector>
464 #include "path/to/a/header.h"
466 void foo() {
467 int a = 0;
468 })";
469 const char *PostCode = R"(
470 #include "clang_tidy/tests/insert_includes_test_header.h"
472 #include <set>
473 #include <vector>
475 #include "path/to/a/header.h"
477 void foo() {
478 int a = 0;
479 })";
481 EXPECT_EQ(PostCode,
482 runCheckOnCode<CXXSystemIncludeInserterCheck>(
483 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
486 TEST(IncludeInserterTest, InsertCXXSystemIncludeBetweenCXXSystemIncludes) {
487 const char *PreCode = R"(
488 #include "clang_tidy/tests/insert_includes_test_header.h"
490 #include <map>
491 #include <vector>
493 #include "path/to/a/header.h"
495 void foo() {
496 int a = 0;
497 })";
498 const char *PostCode = R"(
499 #include "clang_tidy/tests/insert_includes_test_header.h"
501 #include <map>
502 #include <set>
503 #include <vector>
505 #include "path/to/a/header.h"
507 void foo() {
508 int a = 0;
509 })";
511 EXPECT_EQ(PostCode,
512 runCheckOnCode<CXXSystemIncludeInserterCheck>(
513 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
516 TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterMainFileInclude) {
517 const char *PreCode = R"(
518 #include "clang_tidy/tests/insert_includes_test_header.h"
520 #include "path/to/a/header.h"
522 void foo() {
523 int a = 0;
524 })";
525 const char *PostCode = R"(
526 #include "clang_tidy/tests/insert_includes_test_header.h"
528 #include <set>
530 #include "path/to/a/header.h"
532 void foo() {
533 int a = 0;
534 })";
536 EXPECT_EQ(PostCode,
537 runCheckOnCode<CXXSystemIncludeInserterCheck>(
538 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
541 TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterCSystemInclude) {
542 const char *PreCode = R"(
543 #include "clang_tidy/tests/insert_includes_test_header.h"
545 #include <stdlib.h>
547 #include "path/to/a/header.h"
549 void foo() {
550 int a = 0;
551 })";
552 const char *PostCode = R"(
553 #include "clang_tidy/tests/insert_includes_test_header.h"
555 #include <stdlib.h>
557 #include <set>
559 #include "path/to/a/header.h"
561 void foo() {
562 int a = 0;
563 })";
565 EXPECT_EQ(PostCode,
566 runCheckOnCode<CXXSystemIncludeInserterCheck>(
567 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
570 TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeNonSystemInclude) {
571 const char *PreCode = R"(
572 #include "path/to/a/header.h"
574 void foo() {
575 int a = 0;
576 })";
577 const char *PostCode = R"(
578 #include <set>
580 #include "path/to/a/header.h"
582 void foo() {
583 int a = 0;
584 })";
586 EXPECT_EQ(
587 PostCode,
588 runCheckOnCode<CXXSystemIncludeInserterCheck>(
589 PreCode, "repo/clang_tidy/tests/insert_includes_test_header.cc"));
592 TEST(IncludeInserterTest, InsertCSystemIncludeBeforeCXXSystemInclude) {
593 const char *PreCode = R"(
594 #include <set>
596 #include "path/to/a/header.h"
598 void foo() {
599 int a = 0;
600 })";
601 const char *PostCode = R"(
602 #include <stdlib.h>
604 #include <set>
606 #include "path/to/a/header.h"
608 void foo() {
609 int a = 0;
610 })";
612 EXPECT_EQ(
613 PostCode,
614 runCheckOnCode<CSystemIncludeInserterCheck>(
615 PreCode, "repo/clang_tidy/tests/insert_includes_test_header.cc"));
618 TEST(IncludeInserterTest, InsertIncludeIfThereWasNoneBefore) {
619 const char *PreCode = R"(
620 void foo() {
621 int a = 0;
622 })";
623 const char *PostCode = R"(#include <set>
626 void foo() {
627 int a = 0;
628 })";
630 EXPECT_EQ(
631 PostCode,
632 runCheckOnCode<CXXSystemIncludeInserterCheck>(
633 PreCode, "repo/clang_tidy/tests/insert_includes_test_header.cc"));
636 TEST(IncludeInserterTest, DontInsertDuplicateIncludeEvenIfMiscategorized) {
637 const char *PreCode = R"(
638 #include "clang_tidy/tests/insert_includes_test_header.h"
640 #include <map>
641 #include <set>
642 #include <vector>
644 #include "a/header.h"
645 #include "path/to/a/header.h"
646 #include "path/to/header.h"
648 void foo() {
649 int a = 0;
650 })";
652 const char *PostCode = R"(
653 #include "clang_tidy/tests/insert_includes_test_header.h"
655 #include <map>
656 #include <set>
657 #include <vector>
659 #include "a/header.h"
660 #include "path/to/a/header.h"
661 #include "path/to/header.h"
663 void foo() {
664 int a = 0;
665 })";
667 EXPECT_EQ(PostCode, runCheckOnCode<EarlyInAlphabetHeaderInserterCheck>(
668 PreCode, "workspace_folder/clang_tidy/tests/"
669 "insert_includes_test_header.cc"));
672 TEST(IncludeInserterTest, HandleOrderInSubdirectory) {
673 const char *PreCode = R"(
674 #include "clang_tidy/tests/insert_includes_test_header.h"
676 #include <map>
677 #include <set>
678 #include <vector>
680 #include "path/to/a/header.h"
681 #include "path/to/header.h"
683 void foo() {
684 int a = 0;
685 })";
687 const char *PostCode = R"(
688 #include "clang_tidy/tests/insert_includes_test_header.h"
690 #include <map>
691 #include <set>
692 #include <vector>
694 #include "a/header.h"
695 #include "path/to/a/header.h"
696 #include "path/to/header.h"
698 void foo() {
699 int a = 0;
700 })";
702 EXPECT_EQ(PostCode, runCheckOnCode<EarlyInAlphabetHeaderInserterCheck>(
703 PreCode, "workspace_folder/clang_tidy/tests/"
704 "insert_includes_test_header.cc"));
707 TEST(IncludeInserterTest, InvalidHeaderName) {
708 const char *PreCode = R"(
709 #include "clang_tidy/tests/insert_includes_test_header.h"
711 #include <list>
712 #include <map>
714 #include "path/to/a/header.h"
716 void foo() {
717 int a = 0;
718 })";
719 const char *PostCode = R"(
720 #include "clang_tidy/tests/insert_includes_test_header.h"
722 #include <c.h>
724 #include <d>
725 #include <list>
726 #include <map>
728 #include "a.h"
729 #include "b.h"
730 #include "path/to/a/header.h"
732 void foo() {
733 int a = 0;
734 })";
736 EXPECT_EQ(PostCode,
737 runCheckOnCode<InvalidIncludeInserterCheck>(
738 PreCode, "clang_tidy/tests/insert_includes_test_header.cc"));
741 TEST(IncludeInserterTest, InsertHeaderObjectiveC) {
742 const char *PreCode = R"(
743 #import "clang_tidy/tests/insert_includes_test_header.h"
745 void foo() {
746 int a = 0;
747 })";
748 const char *PostCode = R"(
749 #import "clang_tidy/tests/insert_includes_test_header.h"
751 #import "a/header.h"
753 void foo() {
754 int a = 0;
755 })";
757 EXPECT_EQ(
758 PostCode,
759 runCheckOnCode<ObjCEarlyInAlphabetHeaderInserterCheck>(
760 PreCode, "repo/clang_tidy/tests/insert_includes_test_header.mm"));
763 TEST(IncludeInserterTest, InsertCategoryHeaderObjectiveC) {
764 const char *PreCode = R"(
765 #import "top_level_test_header.h"
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"
774 void foo() {
775 int a = 0;
776 })";
778 EXPECT_EQ(PostCode, runCheckOnCode<ObjCCategoryHeaderInserterCheck>(
779 PreCode, "top_level_test_header.mm"));
782 TEST(IncludeInserterTest, InsertGeneratedHeaderObjectiveC) {
783 const char *PreCode = R"(
784 #import "clang_tidy/tests/insert_includes_test_header.h"
786 #include <list>
787 #include <map>
789 #include "path/to/a/header.h"
791 void foo() {
792 int a = 0;
793 })";
794 const char *PostCode = R"(
795 #import "clang_tidy/tests/insert_includes_test_header.h"
797 #include <list>
798 #include <map>
800 #include "path/to/a/header.h"
802 #import "clang_tidy/tests/generated_file.proto.h"
804 void foo() {
805 int a = 0;
806 })";
808 EXPECT_EQ(
809 PostCode,
810 runCheckOnCode<ObjCGeneratedHeaderInserterCheck>(
811 PreCode, "repo/clang_tidy/tests/insert_includes_test_header.mm"));
814 } // anonymous namespace
815 } // namespace tidy
816 } // namespace clang
818 #endif