[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
#include "SyncAPI.h"
|
|
|
|
#include "TestFS.h"
|
2019-06-15 10:26:47 +08:00
|
|
|
#include "TestTU.h"
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
#include "index/Background.h"
|
2018-11-16 17:03:56 +08:00
|
|
|
#include "llvm/Support/ScopedPrinter.h"
|
2018-12-18 23:39:33 +08:00
|
|
|
#include "llvm/Support/Threading.h"
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
#include "gmock/gmock.h"
|
|
|
|
#include "gtest/gtest.h"
|
2018-12-18 23:39:33 +08:00
|
|
|
#include <thread>
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
|
2019-05-06 18:08:47 +08:00
|
|
|
using ::testing::_;
|
|
|
|
using ::testing::AllOf;
|
|
|
|
using ::testing::Contains;
|
|
|
|
using ::testing::ElementsAre;
|
|
|
|
using ::testing::Not;
|
|
|
|
using ::testing::UnorderedElementsAre;
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
|
|
|
|
MATCHER_P(Named, N, "") { return arg.Name == N; }
|
2018-11-14 19:55:45 +08:00
|
|
|
MATCHER(Declared, "") {
|
|
|
|
return !StringRef(arg.CanonicalDeclaration.FileURI).empty();
|
|
|
|
}
|
|
|
|
MATCHER(Defined, "") { return !StringRef(arg.Definition.FileURI).empty(); }
|
|
|
|
MATCHER_P(FileURI, F, "") { return StringRef(arg.Location.FileURI) == F; }
|
2019-05-06 18:08:47 +08:00
|
|
|
::testing::Matcher<const RefSlab &>
|
|
|
|
RefsAre(std::vector<::testing::Matcher<Ref>> Matchers) {
|
|
|
|
return ElementsAre(::testing::Pair(_, UnorderedElementsAreArray(Matchers)));
|
2018-11-06 18:55:21 +08:00
|
|
|
}
|
2018-12-04 19:31:57 +08:00
|
|
|
// URI cannot be empty since it references keys in the IncludeGraph.
|
|
|
|
MATCHER(EmptyIncludeNode, "") {
|
2018-12-05 19:29:27 +08:00
|
|
|
return !arg.IsTU && !arg.URI.empty() && arg.Digest == FileDigest{{0}} &&
|
2018-12-04 19:31:57 +08:00
|
|
|
arg.DirectIncludes.empty();
|
|
|
|
}
|
2019-05-09 22:22:07 +08:00
|
|
|
MATCHER_P(NumReferences, N, "") { return arg.References == N; }
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
|
2018-11-16 17:03:56 +08:00
|
|
|
class MemoryShardStorage : public BackgroundIndexStorage {
|
|
|
|
mutable std::mutex StorageMu;
|
|
|
|
llvm::StringMap<std::string> &Storage;
|
|
|
|
size_t &CacheHits;
|
|
|
|
|
|
|
|
public:
|
|
|
|
MemoryShardStorage(llvm::StringMap<std::string> &Storage, size_t &CacheHits)
|
|
|
|
: Storage(Storage), CacheHits(CacheHits) {}
|
|
|
|
llvm::Error storeShard(llvm::StringRef ShardIdentifier,
|
|
|
|
IndexFileOut Shard) const override {
|
|
|
|
std::lock_guard<std::mutex> Lock(StorageMu);
|
2019-03-08 17:57:33 +08:00
|
|
|
AccessedPaths.insert(ShardIdentifier);
|
2018-11-16 17:03:56 +08:00
|
|
|
Storage[ShardIdentifier] = llvm::to_string(Shard);
|
|
|
|
return llvm::Error::success();
|
|
|
|
}
|
|
|
|
std::unique_ptr<IndexFileIn>
|
|
|
|
loadShard(llvm::StringRef ShardIdentifier) const override {
|
|
|
|
std::lock_guard<std::mutex> Lock(StorageMu);
|
2019-03-08 17:57:33 +08:00
|
|
|
AccessedPaths.insert(ShardIdentifier);
|
2018-11-16 17:03:56 +08:00
|
|
|
if (Storage.find(ShardIdentifier) == Storage.end()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
auto IndexFile = readIndexFile(Storage[ShardIdentifier]);
|
|
|
|
if (!IndexFile) {
|
|
|
|
ADD_FAILURE() << "Error while reading " << ShardIdentifier << ':'
|
|
|
|
<< IndexFile.takeError();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
CacheHits++;
|
|
|
|
return llvm::make_unique<IndexFileIn>(std::move(*IndexFile));
|
|
|
|
}
|
2019-03-08 17:57:33 +08:00
|
|
|
|
|
|
|
mutable llvm::StringSet<> AccessedPaths;
|
2018-11-16 17:03:56 +08:00
|
|
|
};
|
|
|
|
|
2018-11-27 20:09:13 +08:00
|
|
|
class BackgroundIndexTest : public ::testing::Test {
|
|
|
|
protected:
|
2019-04-18 21:46:40 +08:00
|
|
|
BackgroundIndexTest() { BackgroundIndex::preventThreadStarvationInTests(); }
|
2018-11-27 20:09:13 +08:00
|
|
|
};
|
|
|
|
|
2018-12-14 20:39:08 +08:00
|
|
|
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile) {
|
|
|
|
MockFSProvider FS;
|
|
|
|
FS.Files[testPath("root/A.cc")] = "error file";
|
|
|
|
llvm::StringMap<std::string> Storage;
|
|
|
|
size_t CacheHits = 0;
|
|
|
|
MemoryShardStorage MSS(Storage, CacheHits);
|
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
2019-01-22 17:10:20 +08:00
|
|
|
BackgroundIndex Idx(Context::empty(), FS, CDB,
|
2018-12-14 20:39:08 +08:00
|
|
|
[&](llvm::StringRef) { return &MSS; });
|
|
|
|
|
|
|
|
tooling::CompileCommand Cmd;
|
|
|
|
Cmd.Filename = testPath("root/A.cc");
|
|
|
|
Cmd.Directory = testPath("root");
|
|
|
|
Cmd.CommandLine = {"clang++", "-DA=1", testPath("root/A.cc")};
|
|
|
|
CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
|
|
|
|
|
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
|
|
|
}
|
|
|
|
|
2018-11-27 20:09:13 +08:00
|
|
|
TEST_F(BackgroundIndexTest, IndexTwoFiles) {
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
MockFSProvider FS;
|
|
|
|
// a.h yields different symbols when included by A.cc vs B.cc.
|
2018-11-06 18:55:21 +08:00
|
|
|
FS.Files[testPath("root/A.h")] = R"cpp(
|
|
|
|
void common();
|
|
|
|
void f_b();
|
|
|
|
#if A
|
|
|
|
class A_CC {};
|
|
|
|
#else
|
|
|
|
class B_CC{};
|
|
|
|
#endif
|
|
|
|
)cpp";
|
|
|
|
FS.Files[testPath("root/A.cc")] =
|
|
|
|
"#include \"A.h\"\nvoid g() { (void)common; }";
|
|
|
|
FS.Files[testPath("root/B.cc")] =
|
|
|
|
R"cpp(
|
|
|
|
#define A 0
|
|
|
|
#include "A.h"
|
|
|
|
void f_b() {
|
|
|
|
(void)common;
|
2019-05-09 22:22:07 +08:00
|
|
|
(void)common;
|
|
|
|
(void)common;
|
|
|
|
(void)common;
|
2018-11-06 18:55:21 +08:00
|
|
|
})cpp";
|
2018-11-16 17:03:56 +08:00
|
|
|
llvm::StringMap<std::string> Storage;
|
|
|
|
size_t CacheHits = 0;
|
|
|
|
MemoryShardStorage MSS(Storage, CacheHits);
|
[clangd] Auto-index watches global CDB for changes.
Summary:
Instead of receiving compilation commands, auto-index is triggered by just
filenames to reindex, and gets commands from the global comp DB internally.
This has advantages:
- more of the work can be done asynchronously (fetching compilation commands
upfront can be slow for large CDBs)
- we get access to the CDB which can be used to retrieve interpolated commands
for headers (useful in some cases where the original TU goes away)
- fits nicely with the filename-only change observation from r347297
The interface to GlobalCompilationDatabase gets extended: when retrieving a
compile command, the GCDB can optionally report the project the file belongs to.
This naturally fits together with getCompileCommand: it's hard to implement one
without the other. But because most callers don't care, I've ended up with an
awkward optional-out-param-in-virtual method pattern - maybe there's a better
one.
This is the main missing integration point between ClangdServer and
BackgroundIndex, after this we should be able to add an auto-index flag.
Reviewers: ioeric, kadircet
Subscribers: MaskRay, jkorous, arphaman, cfe-commits, ilya-biryukov
Differential Revision: https://reviews.llvm.org/D54865
llvm-svn: 347538
2018-11-26 17:51:50 +08:00
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
2019-01-22 17:10:20 +08:00
|
|
|
BackgroundIndex Idx(Context::empty(), FS, CDB,
|
2018-11-16 17:03:56 +08:00
|
|
|
[&](llvm::StringRef) { return &MSS; });
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
|
|
|
|
tooling::CompileCommand Cmd;
|
|
|
|
Cmd.Filename = testPath("root/A.cc");
|
|
|
|
Cmd.Directory = testPath("root");
|
2018-11-06 18:55:21 +08:00
|
|
|
Cmd.CommandLine = {"clang++", "-DA=1", testPath("root/A.cc")};
|
2018-12-04 19:31:57 +08:00
|
|
|
CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
|
2018-11-06 18:55:21 +08:00
|
|
|
|
[clangd] Enable auto-index behind a flag.
Summary:
Ownership and configuration:
The auto-index (background index) is maintained by ClangdServer, like Dynamic.
(This means ClangdServer will be able to enqueue preamble indexing in future).
For now it's enabled by a simple boolean flag in ClangdServer::Options, but
we probably want to eventually allow injecting the storage strategy.
New 'sync' command:
In order to meaningfully test the integration (not just unit-test components)
we need a way for tests to ensure the asynchronous index reads/writes occur
before a certain point.
Because these tests and assertions are few, I think exposing an explicit "sync"
command for use in tests is simpler than allowing threading to be completely
disabled in the background index (as we do for TUScheduler).
Bugs:
I fixed a couple of trivial bugs I found while testing, but there's one I can't.
JSONCompilationDatabase::getAllFiles() may return relative paths, and currently
we trigger an assertion that assumes they are absolute.
There's no efficient way to resolve them (you have to retrieve the corresponding
command and then resolve against its directory property). In general I think
this behavior is broken and we should fix it in JSONCompilationDatabase and
require CompilationDatabase::getAllFiles() to be absolute.
Reviewers: kadircet
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D54894
llvm-svn: 347567
2018-11-27 00:00:11 +08:00
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
2019-05-09 22:22:07 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(Idx, ""),
|
|
|
|
UnorderedElementsAre(AllOf(Named("common"), NumReferences(1U)),
|
|
|
|
AllOf(Named("A_CC"), NumReferences(0U)),
|
|
|
|
AllOf(Named("g"), NumReferences(0U)),
|
|
|
|
AllOf(Named("f_b"), Declared(),
|
|
|
|
Not(Defined()), NumReferences(0U))));
|
2018-11-06 18:55:21 +08:00
|
|
|
|
|
|
|
Cmd.Filename = testPath("root/B.cc");
|
|
|
|
Cmd.CommandLine = {"clang++", Cmd.Filename};
|
2019-05-09 22:22:07 +08:00
|
|
|
CDB.setCompileCommand(testPath("root/B.cc"), Cmd);
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
|
[clangd] Enable auto-index behind a flag.
Summary:
Ownership and configuration:
The auto-index (background index) is maintained by ClangdServer, like Dynamic.
(This means ClangdServer will be able to enqueue preamble indexing in future).
For now it's enabled by a simple boolean flag in ClangdServer::Options, but
we probably want to eventually allow injecting the storage strategy.
New 'sync' command:
In order to meaningfully test the integration (not just unit-test components)
we need a way for tests to ensure the asynchronous index reads/writes occur
before a certain point.
Because these tests and assertions are few, I think exposing an explicit "sync"
command for use in tests is simpler than allowing threading to be completely
disabled in the background index (as we do for TUScheduler).
Bugs:
I fixed a couple of trivial bugs I found while testing, but there's one I can't.
JSONCompilationDatabase::getAllFiles() may return relative paths, and currently
we trigger an assertion that assumes they are absolute.
There's no efficient way to resolve them (you have to retrieve the corresponding
command and then resolve against its directory property). In general I think
this behavior is broken and we should fix it in JSONCompilationDatabase and
require CompilationDatabase::getAllFiles() to be absolute.
Reviewers: kadircet
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D54894
llvm-svn: 347567
2018-11-27 00:00:11 +08:00
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
2018-11-06 18:55:21 +08:00
|
|
|
// B_CC is dropped as we don't collect symbols from A.h in this compilation.
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(Idx, ""),
|
2019-05-09 22:22:07 +08:00
|
|
|
UnorderedElementsAre(AllOf(Named("common"), NumReferences(5U)),
|
|
|
|
AllOf(Named("A_CC"), NumReferences(0U)),
|
|
|
|
AllOf(Named("g"), NumReferences(0U)),
|
|
|
|
AllOf(Named("f_b"), Declared(), Defined(),
|
|
|
|
NumReferences(1U))));
|
2018-11-06 18:55:21 +08:00
|
|
|
|
|
|
|
auto Syms = runFuzzyFind(Idx, "common");
|
|
|
|
EXPECT_THAT(Syms, UnorderedElementsAre(Named("common")));
|
|
|
|
auto Common = *Syms.begin();
|
|
|
|
EXPECT_THAT(getRefs(Idx, Common.ID),
|
|
|
|
RefsAre({FileURI("unittest:///root/A.h"),
|
|
|
|
FileURI("unittest:///root/A.cc"),
|
2019-05-09 22:22:07 +08:00
|
|
|
FileURI("unittest:///root/B.cc"),
|
|
|
|
FileURI("unittest:///root/B.cc"),
|
|
|
|
FileURI("unittest:///root/B.cc"),
|
2018-11-06 18:55:21 +08:00
|
|
|
FileURI("unittest:///root/B.cc")}));
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
}
|
|
|
|
|
2019-01-11 01:03:04 +08:00
|
|
|
TEST_F(BackgroundIndexTest, ShardStorageTest) {
|
2018-11-16 17:03:56 +08:00
|
|
|
MockFSProvider FS;
|
|
|
|
FS.Files[testPath("root/A.h")] = R"cpp(
|
|
|
|
void common();
|
|
|
|
void f_b();
|
|
|
|
class A_CC {};
|
|
|
|
)cpp";
|
2019-06-15 10:26:47 +08:00
|
|
|
std::string A_CC = "";
|
|
|
|
FS.Files[testPath("root/A.cc")] = R"cpp(
|
|
|
|
#include "A.h"
|
|
|
|
void g() { (void)common; }
|
|
|
|
class B_CC : public A_CC {};
|
|
|
|
)cpp";
|
2018-11-16 17:03:56 +08:00
|
|
|
|
|
|
|
llvm::StringMap<std::string> Storage;
|
|
|
|
size_t CacheHits = 0;
|
|
|
|
MemoryShardStorage MSS(Storage, CacheHits);
|
|
|
|
|
|
|
|
tooling::CompileCommand Cmd;
|
|
|
|
Cmd.Filename = testPath("root/A.cc");
|
|
|
|
Cmd.Directory = testPath("root");
|
|
|
|
Cmd.CommandLine = {"clang++", testPath("root/A.cc")};
|
|
|
|
// Check nothing is loaded from Storage, but A.cc and A.h has been stored.
|
|
|
|
{
|
[clangd] Auto-index watches global CDB for changes.
Summary:
Instead of receiving compilation commands, auto-index is triggered by just
filenames to reindex, and gets commands from the global comp DB internally.
This has advantages:
- more of the work can be done asynchronously (fetching compilation commands
upfront can be slow for large CDBs)
- we get access to the CDB which can be used to retrieve interpolated commands
for headers (useful in some cases where the original TU goes away)
- fits nicely with the filename-only change observation from r347297
The interface to GlobalCompilationDatabase gets extended: when retrieving a
compile command, the GCDB can optionally report the project the file belongs to.
This naturally fits together with getCompileCommand: it's hard to implement one
without the other. But because most callers don't care, I've ended up with an
awkward optional-out-param-in-virtual method pattern - maybe there's a better
one.
This is the main missing integration point between ClangdServer and
BackgroundIndex, after this we should be able to add an auto-index flag.
Reviewers: ioeric, kadircet
Subscribers: MaskRay, jkorous, arphaman, cfe-commits, ilya-biryukov
Differential Revision: https://reviews.llvm.org/D54865
llvm-svn: 347538
2018-11-26 17:51:50 +08:00
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
2019-01-22 17:10:20 +08:00
|
|
|
BackgroundIndex Idx(Context::empty(), FS, CDB,
|
2018-11-16 17:03:56 +08:00
|
|
|
[&](llvm::StringRef) { return &MSS; });
|
2018-12-04 19:31:57 +08:00
|
|
|
CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
|
[clangd] Enable auto-index behind a flag.
Summary:
Ownership and configuration:
The auto-index (background index) is maintained by ClangdServer, like Dynamic.
(This means ClangdServer will be able to enqueue preamble indexing in future).
For now it's enabled by a simple boolean flag in ClangdServer::Options, but
we probably want to eventually allow injecting the storage strategy.
New 'sync' command:
In order to meaningfully test the integration (not just unit-test components)
we need a way for tests to ensure the asynchronous index reads/writes occur
before a certain point.
Because these tests and assertions are few, I think exposing an explicit "sync"
command for use in tests is simpler than allowing threading to be completely
disabled in the background index (as we do for TUScheduler).
Bugs:
I fixed a couple of trivial bugs I found while testing, but there's one I can't.
JSONCompilationDatabase::getAllFiles() may return relative paths, and currently
we trigger an assertion that assumes they are absolute.
There's no efficient way to resolve them (you have to retrieve the corresponding
command and then resolve against its directory property). In general I think
this behavior is broken and we should fix it in JSONCompilationDatabase and
require CompilationDatabase::getAllFiles() to be absolute.
Reviewers: kadircet
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D54894
llvm-svn: 347567
2018-11-27 00:00:11 +08:00
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
2018-11-16 17:03:56 +08:00
|
|
|
}
|
|
|
|
EXPECT_EQ(CacheHits, 0U);
|
|
|
|
EXPECT_EQ(Storage.size(), 2U);
|
|
|
|
|
2019-01-11 01:03:04 +08:00
|
|
|
{
|
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
2019-01-22 17:10:20 +08:00
|
|
|
BackgroundIndex Idx(Context::empty(), FS, CDB,
|
2019-01-11 01:03:04 +08:00
|
|
|
[&](llvm::StringRef) { return &MSS; });
|
|
|
|
CDB.setCompileCommand(testPath("root"), Cmd);
|
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
|
|
|
}
|
|
|
|
EXPECT_EQ(CacheHits, 2U); // Check both A.cc and A.h loaded from cache.
|
|
|
|
EXPECT_EQ(Storage.size(), 2U);
|
|
|
|
|
2018-11-16 17:03:56 +08:00
|
|
|
auto ShardHeader = MSS.loadShard(testPath("root/A.h"));
|
|
|
|
EXPECT_NE(ShardHeader, nullptr);
|
|
|
|
EXPECT_THAT(
|
|
|
|
*ShardHeader->Symbols,
|
|
|
|
UnorderedElementsAre(Named("common"), Named("A_CC"),
|
|
|
|
AllOf(Named("f_b"), Declared(), Not(Defined()))));
|
|
|
|
for (const auto &Ref : *ShardHeader->Refs)
|
|
|
|
EXPECT_THAT(Ref.second,
|
|
|
|
UnorderedElementsAre(FileURI("unittest:///root/A.h")));
|
|
|
|
|
|
|
|
auto ShardSource = MSS.loadShard(testPath("root/A.cc"));
|
|
|
|
EXPECT_NE(ShardSource, nullptr);
|
2019-06-15 10:26:47 +08:00
|
|
|
EXPECT_THAT(*ShardSource->Symbols,
|
|
|
|
UnorderedElementsAre(Named("g"), Named("B_CC")));
|
|
|
|
for (const auto &Ref : *ShardSource->Refs)
|
|
|
|
EXPECT_THAT(Ref.second,
|
|
|
|
UnorderedElementsAre(FileURI("unittest:///root/A.cc")));
|
|
|
|
|
|
|
|
// The BaseOf relationship between A_CC and B_CC is stored in the file
|
|
|
|
// containing the definition of the subject (A_CC)
|
|
|
|
SymbolID A = findSymbol(*ShardHeader->Symbols, "A_CC").ID;
|
|
|
|
SymbolID B = findSymbol(*ShardSource->Symbols, "B_CC").ID;
|
|
|
|
EXPECT_THAT(
|
|
|
|
*ShardHeader->Relations,
|
|
|
|
UnorderedElementsAre(Relation{A, index::SymbolRole::RelationBaseOf, B}));
|
|
|
|
// (and not in the file containing the definition of the object (B_CC)).
|
|
|
|
EXPECT_EQ(ShardSource->Relations->size(), 0u);
|
2018-11-16 17:03:56 +08:00
|
|
|
}
|
|
|
|
|
2018-12-04 19:31:57 +08:00
|
|
|
TEST_F(BackgroundIndexTest, DirectIncludesTest) {
|
|
|
|
MockFSProvider FS;
|
|
|
|
FS.Files[testPath("root/B.h")] = "";
|
|
|
|
FS.Files[testPath("root/A.h")] = R"cpp(
|
|
|
|
#include "B.h"
|
|
|
|
void common();
|
|
|
|
void f_b();
|
|
|
|
class A_CC {};
|
|
|
|
)cpp";
|
|
|
|
std::string A_CC = "#include \"A.h\"\nvoid g() { (void)common; }";
|
|
|
|
FS.Files[testPath("root/A.cc")] = A_CC;
|
|
|
|
|
|
|
|
llvm::StringMap<std::string> Storage;
|
|
|
|
size_t CacheHits = 0;
|
|
|
|
MemoryShardStorage MSS(Storage, CacheHits);
|
|
|
|
|
|
|
|
tooling::CompileCommand Cmd;
|
|
|
|
Cmd.Filename = testPath("root/A.cc");
|
|
|
|
Cmd.Directory = testPath("root");
|
|
|
|
Cmd.CommandLine = {"clang++", testPath("root/A.cc")};
|
|
|
|
{
|
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
2019-01-22 17:10:20 +08:00
|
|
|
BackgroundIndex Idx(Context::empty(), FS, CDB,
|
2018-12-04 19:31:57 +08:00
|
|
|
[&](llvm::StringRef) { return &MSS; });
|
|
|
|
CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
|
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
|
|
|
}
|
|
|
|
|
|
|
|
auto ShardSource = MSS.loadShard(testPath("root/A.cc"));
|
|
|
|
EXPECT_TRUE(ShardSource->Sources);
|
|
|
|
EXPECT_EQ(ShardSource->Sources->size(), 2U); // A.cc, A.h
|
|
|
|
EXPECT_THAT(
|
|
|
|
ShardSource->Sources->lookup("unittest:///root/A.cc").DirectIncludes,
|
|
|
|
UnorderedElementsAre("unittest:///root/A.h"));
|
|
|
|
EXPECT_NE(ShardSource->Sources->lookup("unittest:///root/A.cc").Digest,
|
2018-12-05 19:29:27 +08:00
|
|
|
FileDigest{{0}});
|
2018-12-04 19:31:57 +08:00
|
|
|
EXPECT_THAT(ShardSource->Sources->lookup("unittest:///root/A.h"),
|
|
|
|
EmptyIncludeNode());
|
|
|
|
|
|
|
|
auto ShardHeader = MSS.loadShard(testPath("root/A.h"));
|
|
|
|
EXPECT_TRUE(ShardHeader->Sources);
|
|
|
|
EXPECT_EQ(ShardHeader->Sources->size(), 2U); // A.h, B.h
|
|
|
|
EXPECT_THAT(
|
|
|
|
ShardHeader->Sources->lookup("unittest:///root/A.h").DirectIncludes,
|
|
|
|
UnorderedElementsAre("unittest:///root/B.h"));
|
|
|
|
EXPECT_NE(ShardHeader->Sources->lookup("unittest:///root/A.h").Digest,
|
2018-12-05 19:29:27 +08:00
|
|
|
FileDigest{{0}});
|
2018-12-04 19:31:57 +08:00
|
|
|
EXPECT_THAT(ShardHeader->Sources->lookup("unittest:///root/B.h"),
|
|
|
|
EmptyIncludeNode());
|
|
|
|
}
|
|
|
|
|
2019-01-07 19:18:11 +08:00
|
|
|
// FIXME: figure out the right timeouts or rewrite to not use the timeouts and
|
|
|
|
// re-enable.
|
|
|
|
TEST_F(BackgroundIndexTest, DISABLED_PeriodicalIndex) {
|
2018-12-18 23:39:33 +08:00
|
|
|
MockFSProvider FS;
|
|
|
|
llvm::StringMap<std::string> Storage;
|
|
|
|
size_t CacheHits = 0;
|
|
|
|
MemoryShardStorage MSS(Storage, CacheHits);
|
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
|
|
|
BackgroundIndex Idx(
|
2019-01-22 17:10:20 +08:00
|
|
|
Context::empty(), FS, CDB, [&](llvm::StringRef) { return &MSS; },
|
2018-12-21 00:27:19 +08:00
|
|
|
/*BuildIndexPeriodMs=*/500);
|
2018-12-18 23:39:33 +08:00
|
|
|
|
|
|
|
FS.Files[testPath("root/A.cc")] = "#include \"A.h\"";
|
|
|
|
|
|
|
|
tooling::CompileCommand Cmd;
|
|
|
|
FS.Files[testPath("root/A.h")] = "class X {};";
|
|
|
|
Cmd.Filename = testPath("root/A.cc");
|
|
|
|
Cmd.CommandLine = {"clang++", Cmd.Filename};
|
|
|
|
CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
|
|
|
|
|
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
|
|
|
EXPECT_THAT(runFuzzyFind(Idx, ""), ElementsAre());
|
2018-12-21 00:27:19 +08:00
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
2018-12-18 23:39:33 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(Idx, ""), ElementsAre(Named("X")));
|
|
|
|
|
|
|
|
FS.Files[testPath("root/A.h")] = "class Y {};";
|
|
|
|
FS.Files[testPath("root/A.cc")] += " "; // Force reindex the file.
|
|
|
|
Cmd.CommandLine = {"clang++", "-DA=1", testPath("root/A.cc")};
|
|
|
|
CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
|
|
|
|
|
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
|
|
|
EXPECT_THAT(runFuzzyFind(Idx, ""), ElementsAre(Named("X")));
|
2018-12-21 00:27:19 +08:00
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
2018-12-18 23:39:33 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(Idx, ""), ElementsAre(Named("Y")));
|
|
|
|
}
|
|
|
|
|
2019-01-11 01:03:04 +08:00
|
|
|
TEST_F(BackgroundIndexTest, ShardStorageLoad) {
|
|
|
|
MockFSProvider FS;
|
|
|
|
FS.Files[testPath("root/A.h")] = R"cpp(
|
|
|
|
void common();
|
|
|
|
void f_b();
|
|
|
|
class A_CC {};
|
|
|
|
)cpp";
|
|
|
|
FS.Files[testPath("root/A.cc")] =
|
|
|
|
"#include \"A.h\"\nvoid g() { (void)common; }";
|
|
|
|
|
|
|
|
llvm::StringMap<std::string> Storage;
|
|
|
|
size_t CacheHits = 0;
|
|
|
|
MemoryShardStorage MSS(Storage, CacheHits);
|
|
|
|
|
|
|
|
tooling::CompileCommand Cmd;
|
|
|
|
Cmd.Filename = testPath("root/A.cc");
|
|
|
|
Cmd.Directory = testPath("root");
|
|
|
|
Cmd.CommandLine = {"clang++", testPath("root/A.cc")};
|
|
|
|
// Check nothing is loaded from Storage, but A.cc and A.h has been stored.
|
|
|
|
{
|
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
2019-01-22 17:10:20 +08:00
|
|
|
BackgroundIndex Idx(Context::empty(), FS, CDB,
|
2019-01-11 01:03:04 +08:00
|
|
|
[&](llvm::StringRef) { return &MSS; });
|
|
|
|
CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
|
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Change header.
|
|
|
|
FS.Files[testPath("root/A.h")] = R"cpp(
|
|
|
|
void common();
|
|
|
|
void f_b();
|
|
|
|
class A_CC {};
|
|
|
|
class A_CCnew {};
|
|
|
|
)cpp";
|
|
|
|
{
|
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
2019-01-22 17:10:20 +08:00
|
|
|
BackgroundIndex Idx(Context::empty(), FS, CDB,
|
2019-01-11 01:03:04 +08:00
|
|
|
[&](llvm::StringRef) { return &MSS; });
|
|
|
|
CDB.setCompileCommand(testPath("root"), Cmd);
|
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
|
|
|
}
|
|
|
|
EXPECT_EQ(CacheHits, 2U); // Check both A.cc and A.h loaded from cache.
|
|
|
|
|
|
|
|
// Check if the new symbol has arrived.
|
|
|
|
auto ShardHeader = MSS.loadShard(testPath("root/A.h"));
|
|
|
|
EXPECT_NE(ShardHeader, nullptr);
|
|
|
|
EXPECT_THAT(*ShardHeader->Symbols, Contains(Named("A_CCnew")));
|
|
|
|
|
|
|
|
// Change source.
|
|
|
|
FS.Files[testPath("root/A.cc")] =
|
|
|
|
"#include \"A.h\"\nvoid g() { (void)common; }\nvoid f_b() {}";
|
|
|
|
{
|
|
|
|
CacheHits = 0;
|
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
2019-01-22 17:10:20 +08:00
|
|
|
BackgroundIndex Idx(Context::empty(), FS, CDB,
|
2019-01-11 01:03:04 +08:00
|
|
|
[&](llvm::StringRef) { return &MSS; });
|
|
|
|
CDB.setCompileCommand(testPath("root"), Cmd);
|
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
|
|
|
}
|
|
|
|
EXPECT_EQ(CacheHits, 2U); // Check both A.cc and A.h loaded from cache.
|
|
|
|
|
|
|
|
// Check if the new symbol has arrived.
|
2019-01-15 17:03:33 +08:00
|
|
|
ShardHeader = MSS.loadShard(testPath("root/A.h"));
|
2019-01-11 01:03:04 +08:00
|
|
|
EXPECT_NE(ShardHeader, nullptr);
|
2019-01-15 17:03:33 +08:00
|
|
|
EXPECT_THAT(*ShardHeader->Symbols, Contains(Named("A_CCnew")));
|
|
|
|
auto ShardSource = MSS.loadShard(testPath("root/A.cc"));
|
|
|
|
EXPECT_NE(ShardSource, nullptr);
|
2019-01-11 01:03:04 +08:00
|
|
|
EXPECT_THAT(*ShardSource->Symbols,
|
|
|
|
Contains(AllOf(Named("f_b"), Declared(), Defined())));
|
|
|
|
}
|
|
|
|
|
2019-01-15 17:03:33 +08:00
|
|
|
TEST_F(BackgroundIndexTest, ShardStorageEmptyFile) {
|
|
|
|
MockFSProvider FS;
|
|
|
|
FS.Files[testPath("root/A.h")] = R"cpp(
|
|
|
|
void common();
|
|
|
|
void f_b();
|
|
|
|
class A_CC {};
|
|
|
|
)cpp";
|
|
|
|
FS.Files[testPath("root/B.h")] = R"cpp(
|
|
|
|
#include "A.h"
|
|
|
|
)cpp";
|
|
|
|
FS.Files[testPath("root/A.cc")] =
|
|
|
|
"#include \"B.h\"\nvoid g() { (void)common; }";
|
|
|
|
|
|
|
|
llvm::StringMap<std::string> Storage;
|
|
|
|
size_t CacheHits = 0;
|
|
|
|
MemoryShardStorage MSS(Storage, CacheHits);
|
|
|
|
|
|
|
|
tooling::CompileCommand Cmd;
|
|
|
|
Cmd.Filename = testPath("root/A.cc");
|
|
|
|
Cmd.Directory = testPath("root");
|
|
|
|
Cmd.CommandLine = {"clang++", testPath("root/A.cc")};
|
|
|
|
// Check that A.cc, A.h and B.h has been stored.
|
|
|
|
{
|
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
2019-01-22 17:10:20 +08:00
|
|
|
BackgroundIndex Idx(Context::empty(), FS, CDB,
|
2019-01-15 17:03:33 +08:00
|
|
|
[&](llvm::StringRef) { return &MSS; });
|
|
|
|
CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
|
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
|
|
|
}
|
|
|
|
EXPECT_THAT(Storage.keys(),
|
|
|
|
UnorderedElementsAre(testPath("root/A.cc"), testPath("root/A.h"),
|
|
|
|
testPath("root/B.h")));
|
|
|
|
auto ShardHeader = MSS.loadShard(testPath("root/B.h"));
|
|
|
|
EXPECT_NE(ShardHeader, nullptr);
|
|
|
|
EXPECT_TRUE(ShardHeader->Symbols->empty());
|
|
|
|
|
|
|
|
// Check that A.cc, A.h and B.h has been loaded.
|
|
|
|
{
|
|
|
|
CacheHits = 0;
|
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
2019-01-22 17:10:20 +08:00
|
|
|
BackgroundIndex Idx(Context::empty(), FS, CDB,
|
2019-01-15 17:03:33 +08:00
|
|
|
[&](llvm::StringRef) { return &MSS; });
|
|
|
|
CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
|
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
|
|
|
}
|
|
|
|
EXPECT_EQ(CacheHits, 3U);
|
|
|
|
|
|
|
|
// Update B.h to contain some symbols.
|
|
|
|
FS.Files[testPath("root/B.h")] = R"cpp(
|
|
|
|
#include "A.h"
|
|
|
|
void new_func();
|
|
|
|
)cpp";
|
|
|
|
// Check that B.h has been stored with new contents.
|
|
|
|
{
|
|
|
|
CacheHits = 0;
|
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
2019-01-22 17:10:20 +08:00
|
|
|
BackgroundIndex Idx(Context::empty(), FS, CDB,
|
2019-01-15 17:03:33 +08:00
|
|
|
[&](llvm::StringRef) { return &MSS; });
|
|
|
|
CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
|
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
|
|
|
}
|
|
|
|
EXPECT_EQ(CacheHits, 3U);
|
|
|
|
ShardHeader = MSS.loadShard(testPath("root/B.h"));
|
|
|
|
EXPECT_NE(ShardHeader, nullptr);
|
|
|
|
EXPECT_THAT(*ShardHeader->Symbols,
|
|
|
|
Contains(AllOf(Named("new_func"), Declared(), Not(Defined()))));
|
|
|
|
}
|
|
|
|
|
2019-03-08 17:57:33 +08:00
|
|
|
TEST_F(BackgroundIndexTest, NoDotsInAbsPath) {
|
|
|
|
MockFSProvider FS;
|
|
|
|
llvm::StringMap<std::string> Storage;
|
|
|
|
size_t CacheHits = 0;
|
|
|
|
MemoryShardStorage MSS(Storage, CacheHits);
|
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
|
|
|
BackgroundIndex Idx(Context::empty(), FS, CDB,
|
|
|
|
[&](llvm::StringRef) { return &MSS; });
|
|
|
|
|
|
|
|
tooling::CompileCommand Cmd;
|
|
|
|
FS.Files[testPath("root/A.cc")] = "";
|
|
|
|
Cmd.Filename = "../A.cc";
|
|
|
|
Cmd.Directory = testPath("root/build");
|
|
|
|
Cmd.CommandLine = {"clang++", "../A.cc"};
|
|
|
|
CDB.setCompileCommand(testPath("root/build/../A.cc"), Cmd);
|
|
|
|
|
|
|
|
FS.Files[testPath("root/B.cc")] = "";
|
|
|
|
Cmd.Filename = "./B.cc";
|
|
|
|
Cmd.Directory = testPath("root");
|
|
|
|
Cmd.CommandLine = {"clang++", "./B.cc"};
|
|
|
|
CDB.setCompileCommand(testPath("root/./B.cc"), Cmd);
|
|
|
|
|
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
|
|
|
for (llvm::StringRef AbsPath : MSS.AccessedPaths.keys()) {
|
|
|
|
EXPECT_FALSE(AbsPath.contains("./")) << AbsPath;
|
|
|
|
EXPECT_FALSE(AbsPath.contains("../")) << AbsPath;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-04 17:51:43 +08:00
|
|
|
TEST_F(BackgroundIndexTest, UncompilableFiles) {
|
|
|
|
MockFSProvider FS;
|
|
|
|
llvm::StringMap<std::string> Storage;
|
|
|
|
size_t CacheHits = 0;
|
|
|
|
MemoryShardStorage MSS(Storage, CacheHits);
|
|
|
|
OverlayCDB CDB(/*Base=*/nullptr);
|
|
|
|
BackgroundIndex Idx(Context::empty(), FS, CDB,
|
|
|
|
[&](llvm::StringRef) { return &MSS; });
|
|
|
|
|
|
|
|
tooling::CompileCommand Cmd;
|
|
|
|
FS.Files[testPath("A.h")] = "void foo();";
|
|
|
|
FS.Files[testPath("B.h")] = "#include \"C.h\"\nasdf;";
|
|
|
|
FS.Files[testPath("C.h")] = "";
|
|
|
|
FS.Files[testPath("A.cc")] = R"cpp(
|
|
|
|
#include "A.h"
|
|
|
|
#include "B.h"
|
|
|
|
#include "not_found_header.h"
|
|
|
|
|
|
|
|
void foo() {}
|
|
|
|
)cpp";
|
|
|
|
Cmd.Filename = "../A.cc";
|
|
|
|
Cmd.Directory = testPath("build");
|
|
|
|
Cmd.CommandLine = {"clang++", "../A.cc"};
|
|
|
|
CDB.setCompileCommand(testPath("build/../A.cc"), Cmd);
|
|
|
|
ASSERT_TRUE(Idx.blockUntilIdleForTest());
|
|
|
|
|
|
|
|
// Make sure we only store the shard for main file.
|
|
|
|
EXPECT_THAT(Storage.keys(), ElementsAre(testPath("A.cc")));
|
|
|
|
auto Shard = MSS.loadShard(testPath("A.cc"));
|
|
|
|
EXPECT_THAT(*Shard->Symbols, UnorderedElementsAre(Named("foo")));
|
|
|
|
EXPECT_THAT(Shard->Sources->keys(),
|
|
|
|
UnorderedElementsAre("unittest:///A.cc", "unittest:///A.h",
|
|
|
|
"unittest:///B.h"));
|
|
|
|
}
|
|
|
|
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|