brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.0 KiB · 6df4b57 Raw
457 lines · cpp
1//===--- IndexTests.cpp - Test indexing actions -----------------*- 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 "clang/AST/ASTConsumer.h"10#include "clang/AST/ASTContext.h"11#include "clang/AST/Decl.h"12#include "clang/Basic/SourceLocation.h"13#include "clang/Basic/SourceManager.h"14#include "clang/Frontend/CompilerInstance.h"15#include "clang/Frontend/FrontendAction.h"16#include "clang/Index/IndexDataConsumer.h"17#include "clang/Index/IndexSymbol.h"18#include "clang/Index/IndexingAction.h"19#include "clang/Lex/Preprocessor.h"20#include "clang/Tooling/Tooling.h"21#include "llvm/ADT/StringRef.h"22#include "llvm/Support/VirtualFileSystem.h"23#include "gmock/gmock.h"24#include "gtest/gtest.h"25#include <memory>26 27namespace clang {28namespace index {29namespace {30struct Position {31  size_t Line = 0;32  size_t Column = 0;33 34  Position(size_t Line = 0, size_t Column = 0) : Line(Line), Column(Column) {}35 36  static Position fromSourceLocation(SourceLocation Loc,37                                     const SourceManager &SM) {38    auto [FID, Offset] = SM.getDecomposedSpellingLoc(Loc);39    Position P;40    P.Line = SM.getLineNumber(FID, Offset);41    P.Column = SM.getColumnNumber(FID, Offset);42    return P;43  }44};45 46bool operator==(const Position &LHS, const Position &RHS) {47  return std::tie(LHS.Line, LHS.Column) == std::tie(RHS.Line, RHS.Column);48}49 50llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Position &Pos) {51  return OS << Pos.Line << ':' << Pos.Column;52}53 54struct TestSymbol {55  std::string QName;56  Position WrittenPos;57  Position DeclPos;58  SymbolInfo SymInfo;59  SymbolRoleSet Roles;60  // FIXME: add more information.61};62 63llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TestSymbol &S) {64  return OS << S.QName << '[' << S.WrittenPos << ']' << '@' << S.DeclPos << '('65            << static_cast<unsigned>(S.SymInfo.Kind) << ')';66}67 68class Indexer : public IndexDataConsumer {69public:70  void initialize(ASTContext &Ctx) override {71    AST = &Ctx;72    IndexDataConsumer::initialize(Ctx);73  }74 75  bool handleDeclOccurrence(const Decl *D, SymbolRoleSet Roles,76                            ArrayRef<SymbolRelation>, SourceLocation Loc,77                            ASTNodeInfo) override {78    const auto *ND = llvm::dyn_cast<NamedDecl>(D);79    if (!ND)80      return true;81    TestSymbol S;82    S.SymInfo = getSymbolInfo(D);83    S.QName = ND->getQualifiedNameAsString();84    S.WrittenPos = Position::fromSourceLocation(Loc, AST->getSourceManager());85    S.DeclPos =86        Position::fromSourceLocation(D->getLocation(), AST->getSourceManager());87    S.Roles = Roles;88    Symbols.push_back(std::move(S));89    return true;90  }91 92  bool handleMacroOccurrence(const IdentifierInfo *Name, const MacroInfo *MI,93                             SymbolRoleSet Roles, SourceLocation Loc) override {94    TestSymbol S;95    S.SymInfo = getSymbolInfoForMacro(*MI);96    S.QName = std::string(Name->getName());97    S.WrittenPos = Position::fromSourceLocation(Loc, AST->getSourceManager());98    S.DeclPos = Position::fromSourceLocation(MI->getDefinitionLoc(),99                                             AST->getSourceManager());100    S.Roles = Roles;101    Symbols.push_back(std::move(S));102    return true;103  }104 105  std::vector<TestSymbol> Symbols;106  const ASTContext *AST = nullptr;107};108 109class IndexAction : public ASTFrontendAction {110public:111  IndexAction(std::shared_ptr<Indexer> Index,112              IndexingOptions Opts = IndexingOptions())113      : Index(std::move(Index)), Opts(Opts) {}114 115protected:116  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,117                                                 StringRef InFile) override {118    class Consumer : public ASTConsumer {119      std::shared_ptr<Indexer> Index;120      std::shared_ptr<Preprocessor> PP;121      IndexingOptions Opts;122 123    public:124      Consumer(std::shared_ptr<Indexer> Index, std::shared_ptr<Preprocessor> PP,125               IndexingOptions Opts)126          : Index(std::move(Index)), PP(std::move(PP)), Opts(Opts) {}127 128      void HandleTranslationUnit(ASTContext &Ctx) override {129        std::vector<Decl *> DeclsToIndex(130            Ctx.getTranslationUnitDecl()->decls().begin(),131            Ctx.getTranslationUnitDecl()->decls().end());132        indexTopLevelDecls(Ctx, *PP, DeclsToIndex, *Index, Opts);133      }134    };135    return std::make_unique<Consumer>(Index, CI.getPreprocessorPtr(), Opts);136  }137 138private:139  std::shared_ptr<Indexer> Index;140  IndexingOptions Opts;141};142 143using testing::AllOf;144using testing::Contains;145using testing::Not;146using testing::UnorderedElementsAre;147 148MATCHER_P(QName, Name, "") { return arg.QName == Name; }149MATCHER_P(WrittenAt, Pos, "") { return arg.WrittenPos == Pos; }150MATCHER_P(DeclAt, Pos, "") { return arg.DeclPos == Pos; }151MATCHER_P(Kind, SymKind, "") { return arg.SymInfo.Kind == SymKind; }152MATCHER_P(HasRole, Role, "") { return arg.Roles & static_cast<unsigned>(Role); }153 154TEST(IndexTest, Simple) {155  auto Index = std::make_shared<Indexer>();156  tooling::runToolOnCode(std::make_unique<IndexAction>(Index),157                         "class X {}; void f() {}");158  EXPECT_THAT(Index->Symbols, UnorderedElementsAre(QName("X"), QName("f")));159}160 161TEST(IndexTest, IndexPreprocessorMacros) {162  std::string Code = R"cpp(163    #define INDEX_MAC 1164    #define INDEX_MAC_UNDEF 1165    #undef INDEX_MAC_UNDEF166    #define INDEX_MAC_REDEF 1167    #undef INDEX_MAC_REDEF168    #define INDEX_MAC_REDEF 2169  )cpp";170  auto Index = std::make_shared<Indexer>();171  IndexingOptions Opts;172  Opts.IndexMacrosInPreprocessor = true;173  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);174  EXPECT_THAT(Index->Symbols,175              Contains(AllOf(QName("INDEX_MAC"), WrittenAt(Position(2, 13)),176                             DeclAt(Position(2, 13)),177                             HasRole(SymbolRole::Definition))));178  EXPECT_THAT(179      Index->Symbols,180      AllOf(Contains(AllOf(QName("INDEX_MAC_UNDEF"), WrittenAt(Position(3, 13)),181                           DeclAt(Position(3, 13)),182                           HasRole(SymbolRole::Definition))),183            Contains(AllOf(QName("INDEX_MAC_UNDEF"), WrittenAt(Position(4, 12)),184                           DeclAt(Position(3, 13)),185                           HasRole(SymbolRole::Undefinition)))));186  EXPECT_THAT(187      Index->Symbols,188      AllOf(Contains(AllOf(QName("INDEX_MAC_REDEF"), WrittenAt(Position(5, 13)),189                           DeclAt(Position(5, 13)),190                           HasRole(SymbolRole::Definition))),191            Contains(AllOf(QName("INDEX_MAC_REDEF"), WrittenAt(Position(6, 12)),192                           DeclAt(Position(5, 13)),193                           HasRole(SymbolRole::Undefinition))),194            Contains(AllOf(QName("INDEX_MAC_REDEF"), WrittenAt(Position(7, 13)),195                           DeclAt(Position(7, 13)),196                           HasRole(SymbolRole::Definition)))));197 198  Opts.IndexMacrosInPreprocessor = false;199  Index->Symbols.clear();200  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);201  EXPECT_THAT(Index->Symbols, UnorderedElementsAre());202}203 204TEST(IndexTest, IndexParametersInDecls) {205  std::string Code = "void foo(int bar);";206  auto Index = std::make_shared<Indexer>();207  IndexingOptions Opts;208  Opts.IndexFunctionLocals = true;209  Opts.IndexParametersInDeclarations = true;210  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);211  EXPECT_THAT(Index->Symbols, Contains(QName("bar")));212 213  Opts.IndexParametersInDeclarations = false;214  Index->Symbols.clear();215  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);216  EXPECT_THAT(Index->Symbols, Not(Contains(QName("bar"))));217}218 219TEST(IndexTest, IndexLabels) {220  std::string Code = R"cpp(221        int main() {222          goto theLabel;223          theLabel:224            return 1;225        }226      )cpp";227  auto Index = std::make_shared<Indexer>();228  IndexingOptions Opts;229  Opts.IndexFunctionLocals = true;230  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);231  EXPECT_THAT(Index->Symbols,232              Contains(AllOf(QName("theLabel"), WrittenAt(Position(3, 16)),233                             DeclAt(Position(4, 11)))));234 235  Opts.IndexFunctionLocals = false;236  Index->Symbols.clear();237  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);238  EXPECT_THAT(Index->Symbols, Not(Contains(QName("theLabel"))));239}240 241TEST(IndexTest, IndexExplicitTemplateInstantiation) {242  std::string Code = R"cpp(243    template <typename T>244    struct Foo { void bar() {} };245    template <>246    struct Foo<int> { void bar() {} };247    void foo() {248      Foo<char> abc;249      Foo<int> b;250    }251  )cpp";252  auto Index = std::make_shared<Indexer>();253  IndexingOptions Opts;254  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);255  EXPECT_THAT(Index->Symbols,256              AllOf(Contains(AllOf(QName("Foo"), WrittenAt(Position(8, 7)),257                                   DeclAt(Position(5, 12)))),258                    Contains(AllOf(QName("Foo"), WrittenAt(Position(7, 7)),259                                   DeclAt(Position(3, 12))))));260}261 262TEST(IndexTest, IndexTemplateInstantiationPartial) {263  std::string Code = R"cpp(264    template <typename T1, typename T2>265    struct Foo { void bar() {} };266    template <typename T>267    struct Foo<T, int> { void bar() {} };268    void foo() {269      Foo<char, char> abc;270      Foo<int, int> b;271    }272  )cpp";273  auto Index = std::make_shared<Indexer>();274  IndexingOptions Opts;275  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);276  EXPECT_THAT(Index->Symbols,277              Contains(AllOf(QName("Foo"), WrittenAt(Position(8, 7)),278                             DeclAt(Position(5, 12)))));279}280 281TEST(IndexTest, IndexTypeParmDecls) {282  std::string Code = R"cpp(283    template <typename T, int I, template<typename> class C, typename NoRef>284    struct Foo {285      T t = I;286      C<int> x;287    };288  )cpp";289  auto Index = std::make_shared<Indexer>();290  IndexingOptions Opts;291  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);292  EXPECT_THAT(Index->Symbols, AllOf(Not(Contains(QName("Foo::T"))),293                                    Not(Contains(QName("Foo::I"))),294                                    Not(Contains(QName("Foo::C"))),295                                    Not(Contains(QName("Foo::NoRef")))));296 297  Opts.IndexTemplateParameters = true;298  Index->Symbols.clear();299  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);300  EXPECT_THAT(Index->Symbols,301              AllOf(Contains(AllOf(QName("Foo::T"),302                                   Kind(SymbolKind::TemplateTypeParm))),303                    Contains(AllOf(QName("Foo::I"),304                                   Kind(SymbolKind::NonTypeTemplateParm))),305                    Contains(AllOf(QName("Foo::C"),306                                   Kind(SymbolKind::TemplateTemplateParm))),307                    Contains(QName("Foo::NoRef"))));308}309 310TEST(IndexTest, UsingDecls) {311  std::string Code = R"cpp(312    void foo(int bar);313    namespace std {314      using ::foo;315    }316  )cpp";317  auto Index = std::make_shared<Indexer>();318  IndexingOptions Opts;319  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);320  EXPECT_THAT(Index->Symbols,321              Contains(AllOf(QName("std::foo"), Kind(SymbolKind::Using))));322}323 324TEST(IndexTest, Constructors) {325  std::string Code = R"cpp(326    struct Foo {327      Foo(int);328      ~Foo();329    };330  )cpp";331  auto Index = std::make_shared<Indexer>();332  IndexingOptions Opts;333  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);334  EXPECT_THAT(335      Index->Symbols,336      UnorderedElementsAre(337          AllOf(QName("Foo"), Kind(SymbolKind::Struct),338                WrittenAt(Position(2, 12))),339          AllOf(QName("Foo::Foo"), Kind(SymbolKind::Constructor),340                WrittenAt(Position(3, 7))),341          AllOf(QName("Foo"), Kind(SymbolKind::Struct),342                HasRole(SymbolRole::NameReference), WrittenAt(Position(3, 7))),343          AllOf(QName("Foo::~Foo"), Kind(SymbolKind::Destructor),344                WrittenAt(Position(4, 7))),345          AllOf(QName("Foo"), Kind(SymbolKind::Struct),346                HasRole(SymbolRole::NameReference),347                WrittenAt(Position(4, 8)))));348}349 350TEST(IndexTest, InjectedNameClass) {351  std::string Code = R"cpp(352    template <typename T>353    class Foo {354      void f(Foo x);355    };356  )cpp";357  auto Index = std::make_shared<Indexer>();358  IndexingOptions Opts;359  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);360  EXPECT_THAT(Index->Symbols,361              UnorderedElementsAre(AllOf(QName("Foo"), Kind(SymbolKind::Class),362                                         WrittenAt(Position(3, 11))),363                                   AllOf(QName("Foo::f"),364                                         Kind(SymbolKind::InstanceMethod),365                                         WrittenAt(Position(4, 12))),366                                   AllOf(QName("Foo"), Kind(SymbolKind::Class),367                                         HasRole(SymbolRole::Reference),368                                         WrittenAt(Position(4, 14)))));369}370 371TEST(IndexTest, VisitDefaultArgs) {372  std::string Code = R"cpp(373    int var = 0;374    void f(int s = var) {}375  )cpp";376  auto Index = std::make_shared<Indexer>();377  IndexingOptions Opts;378  Opts.IndexFunctionLocals = true;379  Opts.IndexParametersInDeclarations = true;380  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);381  EXPECT_THAT(Index->Symbols,382              Contains(AllOf(QName("var"), HasRole(SymbolRole::Reference),383                             WrittenAt(Position(3, 20)))));384}385 386TEST(IndexTest, RelationBaseOf) {387  std::string Code = R"cpp(388    class A {};389    template <typename> class B {};390    class C : B<A> {};391  )cpp";392  auto Index = std::make_shared<Indexer>();393  tooling::runToolOnCode(std::make_unique<IndexAction>(Index), Code);394  // A should not be the base of anything.395  EXPECT_THAT(Index->Symbols,396              Contains(AllOf(QName("A"), HasRole(SymbolRole::Reference),397                             Not(HasRole(SymbolRole::RelationBaseOf)))));398}399 400TEST(IndexTest, EnumBase) {401  std::string Code = R"cpp(402    typedef int MyTypedef;403    enum Foo : MyTypedef;404    enum Foo : MyTypedef {};405  )cpp";406  auto Index = std::make_shared<Indexer>();407  tooling::runToolOnCode(std::make_unique<IndexAction>(Index), Code);408  EXPECT_THAT(409      Index->Symbols,410      AllOf(Contains(AllOf(QName("MyTypedef"), HasRole(SymbolRole::Reference),411                           WrittenAt(Position(3, 16)))),412            Contains(AllOf(QName("MyTypedef"), HasRole(SymbolRole::Reference),413                           WrittenAt(Position(4, 16))))));414}415 416TEST(IndexTest, NonTypeTemplateParameter) {417  std::string Code = R"cpp(418    enum class Foobar { foo };419    template <Foobar f>420    constexpr void func() {}421  )cpp";422  auto Index = std::make_shared<Indexer>();423  tooling::runToolOnCode(std::make_unique<IndexAction>(Index), Code);424  EXPECT_THAT(Index->Symbols,425              Contains(AllOf(QName("Foobar"), HasRole(SymbolRole::Reference),426                             WrittenAt(Position(3, 15)))));427}428 429TEST(IndexTest, ReadWriteRoles) {430  std::string Code = R"cpp(431    int main() {432      int foo = 0;433      foo = 2;434      foo += 1;435      int bar = foo;436  }437  )cpp";438  auto Index = std::make_shared<Indexer>();439  IndexingOptions Opts;440  Opts.IndexFunctionLocals = true;441  tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);442  EXPECT_THAT(443      Index->Symbols,444      AllOf(Contains(AllOf(QName("foo"), HasRole(SymbolRole::Write),445                           WrittenAt(Position(4, 7)))),446            Contains(AllOf(QName("foo"),447                           HasRole(static_cast<unsigned>(SymbolRole::Read) |448                                   static_cast<unsigned>(SymbolRole::Write)),449                           WrittenAt(Position(5, 7)))),450            Contains(AllOf(QName("foo"), HasRole(SymbolRole::Read),451                           WrittenAt(Position(6, 17))))));452}453 454} // namespace455} // namespace index456} // namespace clang457