2017-12-15 20:25:02 +08:00
|
|
|
//===-- FileIndexTests.cpp ---------------------------*- C++ -*-----------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "index/FileIndex.h"
|
|
|
|
#include "clang/Frontend/CompilerInvocation.h"
|
|
|
|
#include "clang/Frontend/PCHContainerOperations.h"
|
|
|
|
#include "clang/Frontend/Utils.h"
|
|
|
|
#include "gmock/gmock.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
using testing::UnorderedElementsAre;
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
Symbol symbol(llvm::StringRef ID) {
|
|
|
|
Symbol Sym;
|
|
|
|
Sym.ID = SymbolID(ID);
|
2017-12-19 19:37:40 +08:00
|
|
|
Sym.Name = ID;
|
2017-12-15 20:25:02 +08:00
|
|
|
return Sym;
|
|
|
|
}
|
|
|
|
|
|
|
|
void addNumSymbolsToSlab(int Begin, int End, SymbolSlab *Slab) {
|
|
|
|
for (int i = Begin; i <= End; i++)
|
|
|
|
Slab->insert(symbol(std::to_string(i)));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string>
|
|
|
|
getSymbolNames(const std::vector<const Symbol *> &Symbols) {
|
|
|
|
std::vector<std::string> Names;
|
|
|
|
for (const Symbol *Sym : Symbols)
|
2017-12-19 19:37:40 +08:00
|
|
|
Names.push_back(Sym->Name);
|
2017-12-15 20:25:02 +08:00
|
|
|
return Names;
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileSymbolsTest, UpdateAndGet) {
|
|
|
|
FileSymbols FS;
|
|
|
|
EXPECT_THAT(getSymbolNames(*FS.allSymbols()), UnorderedElementsAre());
|
|
|
|
|
|
|
|
auto Slab = llvm::make_unique<SymbolSlab>();
|
|
|
|
addNumSymbolsToSlab(1, 3, Slab.get());
|
|
|
|
|
|
|
|
FS.update("f1", std::move(Slab));
|
|
|
|
|
|
|
|
EXPECT_THAT(getSymbolNames(*FS.allSymbols()),
|
|
|
|
UnorderedElementsAre("1", "2", "3"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileSymbolsTest, Overlap) {
|
|
|
|
FileSymbols FS;
|
|
|
|
|
|
|
|
auto Slab = llvm::make_unique<SymbolSlab>();
|
|
|
|
addNumSymbolsToSlab(1, 3, Slab.get());
|
|
|
|
|
|
|
|
FS.update("f1", std::move(Slab));
|
|
|
|
|
|
|
|
Slab = llvm::make_unique<SymbolSlab>();
|
|
|
|
addNumSymbolsToSlab(3, 5, Slab.get());
|
|
|
|
|
|
|
|
FS.update("f2", std::move(Slab));
|
|
|
|
|
|
|
|
EXPECT_THAT(getSymbolNames(*FS.allSymbols()),
|
|
|
|
UnorderedElementsAre("1", "2", "3", "3", "4", "5"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileSymbolsTest, SnapshotAliveAfterRemove) {
|
|
|
|
FileSymbols FS;
|
|
|
|
|
|
|
|
auto Slab = llvm::make_unique<SymbolSlab>();
|
|
|
|
addNumSymbolsToSlab(1, 3, Slab.get());
|
|
|
|
|
|
|
|
FS.update("f1", std::move(Slab));
|
|
|
|
|
|
|
|
auto Symbols = FS.allSymbols();
|
|
|
|
EXPECT_THAT(getSymbolNames(*Symbols), UnorderedElementsAre("1", "2", "3"));
|
|
|
|
|
|
|
|
FS.update("f1", nullptr);
|
|
|
|
EXPECT_THAT(getSymbolNames(*FS.allSymbols()), UnorderedElementsAre());
|
|
|
|
|
|
|
|
EXPECT_THAT(getSymbolNames(*Symbols), UnorderedElementsAre("1", "2", "3"));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> match(const SymbolIndex &I,
|
|
|
|
const FuzzyFindRequest &Req) {
|
|
|
|
std::vector<std::string> Matches;
|
|
|
|
auto Ctx = Context::empty();
|
2017-12-19 19:37:40 +08:00
|
|
|
I.fuzzyFind(Ctx, Req, [&](const Symbol &Sym) {
|
2017-12-21 22:58:44 +08:00
|
|
|
Matches.push_back(
|
|
|
|
(Sym.Scope + (Sym.Scope.empty() ? "" : "::") + Sym.Name).str());
|
2017-12-19 19:37:40 +08:00
|
|
|
});
|
2017-12-15 20:25:02 +08:00
|
|
|
return Matches;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create an ParsedAST for \p Code. Returns None if \p Code is empty.
|
|
|
|
llvm::Optional<ParsedAST> build(std::string Path, llvm::StringRef Code) {
|
|
|
|
Context Ctx = Context::empty();
|
|
|
|
if (Code.empty())
|
|
|
|
return llvm::None;
|
|
|
|
const char *Args[] = {"clang", "-xc++", Path.c_str()};
|
|
|
|
|
|
|
|
auto CI = createInvocationFromCommandLine(Args);
|
|
|
|
|
|
|
|
auto Buf = llvm::MemoryBuffer::getMemBuffer(Code);
|
|
|
|
auto AST = ParsedAST::Build(Ctx, std::move(CI), nullptr, std::move(Buf),
|
|
|
|
std::make_shared<PCHContainerOperations>(),
|
|
|
|
vfs::getRealFileSystem());
|
|
|
|
assert(AST.hasValue());
|
|
|
|
return std::move(*AST);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileIndexTest, IndexAST) {
|
|
|
|
FileIndex M;
|
|
|
|
auto Ctx = Context::empty();
|
|
|
|
M.update(
|
|
|
|
Ctx, "f1",
|
|
|
|
build("f1", "namespace ns { void f() {} class X {}; }").getPointer());
|
|
|
|
|
|
|
|
FuzzyFindRequest Req;
|
2017-12-19 19:37:40 +08:00
|
|
|
Req.Query = "";
|
|
|
|
Req.Scopes = {"ns"};
|
2017-12-15 20:25:02 +08:00
|
|
|
EXPECT_THAT(match(M, Req), UnorderedElementsAre("ns::f", "ns::X"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileIndexTest, NoLocal) {
|
|
|
|
FileIndex M;
|
|
|
|
auto Ctx = Context::empty();
|
|
|
|
M.update(
|
|
|
|
Ctx, "f1",
|
|
|
|
build("f1", "namespace ns { void f() { int local = 0; } class X {}; }")
|
|
|
|
.getPointer());
|
|
|
|
|
|
|
|
FuzzyFindRequest Req;
|
|
|
|
Req.Query = "";
|
|
|
|
EXPECT_THAT(match(M, Req), UnorderedElementsAre("ns", "ns::f", "ns::X"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileIndexTest, IndexMultiASTAndDeduplicate) {
|
|
|
|
FileIndex M;
|
|
|
|
auto Ctx = Context::empty();
|
|
|
|
M.update(
|
|
|
|
Ctx, "f1",
|
|
|
|
build("f1", "namespace ns { void f() {} class X {}; }").getPointer());
|
|
|
|
M.update(
|
|
|
|
Ctx, "f2",
|
|
|
|
build("f2", "namespace ns { void ff() {} class X {}; }").getPointer());
|
|
|
|
|
|
|
|
FuzzyFindRequest Req;
|
2017-12-19 19:37:40 +08:00
|
|
|
Req.Query = "";
|
|
|
|
Req.Scopes = {"ns"};
|
|
|
|
EXPECT_THAT(match(M, Req), UnorderedElementsAre("ns::f", "ns::X", "ns::ff"));
|
2017-12-15 20:25:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileIndexTest, RemoveAST) {
|
|
|
|
FileIndex M;
|
|
|
|
auto Ctx = Context::empty();
|
|
|
|
M.update(
|
|
|
|
Ctx, "f1",
|
|
|
|
build("f1", "namespace ns { void f() {} class X {}; }").getPointer());
|
|
|
|
|
|
|
|
FuzzyFindRequest Req;
|
2017-12-19 19:37:40 +08:00
|
|
|
Req.Query = "";
|
|
|
|
Req.Scopes = {"ns"};
|
2017-12-15 20:25:02 +08:00
|
|
|
EXPECT_THAT(match(M, Req), UnorderedElementsAre("ns::f", "ns::X"));
|
|
|
|
|
|
|
|
M.update(Ctx, "f1", nullptr);
|
|
|
|
EXPECT_THAT(match(M, Req), UnorderedElementsAre());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileIndexTest, RemoveNonExisting) {
|
|
|
|
FileIndex M;
|
|
|
|
auto Ctx = Context::empty();
|
|
|
|
M.update(Ctx, "no", nullptr);
|
|
|
|
EXPECT_THAT(match(M, FuzzyFindRequest()), UnorderedElementsAre());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileIndexTest, ClassMembers) {
|
|
|
|
FileIndex M;
|
|
|
|
auto Ctx = Context::empty();
|
|
|
|
M.update(Ctx, "f1",
|
|
|
|
build("f1", "class X { static int m1; int m2;};").getPointer());
|
|
|
|
|
|
|
|
FuzzyFindRequest Req;
|
|
|
|
Req.Query = "";
|
|
|
|
EXPECT_THAT(match(M, Req), UnorderedElementsAre("X", "X::m1", "X::m2"));
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|