2017-12-15 20:25:02 +08:00
|
|
|
//===-- FileIndexTests.cpp ---------------------------*- C++ -*-----------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2017-12-15 20:25:02 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-10-15 19:46:26 +08:00
|
|
|
#include "AST.h"
|
2018-10-15 23:04:03 +08:00
|
|
|
#include "Annotations.h"
|
2018-05-24 23:50:15 +08:00
|
|
|
#include "ClangdUnit.h"
|
2018-10-15 23:04:03 +08:00
|
|
|
#include "SyncAPI.h"
|
2018-05-24 23:50:15 +08:00
|
|
|
#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"
|
2019-02-05 00:19:57 +08:00
|
|
|
#include "index/CanonicalIncludes.h"
|
2017-12-15 20:25:02 +08:00
|
|
|
#include "index/FileIndex.h"
|
2018-11-06 18:55:21 +08:00
|
|
|
#include "index/Index.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-10-15 19:46:26 +08:00
|
|
|
#include "clang/Frontend/Utils.h"
|
2018-09-19 17:35:04 +08:00
|
|
|
#include "clang/Index/IndexSymbol.h"
|
2018-05-24 23:50:15 +08:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
|
|
|
#include "clang/Tooling/CompilationDatabase.h"
|
2018-10-15 23:04:03 +08:00
|
|
|
#include "gmock/gmock.h"
|
2017-12-15 20:25:02 +08:00
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
2019-05-06 18:08:47 +08:00
|
|
|
using ::testing::_;
|
|
|
|
using ::testing::AllOf;
|
|
|
|
using ::testing::Contains;
|
|
|
|
using ::testing::ElementsAre;
|
|
|
|
using ::testing::IsEmpty;
|
|
|
|
using ::testing::Pair;
|
|
|
|
using ::testing::UnorderedElementsAre;
|
2018-09-01 03:53:37 +08:00
|
|
|
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
MATCHER_P(RefRange, Range, "") {
|
[clangd] Encode Line/Column as a 32-bits integer.
Summary:
This would buy us more memory. Using a 32-bits integer is enough for
most human-readable source code (up to 4M lines and 4K columns).
Previsouly, we used 8 bytes for a position, now 4 bytes, it would save
us 8 bytes for each Ref and each Symbol instance.
For LLVM-project binary index file, we save ~13% memory.
| Before | After |
| 412MB | 355MB |
Reviewers: sammccall
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53363
llvm-svn: 344735
2018-10-18 18:43:50 +08:00
|
|
|
return std::make_tuple(arg.Location.Start.line(), arg.Location.Start.column(),
|
|
|
|
arg.Location.End.line(), arg.Location.End.column()) ==
|
|
|
|
std::make_tuple(Range.start.line, Range.start.character,
|
|
|
|
Range.end.line, Range.end.character);
|
2018-09-01 03:53:37 +08:00
|
|
|
}
|
2019-01-07 23:45:19 +08:00
|
|
|
MATCHER_P(FileURI, F, "") { return llvm::StringRef(arg.Location.FileURI) == F; }
|
2018-11-14 19:55:45 +08:00
|
|
|
MATCHER_P(DeclURI, U, "") {
|
2019-01-07 23:45:19 +08:00
|
|
|
return llvm::StringRef(arg.CanonicalDeclaration.FileURI) == U;
|
|
|
|
}
|
|
|
|
MATCHER_P(DefURI, U, "") {
|
|
|
|
return llvm::StringRef(arg.Definition.FileURI) == U;
|
2018-11-14 19:55:45 +08:00
|
|
|
}
|
2018-10-15 23:04:03 +08:00
|
|
|
MATCHER_P(QName, N, "") { return (arg.Scope + arg.Name).str() == N; }
|
2019-05-09 22:22:07 +08:00
|
|
|
MATCHER_P(NumReferences, N, "") { return arg.References == N; }
|
[clangd] Perform merge for main file symbols.
Summary:
Previously, we randomly pick one main file symbol in dynamic index, we
may loose the ideal symbol (with definition location) in the index.
It fixes the issue where sometimes we fail to go to the symbol definition, see:
1. call go-to-decl on Foo in Foo.cpp
2. jump to Foo.h, call go-to-def on Foo in Foo.h
we can't go back to Foo.cpp -- because we open Foo.cpp, Foo.h in clangd, both
files have Foo symbol (one with def&decl, one with decl only), we randomely
choose one.
Reviewers: kadircet
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D63425
llvm-svn: 363568
2019-06-17 22:49:18 +08:00
|
|
|
MATCHER_P(hasOrign, O, "") { return bool(arg.Origin & O); }
|
2017-12-15 20:25:02 +08:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
namespace {
|
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)));
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
}
|
2017-12-15 20:25:02 +08:00
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
Symbol symbol(llvm::StringRef ID) {
|
2017-12-15 20:25:02 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2018-11-14 19:55:45 +08:00
|
|
|
std::unique_ptr<RefSlab> refSlab(const SymbolID &ID, const char *Path) {
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
RefSlab::Builder Slab;
|
|
|
|
Ref R;
|
|
|
|
R.Location.FileURI = Path;
|
|
|
|
R.Kind = RefKind::Reference;
|
|
|
|
Slab.insert(ID, R);
|
|
|
|
return llvm::make_unique<RefSlab>(std::move(Slab).build());
|
2018-09-01 03:53:37 +08:00
|
|
|
}
|
|
|
|
|
2017-12-15 20:25:02 +08:00
|
|
|
TEST(FileSymbolsTest, UpdateAndGet) {
|
|
|
|
FileSymbols FS;
|
2018-10-16 16:53:52 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(*FS.buildIndex(IndexType::Light), ""), IsEmpty());
|
2017-12-15 20:25:02 +08:00
|
|
|
|
2019-06-15 10:26:47 +08:00
|
|
|
FS.update("f1", numSlab(1, 3), refSlab(SymbolID("1"), "f1.cc"), nullptr,
|
|
|
|
false);
|
2018-10-16 16:53:52 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(*FS.buildIndex(IndexType::Light), ""),
|
2018-10-15 23:04:03 +08:00
|
|
|
UnorderedElementsAre(QName("1"), QName("2"), QName("3")));
|
2018-10-16 16:53:52 +08:00
|
|
|
EXPECT_THAT(getRefs(*FS.buildIndex(IndexType::Light), SymbolID("1")),
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
RefsAre({FileURI("f1.cc")}));
|
2017-12-15 20:25:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileSymbolsTest, Overlap) {
|
|
|
|
FileSymbols FS;
|
2019-06-15 10:26:47 +08:00
|
|
|
FS.update("f1", numSlab(1, 3), nullptr, nullptr, false);
|
|
|
|
FS.update("f2", numSlab(3, 5), nullptr, nullptr, false);
|
2018-10-16 16:53:52 +08:00
|
|
|
for (auto Type : {IndexType::Light, IndexType::Heavy})
|
|
|
|
EXPECT_THAT(runFuzzyFind(*FS.buildIndex(Type), ""),
|
|
|
|
UnorderedElementsAre(QName("1"), QName("2"), QName("3"),
|
|
|
|
QName("4"), QName("5")));
|
2017-12-15 20:25:02 +08:00
|
|
|
}
|
|
|
|
|
2018-11-06 18:55:21 +08:00
|
|
|
TEST(FileSymbolsTest, MergeOverlap) {
|
|
|
|
FileSymbols FS;
|
|
|
|
auto OneSymboSlab = [](Symbol Sym) {
|
|
|
|
SymbolSlab::Builder S;
|
|
|
|
S.insert(Sym);
|
2019-01-07 23:45:19 +08:00
|
|
|
return llvm::make_unique<SymbolSlab>(std::move(S).build());
|
2018-11-06 18:55:21 +08:00
|
|
|
};
|
|
|
|
auto X1 = symbol("x");
|
|
|
|
X1.CanonicalDeclaration.FileURI = "file:///x1";
|
|
|
|
auto X2 = symbol("x");
|
|
|
|
X2.Definition.FileURI = "file:///x2";
|
|
|
|
|
2019-06-15 10:26:47 +08:00
|
|
|
FS.update("f1", OneSymboSlab(X1), nullptr, nullptr, false);
|
|
|
|
FS.update("f2", OneSymboSlab(X2), nullptr, nullptr, false);
|
2018-11-06 18:55:21 +08:00
|
|
|
for (auto Type : {IndexType::Light, IndexType::Heavy})
|
|
|
|
EXPECT_THAT(
|
|
|
|
runFuzzyFind(*FS.buildIndex(Type, DuplicateHandling::Merge), "x"),
|
|
|
|
UnorderedElementsAre(
|
|
|
|
AllOf(QName("x"), DeclURI("file:///x1"), DefURI("file:///x2"))));
|
|
|
|
}
|
|
|
|
|
2017-12-15 20:25:02 +08:00
|
|
|
TEST(FileSymbolsTest, SnapshotAliveAfterRemove) {
|
|
|
|
FileSymbols FS;
|
|
|
|
|
2018-09-01 03:53:37 +08:00
|
|
|
SymbolID ID("1");
|
2019-06-15 10:26:47 +08:00
|
|
|
FS.update("f1", numSlab(1, 3), refSlab(ID, "f1.cc"), nullptr, false);
|
2017-12-15 20:25:02 +08:00
|
|
|
|
2018-10-16 16:53:52 +08:00
|
|
|
auto Symbols = FS.buildIndex(IndexType::Light);
|
2018-10-15 23:04:03 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(*Symbols, ""),
|
|
|
|
UnorderedElementsAre(QName("1"), QName("2"), QName("3")));
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
EXPECT_THAT(getRefs(*Symbols, ID), RefsAre({FileURI("f1.cc")}));
|
2017-12-15 20:25:02 +08:00
|
|
|
|
2019-06-15 10:26:47 +08:00
|
|
|
FS.update("f1", nullptr, nullptr, nullptr, false);
|
2018-10-16 16:53:52 +08:00
|
|
|
auto Empty = FS.buildIndex(IndexType::Light);
|
2018-10-15 23:04:03 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(*Empty, ""), IsEmpty());
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
EXPECT_THAT(getRefs(*Empty, ID), ElementsAre());
|
2018-09-01 03:53:37 +08:00
|
|
|
|
2018-10-15 23:04:03 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(*Symbols, ""),
|
|
|
|
UnorderedElementsAre(QName("1"), QName("2"), QName("3")));
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
EXPECT_THAT(getRefs(*Symbols, ID), RefsAre({FileURI("f1.cc")}));
|
2017-12-15 20:25:02 +08:00
|
|
|
}
|
|
|
|
|
[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.
|
2019-01-07 23:45:19 +08:00
|
|
|
void update(FileIndex &M, llvm::StringRef Basename, llvm::StringRef Code) {
|
[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
|
|
|
TestTU File;
|
|
|
|
File.Filename = (Basename + ".cpp").str();
|
|
|
|
File.HeaderFilename = (Basename + ".h").str();
|
|
|
|
File.HeaderCode = Code;
|
|
|
|
auto AST = File.build();
|
2019-02-05 00:19:57 +08:00
|
|
|
M.updatePreamble(File.Filename, AST.getASTContext(), AST.getPreprocessorPtr(),
|
|
|
|
AST.getCanonicalIncludes());
|
2017-12-15 20:25:02 +08:00
|
|
|
}
|
|
|
|
|
2018-06-15 16:55:00 +08:00
|
|
|
TEST(FileIndexTest, CustomizedURIScheme) {
|
[clangd] Cleanup: stop passing around list of supported URI schemes.
Summary:
Instead of passing around a list of supported URI schemes in clangd, we
expose an interface to convert a path to URI using any compatible scheme
that has been registered. It favors customized schemes and falls
back to "file" when no other scheme works.
Changes in this patch are:
- URI::create(AbsPath, URISchemes) -> URI::create(AbsPath). The new API finds a
compatible scheme from the registry.
- Remove URISchemes option everywhere (ClangdServer, SymbolCollecter, FileIndex etc).
- Unit tests will use "unittest" by default.
- Move "test" scheme from ClangdLSPServer to ClangdMain.cpp, and only
register the test scheme when lit-test or enable-lit-scheme is set.
(The new flag is added to make lit protocol.test work; I wonder if there
is alternative here.)
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D54800
llvm-svn: 347467
2018-11-22 23:02:05 +08:00
|
|
|
FileIndex M;
|
2018-06-15 16:55:00 +08:00
|
|
|
update(M, "f", "class string {};");
|
|
|
|
|
2018-10-15 23:04:03 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(M, ""), ElementsAre(DeclURI("unittest:///f.h")));
|
2018-06-15 16:55:00 +08:00
|
|
|
}
|
|
|
|
|
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::"};
|
2018-10-15 23:04:03 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(M, Req),
|
|
|
|
UnorderedElementsAre(QName("ns::f"), QName("ns::X")));
|
2017-12-15 20:25:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2018-10-15 23:04:03 +08:00
|
|
|
EXPECT_THAT(
|
|
|
|
runFuzzyFind(M, ""),
|
|
|
|
UnorderedElementsAre(QName("ns"), QName("ns::f"), QName("ns::X")));
|
2017-12-15 20:25:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2018-01-20 06:18:21 +08:00
|
|
|
Req.Scopes = {"ns::"};
|
2018-10-15 23:04:03 +08:00
|
|
|
EXPECT_THAT(
|
|
|
|
runFuzzyFind(M, Req),
|
|
|
|
UnorderedElementsAre(QName("ns::f"), QName("ns::X"), QName("ns::ff")));
|
2017-12-15 20:25:02 +08:00
|
|
|
}
|
|
|
|
|
[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
|
|
|
|
2018-10-15 23:04:03 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(M, ""),
|
|
|
|
UnorderedElementsAre(QName("X"), QName("X::m1"), QName("X::m2"),
|
|
|
|
QName("X::f")));
|
2017-12-15 20:25:02 +08:00
|
|
|
}
|
|
|
|
|
2019-02-05 00:19:57 +08:00
|
|
|
TEST(FileIndexTest, IncludeCollected) {
|
2018-02-20 02:48:44 +08:00
|
|
|
FileIndex M;
|
2019-02-05 00:19:57 +08:00
|
|
|
update(
|
|
|
|
M, "f",
|
|
|
|
"// IWYU pragma: private, include <the/good/header.h>\nclass string {};");
|
2018-02-20 02:48:44 +08:00
|
|
|
|
2018-10-15 23:04:03 +08:00
|
|
|
auto Symbols = runFuzzyFind(M, "");
|
|
|
|
EXPECT_THAT(Symbols, ElementsAre(_));
|
2019-02-05 00:19:57 +08:00
|
|
|
EXPECT_THAT(Symbols.begin()->IncludeHeaders.front().IncludeHeader,
|
|
|
|
"<the/good/header.h>");
|
2018-02-20 02:48:44 +08:00
|
|
|
}
|
|
|
|
|
2019-02-11 18:31:13 +08:00
|
|
|
TEST(FileIndexTest, HasSystemHeaderMappingsInPreamble) {
|
[clangd] Include insertion: require header guards, drop other heuristics, treat .def like .inc.
Summary:
We do have some reports of include insertion behaving badly in some
codebases. Requiring header guards both makes sense in principle, and is
likely to disable this "nice-to-have" feature in codebases where headers don't
follow the expected pattern.
With this we can drop some other heuristics, such as looking at file
extensions to detect known non-headers - implementation files have no guards.
One wrinkle here is #import - objc headers may not have guards because
they're intended to be used via #import. If the header is the main file
or is #included, we won't collect locations - merge should take care of
this if we see the file #imported somewhere. Seems likely to be OK.
Headers which have a canonicalization (stdlib, IWYU) are exempt from this check.
*.inc files continue to be handled by looking up to the including file.
This patch also adds *.def here - tablegen wants this pattern too.
In terms of code structure, the division between SymbolCollector and
CanonicalIncludes has shifted: SymbolCollector is responsible for more.
This is because SymbolCollector has all the SourceManager/HeaderSearch access
needed for checking for guards, and we interleave these checks with the *.def
checks in a loop (potentially).
We could hand all the info into CanonicalIncludes and put the logic there
if that's preferable.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D60316
llvm-svn: 358571
2019-04-17 18:36:02 +08:00
|
|
|
TestTU TU;
|
|
|
|
TU.HeaderCode = "class Foo{};";
|
|
|
|
TU.HeaderFilename = "algorithm";
|
2019-02-11 18:31:13 +08:00
|
|
|
|
[clangd] Include insertion: require header guards, drop other heuristics, treat .def like .inc.
Summary:
We do have some reports of include insertion behaving badly in some
codebases. Requiring header guards both makes sense in principle, and is
likely to disable this "nice-to-have" feature in codebases where headers don't
follow the expected pattern.
With this we can drop some other heuristics, such as looking at file
extensions to detect known non-headers - implementation files have no guards.
One wrinkle here is #import - objc headers may not have guards because
they're intended to be used via #import. If the header is the main file
or is #included, we won't collect locations - merge should take care of
this if we see the file #imported somewhere. Seems likely to be OK.
Headers which have a canonicalization (stdlib, IWYU) are exempt from this check.
*.inc files continue to be handled by looking up to the including file.
This patch also adds *.def here - tablegen wants this pattern too.
In terms of code structure, the division between SymbolCollector and
CanonicalIncludes has shifted: SymbolCollector is responsible for more.
This is because SymbolCollector has all the SourceManager/HeaderSearch access
needed for checking for guards, and we interleave these checks with the *.def
checks in a loop (potentially).
We could hand all the info into CanonicalIncludes and put the logic there
if that's preferable.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D60316
llvm-svn: 358571
2019-04-17 18:36:02 +08:00
|
|
|
auto Symbols = runFuzzyFind(*TU.index(), "");
|
2019-02-11 18:31:13 +08:00
|
|
|
EXPECT_THAT(Symbols, ElementsAre(_));
|
|
|
|
EXPECT_THAT(Symbols.begin()->IncludeHeaders.front().IncludeHeader,
|
2019-02-11 21:01:47 +08:00
|
|
|
"<algorithm>");
|
2019-02-11 18:31:13 +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
|
|
|
|
2018-10-15 23:04:03 +08:00
|
|
|
auto Symbols = runFuzzyFind(M, "");
|
|
|
|
EXPECT_THAT(Symbols,
|
|
|
|
UnorderedElementsAre(QName("vector"), QName("make_vector")));
|
|
|
|
auto It = Symbols.begin();
|
|
|
|
Symbol Vector = *It++;
|
|
|
|
Symbol MakeVector = *It++;
|
|
|
|
if (MakeVector.Name == "vector")
|
|
|
|
std::swap(MakeVector, Vector);
|
2018-04-13 19:03:07 +08:00
|
|
|
|
2018-10-15 23:04:03 +08:00
|
|
|
EXPECT_EQ(Vector.Signature, "<class Ty>");
|
|
|
|
EXPECT_EQ(Vector.CompletionSnippetSuffix, "<${1:class Ty}>");
|
|
|
|
|
|
|
|
EXPECT_EQ(MakeVector.Signature, "<class Ty>(Arg A)");
|
|
|
|
EXPECT_EQ(MakeVector.CompletionSnippetSuffix, "<${1:class Ty}>(${2:Arg A})");
|
2018-04-13 19:03:07 +08:00
|
|
|
}
|
|
|
|
|
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};
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::StringMap<std::string> Files;
|
2018-05-24 23:50:15 +08:00
|
|
|
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,
|
2019-04-04 20:56:03 +08:00
|
|
|
/*StoreInMemory=*/true,
|
2019-02-05 00:19:57 +08:00
|
|
|
[&](ASTContext &Ctx, std::shared_ptr<Preprocessor> PP,
|
|
|
|
const CanonicalIncludes &CanonIncludes) {
|
[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
|
|
|
EXPECT_FALSE(IndexUpdated) << "Expected only a single index update";
|
|
|
|
IndexUpdated = true;
|
2019-02-05 00:19:57 +08:00
|
|
|
Index.updatePreamble(FooCpp, Ctx, std::move(PP), CanonIncludes);
|
[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
|
|
|
});
|
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::"};
|
|
|
|
|
2018-10-15 23:04:03 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(Index, Req),
|
|
|
|
UnorderedElementsAre(QName("ns_in_header"),
|
|
|
|
QName("ns_in_header::func_in_header")));
|
2018-05-24 23:50:15 +08:00
|
|
|
}
|
|
|
|
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
TEST(FileIndexTest, Refs) {
|
2018-09-01 03:53:37 +08:00
|
|
|
const char *HeaderCode = "class Foo {};";
|
|
|
|
Annotations MainCode(R"cpp(
|
|
|
|
void f() {
|
|
|
|
$foo[[Foo]] foo;
|
|
|
|
}
|
|
|
|
)cpp");
|
|
|
|
|
|
|
|
auto Foo =
|
|
|
|
findSymbol(TestTU::withHeaderCode(HeaderCode).headerSymbols(), "Foo");
|
|
|
|
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
RefsRequest Request;
|
2018-09-01 03:53:37 +08:00
|
|
|
Request.IDs = {Foo.ID};
|
|
|
|
|
[clangd] Cleanup: stop passing around list of supported URI schemes.
Summary:
Instead of passing around a list of supported URI schemes in clangd, we
expose an interface to convert a path to URI using any compatible scheme
that has been registered. It favors customized schemes and falls
back to "file" when no other scheme works.
Changes in this patch are:
- URI::create(AbsPath, URISchemes) -> URI::create(AbsPath). The new API finds a
compatible scheme from the registry.
- Remove URISchemes option everywhere (ClangdServer, SymbolCollecter, FileIndex etc).
- Unit tests will use "unittest" by default.
- Move "test" scheme from ClangdLSPServer to ClangdMain.cpp, and only
register the test scheme when lit-test or enable-lit-scheme is set.
(The new flag is added to make lit protocol.test work; I wonder if there
is alternative here.)
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D54800
llvm-svn: 347467
2018-11-22 23:02:05 +08:00
|
|
|
FileIndex Index;
|
2018-09-01 03:53:37 +08:00
|
|
|
// Add test.cc
|
|
|
|
TestTU Test;
|
|
|
|
Test.HeaderCode = HeaderCode;
|
|
|
|
Test.Code = MainCode.code();
|
|
|
|
Test.Filename = "test.cc";
|
|
|
|
auto AST = Test.build();
|
2018-09-18 21:35:16 +08:00
|
|
|
Index.updateMain(Test.Filename, AST);
|
2018-09-01 03:53:37 +08:00
|
|
|
// Add test2.cc
|
|
|
|
TestTU Test2;
|
|
|
|
Test2.HeaderCode = HeaderCode;
|
|
|
|
Test2.Code = MainCode.code();
|
|
|
|
Test2.Filename = "test2.cc";
|
|
|
|
AST = Test2.build();
|
2018-09-18 21:35:16 +08:00
|
|
|
Index.updateMain(Test2.Filename, AST);
|
2018-09-01 03:53:37 +08:00
|
|
|
|
2018-10-04 22:20:22 +08:00
|
|
|
EXPECT_THAT(getRefs(Index, Foo.ID),
|
[clangd] SymbolOccurrences -> Refs and cleanup
Summary:
A few things that I noticed while merging the SwapIndex patch:
- SymbolOccurrences and particularly SymbolOccurrenceSlab are unwieldy names,
and these names appear *a lot*. Ref, RefSlab, etc seem clear enough
and read/format much better.
- The asymmetry between SymbolSlab and RefSlab (build() vs freeze()) is
confusing and irritating, and doesn't even save much code.
Avoiding RefSlab::Builder was my idea, but it was a bad one; add it.
- DenseMap<SymbolID, ArrayRef<Ref>> seems like a reasonable compromise for
constructing MemIndex - and means many less wasted allocations than the
current DenseMap<SymbolID, vector<Ref*>> for FileIndex, and none for
slabs.
- RefSlab::find() is not actually used for anything, so we can throw
away the DenseMap and keep the representation much more compact.
- A few naming/consistency fixes: e.g. Slabs,Refs -> Symbols,Refs.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D51605
llvm-svn: 341368
2018-09-04 22:39:56 +08:00
|
|
|
RefsAre({AllOf(RefRange(MainCode.range("foo")),
|
|
|
|
FileURI("unittest:///test.cc")),
|
|
|
|
AllOf(RefRange(MainCode.range("foo")),
|
|
|
|
FileURI("unittest:///test2.cc"))}));
|
2018-09-01 03:53:37 +08:00
|
|
|
}
|
|
|
|
|
2018-09-19 17:35:04 +08:00
|
|
|
TEST(FileIndexTest, CollectMacros) {
|
|
|
|
FileIndex M;
|
|
|
|
update(M, "f", "#define CLANGD 1");
|
2018-10-15 23:04:03 +08:00
|
|
|
EXPECT_THAT(runFuzzyFind(M, ""), Contains(QName("CLANGD")));
|
2018-09-19 17:35:04 +08:00
|
|
|
}
|
|
|
|
|
2019-06-15 10:26:47 +08:00
|
|
|
TEST(FileIndexTest, Relations) {
|
|
|
|
TestTU TU;
|
|
|
|
TU.Filename = "f.cpp";
|
|
|
|
TU.HeaderFilename = "f.h";
|
|
|
|
TU.HeaderCode = "class A {}; class B : public A {};";
|
|
|
|
auto AST = TU.build();
|
|
|
|
FileIndex Index;
|
|
|
|
Index.updatePreamble(TU.Filename, AST.getASTContext(),
|
|
|
|
AST.getPreprocessorPtr(), AST.getCanonicalIncludes());
|
|
|
|
SymbolID A = findSymbol(TU.headerSymbols(), "A").ID;
|
|
|
|
uint32_t Results = 0;
|
|
|
|
RelationsRequest Req;
|
|
|
|
Req.Subjects.insert(A);
|
|
|
|
Req.Predicate = index::SymbolRole::RelationBaseOf;
|
|
|
|
Index.relations(Req, [&](const SymbolID &, const Symbol &) { ++Results; });
|
|
|
|
EXPECT_EQ(Results, 1u);
|
|
|
|
}
|
|
|
|
|
2018-10-15 19:46:26 +08:00
|
|
|
TEST(FileIndexTest, ReferencesInMainFileWithPreamble) {
|
[clangd] Include insertion: require header guards, drop other heuristics, treat .def like .inc.
Summary:
We do have some reports of include insertion behaving badly in some
codebases. Requiring header guards both makes sense in principle, and is
likely to disable this "nice-to-have" feature in codebases where headers don't
follow the expected pattern.
With this we can drop some other heuristics, such as looking at file
extensions to detect known non-headers - implementation files have no guards.
One wrinkle here is #import - objc headers may not have guards because
they're intended to be used via #import. If the header is the main file
or is #included, we won't collect locations - merge should take care of
this if we see the file #imported somewhere. Seems likely to be OK.
Headers which have a canonicalization (stdlib, IWYU) are exempt from this check.
*.inc files continue to be handled by looking up to the including file.
This patch also adds *.def here - tablegen wants this pattern too.
In terms of code structure, the division between SymbolCollector and
CanonicalIncludes has shifted: SymbolCollector is responsible for more.
This is because SymbolCollector has all the SourceManager/HeaderSearch access
needed for checking for guards, and we interleave these checks with the *.def
checks in a loop (potentially).
We could hand all the info into CanonicalIncludes and put the logic there
if that's preferable.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D60316
llvm-svn: 358571
2019-04-17 18:36:02 +08:00
|
|
|
TestTU TU;
|
|
|
|
TU.HeaderCode = "class Foo{};";
|
2018-10-15 19:46:26 +08:00
|
|
|
Annotations Main(R"cpp(
|
|
|
|
#include "foo.h"
|
|
|
|
void f() {
|
|
|
|
[[Foo]] foo;
|
|
|
|
}
|
|
|
|
)cpp");
|
[clangd] Include insertion: require header guards, drop other heuristics, treat .def like .inc.
Summary:
We do have some reports of include insertion behaving badly in some
codebases. Requiring header guards both makes sense in principle, and is
likely to disable this "nice-to-have" feature in codebases where headers don't
follow the expected pattern.
With this we can drop some other heuristics, such as looking at file
extensions to detect known non-headers - implementation files have no guards.
One wrinkle here is #import - objc headers may not have guards because
they're intended to be used via #import. If the header is the main file
or is #included, we won't collect locations - merge should take care of
this if we see the file #imported somewhere. Seems likely to be OK.
Headers which have a canonicalization (stdlib, IWYU) are exempt from this check.
*.inc files continue to be handled by looking up to the including file.
This patch also adds *.def here - tablegen wants this pattern too.
In terms of code structure, the division between SymbolCollector and
CanonicalIncludes has shifted: SymbolCollector is responsible for more.
This is because SymbolCollector has all the SourceManager/HeaderSearch access
needed for checking for guards, and we interleave these checks with the *.def
checks in a loop (potentially).
We could hand all the info into CanonicalIncludes and put the logic there
if that's preferable.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D60316
llvm-svn: 358571
2019-04-17 18:36:02 +08:00
|
|
|
TU.Code = Main.code();
|
|
|
|
auto AST = TU.build();
|
2018-10-15 19:46:26 +08:00
|
|
|
FileIndex Index;
|
[clangd] Include insertion: require header guards, drop other heuristics, treat .def like .inc.
Summary:
We do have some reports of include insertion behaving badly in some
codebases. Requiring header guards both makes sense in principle, and is
likely to disable this "nice-to-have" feature in codebases where headers don't
follow the expected pattern.
With this we can drop some other heuristics, such as looking at file
extensions to detect known non-headers - implementation files have no guards.
One wrinkle here is #import - objc headers may not have guards because
they're intended to be used via #import. If the header is the main file
or is #included, we won't collect locations - merge should take care of
this if we see the file #imported somewhere. Seems likely to be OK.
Headers which have a canonicalization (stdlib, IWYU) are exempt from this check.
*.inc files continue to be handled by looking up to the including file.
This patch also adds *.def here - tablegen wants this pattern too.
In terms of code structure, the division between SymbolCollector and
CanonicalIncludes has shifted: SymbolCollector is responsible for more.
This is because SymbolCollector has all the SourceManager/HeaderSearch access
needed for checking for guards, and we interleave these checks with the *.def
checks in a loop (potentially).
We could hand all the info into CanonicalIncludes and put the logic there
if that's preferable.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D60316
llvm-svn: 358571
2019-04-17 18:36:02 +08:00
|
|
|
Index.updateMain(testPath(TU.Filename), AST);
|
2018-10-15 19:46:26 +08:00
|
|
|
|
|
|
|
// Expect to see references in main file, references in headers are excluded
|
|
|
|
// because we only index main AST.
|
[clangd] Include insertion: require header guards, drop other heuristics, treat .def like .inc.
Summary:
We do have some reports of include insertion behaving badly in some
codebases. Requiring header guards both makes sense in principle, and is
likely to disable this "nice-to-have" feature in codebases where headers don't
follow the expected pattern.
With this we can drop some other heuristics, such as looking at file
extensions to detect known non-headers - implementation files have no guards.
One wrinkle here is #import - objc headers may not have guards because
they're intended to be used via #import. If the header is the main file
or is #included, we won't collect locations - merge should take care of
this if we see the file #imported somewhere. Seems likely to be OK.
Headers which have a canonicalization (stdlib, IWYU) are exempt from this check.
*.inc files continue to be handled by looking up to the including file.
This patch also adds *.def here - tablegen wants this pattern too.
In terms of code structure, the division between SymbolCollector and
CanonicalIncludes has shifted: SymbolCollector is responsible for more.
This is because SymbolCollector has all the SourceManager/HeaderSearch access
needed for checking for guards, and we interleave these checks with the *.def
checks in a loop (potentially).
We could hand all the info into CanonicalIncludes and put the logic there
if that's preferable.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D60316
llvm-svn: 358571
2019-04-17 18:36:02 +08:00
|
|
|
EXPECT_THAT(getRefs(Index, findSymbol(TU.headerSymbols(), "Foo").ID),
|
|
|
|
RefsAre({RefRange(Main.range())}));
|
2018-10-15 19:46:26 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Perform merge for main file symbols.
Summary:
Previously, we randomly pick one main file symbol in dynamic index, we
may loose the ideal symbol (with definition location) in the index.
It fixes the issue where sometimes we fail to go to the symbol definition, see:
1. call go-to-decl on Foo in Foo.cpp
2. jump to Foo.h, call go-to-def on Foo in Foo.h
we can't go back to Foo.cpp -- because we open Foo.cpp, Foo.h in clangd, both
files have Foo symbol (one with def&decl, one with decl only), we randomely
choose one.
Reviewers: kadircet
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D63425
llvm-svn: 363568
2019-06-17 22:49:18 +08:00
|
|
|
TEST(FileIndexTest, MergeMainFileSymbols) {
|
|
|
|
const char* CommonHeader = "void foo();";
|
|
|
|
TestTU Header = TestTU::withCode(CommonHeader);
|
|
|
|
TestTU Cpp = TestTU::withCode("void foo() {}");
|
|
|
|
Cpp.Filename = "foo.cpp";
|
|
|
|
Cpp.HeaderFilename = "foo.h";
|
|
|
|
Cpp.HeaderCode = CommonHeader;
|
|
|
|
|
|
|
|
FileIndex Index;
|
|
|
|
auto HeaderAST = Header.build();
|
|
|
|
auto CppAST = Cpp.build();
|
|
|
|
Index.updateMain(testPath("foo.h"), HeaderAST);
|
|
|
|
Index.updateMain(testPath("foo.cpp"), CppAST);
|
|
|
|
|
|
|
|
auto Symbols = runFuzzyFind(Index, "");
|
|
|
|
// Check foo is merged, foo in Cpp wins (as we see the definition there).
|
|
|
|
EXPECT_THAT(Symbols, ElementsAre(AllOf(DeclURI("unittest:///foo.h"),
|
|
|
|
DefURI("unittest:///foo.cpp"),
|
|
|
|
hasOrign(SymbolOrigin::Merge))));
|
|
|
|
}
|
|
|
|
|
2019-05-09 22:22:07 +08:00
|
|
|
TEST(FileSymbolsTest, CountReferencesNoRefSlabs) {
|
|
|
|
FileSymbols FS;
|
2019-06-15 10:26:47 +08:00
|
|
|
FS.update("f1", numSlab(1, 3), nullptr, nullptr, true);
|
|
|
|
FS.update("f2", numSlab(1, 3), nullptr, nullptr, false);
|
2019-05-09 22:22:07 +08:00
|
|
|
EXPECT_THAT(
|
|
|
|
runFuzzyFind(*FS.buildIndex(IndexType::Light, DuplicateHandling::Merge),
|
|
|
|
""),
|
|
|
|
UnorderedElementsAre(AllOf(QName("1"), NumReferences(0u)),
|
|
|
|
AllOf(QName("2"), NumReferences(0u)),
|
|
|
|
AllOf(QName("3"), NumReferences(0u))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FileSymbolsTest, CountReferencesWithRefSlabs) {
|
|
|
|
FileSymbols FS;
|
2019-06-15 10:26:47 +08:00
|
|
|
FS.update("f1cpp", numSlab(1, 3), refSlab(SymbolID("1"), "f1.cpp"), nullptr,
|
|
|
|
true);
|
|
|
|
FS.update("f1h", numSlab(1, 3), refSlab(SymbolID("1"), "f1.h"), nullptr,
|
|
|
|
false);
|
|
|
|
FS.update("f2cpp", numSlab(1, 3), refSlab(SymbolID("2"), "f2.cpp"), nullptr,
|
|
|
|
true);
|
|
|
|
FS.update("f2h", numSlab(1, 3), refSlab(SymbolID("2"), "f2.h"), nullptr,
|
|
|
|
false);
|
|
|
|
FS.update("f3cpp", numSlab(1, 3), refSlab(SymbolID("3"), "f3.cpp"), nullptr,
|
|
|
|
true);
|
|
|
|
FS.update("f3h", numSlab(1, 3), refSlab(SymbolID("3"), "f3.h"), nullptr,
|
|
|
|
false);
|
2019-05-09 22:22:07 +08:00
|
|
|
EXPECT_THAT(
|
|
|
|
runFuzzyFind(*FS.buildIndex(IndexType::Light, DuplicateHandling::Merge),
|
|
|
|
""),
|
|
|
|
UnorderedElementsAre(AllOf(QName("1"), NumReferences(1u)),
|
|
|
|
AllOf(QName("2"), NumReferences(1u)),
|
|
|
|
AllOf(QName("3"), NumReferences(1u))));
|
|
|
|
}
|
2017-12-15 20:25:02 +08:00
|
|
|
} // namespace
|
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|