blob: 52744e101f9261d76b8613b9b4789a95001407d6 [file] [log] [blame]
Eric Liu4d221722018-09-18 08:51:08 +00001//===--- IndexTests.cpp - Test indexing actions -----------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Eric Liu4d221722018-09-18 08:51:08 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "clang/AST/ASTConsumer.h"
Kadir Cetinkayaf53621b2019-02-18 11:30:43 +000010#include "clang/AST/ASTContext.h"
Eric Liu4d221722018-09-18 08:51:08 +000011#include "clang/AST/Decl.h"
Kadir Cetinkayaf53621b2019-02-18 11:30:43 +000012#include "clang/Basic/SourceLocation.h"
13#include "clang/Basic/SourceManager.h"
Eric Liu4d221722018-09-18 08:51:08 +000014#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"
Jonas Devliegherefc514902018-10-10 13:27:25 +000022#include "llvm/Support/VirtualFileSystem.h"
Eric Liu4d221722018-09-18 08:51:08 +000023#include "gmock/gmock.h"
24#include "gtest/gtest.h"
25#include <memory>
26
27namespace clang {
28namespace index {
Kadir Cetinkayaf53621b2019-02-18 11:30:43 +000029namespace {
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 FileID FID;
39 unsigned Offset;
40 std::tie(FID, Offset) = SM.getDecomposedSpellingLoc(Loc);
41 Position P;
42 P.Line = SM.getLineNumber(FID, Offset);
43 P.Column = SM.getColumnNumber(FID, Offset);
44 return P;
45 }
46};
47
48bool operator==(const Position &LHS, const Position &RHS) {
49 return std::tie(LHS.Line, LHS.Column) == std::tie(RHS.Line, RHS.Column);
50}
51
52llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Position &Pos) {
53 return OS << Pos.Line << ':' << Pos.Column;
54}
Eric Liu4d221722018-09-18 08:51:08 +000055
56struct TestSymbol {
57 std::string QName;
Kadir Cetinkayaf53621b2019-02-18 11:30:43 +000058 Position WrittenPos;
59 Position DeclPos;
Kadir Cetinkayaa87ada02019-02-26 14:23:12 +000060 SymbolInfo SymInfo;
Kadir Cetinkayae7eb27a2019-03-08 08:30:20 +000061 SymbolRoleSet Roles;
Eric Liu4d221722018-09-18 08:51:08 +000062 // FIXME: add more information.
63};
64
65llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TestSymbol &S) {
Kadir Cetinkayae7eb27a2019-03-08 08:30:20 +000066 return OS << S.QName << '[' << S.WrittenPos << ']' << '@' << S.DeclPos << '('
67 << static_cast<unsigned>(S.SymInfo.Kind) << ')';
Eric Liu4d221722018-09-18 08:51:08 +000068}
69
Eric Liu4d221722018-09-18 08:51:08 +000070class Indexer : public IndexDataConsumer {
71public:
Kadir Cetinkayaf53621b2019-02-18 11:30:43 +000072 void initialize(ASTContext &Ctx) override {
73 AST = &Ctx;
74 IndexDataConsumer::initialize(Ctx);
75 }
76
Kirill Bobyrev3b9715c2019-12-16 10:33:56 +010077 bool handleDeclOccurrence(const Decl *D, SymbolRoleSet Roles,
78 ArrayRef<SymbolRelation>, SourceLocation Loc,
79 ASTNodeInfo) override {
Eric Liu4d221722018-09-18 08:51:08 +000080 const auto *ND = llvm::dyn_cast<NamedDecl>(D);
81 if (!ND)
82 return true;
83 TestSymbol S;
Kadir Cetinkayaa87ada02019-02-26 14:23:12 +000084 S.SymInfo = getSymbolInfo(D);
Eric Liu4d221722018-09-18 08:51:08 +000085 S.QName = ND->getQualifiedNameAsString();
Kadir Cetinkayaf53621b2019-02-18 11:30:43 +000086 S.WrittenPos = Position::fromSourceLocation(Loc, AST->getSourceManager());
87 S.DeclPos =
88 Position::fromSourceLocation(D->getLocation(), AST->getSourceManager());
Kadir Cetinkayae7eb27a2019-03-08 08:30:20 +000089 S.Roles = Roles;
Eric Liu4d221722018-09-18 08:51:08 +000090 Symbols.push_back(std::move(S));
91 return true;
92 }
93
Kirill Bobyrev3b9715c2019-12-16 10:33:56 +010094 bool handleMacroOccurrence(const IdentifierInfo *Name, const MacroInfo *MI,
95 SymbolRoleSet Roles, SourceLocation Loc) override {
Eric Liu4d221722018-09-18 08:51:08 +000096 TestSymbol S;
Kadir Cetinkayae4407872019-03-08 10:18:40 +000097 S.SymInfo = getSymbolInfoForMacro(*MI);
Benjamin Krameradcd0262020-01-28 20:23:46 +010098 S.QName = std::string(Name->getName());
Kadir Cetinkayae4407872019-03-08 10:18:40 +000099 S.WrittenPos = Position::fromSourceLocation(Loc, AST->getSourceManager());
100 S.DeclPos = Position::fromSourceLocation(MI->getDefinitionLoc(),
101 AST->getSourceManager());
102 S.Roles = Roles;
Eric Liu4d221722018-09-18 08:51:08 +0000103 Symbols.push_back(std::move(S));
104 return true;
105 }
106
107 std::vector<TestSymbol> Symbols;
Kadir Cetinkayaf53621b2019-02-18 11:30:43 +0000108 const ASTContext *AST = nullptr;
Eric Liu4d221722018-09-18 08:51:08 +0000109};
110
111class IndexAction : public ASTFrontendAction {
112public:
113 IndexAction(std::shared_ptr<Indexer> Index,
114 IndexingOptions Opts = IndexingOptions())
115 : Index(std::move(Index)), Opts(Opts) {}
116
117protected:
118 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
119 StringRef InFile) override {
120 class Consumer : public ASTConsumer {
121 std::shared_ptr<Indexer> Index;
122 std::shared_ptr<Preprocessor> PP;
123 IndexingOptions Opts;
124
125 public:
126 Consumer(std::shared_ptr<Indexer> Index, std::shared_ptr<Preprocessor> PP,
127 IndexingOptions Opts)
128 : Index(std::move(Index)), PP(std::move(PP)), Opts(Opts) {}
129
130 void HandleTranslationUnit(ASTContext &Ctx) override {
131 std::vector<Decl *> DeclsToIndex(
132 Ctx.getTranslationUnitDecl()->decls().begin(),
133 Ctx.getTranslationUnitDecl()->decls().end());
134 indexTopLevelDecls(Ctx, *PP, DeclsToIndex, *Index, Opts);
135 }
136 };
Jonas Devlieghere2b3d49b2019-08-14 23:04:18 +0000137 return std::make_unique<Consumer>(Index, CI.getPreprocessorPtr(), Opts);
Eric Liu4d221722018-09-18 08:51:08 +0000138 }
139
140private:
141 std::shared_ptr<Indexer> Index;
142 IndexingOptions Opts;
143};
144
Kadir Cetinkayaf53621b2019-02-18 11:30:43 +0000145using testing::AllOf;
Eric Liu4d221722018-09-18 08:51:08 +0000146using testing::Contains;
147using testing::Not;
148using testing::UnorderedElementsAre;
149
150MATCHER_P(QName, Name, "") { return arg.QName == Name; }
Kadir Cetinkayaf53621b2019-02-18 11:30:43 +0000151MATCHER_P(WrittenAt, Pos, "") { return arg.WrittenPos == Pos; }
152MATCHER_P(DeclAt, Pos, "") { return arg.DeclPos == Pos; }
Kadir Cetinkayaa87ada02019-02-26 14:23:12 +0000153MATCHER_P(Kind, SymKind, "") { return arg.SymInfo.Kind == SymKind; }
Kadir Cetinkayae7eb27a2019-03-08 08:30:20 +0000154MATCHER_P(HasRole, Role, "") { return arg.Roles & static_cast<unsigned>(Role); }
Eric Liu4d221722018-09-18 08:51:08 +0000155
156TEST(IndexTest, Simple) {
157 auto Index = std::make_shared<Indexer>();
Dmitri Gribenkob22804b2019-08-30 09:29:34 +0000158 tooling::runToolOnCode(std::make_unique<IndexAction>(Index),
159 "class X {}; void f() {}");
Eric Liu4d221722018-09-18 08:51:08 +0000160 EXPECT_THAT(Index->Symbols, UnorderedElementsAre(QName("X"), QName("f")));
161}
162
163TEST(IndexTest, IndexPreprocessorMacros) {
164 std::string Code = "#define INDEX_MAC 1";
165 auto Index = std::make_shared<Indexer>();
166 IndexingOptions Opts;
167 Opts.IndexMacrosInPreprocessor = true;
Dmitri Gribenkob22804b2019-08-30 09:29:34 +0000168 tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);
Eric Liu4d221722018-09-18 08:51:08 +0000169 EXPECT_THAT(Index->Symbols, Contains(QName("INDEX_MAC")));
170
171 Opts.IndexMacrosInPreprocessor = false;
172 Index->Symbols.clear();
Dmitri Gribenkob22804b2019-08-30 09:29:34 +0000173 tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);
Eric Liu4d221722018-09-18 08:51:08 +0000174 EXPECT_THAT(Index->Symbols, UnorderedElementsAre());
175}
176
Kadir Cetinkaya0468fc02019-02-11 13:02:21 +0000177TEST(IndexTest, IndexParametersInDecls) {
178 std::string Code = "void foo(int bar);";
179 auto Index = std::make_shared<Indexer>();
180 IndexingOptions Opts;
181 Opts.IndexFunctionLocals = true;
182 Opts.IndexParametersInDeclarations = true;
Dmitri Gribenkob22804b2019-08-30 09:29:34 +0000183 tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);
Kadir Cetinkaya0468fc02019-02-11 13:02:21 +0000184 EXPECT_THAT(Index->Symbols, Contains(QName("bar")));
185
186 Opts.IndexParametersInDeclarations = false;
187 Index->Symbols.clear();
Dmitri Gribenkob22804b2019-08-30 09:29:34 +0000188 tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);
Kadir Cetinkaya0468fc02019-02-11 13:02:21 +0000189 EXPECT_THAT(Index->Symbols, Not(Contains(QName("bar"))));
190}
191
Kadir Cetinkayaf53621b2019-02-18 11:30:43 +0000192TEST(IndexTest, IndexExplicitTemplateInstantiation) {
193 std::string Code = R"cpp(
194 template <typename T>
195 struct Foo { void bar() {} };
196 template <>
197 struct Foo<int> { void bar() {} };
198 void foo() {
199 Foo<char> abc;
200 Foo<int> b;
201 }
202 )cpp";
203 auto Index = std::make_shared<Indexer>();
204 IndexingOptions Opts;
Dmitri Gribenkob22804b2019-08-30 09:29:34 +0000205 tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);
Kadir Cetinkayaf53621b2019-02-18 11:30:43 +0000206 EXPECT_THAT(Index->Symbols,
207 AllOf(Contains(AllOf(QName("Foo"), WrittenAt(Position(8, 7)),
208 DeclAt(Position(5, 12)))),
209 Contains(AllOf(QName("Foo"), WrittenAt(Position(7, 7)),
210 DeclAt(Position(3, 12))))));
211}
212
213TEST(IndexTest, IndexTemplateInstantiationPartial) {
214 std::string Code = R"cpp(
215 template <typename T1, typename T2>
216 struct Foo { void bar() {} };
217 template <typename T>
218 struct Foo<T, int> { void bar() {} };
219 void foo() {
220 Foo<char, char> abc;
221 Foo<int, int> b;
222 }
223 )cpp";
224 auto Index = std::make_shared<Indexer>();
225 IndexingOptions Opts;
Dmitri Gribenkob22804b2019-08-30 09:29:34 +0000226 tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);
Kadir Cetinkayaf53621b2019-02-18 11:30:43 +0000227 EXPECT_THAT(Index->Symbols,
228 Contains(AllOf(QName("Foo"), WrittenAt(Position(8, 7)),
229 DeclAt(Position(5, 12)))));
230}
231
Kadir Cetinkayab7805172019-02-21 09:52:33 +0000232TEST(IndexTest, IndexTypeParmDecls) {
233 std::string Code = R"cpp(
234 template <typename T, int I, template<typename> class C, typename NoRef>
235 struct Foo {
236 T t = I;
237 C<int> x;
238 };
239 )cpp";
240 auto Index = std::make_shared<Indexer>();
241 IndexingOptions Opts;
Dmitri Gribenkob22804b2019-08-30 09:29:34 +0000242 tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);
Kadir Cetinkayab7805172019-02-21 09:52:33 +0000243 EXPECT_THAT(Index->Symbols, AllOf(Not(Contains(QName("Foo::T"))),
244 Not(Contains(QName("Foo::I"))),
245 Not(Contains(QName("Foo::C"))),
246 Not(Contains(QName("Foo::NoRef")))));
247
248 Opts.IndexTemplateParameters = true;
249 Index->Symbols.clear();
Dmitri Gribenkob22804b2019-08-30 09:29:34 +0000250 tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);
Kadir Cetinkayab7805172019-02-21 09:52:33 +0000251 EXPECT_THAT(Index->Symbols,
Kadir Cetinkaya84240e02020-01-30 14:07:42 +0100252 AllOf(Contains(AllOf(QName("Foo::T"),
253 Kind(SymbolKind::TemplateTypeParm))),
254 Contains(AllOf(QName("Foo::I"),
255 Kind(SymbolKind::NonTypeTemplateParm))),
256 Contains(AllOf(QName("Foo::C"),
257 Kind(SymbolKind::TemplateTemplateParm))),
258 Contains(QName("Foo::NoRef"))));
Kadir Cetinkayab7805172019-02-21 09:52:33 +0000259}
260
Kadir Cetinkayaa87ada02019-02-26 14:23:12 +0000261TEST(IndexTest, UsingDecls) {
262 std::string Code = R"cpp(
263 void foo(int bar);
264 namespace std {
265 using ::foo;
266 }
267 )cpp";
268 auto Index = std::make_shared<Indexer>();
269 IndexingOptions Opts;
Dmitri Gribenkob22804b2019-08-30 09:29:34 +0000270 tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);
Kadir Cetinkayaa87ada02019-02-26 14:23:12 +0000271 EXPECT_THAT(Index->Symbols,
272 Contains(AllOf(QName("std::foo"), Kind(SymbolKind::Using))));
273}
274
Kadir Cetinkayae7eb27a2019-03-08 08:30:20 +0000275TEST(IndexTest, Constructors) {
276 std::string Code = R"cpp(
277 struct Foo {
278 Foo(int);
279 ~Foo();
280 };
281 )cpp";
282 auto Index = std::make_shared<Indexer>();
283 IndexingOptions Opts;
Dmitri Gribenkob22804b2019-08-30 09:29:34 +0000284 tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);
Kadir Cetinkayae7eb27a2019-03-08 08:30:20 +0000285 EXPECT_THAT(
286 Index->Symbols,
287 UnorderedElementsAre(
288 AllOf(QName("Foo"), Kind(SymbolKind::Struct),
289 WrittenAt(Position(2, 12))),
290 AllOf(QName("Foo::Foo"), Kind(SymbolKind::Constructor),
291 WrittenAt(Position(3, 7))),
292 AllOf(QName("Foo"), Kind(SymbolKind::Struct),
293 HasRole(SymbolRole::NameReference), WrittenAt(Position(3, 7))),
294 AllOf(QName("Foo::~Foo"), Kind(SymbolKind::Destructor),
295 WrittenAt(Position(4, 7))),
296 AllOf(QName("Foo"), Kind(SymbolKind::Struct),
297 HasRole(SymbolRole::NameReference),
298 WrittenAt(Position(4, 8)))));
299}
300
Haojian Wua133cba2020-01-21 16:42:18 +0100301TEST(IndexTest, InjecatedNameClass) {
302 std::string Code = R"cpp(
303 template <typename T>
304 class Foo {
305 void f(Foo x);
306 };
307 )cpp";
308 auto Index = std::make_shared<Indexer>();
309 IndexingOptions Opts;
310 tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);
311 EXPECT_THAT(Index->Symbols,
312 UnorderedElementsAre(AllOf(QName("Foo"), Kind(SymbolKind::Class),
313 WrittenAt(Position(3, 11))),
314 AllOf(QName("Foo::f"),
315 Kind(SymbolKind::InstanceMethod),
316 WrittenAt(Position(4, 12))),
317 AllOf(QName("Foo"), Kind(SymbolKind::Class),
318 HasRole(SymbolRole::Reference),
319 WrittenAt(Position(4, 14)))));
320}
321
Haojian Wuaf8b0cd2020-02-12 14:42:18 +0100322TEST(IndexTest, VisitDefaultArgs) {
323 std::string Code = R"cpp(
324 int var = 0;
325 void f(int s = var) {}
326 )cpp";
327 auto Index = std::make_shared<Indexer>();
328 IndexingOptions Opts;
329 Opts.IndexFunctionLocals = true;
330 Opts.IndexParametersInDeclarations = true;
331 tooling::runToolOnCode(std::make_unique<IndexAction>(Index, Opts), Code);
332 EXPECT_THAT(Index->Symbols,
333 Contains(AllOf(QName("var"), HasRole(SymbolRole::Reference),
334 WrittenAt(Position(3, 20)))));
335}
336
Eric Liu4d221722018-09-18 08:51:08 +0000337} // namespace
338} // namespace index
339} // namespace clang