brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.5 KiB · d01ba98 Raw
819 lines · cpp
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-exception6//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 before17// storing the virtual entries.18// When resolving virtual entries in the FileManager, the paths (for19// example coming from a #include directive) are not canonicalized20// to native paths; thus, the virtual file is not found.21// This needs to be fixed in the FileManager before we can make22// clang-tidy tests work.23#if !defined(_WIN32)24 25namespace clang {26namespace tidy {27namespace {28 29class IncludeInserterCheckBase : public ClangTidyCheck {30public: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 60class NonSystemHeaderInserterCheck : public IncludeInserterCheckBase {61public: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 70class EarlyInAlphabetHeaderInserterCheck : public IncludeInserterCheckBase {71public: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 80class MultipleHeaderInserterCheck : public IncludeInserterCheckBase {81public: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 90class MultipleHeaderSingleInserterCheck : public IncludeInserterCheckBase {91public: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 103class CSystemIncludeInserterCheck : public IncludeInserterCheckBase {104public: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 113class CXXSystemIncludeInserterCheck : public IncludeInserterCheckBase {114public:115  CXXSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)116      : IncludeInserterCheckBase(CheckName, Context) {}117 118  std::vector<StringRef> headersToInclude() const override { return {"<set>"}; }119};120 121class InvalidIncludeInserterCheck : public IncludeInserterCheckBase {122public: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 131class ObjCEarlyInAlphabetHeaderInserterCheck : public IncludeInserterCheckBase {132public: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 143class ObjCCategoryHeaderInserterCheck : public IncludeInserterCheckBase {144public: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 155class ObjCGeneratedHeaderInserterCheck : public IncludeInserterCheckBase {156public: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 167template <typename Check>168std::string runCheckOnCode(StringRef Code, StringRef Filename) {169  std::vector<ClangTidyError> Errors;170  return test::runCheckOnCode<Check>(Code, &Errors, Filename, {},171                                     ClangTidyOptions(),172                                     {// Main file include173                                      {"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 headers185                                      {"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 headers191                                      {"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 203TEST(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 212void 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 224void 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 233TEST(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 242void 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 255void 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 264TEST(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 273void foo() {274  int a = 0;275})";276  // FIXME: ClangFormat bug - https://bugs.llvm.org/show_bug.cgi?id=49298277  // clang-format off278  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 289void foo() {290  int a = 0;291})";292  // clang-format on293 294  EXPECT_EQ(PostCode,295            runCheckOnCode<MultipleHeaderSingleInserterCheck>(296                PreCode, "clang_tidy/tests/insert_includes_test_input2.cc"));297}298 299TEST(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 308void 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 320void 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 329TEST(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 339void 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 352void 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 361TEST(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 372void 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 380TEST(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 387void 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 398void 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 407TEST(IncludeInserterTest, InsertNonSystemIncludeAfterMainFileInclude) {408  const char *PreCode = R"(409#include "clang_tidy/tests/insert_includes_test_header.h"410 411void 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 419void 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 428TEST(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 437void 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 449void 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 458TEST(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 466void 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 477void 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 486TEST(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 495void 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 507void 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 516TEST(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 522void 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 532void 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 541TEST(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 549void 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 561void 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 570TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeNonSystemInclude) {571  const char *PreCode = R"(572#include "path/to/a/header.h"573 574void foo() {575  int a = 0;576})";577  const char *PostCode = R"(578#include <set>579 580#include "path/to/a/header.h"581 582void 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 592TEST(IncludeInserterTest, InsertCSystemIncludeBeforeCXXSystemInclude) {593  const char *PreCode = R"(594#include <set>595 596#include "path/to/a/header.h"597 598void 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 608void 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 618TEST(IncludeInserterTest, InsertIncludeIfThereWasNoneBefore) {619  const char *PreCode = R"(620void foo() {621  int a = 0;622})";623  const char *PostCode = R"(#include <set>624 625 626void 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 636TEST(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 648void 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 663void 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 672TEST(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 683void 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 698void 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 707TEST(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 716void 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 732void 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 741TEST(IncludeInserterTest, InsertHeaderObjectiveC) {742  const char *PreCode = R"(743#import "clang_tidy/tests/insert_includes_test_header.h"744 745void 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 753void 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 763TEST(IncludeInserterTest, InsertCategoryHeaderObjectiveC) {764  const char *PreCode = R"(765#import "top_level_test_header.h"766 767void 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 774void foo() {775  int a = 0;776})";777 778  EXPECT_EQ(PostCode, runCheckOnCode<ObjCCategoryHeaderInserterCheck>(779                          PreCode, "top_level_test_header.mm"));780}781 782TEST(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 791void 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 804void 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 namespace815} // namespace tidy816} // namespace clang817 818#endif819