brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.3 KiB · 8f75db8 Raw
578 lines · cpp
1//===-- FindAllSymbolsTests.cpp - find all symbols unit tests ---*- C++ -*-===//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 "FindAllSymbolsAction.h"10#include "HeaderMapCollector.h"11#include "SymbolInfo.h"12#include "SymbolReporter.h"13#include "clang/ASTMatchers/ASTMatchFinder.h"14#include "clang/Basic/FileManager.h"15#include "clang/Basic/FileSystemOptions.h"16#include "clang/Frontend/CompilerInstance.h"17#include "clang/Frontend/PCHContainerOperations.h"18#include "clang/Tooling/Tooling.h"19#include "llvm/ADT/IntrusiveRefCntPtr.h"20#include "llvm/ADT/STLExtras.h"21#include "llvm/ADT/StringRef.h"22#include "llvm/Support/MemoryBuffer.h"23#include "llvm/Support/VirtualFileSystem.h"24#include "gtest/gtest.h"25#include <memory>26#include <string>27#include <vector>28 29namespace clang {30namespace find_all_symbols {31 32static const char HeaderName[] = "symbols.h";33 34class TestSymbolReporter : public SymbolReporter {35public:36  ~TestSymbolReporter() override {}37 38  void reportSymbols(llvm::StringRef FileName,39                     const SymbolInfo::SignalMap &NewSymbols) override {40    for (const auto &Entry : NewSymbols)41      Symbols[Entry.first] += Entry.second;42  }43 44  int seen(const SymbolInfo &Symbol) const {45    auto it = Symbols.find(Symbol);46    return it == Symbols.end() ? 0 : it->second.Seen;47  }48 49  int used(const SymbolInfo &Symbol) const {50    auto it = Symbols.find(Symbol);51    return it == Symbols.end() ? 0 : it->second.Used;52  }53 54private:55  SymbolInfo::SignalMap Symbols;56};57 58class FindAllSymbolsTest : public ::testing::Test {59public:60  int seen(const SymbolInfo &Symbol) { return Reporter.seen(Symbol); }61 62  int used(const SymbolInfo &Symbol) { return Reporter.used(Symbol); }63 64  bool runFindAllSymbols(StringRef HeaderCode, StringRef MainCode) {65    llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(66        new llvm::vfs::InMemoryFileSystem);67    llvm::IntrusiveRefCntPtr<FileManager> Files(68        new FileManager(FileSystemOptions(), InMemoryFileSystem));69 70    std::string FileName = "symbol.cc";71 72    const std::string InternalHeader = "internal/internal_header.h";73    const std::string TopHeader = "<top>";74    // Test .inc header path. The header for `IncHeaderClass` should be75    // internal.h, which will eventually be mapped to <top>.76    std::string IncHeader = "internal/private.inc";77    std::string IncHeaderCode = "class IncHeaderClass {};";78 79    HeaderMapCollector::RegexHeaderMap RegexMap = {80        {R"(internal_.*\.h$)", TopHeader.c_str()},81    };82 83    std::string InternalCode =84        "#include \"private.inc\"\nclass Internal {};";85    SymbolInfo InternalSymbol("Internal", SymbolInfo::SymbolKind::Class,86                              TopHeader, {});87    SymbolInfo IncSymbol("IncHeaderClass", SymbolInfo::SymbolKind::Class,88                         TopHeader, {});89    InMemoryFileSystem->addFile(90        IncHeader, 0, llvm::MemoryBuffer::getMemBuffer(IncHeaderCode));91    InMemoryFileSystem->addFile(InternalHeader, 0,92                                llvm::MemoryBuffer::getMemBuffer(InternalCode));93 94    std::unique_ptr<tooling::FrontendActionFactory> Factory(95        new FindAllSymbolsActionFactory(&Reporter, &RegexMap));96 97    tooling::ToolInvocation Invocation(98        {std::string("find_all_symbols"), std::string("-fsyntax-only"),99         std::string("-std=c++11"), FileName},100        Factory->create(), Files.get(),101        std::make_shared<PCHContainerOperations>());102 103    InMemoryFileSystem->addFile(HeaderName, 0,104                                llvm::MemoryBuffer::getMemBuffer(HeaderCode));105 106    std::string Content = "#include\"" + std::string(HeaderName) +107                          "\"\n"108                          "#include \"" +109                          InternalHeader + "\"";110#if !defined(_MSC_VER) && !defined(__MINGW32__)111    // Test path cleaning for both decls and macros.112    const std::string DirtyHeader = "./internal/./a/b.h";113    Content += "\n#include \"" + DirtyHeader + "\"";114    const std::string CleanHeader = "internal/a/b.h";115    const std::string DirtyHeaderContent =116        "#define INTERNAL 1\nclass ExtraInternal {};";117    InMemoryFileSystem->addFile(118        DirtyHeader, 0, llvm::MemoryBuffer::getMemBuffer(DirtyHeaderContent));119    SymbolInfo DirtyMacro("INTERNAL", SymbolInfo::SymbolKind::Macro,120                          CleanHeader, {});121    SymbolInfo DirtySymbol("ExtraInternal", SymbolInfo::SymbolKind::Class,122                           CleanHeader, {});123#endif // _MSC_VER && __MINGW32__124    Content += "\n" + MainCode.str();125    InMemoryFileSystem->addFile(FileName, 0,126                                llvm::MemoryBuffer::getMemBuffer(Content));127    Invocation.run();128    EXPECT_EQ(1, seen(InternalSymbol));129    EXPECT_EQ(1, seen(IncSymbol));130#if !defined(_MSC_VER) && !defined(__MINGW32__)131    EXPECT_EQ(1, seen(DirtySymbol));132    EXPECT_EQ(1, seen(DirtyMacro));133#endif  // _MSC_VER && __MINGW32__134    return true;135  }136 137protected:138  TestSymbolReporter Reporter;139};140 141TEST_F(FindAllSymbolsTest, VariableSymbols) {142  static const char Header[] = R"(143      extern int xargc;144      namespace na {145      static bool SSSS = false;146      namespace nb { const long long *XXXX; }147      })";148  static const char Main[] = R"(149      auto y = &na::nb::XXXX;150      int main() { if (na::SSSS) return xargc; }151  )";152  runFindAllSymbols(Header, Main);153 154  SymbolInfo Symbol =155      SymbolInfo("xargc", SymbolInfo::SymbolKind::Variable, HeaderName, {});156  EXPECT_EQ(1, seen(Symbol));157  EXPECT_EQ(1, used(Symbol));158 159  Symbol = SymbolInfo("SSSS", SymbolInfo::SymbolKind::Variable, HeaderName,160                      {{SymbolInfo::ContextType::Namespace, "na"}});161  EXPECT_EQ(1, seen(Symbol));162  EXPECT_EQ(1, used(Symbol));163 164  Symbol = SymbolInfo("XXXX", SymbolInfo::SymbolKind::Variable, HeaderName,165                      {{SymbolInfo::ContextType::Namespace, "nb"},166                       {SymbolInfo::ContextType::Namespace, "na"}});167  EXPECT_EQ(1, seen(Symbol));168  EXPECT_EQ(1, used(Symbol));169}170 171TEST_F(FindAllSymbolsTest, ExternCSymbols) {172  static const char Header[] = R"(173      extern "C" {174      int C_Func() { return 0; }175      struct C_struct {176        int Member;177      };178      })";179  static const char Main[] = R"(180      C_struct q() {181        int(*ptr)() = C_Func;182        return {0};183      }184  )";185  runFindAllSymbols(Header, Main);186 187  SymbolInfo Symbol =188      SymbolInfo("C_Func", SymbolInfo::SymbolKind::Function, HeaderName, {});189  EXPECT_EQ(1, seen(Symbol));190  EXPECT_EQ(1, used(Symbol));191 192  Symbol =193      SymbolInfo("C_struct", SymbolInfo::SymbolKind::Class, HeaderName, {});194  EXPECT_EQ(1, seen(Symbol));195  EXPECT_EQ(1, used(Symbol));196}197 198TEST_F(FindAllSymbolsTest, CXXRecordSymbols) {199  static const char Header[] = R"(200      struct Glob {};201      struct A; // Not a definition, ignored.202      class NOP; // Not a definition, ignored203      namespace na {204      struct A {205        struct AAAA {};206        int x;207        int y;208        void f() {}209      };210      };  //211      )";212  static const char Main[] = R"(213      static Glob glob;214      static na::A::AAAA* a;215  )";216  runFindAllSymbols(Header, Main);217 218  SymbolInfo Symbol =219      SymbolInfo("Glob", SymbolInfo::SymbolKind::Class, HeaderName, {});220  EXPECT_EQ(1, seen(Symbol));221  EXPECT_EQ(1, used(Symbol));222 223  Symbol = SymbolInfo("A", SymbolInfo::SymbolKind::Class, HeaderName,224                      {{SymbolInfo::ContextType::Namespace, "na"}});225  EXPECT_EQ(1, seen(Symbol));226  EXPECT_EQ(1, used(Symbol));227 228  Symbol = SymbolInfo("AAA", SymbolInfo::SymbolKind::Class, HeaderName,229                      {{SymbolInfo::ContextType::Record, "A"},230                       {SymbolInfo::ContextType::Namespace, "na"}});231  EXPECT_EQ(0, seen(Symbol));232  EXPECT_EQ(0, used(Symbol));233}234 235TEST_F(FindAllSymbolsTest, CXXRecordSymbolsTemplate) {236  static const char Header[] = R"(237      template <typename T>238      struct T_TEMP {239        template <typename _Tp1>240        struct rebind { typedef T_TEMP<_Tp1> other; };241      };242      // Ignore specialization.243      template class T_TEMP<char>;244 245      template <typename T>246      class Observer {247      };248      // Ignore specialization.249      template <> class Observer<int> {};250      )";251  static const char Main[] = R"(252      extern T_TEMP<int>::rebind<char> weirdo;253  )";254  runFindAllSymbols(Header, Main);255 256  SymbolInfo Symbol =257      SymbolInfo("T_TEMP", SymbolInfo::SymbolKind::Class, HeaderName, {});258  EXPECT_EQ(1, seen(Symbol));259  EXPECT_EQ(1, used(Symbol));260}261 262TEST_F(FindAllSymbolsTest, DontIgnoreTemplatePartialSpecialization) {263  static const char Code[] = R"(264      template<class> class Class; // undefined265      template<class R, class... ArgTypes>266      class Class<R(ArgTypes...)> {267      };268 269      template<class T> void f() {};270      template<> void f<int>() {};271      )";272  runFindAllSymbols(Code, "");273  SymbolInfo Symbol =274      SymbolInfo("Class", SymbolInfo::SymbolKind::Class, HeaderName, {});275  EXPECT_EQ(1, seen(Symbol));276  Symbol = SymbolInfo("f", SymbolInfo::SymbolKind::Function, HeaderName, {});277  EXPECT_EQ(1, seen(Symbol));278}279 280TEST_F(FindAllSymbolsTest, FunctionSymbols) {281  static const char Header[] = R"(282      namespace na {283      int gg(int);284      int f(const int &a) { int Local; static int StaticLocal; return 0; }285      static void SSSFFF() {}286      }  // namespace na287      namespace na {288      namespace nb {289      template<typename T>290      void fun(T t) {};291      } // namespace nb292      } // namespace na";293      )";294  static const char Main[] = R"(295      int(*gg)(int) = &na::gg;296      int main() {297        (void)na::SSSFFF;298        na::nb::fun(0);299        return na::f(gg(0));300      }301  )";302  runFindAllSymbols(Header, Main);303 304  SymbolInfo Symbol =305      SymbolInfo("gg", SymbolInfo::SymbolKind::Function, HeaderName,306                 {{SymbolInfo::ContextType::Namespace, "na"}});307  EXPECT_EQ(1, seen(Symbol));308  EXPECT_EQ(1, used(Symbol));309 310  Symbol = SymbolInfo("f", SymbolInfo::SymbolKind::Function, HeaderName,311                      {{SymbolInfo::ContextType::Namespace, "na"}});312  EXPECT_EQ(1, seen(Symbol));313  EXPECT_EQ(1, used(Symbol));314 315  Symbol = SymbolInfo("SSSFFF", SymbolInfo::SymbolKind::Function, HeaderName,316                      {{SymbolInfo::ContextType::Namespace, "na"}});317  EXPECT_EQ(1, seen(Symbol));318  EXPECT_EQ(1, used(Symbol));319 320  Symbol = SymbolInfo("fun", SymbolInfo::SymbolKind::Function, HeaderName,321                      {{SymbolInfo::ContextType::Namespace, "nb"},322                       {SymbolInfo::ContextType::Namespace, "na"}});323  EXPECT_EQ(1, seen(Symbol));324  EXPECT_EQ(1, used(Symbol));325}326 327TEST_F(FindAllSymbolsTest, NamespaceTest) {328  static const char Header[] = R"(329      int X1;330      namespace { int X2; }331      namespace { namespace { int X3; } }332      namespace { namespace nb { int X4; } }333      namespace na { inline namespace __1 { int X5; } }334      )";335  static const char Main[] = R"(336      using namespace nb;337      int main() {338        X1 = X2;339        X3 = X4;340        (void)na::X5;341      }342  )";343  runFindAllSymbols(Header, Main);344 345  SymbolInfo Symbol =346      SymbolInfo("X1", SymbolInfo::SymbolKind::Variable, HeaderName, {});347  EXPECT_EQ(1, seen(Symbol));348  EXPECT_EQ(1, used(Symbol));349 350  Symbol = SymbolInfo("X2", SymbolInfo::SymbolKind::Variable, HeaderName,351                      {{SymbolInfo::ContextType::Namespace, ""}});352  EXPECT_EQ(1, seen(Symbol));353  EXPECT_EQ(1, used(Symbol));354 355  Symbol = SymbolInfo("X3", SymbolInfo::SymbolKind::Variable, HeaderName,356                      {{SymbolInfo::ContextType::Namespace, ""},357                       {SymbolInfo::ContextType::Namespace, ""}});358  EXPECT_EQ(1, seen(Symbol));359  EXPECT_EQ(1, used(Symbol));360 361  Symbol = SymbolInfo("X4", SymbolInfo::SymbolKind::Variable, HeaderName,362                      {{SymbolInfo::ContextType::Namespace, "nb"},363                       {SymbolInfo::ContextType::Namespace, ""}});364  EXPECT_EQ(1, seen(Symbol));365  EXPECT_EQ(1, used(Symbol));366 367  Symbol = SymbolInfo("X5", SymbolInfo::SymbolKind::Variable, HeaderName,368                      {{SymbolInfo::ContextType::Namespace, "na"}});369  EXPECT_EQ(1, seen(Symbol));370  EXPECT_EQ(1, used(Symbol));371}372 373TEST_F(FindAllSymbolsTest, DecayedTypeTest) {374  static const char Header[] = "void DecayedFunc(int x[], int y[10]) {}";375  static const char Main[] = R"(int main() { DecayedFunc(nullptr, nullptr); })";376  runFindAllSymbols(Header, Main);377  SymbolInfo Symbol = SymbolInfo(378      "DecayedFunc", SymbolInfo::SymbolKind::Function, HeaderName, {});379  EXPECT_EQ(1, seen(Symbol));380  EXPECT_EQ(1, used(Symbol));381}382 383TEST_F(FindAllSymbolsTest, CTypedefTest) {384  static const char Header[] = R"(385      typedef unsigned size_t_;386      typedef struct { int x; } X;387      using XX = X;388      )";389  static const char Main[] = R"(390      size_t_ f;391      template<typename T> struct vector{};392      vector<X> list;393      void foo(const XX&){}394  )";395  runFindAllSymbols(Header, Main);396 397  SymbolInfo Symbol = SymbolInfo("size_t_", SymbolInfo::SymbolKind::TypedefName,398                                 HeaderName, {});399  EXPECT_EQ(1, seen(Symbol));400  EXPECT_EQ(1, used(Symbol));401 402  Symbol = SymbolInfo("X", SymbolInfo::SymbolKind::TypedefName, HeaderName, {});403  EXPECT_EQ(1, seen(Symbol));404  EXPECT_EQ(1, used(Symbol));405 406  Symbol =407      SymbolInfo("XX", SymbolInfo::SymbolKind::TypedefName, HeaderName, {});408  EXPECT_EQ(1, seen(Symbol));409  EXPECT_EQ(1, used(Symbol));410}411 412TEST_F(FindAllSymbolsTest, EnumTest) {413  static const char Header[] = R"(414      enum Glob_E { G1, G2 };415      enum class Altitude { high='h', low='l'};416      enum { A1, A2 };417      class A {418      public:419        enum A_ENUM { X1, X2 };420      };421      enum DECL : int;422      )";423  static const char Main[] = R"(424      static auto flags = G1 | G2;425      static auto alt = Altitude::high;426      static auto nested = A::X1;427      extern DECL whatever;428      static auto flags2 = A1 | A2;429  )";430  runFindAllSymbols(Header, Main);431 432  SymbolInfo Symbol =433      SymbolInfo("Glob_E", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});434  EXPECT_EQ(1, seen(Symbol));435  EXPECT_EQ(0, used(Symbol));436 437  Symbol =438      SymbolInfo("G1", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName,439                 {{SymbolInfo::ContextType::EnumDecl, "Glob_E"}});440  EXPECT_EQ(1, seen(Symbol));441  EXPECT_EQ(1, used(Symbol));442 443  Symbol =444      SymbolInfo("G2", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName,445                 {{SymbolInfo::ContextType::EnumDecl, "Glob_E"}});446  EXPECT_EQ(1, seen(Symbol));447  EXPECT_EQ(1, used(Symbol));448 449  Symbol =450      SymbolInfo("Altitude", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});451  EXPECT_EQ(1, seen(Symbol));452  EXPECT_EQ(1, used(Symbol));453  Symbol =454      SymbolInfo("high", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName,455                 {{SymbolInfo::ContextType::EnumDecl, "Altitude"}});456  EXPECT_EQ(0, seen(Symbol));457  EXPECT_EQ(0, used(Symbol));458 459  Symbol = SymbolInfo("A1", SymbolInfo::SymbolKind::EnumConstantDecl,460                      HeaderName, {{SymbolInfo::ContextType::EnumDecl, ""}});461  EXPECT_EQ(1, seen(Symbol));462  EXPECT_EQ(1, used(Symbol));463  Symbol = SymbolInfo("A2", SymbolInfo::SymbolKind::EnumConstantDecl,464                      HeaderName, {{SymbolInfo::ContextType::EnumDecl, ""}});465  EXPECT_EQ(1, seen(Symbol));466  EXPECT_EQ(1, used(Symbol));467  Symbol = SymbolInfo("", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});468  EXPECT_EQ(0, seen(Symbol));469  EXPECT_EQ(0, used(Symbol));470 471  Symbol = SymbolInfo("A_ENUM", SymbolInfo::SymbolKind::EnumDecl, HeaderName,472                      {{SymbolInfo::ContextType::Record, "A"}});473  EXPECT_EQ(0, seen(Symbol));474  EXPECT_EQ(0, used(Symbol));475 476  Symbol = SymbolInfo("X1", SymbolInfo::SymbolKind::EnumDecl, HeaderName,477                      {{SymbolInfo::ContextType::EnumDecl, "A_ENUM"},478                       {SymbolInfo::ContextType::Record, "A"}});479  EXPECT_EQ(0, seen(Symbol));480 481  Symbol = SymbolInfo("DECL", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});482  EXPECT_EQ(0, seen(Symbol));483}484 485TEST_F(FindAllSymbolsTest, IWYUPrivatePragmaTest) {486  static const char Header[] = R"(487    // IWYU pragma: private, include "bar.h"488    struct Bar {489    };490  )";491  static const char Main[] = R"(492    Bar bar;493  )";494  runFindAllSymbols(Header, Main);495 496  SymbolInfo Symbol =497      SymbolInfo("Bar", SymbolInfo::SymbolKind::Class, "bar.h", {});498  EXPECT_EQ(1, seen(Symbol));499  EXPECT_EQ(1, used(Symbol));500}501 502TEST_F(FindAllSymbolsTest, MacroTest) {503  static const char Header[] = R"(504    #define X505    #define Y 1506    #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))507  )";508  static const char Main[] = R"(509    #ifdef X510    int main() { return MAX(0,Y); }511    #endif512  )";513  runFindAllSymbols(Header, Main);514  SymbolInfo Symbol =515      SymbolInfo("X", SymbolInfo::SymbolKind::Macro, HeaderName, {});516  EXPECT_EQ(1, seen(Symbol));517  EXPECT_EQ(1, used(Symbol));518 519  Symbol = SymbolInfo("Y", SymbolInfo::SymbolKind::Macro, HeaderName, {});520  EXPECT_EQ(1, seen(Symbol));521  EXPECT_EQ(1, used(Symbol));522 523  Symbol = SymbolInfo("MAX", SymbolInfo::SymbolKind::Macro, HeaderName, {});524  EXPECT_EQ(1, seen(Symbol));525  EXPECT_EQ(1, used(Symbol));526}527 528TEST_F(FindAllSymbolsTest, MacroTestWithIWYU) {529  static const char Header[] = R"(530    // IWYU pragma: private, include "bar.h"531    #define X 1532    #define Y 1533    #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))534  )";535  static const char Main[] = R"(536    #ifdef X537    int main() { return MAX(0,Y); }538    #endif539  )";540  runFindAllSymbols(Header, Main);541  SymbolInfo Symbol =542      SymbolInfo("X", SymbolInfo::SymbolKind::Macro, "bar.h", {});543  EXPECT_EQ(1, seen(Symbol));544  EXPECT_EQ(1, used(Symbol));545 546  Symbol = SymbolInfo("Y", SymbolInfo::SymbolKind::Macro, "bar.h", {});547  EXPECT_EQ(1, seen(Symbol));548  EXPECT_EQ(1, used(Symbol));549 550  Symbol = SymbolInfo("MAX", SymbolInfo::SymbolKind::Macro, "bar.h", {});551  EXPECT_EQ(1, seen(Symbol));552  EXPECT_EQ(1, used(Symbol));553}554 555TEST_F(FindAllSymbolsTest, NoFriendTest) {556  static const char Header[] = R"(557    class WorstFriend {558      friend void Friend();559      friend class BestFriend;560    };561  )";562  runFindAllSymbols(Header, "");563  SymbolInfo Symbol =564      SymbolInfo("WorstFriend", SymbolInfo::SymbolKind::Class, HeaderName, {});565  EXPECT_EQ(1, seen(Symbol));566 567  Symbol =568      SymbolInfo("Friend", SymbolInfo::SymbolKind::Function, HeaderName, {});569  EXPECT_EQ(0, seen(Symbol));570 571  Symbol =572      SymbolInfo("BestFriend", SymbolInfo::SymbolKind::Class, HeaderName, {});573  EXPECT_EQ(0, seen(Symbol));574}575 576} // namespace find_all_symbols577} // namespace clang578