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.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-05-24 23:50:15 +08:00
|
|
|
#include "ClangdUnit.h"
|
|
|
|
#include "TestFS.h"
|
[clangd] Extract scoring/ranking logic, and shave yaks.
Summary:
Code completion scoring was embedded in CodeComplete.cpp, which is bad:
- awkward to test. The mechanisms (extracting info from index/sema) can be
unit-tested well, the policy (scoring) should be quantitatively measured.
Neither was easily possible, and debugging was hard.
The intermediate signal struct makes this easier.
- hard to reuse. This is a bug in workspaceSymbols: it just presents the
results in the index order, which is not sorted in practice, it needs to rank
them!
Also, index implementations care about scoring (both query-dependent and
independent) in order to truncate result lists appropriately.
The main yak shaved here is the build() function that had 3 variants across
unit tests is unified in TestTU.h (rather than adding a 4th variant).
Reviewers: ilya-biryukov
Subscribers: klimek, mgorny, ioeric, MaskRay, jkorous, mgrang, cfe-commits
Differential Revision: https://reviews.llvm.org/D46524
llvm-svn: 332378
2018-05-16 01:43:27 +08:00
|
|
|
#include "TestTU.h"
|
2017-12-15 20:25:02 +08:00
|
|
|
#include "index/FileIndex.h"
|
[clangd] Keep only a limited number of idle ASTs in memory
Summary:
After this commit, clangd will only keep the last 3 accessed ASTs in
memory. Preambles for each of the opened files are still kept in
memory to make completion and AST rebuilds fast.
AST rebuilds are usually fast enough, but having the last ASTs in
memory still considerably improves latency of operations like
findDefinition and documeneHighlight, which are often sent multiple
times a second when moving around the code. So keeping some of the last
accessed ASTs in memory seems like a reasonable tradeoff.
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: malaperle, arphaman, klimek, javed.absar, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D47063
llvm-svn: 333737
2018-06-01 18:08:43 +08:00
|
|
|
#include "clang/Frontend/CompilerInvocation.h"
|
2018-05-24 23:50:15 +08:00
|
|
|
#include "clang/Frontend/PCHContainerOperations.h"
|
|
|
|
#include "clang/Lex/Preprocessor.h"
|
|
|
|
#include "clang/Tooling/CompilationDatabase.h"
|
2017-12-15 20:25:02 +08:00
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
2017-12-24 03:38:03 +08:00
|
|
|
std::unique_ptr<SymbolSlab> numSlab(int Begin, int End) {
|
|
|
|
SymbolSlab::Builder Slab;
|
2017-12-15 20:25:02 +08:00
|
|
|
for (int i = Begin; i <= End; i++)
|
2017-12-24 03:38:03 +08:00
|
|
|
Slab.insert(symbol(std::to_string(i)));
|
|
|
|
return llvm::make_unique<SymbolSlab>(std::move(Slab).build());
|
2017-12-15 20:25:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
|
|
|
|
2017-12-24 03:38:03 +08:00
|
|
|
FS.update("f1", numSlab(1, 3));
|
2017-12-15 20:25:02 +08:00
|
|
|
EXPECT_THAT(getSymbolNames(*FS.allSymbols()),
|
|
|
|
UnorderedElementsAre("1", "2", "3"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileSymbolsTest, Overlap) {
|
|
|
|
FileSymbols FS;
|
2017-12-24 03:38:03 +08:00
|
|
|
FS.update("f1", numSlab(1, 3));
|
|
|
|
FS.update("f2", numSlab(3, 5));
|
2017-12-15 20:25:02 +08:00
|
|
|
EXPECT_THAT(getSymbolNames(*FS.allSymbols()),
|
|
|
|
UnorderedElementsAre("1", "2", "3", "3", "4", "5"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileSymbolsTest, SnapshotAliveAfterRemove) {
|
|
|
|
FileSymbols FS;
|
|
|
|
|
2017-12-24 03:38:03 +08:00
|
|
|
FS.update("f1", numSlab(1, 3));
|
2017-12-15 20:25:02 +08:00
|
|
|
|
|
|
|
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;
|
[clangd] Pass Context implicitly using TLS.
Summary:
Instead of passing Context explicitly around, we now have a thread-local
Context object `Context::current()` which is an implicit argument to
every function.
Most manipulation of this should use the WithContextValue helper, which
augments the current Context to add a single KV pair, and restores the
old context on destruction.
Advantages are:
- less boilerplate in functions that just propagate contexts
- reading most code doesn't require understanding context at all, and
using context as values in fewer places still
- fewer options to pass the "wrong" context when it changes within a
scope (e.g. when using Span)
- contexts pass through interfaces we can't modify, such as VFS
- propagating contexts across threads was slightly tricky (e.g.
copy vs move, no move-init in lambdas), and is now encapsulated in
the threadpool
Disadvantages are all the usual TLS stuff - hidden magic, and
potential for higher memory usage on threads that don't use the
context. (In practice, it's just one pointer)
Reviewers: ilya-biryukov
Subscribers: klimek, jkorous-apple, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D42517
llvm-svn: 323872
2018-01-31 21:40:48 +08:00
|
|
|
I.fuzzyFind(Req, [&](const Symbol &Sym) {
|
2018-01-20 06:18:21 +08:00
|
|
|
Matches.push_back((Sym.Scope + Sym.Name).str());
|
2017-12-19 19:37:40 +08:00
|
|
|
});
|
2017-12-15 20:25:02 +08:00
|
|
|
return Matches;
|
|
|
|
}
|
|
|
|
|
[clangd] Extract scoring/ranking logic, and shave yaks.
Summary:
Code completion scoring was embedded in CodeComplete.cpp, which is bad:
- awkward to test. The mechanisms (extracting info from index/sema) can be
unit-tested well, the policy (scoring) should be quantitatively measured.
Neither was easily possible, and debugging was hard.
The intermediate signal struct makes this easier.
- hard to reuse. This is a bug in workspaceSymbols: it just presents the
results in the index order, which is not sorted in practice, it needs to rank
them!
Also, index implementations care about scoring (both query-dependent and
independent) in order to truncate result lists appropriately.
The main yak shaved here is the build() function that had 3 variants across
unit tests is unified in TestTU.h (rather than adding a 4th variant).
Reviewers: ilya-biryukov
Subscribers: klimek, mgorny, ioeric, MaskRay, jkorous, mgrang, cfe-commits
Differential Revision: https://reviews.llvm.org/D46524
llvm-svn: 332378
2018-05-16 01:43:27 +08:00
|
|
|
// Adds Basename.cpp, which includes Basename.h, which contains Code.
|
|
|
|
void update(FileIndex &M, llvm::StringRef Basename, llvm::StringRef Code) {
|
|
|
|
TestTU File;
|
|
|
|
File.Filename = (Basename + ".cpp").str();
|
|
|
|
File.HeaderFilename = (Basename + ".h").str();
|
|
|
|
File.HeaderCode = Code;
|
|
|
|
auto AST = File.build();
|
2018-05-24 23:50:15 +08:00
|
|
|
M.update(File.Filename, &AST.getASTContext(), AST.getPreprocessorPtr());
|
2017-12-15 20:25:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileIndexTest, IndexAST) {
|
|
|
|
FileIndex M;
|
[clangd] Extract scoring/ranking logic, and shave yaks.
Summary:
Code completion scoring was embedded in CodeComplete.cpp, which is bad:
- awkward to test. The mechanisms (extracting info from index/sema) can be
unit-tested well, the policy (scoring) should be quantitatively measured.
Neither was easily possible, and debugging was hard.
The intermediate signal struct makes this easier.
- hard to reuse. This is a bug in workspaceSymbols: it just presents the
results in the index order, which is not sorted in practice, it needs to rank
them!
Also, index implementations care about scoring (both query-dependent and
independent) in order to truncate result lists appropriately.
The main yak shaved here is the build() function that had 3 variants across
unit tests is unified in TestTU.h (rather than adding a 4th variant).
Reviewers: ilya-biryukov
Subscribers: klimek, mgorny, ioeric, MaskRay, jkorous, mgrang, cfe-commits
Differential Revision: https://reviews.llvm.org/D46524
llvm-svn: 332378
2018-05-16 01:43:27 +08:00
|
|
|
update(M, "f1", "namespace ns { void f() {} class X {}; }");
|
2017-12-15 20:25:02 +08:00
|
|
|
|
|
|
|
FuzzyFindRequest Req;
|
2017-12-19 19:37:40 +08:00
|
|
|
Req.Query = "";
|
2018-01-20 06:18:21 +08:00
|
|
|
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;
|
[clangd] Extract scoring/ranking logic, and shave yaks.
Summary:
Code completion scoring was embedded in CodeComplete.cpp, which is bad:
- awkward to test. The mechanisms (extracting info from index/sema) can be
unit-tested well, the policy (scoring) should be quantitatively measured.
Neither was easily possible, and debugging was hard.
The intermediate signal struct makes this easier.
- hard to reuse. This is a bug in workspaceSymbols: it just presents the
results in the index order, which is not sorted in practice, it needs to rank
them!
Also, index implementations care about scoring (both query-dependent and
independent) in order to truncate result lists appropriately.
The main yak shaved here is the build() function that had 3 variants across
unit tests is unified in TestTU.h (rather than adding a 4th variant).
Reviewers: ilya-biryukov
Subscribers: klimek, mgorny, ioeric, MaskRay, jkorous, mgrang, cfe-commits
Differential Revision: https://reviews.llvm.org/D46524
llvm-svn: 332378
2018-05-16 01:43:27 +08:00
|
|
|
update(M, "f1", "namespace ns { void f() { int local = 0; } class X {}; }");
|
2017-12-15 20:25:02 +08:00
|
|
|
|
|
|
|
FuzzyFindRequest Req;
|
|
|
|
Req.Query = "";
|
|
|
|
EXPECT_THAT(match(M, Req), UnorderedElementsAre("ns", "ns::f", "ns::X"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileIndexTest, IndexMultiASTAndDeduplicate) {
|
|
|
|
FileIndex M;
|
[clangd] Extract scoring/ranking logic, and shave yaks.
Summary:
Code completion scoring was embedded in CodeComplete.cpp, which is bad:
- awkward to test. The mechanisms (extracting info from index/sema) can be
unit-tested well, the policy (scoring) should be quantitatively measured.
Neither was easily possible, and debugging was hard.
The intermediate signal struct makes this easier.
- hard to reuse. This is a bug in workspaceSymbols: it just presents the
results in the index order, which is not sorted in practice, it needs to rank
them!
Also, index implementations care about scoring (both query-dependent and
independent) in order to truncate result lists appropriately.
The main yak shaved here is the build() function that had 3 variants across
unit tests is unified in TestTU.h (rather than adding a 4th variant).
Reviewers: ilya-biryukov
Subscribers: klimek, mgorny, ioeric, MaskRay, jkorous, mgrang, cfe-commits
Differential Revision: https://reviews.llvm.org/D46524
llvm-svn: 332378
2018-05-16 01:43:27 +08:00
|
|
|
update(M, "f1", "namespace ns { void f() {} class X {}; }");
|
|
|
|
update(M, "f2", "namespace ns { void ff() {} class X {}; }");
|
2017-12-15 20:25:02 +08:00
|
|
|
|
|
|
|
FuzzyFindRequest Req;
|
2017-12-19 19:37:40 +08:00
|
|
|
Req.Query = "";
|
2018-01-20 06:18:21 +08:00
|
|
|
Req.Scopes = {"ns::"};
|
2017-12-19 19:37:40 +08:00
|
|
|
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;
|
[clangd] Extract scoring/ranking logic, and shave yaks.
Summary:
Code completion scoring was embedded in CodeComplete.cpp, which is bad:
- awkward to test. The mechanisms (extracting info from index/sema) can be
unit-tested well, the policy (scoring) should be quantitatively measured.
Neither was easily possible, and debugging was hard.
The intermediate signal struct makes this easier.
- hard to reuse. This is a bug in workspaceSymbols: it just presents the
results in the index order, which is not sorted in practice, it needs to rank
them!
Also, index implementations care about scoring (both query-dependent and
independent) in order to truncate result lists appropriately.
The main yak shaved here is the build() function that had 3 variants across
unit tests is unified in TestTU.h (rather than adding a 4th variant).
Reviewers: ilya-biryukov
Subscribers: klimek, mgorny, ioeric, MaskRay, jkorous, mgrang, cfe-commits
Differential Revision: https://reviews.llvm.org/D46524
llvm-svn: 332378
2018-05-16 01:43:27 +08:00
|
|
|
update(M, "f1", "namespace ns { void f() {} class X {}; }");
|
2017-12-15 20:25:02 +08:00
|
|
|
|
|
|
|
FuzzyFindRequest Req;
|
2017-12-19 19:37:40 +08:00
|
|
|
Req.Query = "";
|
2018-01-20 06:18:21 +08:00
|
|
|
Req.Scopes = {"ns::"};
|
2017-12-15 20:25:02 +08:00
|
|
|
EXPECT_THAT(match(M, Req), UnorderedElementsAre("ns::f", "ns::X"));
|
|
|
|
|
2018-05-24 23:50:15 +08:00
|
|
|
M.update("f1.cpp", nullptr, nullptr);
|
2017-12-15 20:25:02 +08:00
|
|
|
EXPECT_THAT(match(M, Req), UnorderedElementsAre());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileIndexTest, RemoveNonExisting) {
|
|
|
|
FileIndex M;
|
2018-05-24 23:50:15 +08:00
|
|
|
M.update("no.cpp", nullptr, nullptr);
|
2017-12-15 20:25:02 +08:00
|
|
|
EXPECT_THAT(match(M, FuzzyFindRequest()), UnorderedElementsAre());
|
|
|
|
}
|
|
|
|
|
[clangd] Add "member" symbols to the index
Summary:
This adds more symbols to the index:
- member variables and functions
- enum constants in scoped enums
The code completion behavior should remain intact but workspace symbols should
now provide much more useful symbols.
Other symbols should be considered such as the ones in "main files" (files not
being included) but this can be done separately as this introduces its fair
share of problems.
Signed-off-by: Marc-Andre Laperle <marc-andre.laperle@ericsson.com>
Reviewers: ioeric, sammccall
Reviewed By: ioeric, sammccall
Subscribers: hokein, sammccall, jkorous, klimek, ilya-biryukov, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44954
llvm-svn: 334017
2018-06-05 22:01:40 +08:00
|
|
|
TEST(FileIndexTest, ClassMembers) {
|
2017-12-15 20:25:02 +08:00
|
|
|
FileIndex M;
|
[clangd] Extract scoring/ranking logic, and shave yaks.
Summary:
Code completion scoring was embedded in CodeComplete.cpp, which is bad:
- awkward to test. The mechanisms (extracting info from index/sema) can be
unit-tested well, the policy (scoring) should be quantitatively measured.
Neither was easily possible, and debugging was hard.
The intermediate signal struct makes this easier.
- hard to reuse. This is a bug in workspaceSymbols: it just presents the
results in the index order, which is not sorted in practice, it needs to rank
them!
Also, index implementations care about scoring (both query-dependent and
independent) in order to truncate result lists appropriately.
The main yak shaved here is the build() function that had 3 variants across
unit tests is unified in TestTU.h (rather than adding a 4th variant).
Reviewers: ilya-biryukov
Subscribers: klimek, mgorny, ioeric, MaskRay, jkorous, mgrang, cfe-commits
Differential Revision: https://reviews.llvm.org/D46524
llvm-svn: 332378
2018-05-16 01:43:27 +08:00
|
|
|
update(M, "f1", "class X { static int m1; int m2; static void f(); };");
|
2017-12-15 20:25:02 +08:00
|
|
|
|
|
|
|
FuzzyFindRequest Req;
|
|
|
|
Req.Query = "";
|
[clangd] Add "member" symbols to the index
Summary:
This adds more symbols to the index:
- member variables and functions
- enum constants in scoped enums
The code completion behavior should remain intact but workspace symbols should
now provide much more useful symbols.
Other symbols should be considered such as the ones in "main files" (files not
being included) but this can be done separately as this introduces its fair
share of problems.
Signed-off-by: Marc-Andre Laperle <marc-andre.laperle@ericsson.com>
Reviewers: ioeric, sammccall
Reviewed By: ioeric, sammccall
Subscribers: hokein, sammccall, jkorous, klimek, ilya-biryukov, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44954
llvm-svn: 334017
2018-06-05 22:01:40 +08:00
|
|
|
EXPECT_THAT(match(M, Req),
|
|
|
|
UnorderedElementsAre("X", "X::m1", "X::m2", "X::f"));
|
2017-12-15 20:25:02 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Not collect include headers for dynamic index for now.
Summary:
The new behaviors introduced by this patch:
o When include collection is enabled, we always set IncludeHeader field in Symbol
even if it's the same as FileURI in decl.
o Disable include collection in FileIndex which is currently only used to build
dynamic index. We should revisit when we actually want to use FileIndex to global
index.
o Code-completion only uses IncludeHeader to insert headers but not FileURI in
CanonicalDeclaration. This ensures that inserted headers are always canonicalized.
Note that include insertion can still be triggered for symbols that are already
included if they are merged from dynamic index and static index, but we would
only use includes that are already canonicalized (e.g. from static index).
Reason for change:
Collecting header includes in dynamic index enables inserting includes for headers
that are not indexed but opened in the editor. Comparing to inserting includes for
symbols in global/static index, this is nice-to-have but would probably require
non-trivial amount of work to get right. For example:
o Currently it's not easy to fully support CanonicalIncludes in dynamic index, given the way
we run dynamic index.
o It's also harder to reason about the correctness of include canonicalization for dynamic index
(i.e. symbols in the current file/TU) than static index where symbols are collected
offline and sanity check is possible before shipping to production.
o We have less control/flexibility over symbol info in the dynamic index
(e.g. URIs, path normalization), which could be used to help make decision when inserting includes.
As header collection (especially canonicalization) is relatively new, and enabling
it for dynamic index would immediately affect current users with only dynamic
index support, I propose we disable it for dynamic index for now to avoid
compromising other hot features like code completion and only support it for
static index where include insertion would likely to bring more value.
Reviewers: ilya-biryukov, sammccall, hokein
Subscribers: klimek, jkorous-apple, cfe-commits
Differential Revision: https://reviews.llvm.org/D43550
llvm-svn: 325764
2018-02-22 18:14:05 +08:00
|
|
|
TEST(FileIndexTest, NoIncludeCollected) {
|
2018-02-20 02:48:44 +08:00
|
|
|
FileIndex M;
|
[clangd] Extract scoring/ranking logic, and shave yaks.
Summary:
Code completion scoring was embedded in CodeComplete.cpp, which is bad:
- awkward to test. The mechanisms (extracting info from index/sema) can be
unit-tested well, the policy (scoring) should be quantitatively measured.
Neither was easily possible, and debugging was hard.
The intermediate signal struct makes this easier.
- hard to reuse. This is a bug in workspaceSymbols: it just presents the
results in the index order, which is not sorted in practice, it needs to rank
them!
Also, index implementations care about scoring (both query-dependent and
independent) in order to truncate result lists appropriately.
The main yak shaved here is the build() function that had 3 variants across
unit tests is unified in TestTU.h (rather than adding a 4th variant).
Reviewers: ilya-biryukov
Subscribers: klimek, mgorny, ioeric, MaskRay, jkorous, mgrang, cfe-commits
Differential Revision: https://reviews.llvm.org/D46524
llvm-svn: 332378
2018-05-16 01:43:27 +08:00
|
|
|
update(M, "f", "class string {};");
|
2018-02-20 02:48:44 +08:00
|
|
|
|
|
|
|
FuzzyFindRequest Req;
|
|
|
|
Req.Query = "";
|
[clangd] Not collect include headers for dynamic index for now.
Summary:
The new behaviors introduced by this patch:
o When include collection is enabled, we always set IncludeHeader field in Symbol
even if it's the same as FileURI in decl.
o Disable include collection in FileIndex which is currently only used to build
dynamic index. We should revisit when we actually want to use FileIndex to global
index.
o Code-completion only uses IncludeHeader to insert headers but not FileURI in
CanonicalDeclaration. This ensures that inserted headers are always canonicalized.
Note that include insertion can still be triggered for symbols that are already
included if they are merged from dynamic index and static index, but we would
only use includes that are already canonicalized (e.g. from static index).
Reason for change:
Collecting header includes in dynamic index enables inserting includes for headers
that are not indexed but opened in the editor. Comparing to inserting includes for
symbols in global/static index, this is nice-to-have but would probably require
non-trivial amount of work to get right. For example:
o Currently it's not easy to fully support CanonicalIncludes in dynamic index, given the way
we run dynamic index.
o It's also harder to reason about the correctness of include canonicalization for dynamic index
(i.e. symbols in the current file/TU) than static index where symbols are collected
offline and sanity check is possible before shipping to production.
o We have less control/flexibility over symbol info in the dynamic index
(e.g. URIs, path normalization), which could be used to help make decision when inserting includes.
As header collection (especially canonicalization) is relatively new, and enabling
it for dynamic index would immediately affect current users with only dynamic
index support, I propose we disable it for dynamic index for now to avoid
compromising other hot features like code completion and only support it for
static index where include insertion would likely to bring more value.
Reviewers: ilya-biryukov, sammccall, hokein
Subscribers: klimek, jkorous-apple, cfe-commits
Differential Revision: https://reviews.llvm.org/D43550
llvm-svn: 325764
2018-02-22 18:14:05 +08:00
|
|
|
bool SeenSymbol = false;
|
2018-02-20 02:48:44 +08:00
|
|
|
M.fuzzyFind(Req, [&](const Symbol &Sym) {
|
[clangd] Not collect include headers for dynamic index for now.
Summary:
The new behaviors introduced by this patch:
o When include collection is enabled, we always set IncludeHeader field in Symbol
even if it's the same as FileURI in decl.
o Disable include collection in FileIndex which is currently only used to build
dynamic index. We should revisit when we actually want to use FileIndex to global
index.
o Code-completion only uses IncludeHeader to insert headers but not FileURI in
CanonicalDeclaration. This ensures that inserted headers are always canonicalized.
Note that include insertion can still be triggered for symbols that are already
included if they are merged from dynamic index and static index, but we would
only use includes that are already canonicalized (e.g. from static index).
Reason for change:
Collecting header includes in dynamic index enables inserting includes for headers
that are not indexed but opened in the editor. Comparing to inserting includes for
symbols in global/static index, this is nice-to-have but would probably require
non-trivial amount of work to get right. For example:
o Currently it's not easy to fully support CanonicalIncludes in dynamic index, given the way
we run dynamic index.
o It's also harder to reason about the correctness of include canonicalization for dynamic index
(i.e. symbols in the current file/TU) than static index where symbols are collected
offline and sanity check is possible before shipping to production.
o We have less control/flexibility over symbol info in the dynamic index
(e.g. URIs, path normalization), which could be used to help make decision when inserting includes.
As header collection (especially canonicalization) is relatively new, and enabling
it for dynamic index would immediately affect current users with only dynamic
index support, I propose we disable it for dynamic index for now to avoid
compromising other hot features like code completion and only support it for
static index where include insertion would likely to bring more value.
Reviewers: ilya-biryukov, sammccall, hokein
Subscribers: klimek, jkorous-apple, cfe-commits
Differential Revision: https://reviews.llvm.org/D43550
llvm-svn: 325764
2018-02-22 18:14:05 +08:00
|
|
|
EXPECT_TRUE(Sym.Detail->IncludeHeader.empty());
|
|
|
|
SeenSymbol = true;
|
2018-02-20 02:48:44 +08:00
|
|
|
});
|
[clangd] Not collect include headers for dynamic index for now.
Summary:
The new behaviors introduced by this patch:
o When include collection is enabled, we always set IncludeHeader field in Symbol
even if it's the same as FileURI in decl.
o Disable include collection in FileIndex which is currently only used to build
dynamic index. We should revisit when we actually want to use FileIndex to global
index.
o Code-completion only uses IncludeHeader to insert headers but not FileURI in
CanonicalDeclaration. This ensures that inserted headers are always canonicalized.
Note that include insertion can still be triggered for symbols that are already
included if they are merged from dynamic index and static index, but we would
only use includes that are already canonicalized (e.g. from static index).
Reason for change:
Collecting header includes in dynamic index enables inserting includes for headers
that are not indexed but opened in the editor. Comparing to inserting includes for
symbols in global/static index, this is nice-to-have but would probably require
non-trivial amount of work to get right. For example:
o Currently it's not easy to fully support CanonicalIncludes in dynamic index, given the way
we run dynamic index.
o It's also harder to reason about the correctness of include canonicalization for dynamic index
(i.e. symbols in the current file/TU) than static index where symbols are collected
offline and sanity check is possible before shipping to production.
o We have less control/flexibility over symbol info in the dynamic index
(e.g. URIs, path normalization), which could be used to help make decision when inserting includes.
As header collection (especially canonicalization) is relatively new, and enabling
it for dynamic index would immediately affect current users with only dynamic
index support, I propose we disable it for dynamic index for now to avoid
compromising other hot features like code completion and only support it for
static index where include insertion would likely to bring more value.
Reviewers: ilya-biryukov, sammccall, hokein
Subscribers: klimek, jkorous-apple, cfe-commits
Differential Revision: https://reviews.llvm.org/D43550
llvm-svn: 325764
2018-02-22 18:14:05 +08:00
|
|
|
EXPECT_TRUE(SeenSymbol);
|
2018-02-20 02:48:44 +08:00
|
|
|
}
|
|
|
|
|
2018-04-13 19:03:07 +08:00
|
|
|
TEST(FileIndexTest, TemplateParamsInLabel) {
|
|
|
|
auto Source = R"cpp(
|
|
|
|
template <class Ty>
|
|
|
|
class vector {
|
|
|
|
};
|
|
|
|
|
2018-04-15 00:27:35 +08:00
|
|
|
template <class Ty, class Arg>
|
|
|
|
vector<Ty> make_vector(Arg A) {}
|
2018-04-13 19:03:07 +08:00
|
|
|
)cpp";
|
|
|
|
|
|
|
|
FileIndex M;
|
[clangd] Extract scoring/ranking logic, and shave yaks.
Summary:
Code completion scoring was embedded in CodeComplete.cpp, which is bad:
- awkward to test. The mechanisms (extracting info from index/sema) can be
unit-tested well, the policy (scoring) should be quantitatively measured.
Neither was easily possible, and debugging was hard.
The intermediate signal struct makes this easier.
- hard to reuse. This is a bug in workspaceSymbols: it just presents the
results in the index order, which is not sorted in practice, it needs to rank
them!
Also, index implementations care about scoring (both query-dependent and
independent) in order to truncate result lists appropriately.
The main yak shaved here is the build() function that had 3 variants across
unit tests is unified in TestTU.h (rather than adding a 4th variant).
Reviewers: ilya-biryukov
Subscribers: klimek, mgorny, ioeric, MaskRay, jkorous, mgrang, cfe-commits
Differential Revision: https://reviews.llvm.org/D46524
llvm-svn: 332378
2018-05-16 01:43:27 +08:00
|
|
|
update(M, "f", Source);
|
2018-04-13 19:03:07 +08:00
|
|
|
|
|
|
|
FuzzyFindRequest Req;
|
|
|
|
Req.Query = "";
|
|
|
|
bool SeenVector = false;
|
|
|
|
bool SeenMakeVector = false;
|
|
|
|
M.fuzzyFind(Req, [&](const Symbol &Sym) {
|
|
|
|
if (Sym.Name == "vector") {
|
|
|
|
EXPECT_EQ(Sym.CompletionLabel, "vector<class Ty>");
|
|
|
|
EXPECT_EQ(Sym.CompletionSnippetInsertText, "vector<${1:class Ty}>");
|
|
|
|
EXPECT_EQ(Sym.CompletionPlainInsertText, "vector");
|
|
|
|
SeenVector = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Sym.Name == "make_vector") {
|
2018-04-15 00:27:35 +08:00
|
|
|
EXPECT_EQ(Sym.CompletionLabel, "make_vector<class Ty>(Arg A)");
|
2018-04-13 19:03:07 +08:00
|
|
|
EXPECT_EQ(Sym.CompletionSnippetInsertText,
|
2018-04-15 00:27:35 +08:00
|
|
|
"make_vector<${1:class Ty}>(${2:Arg A})");
|
2018-04-13 19:03:07 +08:00
|
|
|
EXPECT_EQ(Sym.CompletionPlainInsertText, "make_vector");
|
|
|
|
SeenMakeVector = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
EXPECT_TRUE(SeenVector);
|
|
|
|
EXPECT_TRUE(SeenMakeVector);
|
|
|
|
}
|
|
|
|
|
2018-05-24 23:50:15 +08:00
|
|
|
TEST(FileIndexTest, RebuildWithPreamble) {
|
|
|
|
auto FooCpp = testPath("foo.cpp");
|
|
|
|
auto FooH = testPath("foo.h");
|
|
|
|
// Preparse ParseInputs.
|
|
|
|
ParseInputs PI;
|
|
|
|
PI.CompileCommand.Directory = testRoot();
|
|
|
|
PI.CompileCommand.Filename = FooCpp;
|
|
|
|
PI.CompileCommand.CommandLine = {"clang", "-xc++", FooCpp};
|
|
|
|
|
|
|
|
llvm::StringMap<std::string> Files;
|
|
|
|
Files[FooCpp] = "";
|
|
|
|
Files[FooH] = R"cpp(
|
|
|
|
namespace ns_in_header {
|
|
|
|
int func_in_header();
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
PI.FS = buildTestFS(std::move(Files));
|
|
|
|
|
|
|
|
PI.Contents = R"cpp(
|
|
|
|
#include "foo.h"
|
|
|
|
namespace ns_in_source {
|
|
|
|
int func_in_source();
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
|
|
|
|
// Rebuild the file.
|
[clangd] Keep only a limited number of idle ASTs in memory
Summary:
After this commit, clangd will only keep the last 3 accessed ASTs in
memory. Preambles for each of the opened files are still kept in
memory to make completion and AST rebuilds fast.
AST rebuilds are usually fast enough, but having the last ASTs in
memory still considerably improves latency of operations like
findDefinition and documeneHighlight, which are often sent multiple
times a second when moving around the code. So keeping some of the last
accessed ASTs in memory seems like a reasonable tradeoff.
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: malaperle, arphaman, klimek, javed.absar, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D47063
llvm-svn: 333737
2018-06-01 18:08:43 +08:00
|
|
|
auto CI = buildCompilerInvocation(PI);
|
|
|
|
|
|
|
|
FileIndex Index;
|
|
|
|
bool IndexUpdated = false;
|
|
|
|
buildPreamble(
|
|
|
|
FooCpp, *CI, /*OldPreamble=*/nullptr, tooling::CompileCommand(), PI,
|
|
|
|
std::make_shared<PCHContainerOperations>(), /*StoreInMemory=*/true,
|
|
|
|
[&Index, &IndexUpdated](PathRef FilePath, ASTContext &Ctx,
|
|
|
|
std::shared_ptr<Preprocessor> PP) {
|
|
|
|
EXPECT_FALSE(IndexUpdated) << "Expected only a single index update";
|
|
|
|
IndexUpdated = true;
|
|
|
|
Index.update(FilePath, &Ctx, std::move(PP));
|
|
|
|
});
|
2018-05-24 23:50:15 +08:00
|
|
|
ASSERT_TRUE(IndexUpdated);
|
|
|
|
|
|
|
|
// Check the index contains symbols from the preamble, but not from the main
|
|
|
|
// file.
|
|
|
|
FuzzyFindRequest Req;
|
|
|
|
Req.Query = "";
|
|
|
|
Req.Scopes = {"", "ns_in_header::"};
|
|
|
|
|
|
|
|
EXPECT_THAT(
|
|
|
|
match(Index, Req),
|
|
|
|
UnorderedElementsAre("ns_in_header", "ns_in_header::func_in_header"));
|
|
|
|
}
|
|
|
|
|
2017-12-15 20:25:02 +08:00
|
|
|
} // namespace
|
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|