2017-12-21 00:06:05 +08:00
|
|
|
//===-- XRefsTests.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-21 00:06:05 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Annotations.h"
|
2018-02-14 01:47:16 +08:00
|
|
|
#include "Compiler.h"
|
2017-12-21 00:06:05 +08:00
|
|
|
#include "Matchers.h"
|
2019-09-04 17:46:06 +08:00
|
|
|
#include "ParsedAST.h"
|
2019-05-28 18:29:58 +08:00
|
|
|
#include "Protocol.h"
|
2019-09-26 15:27:43 +08:00
|
|
|
#include "SourceCode.h"
|
2018-02-15 21:15:47 +08:00
|
|
|
#include "SyncAPI.h"
|
2018-01-29 23:37:46 +08:00
|
|
|
#include "TestFS.h"
|
2019-07-10 01:59:50 +08:00
|
|
|
#include "TestIndex.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-21 00:06:05 +08:00
|
|
|
#include "XRefs.h"
|
2018-04-30 23:24:17 +08:00
|
|
|
#include "index/FileIndex.h"
|
2019-07-10 01:59:50 +08:00
|
|
|
#include "index/MemIndex.h"
|
2018-04-30 23:24:17 +08:00
|
|
|
#include "index/SymbolCollector.h"
|
2019-09-26 15:27:43 +08:00
|
|
|
#include "clang/AST/Decl.h"
|
|
|
|
#include "clang/Basic/SourceLocation.h"
|
2018-04-30 23:24:17 +08:00
|
|
|
#include "clang/Index/IndexingAction.h"
|
2019-05-28 18:29:58 +08:00
|
|
|
#include "llvm/ADT/None.h"
|
2019-09-26 15:27:43 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/Error.h"
|
2017-12-21 00:06:05 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
#include "llvm/Support/ScopedPrinter.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 "gmock/gmock.h"
|
2017-12-21 00:06:05 +08:00
|
|
|
#include "gtest/gtest.h"
|
2019-06-13 16:51:44 +08:00
|
|
|
#include <string>
|
2019-09-26 15:27:43 +08:00
|
|
|
#include <vector>
|
2017-12-21 00:06:05 +08:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
namespace {
|
2018-10-20 23:30:37 +08:00
|
|
|
|
2021-01-27 00:16:57 +08:00
|
|
|
using ::testing::AllOf;
|
2019-05-06 18:08:47 +08:00
|
|
|
using ::testing::ElementsAre;
|
[clangd] Add a textual fallback for go-to-definition
Summary:
This facilitates performing go-to-definition in contexts where AST-based
resolution does not work, such as comments, string literals, preprocessor
disabled regions, and macro definitions, based on textual lookup in the index.
Partially fixes https://github.com/clangd/clangd/issues/241
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72874
2020-03-06 05:47:32 +08:00
|
|
|
using ::testing::Eq;
|
2019-05-06 18:08:47 +08:00
|
|
|
using ::testing::IsEmpty;
|
|
|
|
using ::testing::Matcher;
|
2020-07-31 20:32:18 +08:00
|
|
|
using ::testing::UnorderedElementsAre;
|
2019-05-06 18:08:47 +08:00
|
|
|
using ::testing::UnorderedElementsAreArray;
|
2020-11-19 01:13:11 +08:00
|
|
|
using ::testing::UnorderedPointwise;
|
2017-12-21 00:06:05 +08:00
|
|
|
|
2018-11-28 18:30:42 +08:00
|
|
|
MATCHER_P2(FileRange, File, Range, "") {
|
|
|
|
return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg;
|
|
|
|
}
|
2020-08-07 17:36:33 +08:00
|
|
|
MATCHER(DeclRange, "") {
|
|
|
|
const LocatedSymbol &Sym = ::testing::get<0>(arg);
|
|
|
|
const Range &Range = ::testing::get<1>(arg);
|
|
|
|
return Sym.PreferredDeclaration.range == Range;
|
|
|
|
}
|
2018-11-28 18:30:42 +08:00
|
|
|
|
2017-12-21 00:06:05 +08:00
|
|
|
// Extracts ranges from an annotated example, and constructs a matcher for a
|
|
|
|
// highlight set. Ranges should be named $read/$write as appropriate.
|
|
|
|
Matcher<const std::vector<DocumentHighlight> &>
|
|
|
|
HighlightsFrom(const Annotations &Test) {
|
|
|
|
std::vector<DocumentHighlight> Expected;
|
|
|
|
auto Add = [&](const Range &R, DocumentHighlightKind K) {
|
|
|
|
Expected.emplace_back();
|
|
|
|
Expected.back().range = R;
|
|
|
|
Expected.back().kind = K;
|
|
|
|
};
|
|
|
|
for (const auto &Range : Test.ranges())
|
|
|
|
Add(Range, DocumentHighlightKind::Text);
|
|
|
|
for (const auto &Range : Test.ranges("read"))
|
|
|
|
Add(Range, DocumentHighlightKind::Read);
|
|
|
|
for (const auto &Range : Test.ranges("write"))
|
|
|
|
Add(Range, DocumentHighlightKind::Write);
|
|
|
|
return UnorderedElementsAreArray(Expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(HighlightsTest, All) {
|
|
|
|
const char *Tests[] = {
|
|
|
|
R"cpp(// Local variable
|
|
|
|
int main() {
|
|
|
|
int [[bonjour]];
|
|
|
|
$write[[^bonjour]] = 2;
|
|
|
|
int test1 = $read[[bonjour]];
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Struct
|
|
|
|
namespace ns1 {
|
|
|
|
struct [[MyClass]] {
|
|
|
|
static void foo([[MyClass]]*) {}
|
|
|
|
};
|
|
|
|
} // namespace ns1
|
|
|
|
int main() {
|
|
|
|
ns1::[[My^Class]]* Params;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Function
|
|
|
|
int [[^foo]](int) {}
|
|
|
|
int main() {
|
|
|
|
[[foo]]([[foo]](42));
|
|
|
|
auto *X = &[[foo]];
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-02-11 21:03:08 +08:00
|
|
|
|
|
|
|
R"cpp(// Function parameter in decl
|
|
|
|
void foo(int [[^bar]]);
|
|
|
|
)cpp",
|
2020-02-26 20:39:46 +08:00
|
|
|
R"cpp(// Not touching any identifiers.
|
|
|
|
struct Foo {
|
|
|
|
[[~]]Foo() {};
|
|
|
|
};
|
|
|
|
void foo() {
|
|
|
|
Foo f;
|
|
|
|
f.[[^~]]Foo();
|
|
|
|
}
|
|
|
|
)cpp",
|
2017-12-21 00:06:05 +08:00
|
|
|
};
|
|
|
|
for (const char *Test : Tests) {
|
|
|
|
Annotations T(Test);
|
[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
|
|
|
auto AST = TestTU::withCode(T.code()).build();
|
[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
|
|
|
EXPECT_THAT(findDocumentHighlights(AST, T.point()), HighlightsFrom(T))
|
2017-12-21 00:06:05 +08:00
|
|
|
<< Test;
|
2020-04-19 08:19:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(HighlightsTest, ControlFlow) {
|
|
|
|
const char *Tests[] = {
|
|
|
|
R"cpp(
|
|
|
|
// Highlight same-function returns.
|
|
|
|
int fib(unsigned n) {
|
|
|
|
if (n <= 1) [[ret^urn]] 1;
|
|
|
|
[[return]] fib(n - 1) + fib(n - 2);
|
|
|
|
|
|
|
|
// Returns from other functions not highlighted.
|
|
|
|
auto Lambda = [] { return; };
|
|
|
|
class LocalClass { void x() { return; } };
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
#define FAIL() return false
|
|
|
|
#define DO(x) { x; }
|
|
|
|
bool foo(int n) {
|
|
|
|
if (n < 0) [[FAIL]]();
|
|
|
|
DO([[re^turn]] true)
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
// Highlight loop control flow
|
|
|
|
int magic() {
|
|
|
|
int counter = 0;
|
|
|
|
[[^for]] (char c : "fruit loops!") {
|
|
|
|
if (c == ' ') [[continue]];
|
|
|
|
counter += c;
|
|
|
|
if (c == '!') [[break]];
|
|
|
|
if (c == '?') [[return]] -1;
|
|
|
|
}
|
|
|
|
return counter;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
// Highlight loop and same-loop control flow
|
|
|
|
void nonsense() {
|
|
|
|
[[while]] (true) {
|
|
|
|
if (false) [[bre^ak]];
|
|
|
|
switch (1) break;
|
|
|
|
[[continue]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
// Highlight switch for break (but not other breaks).
|
|
|
|
void describe(unsigned n) {
|
|
|
|
[[switch]](n) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
[[default]]:
|
|
|
|
[[^break]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
// Highlight case and exits for switch-break (but not other cases).
|
|
|
|
void describe(unsigned n) {
|
|
|
|
[[switch]](n) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
[[case]] 1:
|
|
|
|
[[default]]:
|
|
|
|
[[return]];
|
|
|
|
[[^break]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
// Highlight exits and switch for case
|
|
|
|
void describe(unsigned n) {
|
|
|
|
[[switch]](n) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
[[case]] 1:
|
|
|
|
[[d^efault]]:
|
|
|
|
[[return]];
|
|
|
|
[[break]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
// Highlight nothing for switch.
|
|
|
|
void describe(unsigned n) {
|
|
|
|
s^witch(n) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
// FIXME: match exception type against catch blocks
|
|
|
|
int catchy() {
|
|
|
|
try { // wrong: highlight try with matching catch
|
|
|
|
try { // correct: has no matching catch
|
|
|
|
[[thr^ow]] "oh no!";
|
|
|
|
} catch (int) { } // correct: catch doesn't match type
|
|
|
|
[[return]] -1; // correct: exits the matching catch
|
|
|
|
} catch (const char*) { } // wrong: highlight matching catch
|
|
|
|
[[return]] 42; // wrong: throw doesn't exit function
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
// Loop highlights goto exiting the loop, but not jumping within it.
|
|
|
|
void jumpy() {
|
|
|
|
[[wh^ile]](1) {
|
|
|
|
up:
|
|
|
|
if (0) [[goto]] out;
|
|
|
|
goto up;
|
|
|
|
}
|
|
|
|
out: return;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
};
|
|
|
|
for (const char *Test : Tests) {
|
|
|
|
Annotations T(Test);
|
2020-05-28 23:12:43 +08:00
|
|
|
auto TU = TestTU::withCode(T.code());
|
|
|
|
TU.ExtraArgs.push_back("-fexceptions"); // FIXME: stop testing on PS4.
|
|
|
|
auto AST = TU.build();
|
2020-04-19 08:19:25 +08:00
|
|
|
EXPECT_THAT(findDocumentHighlights(AST, T.point()), HighlightsFrom(T))
|
|
|
|
<< Test;
|
2017-12-21 00:06:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
MATCHER_P3(Sym, Name, Decl, DefOrNone, "") {
|
|
|
|
llvm::Optional<Range> Def = DefOrNone;
|
|
|
|
if (Name != arg.Name) {
|
|
|
|
*result_listener << "Name is " << arg.Name;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (Decl != arg.PreferredDeclaration.range) {
|
|
|
|
*result_listener << "Declaration is "
|
|
|
|
<< llvm::to_string(arg.PreferredDeclaration);
|
|
|
|
return false;
|
|
|
|
}
|
2020-07-31 20:32:18 +08:00
|
|
|
if (!Def && !arg.Definition)
|
|
|
|
return true;
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
if (Def && !arg.Definition) {
|
|
|
|
*result_listener << "Has no definition";
|
|
|
|
return false;
|
|
|
|
}
|
2020-07-31 20:32:18 +08:00
|
|
|
if (!Def && arg.Definition) {
|
|
|
|
*result_listener << "Definition is " << llvm::to_string(arg.Definition);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (arg.Definition->range != *Def) {
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
*result_listener << "Definition is " << llvm::to_string(arg.Definition);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2020-07-31 20:32:18 +08:00
|
|
|
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
MATCHER_P(Sym, Name, "") { return arg.Name == Name; }
|
|
|
|
|
2021-01-27 00:16:57 +08:00
|
|
|
MATCHER_P(RangeIs, R, "") { return arg.Loc.range == R; }
|
|
|
|
MATCHER_P(AttrsAre, A, "") { return arg.Attributes == A; }
|
2017-12-21 00:06:05 +08:00
|
|
|
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
TEST(LocateSymbol, WithIndex) {
|
2018-04-30 23:24:17 +08:00
|
|
|
Annotations SymbolHeader(R"cpp(
|
|
|
|
class $forward[[Forward]];
|
|
|
|
class $foo[[Foo]] {};
|
|
|
|
|
|
|
|
void $f1[[f1]]();
|
|
|
|
|
|
|
|
inline void $f2[[f2]]() {}
|
|
|
|
)cpp");
|
|
|
|
Annotations SymbolCpp(R"cpp(
|
|
|
|
class $forward[[forward]] {};
|
|
|
|
void $f1[[f1]]() {}
|
|
|
|
)cpp");
|
|
|
|
|
[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 TU;
|
2020-01-29 03:23:46 +08:00
|
|
|
TU.Code = std::string(SymbolCpp.code());
|
|
|
|
TU.HeaderCode = std::string(SymbolHeader.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
|
|
|
auto Index = TU.index();
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
auto LocateWithIndex = [&Index](const Annotations &Main) {
|
[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
|
|
|
auto AST = TestTU::withCode(Main.code()).build();
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
return clangd::locateSymbolAt(AST, Main.point(), Index.get());
|
2018-04-30 23:24:17 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
Annotations Test(R"cpp(// only declaration in AST.
|
|
|
|
void [[f1]]();
|
|
|
|
int main() {
|
|
|
|
^f1();
|
|
|
|
}
|
|
|
|
)cpp");
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
EXPECT_THAT(LocateWithIndex(Test),
|
|
|
|
ElementsAre(Sym("f1", Test.range(), SymbolCpp.range("f1"))));
|
2018-04-30 23:24:17 +08:00
|
|
|
|
|
|
|
Test = Annotations(R"cpp(// definition in AST.
|
|
|
|
void [[f1]]() {}
|
|
|
|
int main() {
|
|
|
|
^f1();
|
|
|
|
}
|
|
|
|
)cpp");
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
EXPECT_THAT(LocateWithIndex(Test),
|
|
|
|
ElementsAre(Sym("f1", SymbolHeader.range("f1"), Test.range())));
|
2018-04-30 23:24:17 +08:00
|
|
|
|
|
|
|
Test = Annotations(R"cpp(// forward declaration in AST.
|
|
|
|
class [[Foo]];
|
|
|
|
F^oo* create();
|
|
|
|
)cpp");
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
EXPECT_THAT(LocateWithIndex(Test),
|
|
|
|
ElementsAre(Sym("Foo", Test.range(), SymbolHeader.range("foo"))));
|
2018-04-30 23:24:17 +08:00
|
|
|
|
2020-01-04 23:28:41 +08:00
|
|
|
Test = Annotations(R"cpp(// definition in AST.
|
2018-04-30 23:24:17 +08:00
|
|
|
class [[Forward]] {};
|
|
|
|
F^orward create();
|
|
|
|
)cpp");
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
EXPECT_THAT(
|
|
|
|
LocateWithIndex(Test),
|
|
|
|
ElementsAre(Sym("Forward", SymbolHeader.range("forward"), Test.range())));
|
2018-04-30 23:24:17 +08:00
|
|
|
}
|
|
|
|
|
2020-12-14 15:55:47 +08:00
|
|
|
TEST(LocateSymbol, FindOverrides) {
|
|
|
|
auto Code = Annotations(R"cpp(
|
|
|
|
class Foo {
|
|
|
|
virtual void $1[[fo^o]]() = 0;
|
|
|
|
};
|
|
|
|
class Bar : public Foo {
|
|
|
|
void $2[[foo]]() override;
|
|
|
|
};
|
|
|
|
)cpp");
|
|
|
|
TestTU TU = TestTU::withCode(Code.code());
|
|
|
|
auto AST = TU.build();
|
|
|
|
EXPECT_THAT(locateSymbolAt(AST, Code.point(), TU.index().get()),
|
|
|
|
UnorderedElementsAre(Sym("foo", Code.range("1"), llvm::None),
|
|
|
|
Sym("foo", Code.range("2"), llvm::None)));
|
|
|
|
}
|
|
|
|
|
2019-02-11 23:05:29 +08:00
|
|
|
TEST(LocateSymbol, WithIndexPreferredLocation) {
|
|
|
|
Annotations SymbolHeader(R"cpp(
|
2019-05-03 20:11:14 +08:00
|
|
|
class $p[[Proto]] {};
|
|
|
|
void $f[[func]]() {};
|
2019-02-11 23:05:29 +08:00
|
|
|
)cpp");
|
|
|
|
TestTU TU;
|
2020-01-29 03:23:46 +08:00
|
|
|
TU.HeaderCode = std::string(SymbolHeader.code());
|
2019-02-11 23:05:29 +08:00
|
|
|
TU.HeaderFilename = "x.proto"; // Prefer locations in codegen files.
|
|
|
|
auto Index = TU.index();
|
|
|
|
|
|
|
|
Annotations Test(R"cpp(// only declaration in AST.
|
|
|
|
// Shift to make range different.
|
2019-05-03 20:11:14 +08:00
|
|
|
class Proto;
|
|
|
|
void func() {}
|
|
|
|
P$p^roto* create() {
|
|
|
|
fu$f^nc();
|
|
|
|
return nullptr;
|
|
|
|
}
|
2019-02-11 23:05:29 +08:00
|
|
|
)cpp");
|
|
|
|
|
|
|
|
auto AST = TestTU::withCode(Test.code()).build();
|
2019-05-03 20:11:14 +08:00
|
|
|
{
|
|
|
|
auto Locs = clangd::locateSymbolAt(AST, Test.point("p"), Index.get());
|
|
|
|
auto CodeGenLoc = SymbolHeader.range("p");
|
|
|
|
EXPECT_THAT(Locs, ElementsAre(Sym("Proto", CodeGenLoc, CodeGenLoc)));
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto Locs = clangd::locateSymbolAt(AST, Test.point("f"), Index.get());
|
|
|
|
auto CodeGenLoc = SymbolHeader.range("f");
|
|
|
|
EXPECT_THAT(Locs, ElementsAre(Sym("func", CodeGenLoc, CodeGenLoc)));
|
|
|
|
}
|
2019-02-11 23:05:29 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
TEST(LocateSymbol, All) {
|
|
|
|
// Ranges in tests:
|
|
|
|
// $decl is the declaration location (if absent, no symbol is located)
|
|
|
|
// $def is the definition location (if absent, symbol has no definition)
|
|
|
|
// unnamed range becomes both $decl and $def.
|
2017-12-21 00:06:05 +08:00
|
|
|
const char *Tests[] = {
|
|
|
|
R"cpp(// Local variable
|
|
|
|
int main() {
|
2018-03-09 22:00:34 +08:00
|
|
|
int [[bonjour]];
|
2017-12-21 00:06:05 +08:00
|
|
|
^bonjour = 2;
|
|
|
|
int test1 = bonjour;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Struct
|
|
|
|
namespace ns1 {
|
2018-03-09 22:00:34 +08:00
|
|
|
struct [[MyClass]] {};
|
2017-12-21 00:06:05 +08:00
|
|
|
} // namespace ns1
|
|
|
|
int main() {
|
|
|
|
ns1::My^Class* Params;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Function definition via pointer
|
2020-01-02 14:08:05 +08:00
|
|
|
void [[foo]](int) {}
|
2017-12-21 00:06:05 +08:00
|
|
|
int main() {
|
|
|
|
auto *X = &^foo;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Function declaration via call
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
int $decl[[foo]](int);
|
2017-12-21 00:06:05 +08:00
|
|
|
int main() {
|
|
|
|
return ^foo(42);
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Field
|
2018-03-09 22:00:34 +08:00
|
|
|
struct Foo { int [[x]]; };
|
2017-12-21 00:06:05 +08:00
|
|
|
int main() {
|
|
|
|
Foo bar;
|
2020-01-02 14:08:05 +08:00
|
|
|
(void)bar.^x;
|
2017-12-21 00:06:05 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Field, member initializer
|
|
|
|
struct Foo {
|
2018-03-09 22:00:34 +08:00
|
|
|
int [[x]];
|
2017-12-21 00:06:05 +08:00
|
|
|
Foo() : ^x(0) {}
|
|
|
|
};
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Field, field designator
|
2018-03-09 22:00:34 +08:00
|
|
|
struct Foo { int [[x]]; };
|
2017-12-21 00:06:05 +08:00
|
|
|
int main() {
|
|
|
|
Foo bar = { .^x = 2 };
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Method call
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
struct Foo { int $decl[[x]](); };
|
2017-12-21 00:06:05 +08:00
|
|
|
int main() {
|
|
|
|
Foo bar;
|
|
|
|
bar.^x();
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Typedef
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
typedef int $decl[[Foo]];
|
2017-12-21 00:06:05 +08:00
|
|
|
int main() {
|
|
|
|
^Foo bar;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Template type parameter
|
2019-02-21 17:55:00 +08:00
|
|
|
template <typename [[T]]>
|
2017-12-21 00:06:05 +08:00
|
|
|
void foo() { ^T t; }
|
2019-02-21 17:55:00 +08:00
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Template template type parameter
|
|
|
|
template <template<typename> class [[T]]>
|
|
|
|
void foo() { ^T<int> t; }
|
|
|
|
)cpp",
|
2017-12-21 00:06:05 +08:00
|
|
|
|
|
|
|
R"cpp(// Namespace
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
namespace $decl[[ns]] {
|
2020-01-02 14:08:05 +08:00
|
|
|
struct Foo { static void bar(); };
|
2018-03-09 22:00:34 +08:00
|
|
|
} // namespace ns
|
2017-12-21 00:06:05 +08:00
|
|
|
int main() { ^ns::Foo::bar(); }
|
|
|
|
)cpp",
|
|
|
|
|
2018-03-13 20:30:59 +08:00
|
|
|
R"cpp(// Macro
|
|
|
|
class TTT { public: int a; };
|
2018-03-13 22:31:31 +08:00
|
|
|
#define [[FF]](S) if (int b = S.a) {}
|
2018-03-13 20:30:59 +08:00
|
|
|
void f() {
|
|
|
|
TTT t;
|
|
|
|
F^F(t);
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
2018-04-09 22:28:52 +08:00
|
|
|
R"cpp(// Macro argument
|
|
|
|
int [[i]];
|
|
|
|
#define ADDRESSOF(X) &X;
|
|
|
|
int *j = ADDRESSOF(^i);
|
|
|
|
)cpp",
|
2019-12-24 02:38:04 +08:00
|
|
|
R"cpp(// Macro argument appearing multiple times in expansion
|
|
|
|
#define VALIDATE_TYPE(x) (void)x;
|
|
|
|
#define ASSERT(expr) \
|
|
|
|
do { \
|
|
|
|
VALIDATE_TYPE(expr); \
|
|
|
|
if (!expr); \
|
|
|
|
} while (false)
|
|
|
|
bool [[waldo]]() { return true; }
|
|
|
|
void foo() {
|
|
|
|
ASSERT(wa^ldo());
|
|
|
|
}
|
|
|
|
)cpp",
|
2018-04-09 22:28:52 +08:00
|
|
|
R"cpp(// Symbol concatenated inside macro (not supported)
|
|
|
|
int *pi;
|
2020-01-02 14:08:05 +08:00
|
|
|
#define POINTER(X) p ## X;
|
[clangd] Add a textual fallback for go-to-definition
Summary:
This facilitates performing go-to-definition in contexts where AST-based
resolution does not work, such as comments, string literals, preprocessor
disabled regions, and macro definitions, based on textual lookup in the index.
Partially fixes https://github.com/clangd/clangd/issues/241
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72874
2020-03-06 05:47:32 +08:00
|
|
|
int x = *POINTER(^i);
|
2018-04-09 22:28:52 +08:00
|
|
|
)cpp",
|
|
|
|
|
2018-01-12 22:21:10 +08:00
|
|
|
R"cpp(// Forward class declaration
|
2020-01-25 01:31:37 +08:00
|
|
|
class $decl[[Foo]];
|
|
|
|
class $def[[Foo]] {};
|
2018-01-12 22:21:10 +08:00
|
|
|
F^oo* foo();
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Function declaration
|
2020-01-25 01:31:37 +08:00
|
|
|
void $decl[[foo]]();
|
2018-01-12 22:21:10 +08:00
|
|
|
void g() { f^oo(); }
|
2020-01-25 01:31:37 +08:00
|
|
|
void $def[[foo]]() {}
|
2018-03-09 22:00:34 +08:00
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
#define FF(name) class name##_Test {};
|
|
|
|
[[FF]](my);
|
|
|
|
void f() { my^_Test a; }
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
#define FF() class [[Test]] {};
|
|
|
|
FF();
|
|
|
|
void f() { T^est a; }
|
2018-01-12 22:21:10 +08:00
|
|
|
)cpp",
|
2019-02-18 22:23:19 +08:00
|
|
|
|
|
|
|
R"cpp(// explicit template specialization
|
|
|
|
template <typename T>
|
|
|
|
struct Foo { void bar() {} };
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct [[Foo]]<int> { void bar() {} };
|
|
|
|
|
|
|
|
void foo() {
|
|
|
|
Foo<char> abc;
|
|
|
|
Fo^o<int> b;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// implicit template specialization
|
|
|
|
template <typename T>
|
|
|
|
struct [[Foo]] { void bar() {} };
|
|
|
|
template <>
|
|
|
|
struct Foo<int> { void bar() {} };
|
|
|
|
void foo() {
|
|
|
|
Fo^o<char> abc;
|
|
|
|
Foo<int> b;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// partial template specialization
|
|
|
|
template <typename T>
|
|
|
|
struct Foo { void bar() {} };
|
|
|
|
template <typename T>
|
|
|
|
struct [[Foo]]<T*> { void bar() {} };
|
|
|
|
^Foo<int*> x;
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// function template specializations
|
|
|
|
template <class T>
|
|
|
|
void foo(T) {}
|
|
|
|
template <>
|
|
|
|
void [[foo]](int) {}
|
|
|
|
void bar() {
|
|
|
|
fo^o(10);
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// variable template decls
|
|
|
|
template <class T>
|
|
|
|
T var = T();
|
|
|
|
|
|
|
|
template <>
|
|
|
|
double [[var]]<int> = 10;
|
|
|
|
|
|
|
|
double y = va^r<int>;
|
|
|
|
)cpp",
|
2019-02-21 22:48:33 +08:00
|
|
|
|
|
|
|
R"cpp(// No implicit constructors
|
2020-01-02 14:08:05 +08:00
|
|
|
struct X {
|
2019-02-21 22:48:33 +08:00
|
|
|
X(X&& x) = default;
|
|
|
|
};
|
2020-01-02 14:08:05 +08:00
|
|
|
X $decl[[makeX]]();
|
2019-02-21 22:48:33 +08:00
|
|
|
void foo() {
|
|
|
|
auto x = m^akeX();
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-10-01 19:03:56 +08:00
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
struct X {
|
2020-01-02 14:08:05 +08:00
|
|
|
X& $decl[[operator]]++();
|
2019-10-01 19:03:56 +08:00
|
|
|
};
|
|
|
|
void foo(X& x) {
|
|
|
|
+^+x;
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-06 05:29:59 +08:00
|
|
|
|
2020-03-16 23:37:19 +08:00
|
|
|
R"cpp(
|
|
|
|
struct S1 { void f(); };
|
|
|
|
struct S2 { S1 * $decl[[operator]]->(); };
|
|
|
|
void test(S2 s2) {
|
|
|
|
s2-^>f();
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
2019-12-06 05:29:59 +08:00
|
|
|
R"cpp(// Declaration of explicit template specialization
|
|
|
|
template <typename T>
|
|
|
|
struct $decl[[Foo]] {};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct Fo^o<int> {};
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Declaration of partial template specialization
|
|
|
|
template <typename T>
|
|
|
|
struct $decl[[Foo]] {};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct Fo^o<T*> {};
|
2019-12-06 07:29:32 +08:00
|
|
|
)cpp",
|
|
|
|
|
2020-12-15 23:31:25 +08:00
|
|
|
R"cpp(// auto builtin type (not supported)
|
|
|
|
^auto x = 42;
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// auto on lambda
|
|
|
|
auto x = [[[]]]{};
|
|
|
|
^auto y = x;
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// auto on struct
|
|
|
|
namespace ns1 {
|
|
|
|
struct [[S1]] {};
|
|
|
|
} // namespace ns1
|
|
|
|
|
|
|
|
^auto x = ns1::S1{};
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// decltype on struct
|
|
|
|
namespace ns1 {
|
|
|
|
struct [[S1]] {};
|
|
|
|
} // namespace ns1
|
|
|
|
|
|
|
|
ns1::S1 i;
|
|
|
|
^decltype(i) j;
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// decltype(auto) on struct
|
|
|
|
namespace ns1 {
|
|
|
|
struct [[S1]] {};
|
|
|
|
} // namespace ns1
|
|
|
|
|
|
|
|
ns1::S1 i;
|
|
|
|
ns1::S1& j = i;
|
|
|
|
^decltype(auto) k = j;
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// auto on template class
|
|
|
|
template<typename T> class [[Foo]] {};
|
|
|
|
|
|
|
|
^auto x = Foo<int>();
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// auto on template class with forward declared class
|
|
|
|
template<typename T> class [[Foo]] {};
|
|
|
|
class X;
|
|
|
|
|
|
|
|
^auto x = Foo<X>();
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// auto on specialized template class
|
|
|
|
template<typename T> class Foo {};
|
|
|
|
template<> class [[Foo]]<int> {};
|
|
|
|
|
|
|
|
^auto x = Foo<int>();
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// auto on initializer list.
|
|
|
|
namespace std
|
|
|
|
{
|
|
|
|
template<class _E>
|
|
|
|
class [[initializer_list]] {};
|
|
|
|
}
|
|
|
|
|
|
|
|
^auto i = {1,2};
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// auto function return with trailing type
|
|
|
|
struct [[Bar]] {};
|
|
|
|
^auto test() -> decltype(Bar()) {
|
|
|
|
return Bar();
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// decltype in trailing return type
|
|
|
|
struct [[Bar]] {};
|
|
|
|
auto test() -> ^decltype(Bar()) {
|
|
|
|
return Bar();
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// auto in function return
|
|
|
|
struct [[Bar]] {};
|
|
|
|
^auto test() {
|
|
|
|
return Bar();
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// auto& in function return
|
|
|
|
struct [[Bar]] {};
|
|
|
|
^auto& test() {
|
|
|
|
static Bar x;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// auto* in function return
|
|
|
|
struct [[Bar]] {};
|
|
|
|
^auto* test() {
|
|
|
|
Bar* x;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// const auto& in function return
|
|
|
|
struct [[Bar]] {};
|
|
|
|
const ^auto& test() {
|
|
|
|
static Bar x;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// decltype(auto) in function return
|
|
|
|
struct [[Bar]] {};
|
|
|
|
^decltype(auto) test() {
|
|
|
|
return Bar();
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// decltype of function with trailing return type.
|
|
|
|
struct [[Bar]] {};
|
|
|
|
auto test() -> decltype(Bar()) {
|
|
|
|
return Bar();
|
|
|
|
}
|
|
|
|
void foo() {
|
|
|
|
^decltype(test()) i = test();
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
2020-01-25 01:21:47 +08:00
|
|
|
R"cpp(// Override specifier jumps to overridden method
|
|
|
|
class Y { virtual void $decl[[a]]() = 0; };
|
|
|
|
class X : Y { void a() ^override {} };
|
|
|
|
)cpp",
|
|
|
|
|
2020-01-30 19:45:43 +08:00
|
|
|
R"cpp(// Final specifier jumps to overridden method
|
|
|
|
class Y { virtual void $decl[[a]]() = 0; };
|
|
|
|
class X : Y { void a() ^final {} };
|
|
|
|
)cpp",
|
|
|
|
|
2019-12-06 07:29:32 +08:00
|
|
|
R"cpp(// Heuristic resolution of dependent method
|
|
|
|
template <typename T>
|
|
|
|
struct S {
|
|
|
|
void [[bar]]() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void foo(S<T> arg) {
|
|
|
|
arg.ba^r();
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Heuristic resolution of dependent method via this->
|
|
|
|
template <typename T>
|
|
|
|
struct S {
|
|
|
|
void [[foo]]() {
|
|
|
|
this->fo^o();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Heuristic resolution of dependent static method
|
|
|
|
template <typename T>
|
|
|
|
struct S {
|
|
|
|
static void [[bar]]() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void foo() {
|
|
|
|
S<T>::ba^r();
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
2019-12-16 09:42:25 +08:00
|
|
|
R"cpp(// Heuristic resolution of dependent method
|
2019-12-06 07:29:32 +08:00
|
|
|
// invoked via smart pointer
|
2019-12-16 09:42:25 +08:00
|
|
|
template <typename> struct S { void [[foo]]() {} };
|
2019-12-06 07:29:32 +08:00
|
|
|
template <typename T> struct unique_ptr {
|
|
|
|
T* operator->();
|
|
|
|
};
|
|
|
|
template <typename T>
|
|
|
|
void test(unique_ptr<S<T>>& V) {
|
|
|
|
V->fo^o();
|
|
|
|
}
|
2020-03-13 06:22:44 +08:00
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Heuristic resolution of dependent enumerator
|
|
|
|
template <typename T>
|
|
|
|
struct Foo {
|
|
|
|
enum class E { [[A]], B };
|
|
|
|
E e = E::A^;
|
|
|
|
};
|
2020-07-10 02:29:15 +08:00
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"objc(
|
|
|
|
@protocol Dog;
|
|
|
|
@protocol $decl[[Dog]]
|
|
|
|
- (void)bark;
|
|
|
|
@end
|
|
|
|
id<Do^g> getDoggo() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
)objc",
|
|
|
|
|
|
|
|
R"objc(
|
|
|
|
@interface Cat
|
|
|
|
@end
|
|
|
|
@implementation Cat
|
|
|
|
@end
|
|
|
|
@interface $decl[[Cat]] (Exte^nsion)
|
|
|
|
- (void)meow;
|
|
|
|
@end
|
|
|
|
@implementation $def[[Cat]] (Extension)
|
|
|
|
- (void)meow {}
|
|
|
|
@end
|
|
|
|
)objc",
|
|
|
|
|
|
|
|
R"objc(
|
|
|
|
@class $decl[[Foo]];
|
|
|
|
Fo^o * getFoo() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
)objc",
|
|
|
|
|
|
|
|
R"objc(// Prefer interface definition over forward declaration
|
|
|
|
@class Foo;
|
|
|
|
@interface $decl[[Foo]]
|
|
|
|
@end
|
|
|
|
Fo^o * getFoo() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
)objc",
|
|
|
|
|
|
|
|
R"objc(
|
|
|
|
@class Foo;
|
|
|
|
@interface $decl[[Foo]]
|
|
|
|
@end
|
|
|
|
@implementation $def[[Foo]]
|
|
|
|
@end
|
|
|
|
Fo^o * getFoo() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
)objc"};
|
2017-12-21 00:06:05 +08:00
|
|
|
for (const char *Test : Tests) {
|
|
|
|
Annotations T(Test);
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
llvm::Optional<Range> WantDecl;
|
|
|
|
llvm::Optional<Range> WantDef;
|
|
|
|
if (!T.ranges().empty())
|
|
|
|
WantDecl = WantDef = T.range();
|
|
|
|
if (!T.ranges("decl").empty())
|
|
|
|
WantDecl = T.range("decl");
|
|
|
|
if (!T.ranges("def").empty())
|
|
|
|
WantDef = T.range("def");
|
|
|
|
|
2019-10-13 21:15:27 +08:00
|
|
|
TestTU TU;
|
2020-01-29 03:23:46 +08:00
|
|
|
TU.Code = std::string(T.code());
|
2019-10-13 21:15:27 +08:00
|
|
|
|
|
|
|
// FIXME: Auto-completion in a template requires disabling delayed template
|
|
|
|
// parsing.
|
|
|
|
TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
|
2020-07-10 02:29:15 +08:00
|
|
|
TU.ExtraArgs.push_back("-xobjective-c++");
|
2019-10-13 21:15:27 +08:00
|
|
|
|
2020-01-02 14:08:05 +08:00
|
|
|
auto AST = TU.build();
|
|
|
|
auto Results = locateSymbolAt(AST, T.point());
|
|
|
|
|
|
|
|
if (!WantDecl) {
|
|
|
|
EXPECT_THAT(Results, IsEmpty()) << Test;
|
|
|
|
} else {
|
|
|
|
ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
|
|
|
|
EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
|
|
|
|
llvm::Optional<Range> GotDef;
|
|
|
|
if (Results[0].Definition)
|
|
|
|
GotDef = Results[0].Definition->range;
|
|
|
|
EXPECT_EQ(WantDef, GotDef) << Test;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-10 02:29:15 +08:00
|
|
|
TEST(LocateSymbol, AllMulti) {
|
|
|
|
// Ranges in tests:
|
|
|
|
// $declN is the declaration location
|
|
|
|
// $defN is the definition location (if absent, symbol has no definition)
|
|
|
|
//
|
|
|
|
// NOTE:
|
|
|
|
// N starts at 0.
|
|
|
|
struct ExpectedRanges {
|
|
|
|
Range WantDecl;
|
|
|
|
llvm::Optional<Range> WantDef;
|
|
|
|
};
|
|
|
|
const char *Tests[] = {
|
|
|
|
R"objc(
|
|
|
|
@interface $decl0[[Cat]]
|
|
|
|
@end
|
|
|
|
@implementation $def0[[Cat]]
|
|
|
|
@end
|
|
|
|
@interface $decl1[[Ca^t]] (Extension)
|
|
|
|
- (void)meow;
|
|
|
|
@end
|
|
|
|
@implementation $def1[[Cat]] (Extension)
|
|
|
|
- (void)meow {}
|
|
|
|
@end
|
|
|
|
)objc",
|
|
|
|
|
|
|
|
R"objc(
|
|
|
|
@interface $decl0[[Cat]]
|
|
|
|
@end
|
|
|
|
@implementation $def0[[Cat]]
|
|
|
|
@end
|
|
|
|
@interface $decl1[[Cat]] (Extension)
|
|
|
|
- (void)meow;
|
|
|
|
@end
|
|
|
|
@implementation $def1[[Ca^t]] (Extension)
|
|
|
|
- (void)meow {}
|
|
|
|
@end
|
|
|
|
)objc",
|
|
|
|
|
|
|
|
R"objc(
|
|
|
|
@interface $decl0[[Cat]]
|
|
|
|
@end
|
|
|
|
@interface $decl1[[Ca^t]] ()
|
|
|
|
- (void)meow;
|
|
|
|
@end
|
|
|
|
@implementation $def0[[$def1[[Cat]]]]
|
|
|
|
- (void)meow {}
|
|
|
|
@end
|
|
|
|
)objc",
|
|
|
|
};
|
|
|
|
for (const char *Test : Tests) {
|
|
|
|
Annotations T(Test);
|
|
|
|
std::vector<ExpectedRanges> Ranges;
|
|
|
|
for (int Idx = 0; true; Idx++) {
|
|
|
|
bool HasDecl = !T.ranges("decl" + std::to_string(Idx)).empty();
|
|
|
|
bool HasDef = !T.ranges("def" + std::to_string(Idx)).empty();
|
|
|
|
if (!HasDecl && !HasDef)
|
|
|
|
break;
|
|
|
|
ExpectedRanges Range;
|
|
|
|
if (HasDecl)
|
|
|
|
Range.WantDecl = T.range("decl" + std::to_string(Idx));
|
|
|
|
if (HasDef)
|
|
|
|
Range.WantDef = T.range("def" + std::to_string(Idx));
|
|
|
|
Ranges.push_back(Range);
|
|
|
|
}
|
|
|
|
|
|
|
|
TestTU TU;
|
|
|
|
TU.Code = std::string(T.code());
|
|
|
|
TU.ExtraArgs.push_back("-xobjective-c++");
|
|
|
|
|
|
|
|
auto AST = TU.build();
|
|
|
|
auto Results = locateSymbolAt(AST, T.point());
|
|
|
|
|
|
|
|
ASSERT_THAT(Results, ::testing::SizeIs(Ranges.size())) << Test;
|
|
|
|
for (size_t Idx = 0; Idx < Ranges.size(); Idx++) {
|
|
|
|
EXPECT_EQ(Results[Idx].PreferredDeclaration.range, Ranges[Idx].WantDecl)
|
|
|
|
<< "($decl" << Idx << ")" << Test;
|
|
|
|
llvm::Optional<Range> GotDef;
|
|
|
|
if (Results[Idx].Definition)
|
|
|
|
GotDef = Results[Idx].Definition->range;
|
|
|
|
EXPECT_EQ(GotDef, Ranges[Idx].WantDef) << "($def" << Idx << ")" << Test;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-02 14:08:05 +08:00
|
|
|
// LocateSymbol test cases that produce warnings.
|
|
|
|
// These are separated out from All so that in All we can assert
|
|
|
|
// that there are no diagnostics.
|
|
|
|
TEST(LocateSymbol, Warnings) {
|
|
|
|
const char *Tests[] = {
|
|
|
|
R"cpp(// Field, GNU old-style field designator
|
|
|
|
struct Foo { int [[x]]; };
|
|
|
|
int main() {
|
|
|
|
Foo bar = { ^x : 1 };
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Macro
|
|
|
|
#define MACRO 0
|
|
|
|
#define [[MACRO]] 1
|
|
|
|
int main() { return ^MACRO; }
|
|
|
|
#define MACRO 2
|
|
|
|
#undef macro
|
|
|
|
)cpp",
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const char *Test : Tests) {
|
|
|
|
Annotations T(Test);
|
|
|
|
llvm::Optional<Range> WantDecl;
|
|
|
|
llvm::Optional<Range> WantDef;
|
|
|
|
if (!T.ranges().empty())
|
|
|
|
WantDecl = WantDef = T.range();
|
|
|
|
if (!T.ranges("decl").empty())
|
|
|
|
WantDecl = T.range("decl");
|
|
|
|
if (!T.ranges("def").empty())
|
|
|
|
WantDef = T.range("def");
|
|
|
|
|
|
|
|
TestTU TU;
|
2020-01-29 03:23:46 +08:00
|
|
|
TU.Code = std::string(T.code());
|
2020-01-02 14:08:05 +08:00
|
|
|
|
2019-10-13 21:15:27 +08:00
|
|
|
auto AST = TU.build();
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
auto Results = locateSymbolAt(AST, T.point());
|
|
|
|
|
|
|
|
if (!WantDecl) {
|
|
|
|
EXPECT_THAT(Results, IsEmpty()) << Test;
|
|
|
|
} else {
|
|
|
|
ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
|
|
|
|
EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
|
|
|
|
llvm::Optional<Range> GotDef;
|
|
|
|
if (Results[0].Definition)
|
|
|
|
GotDef = Results[0].Definition->range;
|
|
|
|
EXPECT_EQ(WantDef, GotDef) << Test;
|
|
|
|
}
|
2017-12-21 00:06:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[clangd] Add a textual fallback for go-to-definition
Summary:
This facilitates performing go-to-definition in contexts where AST-based
resolution does not work, such as comments, string literals, preprocessor
disabled regions, and macro definitions, based on textual lookup in the index.
Partially fixes https://github.com/clangd/clangd/issues/241
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72874
2020-03-06 05:47:32 +08:00
|
|
|
TEST(LocateSymbol, TextualSmoke) {
|
|
|
|
auto T = Annotations(
|
|
|
|
R"cpp(
|
|
|
|
struct [[MyClass]] {};
|
|
|
|
// Comment mentioning M^yClass
|
|
|
|
)cpp");
|
|
|
|
|
|
|
|
auto TU = TestTU::withCode(T.code());
|
|
|
|
auto AST = TU.build();
|
|
|
|
auto Index = TU.index();
|
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point(), Index.get()),
|
2020-07-31 20:32:18 +08:00
|
|
|
ElementsAre(Sym("MyClass", T.range(), T.range())));
|
[clangd] Add a textual fallback for go-to-definition
Summary:
This facilitates performing go-to-definition in contexts where AST-based
resolution does not work, such as comments, string literals, preprocessor
disabled regions, and macro definitions, based on textual lookup in the index.
Partially fixes https://github.com/clangd/clangd/issues/241
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72874
2020-03-06 05:47:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(LocateSymbol, Textual) {
|
|
|
|
const char *Tests[] = {
|
|
|
|
R"cpp(// Comment
|
|
|
|
struct [[MyClass]] {};
|
|
|
|
// Comment mentioning M^yClass
|
|
|
|
)cpp",
|
|
|
|
R"cpp(// String
|
2020-03-13 05:08:49 +08:00
|
|
|
struct MyClass {};
|
|
|
|
// Not triggered for string literal tokens.
|
[clangd] Add a textual fallback for go-to-definition
Summary:
This facilitates performing go-to-definition in contexts where AST-based
resolution does not work, such as comments, string literals, preprocessor
disabled regions, and macro definitions, based on textual lookup in the index.
Partially fixes https://github.com/clangd/clangd/issues/241
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72874
2020-03-06 05:47:32 +08:00
|
|
|
const char* s = "String literal mentioning M^yClass";
|
|
|
|
)cpp",
|
|
|
|
R"cpp(// Ifdef'ed out code
|
|
|
|
struct [[MyClass]] {};
|
|
|
|
#ifdef WALDO
|
|
|
|
M^yClass var;
|
|
|
|
#endif
|
|
|
|
)cpp",
|
|
|
|
R"cpp(// Macro definition
|
|
|
|
struct [[MyClass]] {};
|
|
|
|
#define DECLARE_MYCLASS_OBJ(name) M^yClass name;
|
|
|
|
)cpp",
|
|
|
|
R"cpp(// Invalid code
|
|
|
|
/*error-ok*/
|
|
|
|
int myFunction(int);
|
|
|
|
// Not triggered for token which survived preprocessing.
|
|
|
|
int var = m^yFunction();
|
|
|
|
)cpp"};
|
|
|
|
|
|
|
|
for (const char *Test : Tests) {
|
|
|
|
Annotations T(Test);
|
|
|
|
llvm::Optional<Range> WantDecl;
|
|
|
|
if (!T.ranges().empty())
|
|
|
|
WantDecl = T.range();
|
|
|
|
|
|
|
|
auto TU = TestTU::withCode(T.code());
|
|
|
|
|
|
|
|
auto AST = TU.build();
|
|
|
|
auto Index = TU.index();
|
2020-03-03 05:45:25 +08:00
|
|
|
auto Word = SpelledWord::touching(
|
[clangd] Add a textual fallback for go-to-definition
Summary:
This facilitates performing go-to-definition in contexts where AST-based
resolution does not work, such as comments, string literals, preprocessor
disabled regions, and macro definitions, based on textual lookup in the index.
Partially fixes https://github.com/clangd/clangd/issues/241
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72874
2020-03-06 05:47:32 +08:00
|
|
|
cantFail(sourceLocationInMainFile(AST.getSourceManager(), T.point())),
|
2020-03-03 05:45:25 +08:00
|
|
|
AST.getTokens(), AST.getLangOpts());
|
|
|
|
if (!Word) {
|
|
|
|
ADD_FAILURE() << "No word touching point!" << Test;
|
|
|
|
continue;
|
|
|
|
}
|
2020-03-20 04:28:53 +08:00
|
|
|
auto Results = locateSymbolTextually(*Word, AST, Index.get(),
|
|
|
|
testPath(TU.Filename), ASTNodeKind());
|
[clangd] Add a textual fallback for go-to-definition
Summary:
This facilitates performing go-to-definition in contexts where AST-based
resolution does not work, such as comments, string literals, preprocessor
disabled regions, and macro definitions, based on textual lookup in the index.
Partially fixes https://github.com/clangd/clangd/issues/241
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72874
2020-03-06 05:47:32 +08:00
|
|
|
|
|
|
|
if (!WantDecl) {
|
|
|
|
EXPECT_THAT(Results, IsEmpty()) << Test;
|
|
|
|
} else {
|
|
|
|
ASSERT_THAT(Results, ::testing::SizeIs(1)) << Test;
|
|
|
|
EXPECT_EQ(Results[0].PreferredDeclaration.range, *WantDecl) << Test;
|
|
|
|
}
|
|
|
|
}
|
2020-03-13 05:08:49 +08:00
|
|
|
} // namespace
|
[clangd] Add a textual fallback for go-to-definition
Summary:
This facilitates performing go-to-definition in contexts where AST-based
resolution does not work, such as comments, string literals, preprocessor
disabled regions, and macro definitions, based on textual lookup in the index.
Partially fixes https://github.com/clangd/clangd/issues/241
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72874
2020-03-06 05:47:32 +08:00
|
|
|
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
TEST(LocateSymbol, Ambiguous) {
|
2018-09-05 20:00:15 +08:00
|
|
|
auto T = Annotations(R"cpp(
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
struct Foo {
|
|
|
|
Foo();
|
|
|
|
Foo(Foo&&);
|
2019-10-18 06:48:39 +08:00
|
|
|
$ConstructorLoc[[Foo]](const char*);
|
2018-09-05 20:00:15 +08:00
|
|
|
};
|
|
|
|
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
Foo f();
|
2018-09-05 20:00:15 +08:00
|
|
|
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
void g(Foo foo);
|
2018-09-05 20:00:15 +08:00
|
|
|
|
|
|
|
void call() {
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
const char* str = "123";
|
2018-09-05 20:00:15 +08:00
|
|
|
Foo a = $1^str;
|
|
|
|
Foo b = Foo($2^str);
|
|
|
|
Foo c = $3^f();
|
|
|
|
$4^g($5^f());
|
|
|
|
g($6^str);
|
2019-02-21 22:48:33 +08:00
|
|
|
Foo ab$7^c;
|
|
|
|
Foo ab$8^cd("asdf");
|
|
|
|
Foo foox = Fo$9^o("asdf");
|
2019-10-18 06:48:39 +08:00
|
|
|
Foo abcde$10^("asdf");
|
|
|
|
Foo foox2 = Foo$11^("asdf");
|
2018-09-05 20:00:15 +08:00
|
|
|
}
|
2019-12-06 07:29:32 +08:00
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct S {
|
|
|
|
void $NonstaticOverload1[[bar]](int);
|
|
|
|
void $NonstaticOverload2[[bar]](float);
|
|
|
|
|
|
|
|
static void $StaticOverload1[[baz]](int);
|
|
|
|
static void $StaticOverload2[[baz]](float);
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T, typename U>
|
|
|
|
void dependent_call(S<T> s, U u) {
|
|
|
|
s.ba$12^r(u);
|
|
|
|
S<T>::ba$13^z(u);
|
|
|
|
}
|
2018-09-05 20:00:15 +08:00
|
|
|
)cpp");
|
2019-12-13 08:57:45 +08:00
|
|
|
auto TU = TestTU::withCode(T.code());
|
|
|
|
// FIXME: Go-to-definition in a template requires disabling delayed template
|
|
|
|
// parsing.
|
|
|
|
TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
|
|
|
|
auto AST = TU.build();
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
// Ordered assertions are deliberate: we expect a predictable order.
|
2019-02-21 22:48:33 +08:00
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point("1")), ElementsAre(Sym("str")));
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point("2")), ElementsAre(Sym("str")));
|
2019-02-21 22:48:33 +08:00
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point("3")), ElementsAre(Sym("f")));
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point("4")), ElementsAre(Sym("g")));
|
2019-02-21 22:48:33 +08:00
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point("5")), ElementsAre(Sym("f")));
|
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point("6")), ElementsAre(Sym("str")));
|
2019-10-18 06:48:39 +08:00
|
|
|
// FIXME: Target the constructor as well.
|
2019-02-21 22:48:33 +08:00
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point("7")), ElementsAre(Sym("abc")));
|
2019-10-18 06:48:39 +08:00
|
|
|
// FIXME: Target the constructor as well.
|
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point("8")), ElementsAre(Sym("abcd")));
|
|
|
|
// FIXME: Target the constructor as well.
|
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point("9")), ElementsAre(Sym("Foo")));
|
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point("10")),
|
2020-07-31 20:32:18 +08:00
|
|
|
ElementsAre(Sym("Foo", T.range("ConstructorLoc"), llvm::None)));
|
2019-10-18 06:48:39 +08:00
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point("11")),
|
2020-07-31 20:32:18 +08:00
|
|
|
ElementsAre(Sym("Foo", T.range("ConstructorLoc"), llvm::None)));
|
2019-12-06 07:29:32 +08:00
|
|
|
// These assertions are unordered because the order comes from
|
|
|
|
// CXXRecordDecl::lookupDependentName() which doesn't appear to provide
|
|
|
|
// an order guarantee.
|
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point("12")),
|
2020-07-31 20:32:18 +08:00
|
|
|
UnorderedElementsAre(
|
|
|
|
Sym("bar", T.range("NonstaticOverload1"), llvm::None),
|
|
|
|
Sym("bar", T.range("NonstaticOverload2"), llvm::None)));
|
|
|
|
EXPECT_THAT(
|
|
|
|
locateSymbolAt(AST, T.point("13")),
|
|
|
|
UnorderedElementsAre(Sym("baz", T.range("StaticOverload1"), llvm::None),
|
|
|
|
Sym("baz", T.range("StaticOverload2"), llvm::None)));
|
2018-09-05 20:00:15 +08:00
|
|
|
}
|
|
|
|
|
2020-03-20 04:28:53 +08:00
|
|
|
TEST(LocateSymbol, TextualDependent) {
|
|
|
|
// Put the declarations in the header to make sure we are
|
|
|
|
// finding them via the index heuristic and not the
|
|
|
|
// nearby-ident heuristic.
|
|
|
|
Annotations Header(R"cpp(
|
[clangd] Add a textual fallback for go-to-definition
Summary:
This facilitates performing go-to-definition in contexts where AST-based
resolution does not work, such as comments, string literals, preprocessor
disabled regions, and macro definitions, based on textual lookup in the index.
Partially fixes https://github.com/clangd/clangd/issues/241
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72874
2020-03-06 05:47:32 +08:00
|
|
|
struct Foo {
|
|
|
|
void $FooLoc[[uniqueMethodName]]();
|
|
|
|
};
|
|
|
|
struct Bar {
|
|
|
|
void $BarLoc[[uniqueMethodName]]();
|
|
|
|
};
|
2020-03-20 04:28:53 +08:00
|
|
|
)cpp");
|
|
|
|
Annotations Source(R"cpp(
|
[clangd] Add a textual fallback for go-to-definition
Summary:
This facilitates performing go-to-definition in contexts where AST-based
resolution does not work, such as comments, string literals, preprocessor
disabled regions, and macro definitions, based on textual lookup in the index.
Partially fixes https://github.com/clangd/clangd/issues/241
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72874
2020-03-06 05:47:32 +08:00
|
|
|
template <typename T>
|
2020-03-20 04:28:53 +08:00
|
|
|
void f(T t) {
|
|
|
|
t.u^niqueMethodName();
|
|
|
|
}
|
[clangd] Add a textual fallback for go-to-definition
Summary:
This facilitates performing go-to-definition in contexts where AST-based
resolution does not work, such as comments, string literals, preprocessor
disabled regions, and macro definitions, based on textual lookup in the index.
Partially fixes https://github.com/clangd/clangd/issues/241
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72874
2020-03-06 05:47:32 +08:00
|
|
|
)cpp");
|
2020-03-20 04:28:53 +08:00
|
|
|
TestTU TU;
|
|
|
|
TU.Code = std::string(Source.code());
|
|
|
|
TU.HeaderCode = std::string(Header.code());
|
[clangd] Add a textual fallback for go-to-definition
Summary:
This facilitates performing go-to-definition in contexts where AST-based
resolution does not work, such as comments, string literals, preprocessor
disabled regions, and macro definitions, based on textual lookup in the index.
Partially fixes https://github.com/clangd/clangd/issues/241
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72874
2020-03-06 05:47:32 +08:00
|
|
|
auto AST = TU.build();
|
|
|
|
auto Index = TU.index();
|
2020-03-20 04:28:53 +08:00
|
|
|
// Need to use locateSymbolAt() since we are testing an
|
|
|
|
// interaction between locateASTReferent() and
|
|
|
|
// locateSymbolNamedTextuallyAt().
|
|
|
|
auto Results = locateSymbolAt(AST, Source.point(), Index.get());
|
2020-07-31 20:32:18 +08:00
|
|
|
EXPECT_THAT(Results,
|
|
|
|
UnorderedElementsAre(
|
|
|
|
Sym("uniqueMethodName", Header.range("FooLoc"), llvm::None),
|
|
|
|
Sym("uniqueMethodName", Header.range("BarLoc"), llvm::None)));
|
[clangd] Add a textual fallback for go-to-definition
Summary:
This facilitates performing go-to-definition in contexts where AST-based
resolution does not work, such as comments, string literals, preprocessor
disabled regions, and macro definitions, based on textual lookup in the index.
Partially fixes https://github.com/clangd/clangd/issues/241
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72874
2020-03-06 05:47:32 +08:00
|
|
|
}
|
|
|
|
|
2020-08-07 17:36:33 +08:00
|
|
|
TEST(LocateSymbol, Alias) {
|
|
|
|
const char *Tests[] = {
|
2020-03-13 07:27:18 +08:00
|
|
|
R"cpp(
|
2020-08-07 17:36:33 +08:00
|
|
|
template <class T> struct function {};
|
|
|
|
template <class T> using [[callback]] = function<T()>;
|
|
|
|
|
|
|
|
c^allback<int> foo;
|
|
|
|
)cpp",
|
|
|
|
|
2020-03-13 07:27:18 +08:00
|
|
|
// triggered on non-definition of a renaming alias: should not give any
|
|
|
|
// underlying decls.
|
|
|
|
R"cpp(
|
2020-08-07 17:36:33 +08:00
|
|
|
class Foo {};
|
|
|
|
typedef Foo [[Bar]];
|
|
|
|
|
|
|
|
B^ar b;
|
|
|
|
)cpp",
|
2020-03-13 07:27:18 +08:00
|
|
|
R"cpp(
|
2020-08-07 17:36:33 +08:00
|
|
|
class Foo {};
|
|
|
|
using [[Bar]] = Foo; // definition
|
|
|
|
Ba^r b;
|
|
|
|
)cpp",
|
|
|
|
|
2020-03-13 07:27:18 +08:00
|
|
|
// triggered on the underlying decl of a renaming alias.
|
|
|
|
R"cpp(
|
2020-08-07 17:36:33 +08:00
|
|
|
class [[Foo]];
|
|
|
|
using Bar = Fo^o;
|
|
|
|
)cpp",
|
|
|
|
|
2020-03-13 07:27:18 +08:00
|
|
|
// triggered on definition of a non-renaming alias: should give underlying
|
|
|
|
// decls.
|
|
|
|
R"cpp(
|
2020-08-07 17:36:33 +08:00
|
|
|
namespace ns { class [[Foo]] {}; }
|
2020-10-12 22:07:15 +08:00
|
|
|
using ns::F^oo;
|
2020-08-07 17:36:33 +08:00
|
|
|
)cpp",
|
|
|
|
|
2020-03-13 07:27:18 +08:00
|
|
|
R"cpp(
|
2020-08-07 17:36:33 +08:00
|
|
|
namespace ns { int [[x]](char); int [[x]](double); }
|
2020-10-12 22:07:15 +08:00
|
|
|
using ns::^x;
|
2020-08-07 17:36:33 +08:00
|
|
|
)cpp",
|
|
|
|
|
2020-03-13 07:27:18 +08:00
|
|
|
R"cpp(
|
2020-08-07 17:36:33 +08:00
|
|
|
namespace ns { int [[x]](char); int x(double); }
|
2020-10-07 16:01:04 +08:00
|
|
|
using ns::[[x]];
|
2020-08-07 17:36:33 +08:00
|
|
|
int y = ^x('a');
|
|
|
|
)cpp",
|
|
|
|
|
2020-03-13 07:27:18 +08:00
|
|
|
R"cpp(
|
2020-08-07 17:36:33 +08:00
|
|
|
namespace ns { class [[Foo]] {}; }
|
|
|
|
using ns::Foo;
|
|
|
|
F^oo f;
|
|
|
|
)cpp",
|
|
|
|
|
2020-03-13 07:27:18 +08:00
|
|
|
// other cases that don't matter much.
|
|
|
|
R"cpp(
|
2020-08-07 17:36:33 +08:00
|
|
|
class Foo {};
|
|
|
|
typedef Foo [[Ba^r]];
|
|
|
|
)cpp",
|
2020-03-13 07:27:18 +08:00
|
|
|
R"cpp(
|
2020-08-07 17:36:33 +08:00
|
|
|
class Foo {};
|
|
|
|
using [[B^ar]] = Foo;
|
|
|
|
)cpp",
|
2020-03-13 07:27:18 +08:00
|
|
|
|
|
|
|
// Member of dependent base
|
|
|
|
R"cpp(
|
|
|
|
template <typename T>
|
|
|
|
struct Base {
|
|
|
|
void [[waldo]]() {}
|
|
|
|
};
|
|
|
|
template <typename T>
|
|
|
|
struct Derived : Base<T> {
|
2020-10-12 22:07:15 +08:00
|
|
|
using Base<T>::w^aldo;
|
2020-03-13 07:27:18 +08:00
|
|
|
};
|
|
|
|
)cpp",
|
2020-08-07 17:36:33 +08:00
|
|
|
};
|
2019-05-24 00:48:47 +08:00
|
|
|
|
2020-11-19 01:13:11 +08:00
|
|
|
for (const auto *Case : Tests) {
|
2020-08-07 17:36:33 +08:00
|
|
|
SCOPED_TRACE(Case);
|
|
|
|
auto T = Annotations(Case);
|
|
|
|
auto AST = TestTU::withCode(T.code()).build();
|
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point()),
|
2020-11-19 01:13:11 +08:00
|
|
|
UnorderedPointwise(DeclRange(), T.ranges()));
|
2020-08-07 17:36:33 +08:00
|
|
|
}
|
2019-05-24 00:48:47 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
TEST(LocateSymbol, RelPathsInCompileCommand) {
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
// The source is in "/clangd-test/src".
|
|
|
|
// We build in "/clangd-test/build".
|
|
|
|
|
2018-02-14 01:47:16 +08:00
|
|
|
Annotations SourceAnnotations(R"cpp(
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
#include "header_in_preamble.h"
|
2018-03-09 22:00:34 +08:00
|
|
|
int [[foo]];
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
#include "header_not_in_preamble.h"
|
|
|
|
int baz = f$p1^oo + bar_pre$p2^amble + bar_not_pre$p3^amble;
|
|
|
|
)cpp");
|
|
|
|
|
|
|
|
Annotations HeaderInPreambleAnnotations(R"cpp(
|
|
|
|
int [[bar_preamble]];
|
2018-02-14 01:47:16 +08:00
|
|
|
)cpp");
|
|
|
|
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
Annotations HeaderNotInPreambleAnnotations(R"cpp(
|
|
|
|
int [[bar_not_preamble]];
|
|
|
|
)cpp");
|
|
|
|
|
|
|
|
// Make the compilation paths appear as ../src/foo.cpp in the compile
|
|
|
|
// commands.
|
|
|
|
SmallString<32> RelPathPrefix("..");
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::sys::path::append(RelPathPrefix, "src");
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
std::string BuildDir = testPath("build");
|
|
|
|
MockCompilationDatabase CDB(BuildDir, RelPathPrefix);
|
|
|
|
|
2020-06-17 17:53:32 +08:00
|
|
|
MockFS FS;
|
2020-01-24 21:08:56 +08:00
|
|
|
ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
|
2018-02-14 01:47:16 +08:00
|
|
|
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
// Fill the filesystem.
|
|
|
|
auto FooCpp = testPath("src/foo.cpp");
|
2018-02-14 01:47:16 +08:00
|
|
|
FS.Files[FooCpp] = "";
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
auto HeaderInPreambleH = testPath("src/header_in_preamble.h");
|
2020-01-29 03:23:46 +08:00
|
|
|
FS.Files[HeaderInPreambleH] = std::string(HeaderInPreambleAnnotations.code());
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
auto HeaderNotInPreambleH = testPath("src/header_not_in_preamble.h");
|
2020-01-29 03:23:46 +08:00
|
|
|
FS.Files[HeaderNotInPreambleH] =
|
|
|
|
std::string(HeaderNotInPreambleAnnotations.code());
|
2018-02-14 01:47:16 +08:00
|
|
|
|
2018-03-06 01:28:54 +08:00
|
|
|
runAddDocument(Server, FooCpp, SourceAnnotations.code());
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
|
|
|
|
// Go to a definition in main source file.
|
2018-02-15 21:15:47 +08:00
|
|
|
auto Locations =
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("p1"));
|
2018-02-14 01:47:16 +08:00
|
|
|
EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
|
2020-07-31 20:32:18 +08:00
|
|
|
EXPECT_THAT(*Locations, ElementsAre(Sym("foo", SourceAnnotations.range(),
|
|
|
|
SourceAnnotations.range())));
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
|
|
|
|
// Go to a definition in header_in_preamble.h.
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("p2"));
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
EXPECT_THAT(
|
|
|
|
*Locations,
|
2020-07-31 20:32:18 +08:00
|
|
|
ElementsAre(Sym("bar_preamble", HeaderInPreambleAnnotations.range(),
|
|
|
|
HeaderInPreambleAnnotations.range())));
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
|
|
|
|
// Go to a definition in header_not_in_preamble.h.
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("p3"));
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
|
|
|
|
EXPECT_THAT(*Locations,
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
ElementsAre(Sym("bar_not_preamble",
|
2020-07-31 20:32:18 +08:00
|
|
|
HeaderNotInPreambleAnnotations.range(),
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
HeaderNotInPreambleAnnotations.range())));
|
2018-02-14 01:47:16 +08:00
|
|
|
}
|
|
|
|
|
2018-02-21 10:39:08 +08:00
|
|
|
TEST(GoToInclude, All) {
|
2020-06-17 17:53:32 +08:00
|
|
|
MockFS FS;
|
2018-02-21 10:39:08 +08:00
|
|
|
MockCompilationDatabase CDB;
|
2020-01-24 21:08:56 +08:00
|
|
|
ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
|
2018-02-21 10:39:08 +08:00
|
|
|
|
|
|
|
auto FooCpp = testPath("foo.cpp");
|
|
|
|
const char *SourceContents = R"cpp(
|
|
|
|
#include ^"$2^foo.h$3^"
|
|
|
|
#include "$4^invalid.h"
|
|
|
|
int b = a;
|
|
|
|
// test
|
|
|
|
int foo;
|
|
|
|
#in$5^clude "$6^foo.h"$7^
|
|
|
|
)cpp";
|
|
|
|
Annotations SourceAnnotations(SourceContents);
|
2020-01-29 03:23:46 +08:00
|
|
|
FS.Files[FooCpp] = std::string(SourceAnnotations.code());
|
2018-02-21 10:39:08 +08:00
|
|
|
auto FooH = testPath("foo.h");
|
|
|
|
|
2018-03-13 00:49:24 +08:00
|
|
|
const char *HeaderContents = R"cpp([[]]#pragma once
|
|
|
|
int a;
|
|
|
|
)cpp";
|
2018-02-21 10:39:08 +08:00
|
|
|
Annotations HeaderAnnotations(HeaderContents);
|
2020-01-29 03:23:46 +08:00
|
|
|
FS.Files[FooH] = std::string(HeaderAnnotations.code());
|
2018-02-21 10:39:08 +08:00
|
|
|
|
2020-11-19 15:47:25 +08:00
|
|
|
runAddDocument(Server, FooH, HeaderAnnotations.code());
|
|
|
|
runAddDocument(Server, FooCpp, SourceAnnotations.code());
|
2018-02-21 10:39:08 +08:00
|
|
|
|
|
|
|
// Test include in preamble.
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
auto Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point());
|
|
|
|
ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
|
2020-07-31 20:32:18 +08:00
|
|
|
EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(),
|
|
|
|
HeaderAnnotations.range())));
|
2018-02-21 10:39:08 +08:00
|
|
|
|
|
|
|
// Test include in preamble, last char.
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("2"));
|
|
|
|
ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
|
2020-07-31 20:32:18 +08:00
|
|
|
EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(),
|
|
|
|
HeaderAnnotations.range())));
|
2018-02-21 10:39:08 +08:00
|
|
|
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("3"));
|
|
|
|
ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
|
2020-07-31 20:32:18 +08:00
|
|
|
EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(),
|
|
|
|
HeaderAnnotations.range())));
|
2018-02-21 10:39:08 +08:00
|
|
|
|
|
|
|
// Test include outside of preamble.
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("6"));
|
|
|
|
ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
|
2020-07-31 20:32:18 +08:00
|
|
|
EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(),
|
|
|
|
HeaderAnnotations.range())));
|
2018-02-21 10:39:08 +08:00
|
|
|
|
|
|
|
// Test a few positions that do not result in Locations.
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("4"));
|
|
|
|
ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
|
2018-03-13 07:22:35 +08:00
|
|
|
EXPECT_THAT(*Locations, IsEmpty());
|
2018-02-21 10:39:08 +08:00
|
|
|
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("5"));
|
|
|
|
ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
|
2020-07-31 20:32:18 +08:00
|
|
|
EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(),
|
|
|
|
HeaderAnnotations.range())));
|
2018-02-21 10:39:08 +08:00
|
|
|
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("7"));
|
|
|
|
ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
|
2020-07-31 20:32:18 +08:00
|
|
|
EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(),
|
|
|
|
HeaderAnnotations.range())));
|
2019-04-04 21:09:02 +08:00
|
|
|
|
|
|
|
// Objective C #import directive.
|
|
|
|
Annotations ObjC(R"objc(
|
|
|
|
#import "^foo.h"
|
|
|
|
)objc");
|
|
|
|
auto FooM = testPath("foo.m");
|
2020-01-29 03:23:46 +08:00
|
|
|
FS.Files[FooM] = std::string(ObjC.code());
|
2019-04-04 21:09:02 +08:00
|
|
|
|
2020-11-19 15:47:25 +08:00
|
|
|
runAddDocument(Server, FooM, ObjC.code());
|
2019-04-04 21:09:02 +08:00
|
|
|
Locations = runLocateSymbolAt(Server, FooM, ObjC.point());
|
|
|
|
ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error";
|
2020-07-31 20:32:18 +08:00
|
|
|
EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(),
|
|
|
|
HeaderAnnotations.range())));
|
2018-02-21 10:39:08 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
TEST(LocateSymbol, WithPreamble) {
|
2018-08-17 16:15:22 +08:00
|
|
|
// Test stragety: AST should always use the latest preamble instead of last
|
|
|
|
// good preamble.
|
2020-06-17 17:53:32 +08:00
|
|
|
MockFS FS;
|
2018-08-17 16:15:22 +08:00
|
|
|
MockCompilationDatabase CDB;
|
2020-01-24 21:08:56 +08:00
|
|
|
ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
|
2018-08-17 16:15:22 +08:00
|
|
|
|
|
|
|
auto FooCpp = testPath("foo.cpp");
|
|
|
|
// The trigger locations must be the same.
|
|
|
|
Annotations FooWithHeader(R"cpp(#include "fo^o.h")cpp");
|
|
|
|
Annotations FooWithoutHeader(R"cpp(double [[fo^o]]();)cpp");
|
|
|
|
|
2020-01-29 03:23:46 +08:00
|
|
|
FS.Files[FooCpp] = std::string(FooWithHeader.code());
|
2018-08-17 16:15:22 +08:00
|
|
|
|
|
|
|
auto FooH = testPath("foo.h");
|
|
|
|
Annotations FooHeader(R"cpp([[]])cpp");
|
2020-01-29 03:23:46 +08:00
|
|
|
FS.Files[FooH] = std::string(FooHeader.code());
|
2018-08-17 16:15:22 +08:00
|
|
|
|
|
|
|
runAddDocument(Server, FooCpp, FooWithHeader.code());
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
// LocateSymbol goes to a #include file: the result comes from the preamble.
|
2018-08-17 16:15:22 +08:00
|
|
|
EXPECT_THAT(
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
cantFail(runLocateSymbolAt(Server, FooCpp, FooWithHeader.point())),
|
2020-07-31 20:32:18 +08:00
|
|
|
ElementsAre(Sym("foo.h", FooHeader.range(), FooHeader.range())));
|
2018-08-17 16:15:22 +08:00
|
|
|
|
|
|
|
// Only preamble is built, and no AST is built in this request.
|
[clangd] Track document versions, include them with diags, enhance logs
Summary:
This ties to an LSP feature (diagnostic versioning) but really a lot
of the value is in being able to log what's happening with file versions
and queues more descriptively and clearly.
As such it's fairly invasive, for a logging patch :-\
Key decisions:
- at the LSP layer, we don't reqire the client to provide versions (LSP
makes it mandatory but we never enforced it). If not provided,
versions start at 0 and increment. DraftStore handles this.
- don't propagate magically using contexts, but rather manually:
addDocument -> ParseInputs -> (ParsedAST, Preamble, various callbacks)
Context-propagation would hide the versions from ClangdServer, which
would make producing good log messages hard
- within ClangdServer, treat versions as opaque and unordered.
std::string is a convenient type for this, and allows richer versions
for embedders. They're "mandatory" but "null" is a reasonable default.
Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D75582
2020-03-04 07:33:29 +08:00
|
|
|
Server.addDocument(FooCpp, FooWithoutHeader.code(), "null",
|
|
|
|
WantDiagnostics::No);
|
2018-08-17 16:15:22 +08:00
|
|
|
// We build AST here, and it should use the latest preamble rather than the
|
|
|
|
// stale one.
|
|
|
|
EXPECT_THAT(
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
cantFail(runLocateSymbolAt(Server, FooCpp, FooWithoutHeader.point())),
|
2020-07-31 20:32:18 +08:00
|
|
|
ElementsAre(Sym("foo", FooWithoutHeader.range(), llvm::None)));
|
2018-08-17 16:15:22 +08:00
|
|
|
|
|
|
|
// Reset test environment.
|
|
|
|
runAddDocument(Server, FooCpp, FooWithHeader.code());
|
|
|
|
// Both preamble and AST are built in this request.
|
[clangd] Track document versions, include them with diags, enhance logs
Summary:
This ties to an LSP feature (diagnostic versioning) but really a lot
of the value is in being able to log what's happening with file versions
and queues more descriptively and clearly.
As such it's fairly invasive, for a logging patch :-\
Key decisions:
- at the LSP layer, we don't reqire the client to provide versions (LSP
makes it mandatory but we never enforced it). If not provided,
versions start at 0 and increment. DraftStore handles this.
- don't propagate magically using contexts, but rather manually:
addDocument -> ParseInputs -> (ParsedAST, Preamble, various callbacks)
Context-propagation would hide the versions from ClangdServer, which
would make producing good log messages hard
- within ClangdServer, treat versions as opaque and unordered.
std::string is a convenient type for this, and allows richer versions
for embedders. They're "mandatory" but "null" is a reasonable default.
Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D75582
2020-03-04 07:33:29 +08:00
|
|
|
Server.addDocument(FooCpp, FooWithoutHeader.code(), "null",
|
|
|
|
WantDiagnostics::Yes);
|
2018-08-17 16:15:22 +08:00
|
|
|
// Use the AST being built in above request.
|
|
|
|
EXPECT_THAT(
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
cantFail(runLocateSymbolAt(Server, FooCpp, FooWithoutHeader.point())),
|
2020-07-31 20:32:18 +08:00
|
|
|
ElementsAre(Sym("foo", FooWithoutHeader.range(), llvm::None)));
|
2018-08-17 16:15:22 +08:00
|
|
|
}
|
|
|
|
|
2020-03-03 05:45:25 +08:00
|
|
|
TEST(LocateSymbol, NearbyTokenSmoke) {
|
|
|
|
auto T = Annotations(R"cpp(
|
|
|
|
// prints e^rr and crashes
|
|
|
|
void die(const char* [[err]]);
|
|
|
|
)cpp");
|
|
|
|
auto AST = TestTU::withCode(T.code()).build();
|
|
|
|
// We don't pass an index, so can't hit index-based fallback.
|
|
|
|
EXPECT_THAT(locateSymbolAt(AST, T.point()),
|
2020-07-31 20:32:18 +08:00
|
|
|
ElementsAre(Sym("err", T.range(), T.range())));
|
2020-03-03 05:45:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(LocateSymbol, NearbyIdentifier) {
|
|
|
|
const char *Tests[] = {
|
|
|
|
R"cpp(
|
|
|
|
// regular identifiers (won't trigger)
|
|
|
|
int hello;
|
|
|
|
int y = he^llo;
|
|
|
|
)cpp",
|
|
|
|
R"cpp(
|
|
|
|
// disabled preprocessor sections
|
|
|
|
int [[hello]];
|
|
|
|
#if 0
|
|
|
|
int y = ^hello;
|
|
|
|
#endif
|
|
|
|
)cpp",
|
|
|
|
R"cpp(
|
|
|
|
// comments
|
|
|
|
// he^llo, world
|
|
|
|
int [[hello]];
|
|
|
|
)cpp",
|
|
|
|
R"cpp(
|
|
|
|
// not triggered by string literals
|
|
|
|
int hello;
|
|
|
|
const char* greeting = "h^ello, world";
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
// can refer to macro invocations
|
|
|
|
#define INT int
|
|
|
|
[[INT]] x;
|
|
|
|
// I^NT
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
// can refer to macro invocations (even if they expand to nothing)
|
|
|
|
#define EMPTY
|
|
|
|
[[EMPTY]] int x;
|
|
|
|
// E^MPTY
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
// prefer nearest occurrence, backwards is worse than forwards
|
|
|
|
int hello;
|
|
|
|
int x = hello;
|
|
|
|
// h^ello
|
|
|
|
int y = [[hello]];
|
|
|
|
int z = hello;
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
// short identifiers find near results
|
|
|
|
int [[hi]];
|
|
|
|
// h^i
|
|
|
|
)cpp",
|
|
|
|
R"cpp(
|
|
|
|
// short identifiers don't find far results
|
|
|
|
int hi;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// h^i
|
2020-09-30 00:54:33 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int x = hi;
|
2020-03-03 05:45:25 +08:00
|
|
|
)cpp",
|
2020-07-30 17:45:07 +08:00
|
|
|
R"cpp(
|
|
|
|
// prefer nearest occurrence even if several matched tokens
|
|
|
|
// have the same value of `floor(log2(<token line> - <word line>))`.
|
|
|
|
int hello;
|
|
|
|
int x = hello, y = hello;
|
|
|
|
int z = [[hello]];
|
|
|
|
// h^ello
|
|
|
|
)cpp"};
|
2020-03-03 05:45:25 +08:00
|
|
|
for (const char *Test : Tests) {
|
|
|
|
Annotations T(Test);
|
|
|
|
auto AST = TestTU::withCode(T.code()).build();
|
|
|
|
const auto &SM = AST.getSourceManager();
|
|
|
|
llvm::Optional<Range> Nearby;
|
|
|
|
auto Word =
|
|
|
|
SpelledWord::touching(cantFail(sourceLocationInMainFile(SM, T.point())),
|
|
|
|
AST.getTokens(), AST.getLangOpts());
|
|
|
|
if (!Word) {
|
|
|
|
ADD_FAILURE() << "No word at point! " << Test;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (const auto *Tok = findNearbyIdentifier(*Word, AST.getTokens()))
|
|
|
|
Nearby = halfOpenToRange(SM, CharSourceRange::getCharRange(
|
|
|
|
Tok->location(), Tok->endLocation()));
|
|
|
|
if (T.ranges().empty())
|
|
|
|
EXPECT_THAT(Nearby, Eq(llvm::None)) << Test;
|
|
|
|
else
|
|
|
|
EXPECT_EQ(Nearby, T.range()) << Test;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-19 01:13:11 +08:00
|
|
|
TEST(FindImplementations, Inheritance) {
|
|
|
|
llvm::StringRef Test = R"cpp(
|
2020-12-03 16:42:46 +08:00
|
|
|
struct $0^Base {
|
2020-11-19 01:13:11 +08:00
|
|
|
virtual void F$1^oo();
|
|
|
|
void C$4^oncrete();
|
|
|
|
};
|
2020-12-03 16:42:46 +08:00
|
|
|
struct $0[[Child1]] : Base {
|
2020-11-19 01:13:11 +08:00
|
|
|
void $1[[Fo$3^o]]() override;
|
|
|
|
virtual void B$2^ar();
|
|
|
|
void Concrete(); // No implementations for concrete methods.
|
|
|
|
};
|
|
|
|
struct Child2 : Child1 {
|
|
|
|
void $3[[Foo]]() override;
|
|
|
|
void $2[[Bar]]() override;
|
|
|
|
};
|
|
|
|
void FromReference() {
|
2020-12-03 16:42:46 +08:00
|
|
|
$0^Base* B;
|
2020-11-19 01:13:11 +08:00
|
|
|
B->Fo$1^o();
|
|
|
|
B->C$4^oncrete();
|
|
|
|
&Base::Fo$1^o;
|
|
|
|
Child1 * C1;
|
|
|
|
C1->B$2^ar();
|
|
|
|
C1->Fo$3^o();
|
|
|
|
}
|
2020-12-03 16:42:46 +08:00
|
|
|
// CRTP should work.
|
|
|
|
template<typename T>
|
|
|
|
struct $5^TemplateBase {};
|
|
|
|
struct $5[[Child3]] : public TemplateBase<Child3> {};
|
2021-01-16 00:19:53 +08:00
|
|
|
|
|
|
|
// Local classes.
|
|
|
|
void LocationFunction() {
|
|
|
|
struct $0[[LocalClass1]] : Base {
|
|
|
|
void $1[[Foo]]() override;
|
|
|
|
};
|
|
|
|
struct $6^LocalBase {
|
|
|
|
virtual void $7^Bar();
|
|
|
|
};
|
|
|
|
struct $6[[LocalClass2]]: LocalBase {
|
|
|
|
void $7[[Bar]]() override;
|
|
|
|
};
|
|
|
|
}
|
2020-11-19 01:13:11 +08:00
|
|
|
)cpp";
|
|
|
|
|
|
|
|
Annotations Code(Test);
|
|
|
|
auto TU = TestTU::withCode(Code.code());
|
|
|
|
auto AST = TU.build();
|
2021-01-16 00:19:53 +08:00
|
|
|
auto Index = TU.index();
|
|
|
|
for (StringRef Label : {"0", "1", "2", "3", "4", "5", "6", "7"}) {
|
2020-11-19 01:13:11 +08:00
|
|
|
for (const auto &Point : Code.points(Label)) {
|
2021-01-16 00:19:53 +08:00
|
|
|
EXPECT_THAT(findImplementations(AST, Point, Index.get()),
|
2020-11-19 01:13:11 +08:00
|
|
|
UnorderedPointwise(DeclRange(), Code.ranges(Label)))
|
|
|
|
<< Code.code() << " at " << Point << " for Label " << Label;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FindImplementations, CaptureDefintion) {
|
|
|
|
llvm::StringRef Test = R"cpp(
|
|
|
|
struct Base {
|
|
|
|
virtual void F^oo();
|
|
|
|
};
|
|
|
|
struct Child1 : Base {
|
|
|
|
void $Decl[[Foo]]() override;
|
|
|
|
};
|
|
|
|
struct Child2 : Base {
|
|
|
|
void $Child2[[Foo]]() override;
|
|
|
|
};
|
|
|
|
void Child1::$Def[[Foo]]() { /* Definition */ }
|
|
|
|
)cpp";
|
|
|
|
Annotations Code(Test);
|
|
|
|
auto TU = TestTU::withCode(Code.code());
|
|
|
|
auto AST = TU.build();
|
|
|
|
EXPECT_THAT(
|
|
|
|
findImplementations(AST, Code.point(), TU.index().get()),
|
|
|
|
UnorderedElementsAre(Sym("Foo", Code.range("Decl"), Code.range("Def")),
|
|
|
|
Sym("Foo", Code.range("Child2"), llvm::None)))
|
|
|
|
<< Test;
|
|
|
|
}
|
|
|
|
|
2021-01-27 00:16:57 +08:00
|
|
|
void checkFindRefs(llvm::StringRef Test, bool UseIndex = false) {
|
|
|
|
Annotations T(Test);
|
|
|
|
auto TU = TestTU::withCode(T.code());
|
|
|
|
auto AST = TU.build();
|
|
|
|
std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
|
|
|
|
for (const auto &R : T.ranges())
|
|
|
|
ExpectedLocations.push_back(AllOf(RangeIs(R), AttrsAre(0u)));
|
|
|
|
// $def is actually shorthand for both definition and declaration.
|
|
|
|
// If we have cases that are definition-only, we should change this.
|
|
|
|
for (const auto &R : T.ranges("def"))
|
|
|
|
ExpectedLocations.push_back(
|
|
|
|
AllOf(RangeIs(R), AttrsAre(ReferencesResult::Definition |
|
|
|
|
ReferencesResult::Declaration)));
|
|
|
|
for (const auto &R : T.ranges("decl"))
|
|
|
|
ExpectedLocations.push_back(
|
|
|
|
AllOf(RangeIs(R), AttrsAre(ReferencesResult::Declaration)));
|
|
|
|
EXPECT_THAT(
|
|
|
|
findReferences(AST, T.point(), 0, UseIndex ? TU.index().get() : nullptr)
|
|
|
|
.References,
|
|
|
|
UnorderedElementsAreArray(ExpectedLocations))
|
|
|
|
<< Test;
|
|
|
|
}
|
|
|
|
|
2018-09-05 18:33:36 +08:00
|
|
|
TEST(FindReferences, WithinAST) {
|
|
|
|
const char *Tests[] = {
|
|
|
|
R"cpp(// Local variable
|
|
|
|
int main() {
|
2021-01-27 00:16:57 +08:00
|
|
|
int $def[[foo]];
|
2018-10-04 17:56:08 +08:00
|
|
|
[[^foo]] = 2;
|
|
|
|
int test1 = [[foo]];
|
2018-09-05 18:33:36 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Struct
|
|
|
|
namespace ns1 {
|
2021-01-27 00:16:57 +08:00
|
|
|
struct $def[[Foo]] {};
|
2018-09-05 18:33:36 +08:00
|
|
|
} // namespace ns1
|
|
|
|
int main() {
|
2018-10-04 17:56:08 +08:00
|
|
|
ns1::[[Fo^o]]* Params;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Forward declaration
|
2021-01-27 00:16:57 +08:00
|
|
|
class $decl[[Foo]];
|
|
|
|
class $def[[Foo]] {};
|
2018-10-04 17:56:08 +08:00
|
|
|
int main() {
|
|
|
|
[[Fo^o]] foo;
|
2018-09-05 18:33:36 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Function
|
2021-01-27 00:16:57 +08:00
|
|
|
int $def[[foo]](int) {}
|
2018-09-05 18:33:36 +08:00
|
|
|
int main() {
|
2018-10-04 17:56:08 +08:00
|
|
|
auto *X = &[[^foo]];
|
[clangd] Errors in TestTU cause test failures unless suppressed with error-ok.
Summary:
The historic behavior of TestTU is to gather diagnostics and otherwise ignore
them. So if a test has a syntax error, and doesn't assert diagnostics, it
silently misbehaves.
This can be annoying when developing tests, as evidenced by various tests
gaining "assert no diagnostics" where that's not really the point of the test.
This patch aims to make that default behavior. For the first error
(not warning), TestTU will call ADD_FAILURE().
This can be suppressed with a comment containing "error-ok". For now that will
suppress any errors in the TU. We can make this stricter later -verify style.
(-verify itself is hard to reuse because of DiagnosticConsumer interfaces...)
A magic-comment was chosen over a TestTU option because of table-driven tests.
In addition to the behavior change, this patch:
- adds //error-ok where we're knowingly testing invalid code
(e.g. for diagnostics, crash-resilience, or token-level tests)
- fixes a bunch of errors in the checked-in tests, mostly trivial (missing ;)
- removes a bunch of now-redundant instances of "assert no diagnostics"
Reviewers: kadircet
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D73199
2020-01-22 23:38:41 +08:00
|
|
|
[[foo]](42);
|
2018-09-05 18:33:36 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Field
|
|
|
|
struct Foo {
|
2021-01-27 00:16:57 +08:00
|
|
|
int $def[[foo]];
|
2018-10-04 17:56:08 +08:00
|
|
|
Foo() : [[foo]](0) {}
|
2018-09-05 18:33:36 +08:00
|
|
|
};
|
|
|
|
int main() {
|
|
|
|
Foo f;
|
2018-10-04 17:56:08 +08:00
|
|
|
f.[[f^oo]] = 1;
|
2018-09-05 18:33:36 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Method call
|
2021-01-27 00:16:57 +08:00
|
|
|
struct Foo { int $decl[[foo]](); };
|
|
|
|
int Foo::$def[[foo]]() {}
|
2018-09-05 18:33:36 +08:00
|
|
|
int main() {
|
|
|
|
Foo f;
|
2018-10-04 17:56:08 +08:00
|
|
|
f.[[^foo]]();
|
2018-09-05 18:33:36 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
2019-03-08 17:54:37 +08:00
|
|
|
|
|
|
|
R"cpp(// Constructor
|
|
|
|
struct Foo {
|
2021-01-27 00:16:57 +08:00
|
|
|
$decl[[F^oo]](int);
|
2019-03-08 17:54:37 +08:00
|
|
|
};
|
|
|
|
void foo() {
|
|
|
|
Foo f = [[Foo]](42);
|
|
|
|
}
|
|
|
|
)cpp",
|
2018-09-05 18:33:36 +08:00
|
|
|
|
|
|
|
R"cpp(// Typedef
|
2021-01-27 00:16:57 +08:00
|
|
|
typedef int $def[[Foo]];
|
2018-09-05 18:33:36 +08:00
|
|
|
int main() {
|
2018-10-04 17:56:08 +08:00
|
|
|
[[^Foo]] bar;
|
2018-09-05 18:33:36 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(// Namespace
|
2021-01-27 00:16:57 +08:00
|
|
|
namespace $decl[[ns]] { // FIXME: def?
|
2018-09-05 18:33:36 +08:00
|
|
|
struct Foo {};
|
|
|
|
} // namespace ns
|
2018-10-04 17:56:08 +08:00
|
|
|
int main() { [[^ns]]::Foo foo; }
|
2018-09-05 18:33:36 +08:00
|
|
|
)cpp",
|
[clangd] Use expansion location when the ref is inside macros.
Summary:
Previously, xrefs has inconsistent behavior when the reference is inside
macro body:
- AST-based xrefs (for main file) uses the expansion location;
- our index uses the spelling location;
This patch makes our index use file locations for references, which is
consistent with AST-based xrefs, and kythe as well.
After this patch, memory usage of static index on LLVM increases ~5%.
Reviewers: ilya-biryukov
Subscribers: merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D70480
2019-12-09 19:00:42 +08:00
|
|
|
|
|
|
|
R"cpp(// Macros
|
|
|
|
#define TYPE(X) X
|
|
|
|
#define FOO Foo
|
|
|
|
#define CAT(X, Y) X##Y
|
2021-01-27 00:16:57 +08:00
|
|
|
class $def[[Fo^o]] {};
|
[clangd] Use expansion location when the ref is inside macros.
Summary:
Previously, xrefs has inconsistent behavior when the reference is inside
macro body:
- AST-based xrefs (for main file) uses the expansion location;
- our index uses the spelling location;
This patch makes our index use file locations for references, which is
consistent with AST-based xrefs, and kythe as well.
After this patch, memory usage of static index on LLVM increases ~5%.
Reviewers: ilya-biryukov
Subscribers: merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D70480
2019-12-09 19:00:42 +08:00
|
|
|
void test() {
|
|
|
|
TYPE([[Foo]]) foo;
|
|
|
|
[[FOO]] foo2;
|
|
|
|
TYPE(TYPE([[Foo]])) foo3;
|
|
|
|
[[CAT]](Fo, o) foo4;
|
|
|
|
}
|
|
|
|
)cpp",
|
2020-01-08 20:57:00 +08:00
|
|
|
|
|
|
|
R"cpp(// Macros
|
2021-01-27 00:16:57 +08:00
|
|
|
#define $def[[MA^CRO]](X) (X+1)
|
2020-01-08 20:57:00 +08:00
|
|
|
void test() {
|
|
|
|
int x = [[MACRO]]([[MACRO]](1));
|
|
|
|
}
|
|
|
|
)cpp",
|
2020-02-12 21:42:18 +08:00
|
|
|
|
2020-11-08 15:58:17 +08:00
|
|
|
R"cpp(// Macro outside preamble
|
|
|
|
int breakPreamble;
|
2021-01-27 00:16:57 +08:00
|
|
|
#define $def[[MA^CRO]](X) (X+1)
|
2020-11-08 15:58:17 +08:00
|
|
|
void test() {
|
|
|
|
int x = [[MACRO]]([[MACRO]](1));
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
2020-02-12 21:42:18 +08:00
|
|
|
R"cpp(
|
2021-01-27 00:16:57 +08:00
|
|
|
int $def[[v^ar]] = 0;
|
2020-02-12 21:42:18 +08:00
|
|
|
void foo(int s = [[var]]);
|
|
|
|
)cpp",
|
2020-02-19 19:27:12 +08:00
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
template <typename T>
|
2021-01-27 00:16:57 +08:00
|
|
|
class $def[[Fo^o]] {};
|
2020-02-19 19:27:12 +08:00
|
|
|
void func([[Foo]]<int>);
|
|
|
|
)cpp",
|
2020-02-20 22:22:07 +08:00
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
template <typename T>
|
2021-01-27 00:16:57 +08:00
|
|
|
class $def[[Foo]] {};
|
2020-02-20 22:22:07 +08:00
|
|
|
void func([[Fo^o]]<int>);
|
|
|
|
)cpp",
|
2020-02-26 20:39:46 +08:00
|
|
|
R"cpp(// Not touching any identifiers.
|
|
|
|
struct Foo {
|
2021-01-27 00:16:57 +08:00
|
|
|
$def[[~]]Foo() {};
|
2020-02-26 20:39:46 +08:00
|
|
|
};
|
|
|
|
void foo() {
|
|
|
|
Foo f;
|
|
|
|
f.[[^~]]Foo();
|
|
|
|
}
|
|
|
|
)cpp",
|
2020-09-08 08:10:45 +08:00
|
|
|
R"cpp(// Lambda capture initializer
|
|
|
|
void foo() {
|
2021-01-27 00:16:57 +08:00
|
|
|
int $def[[w^aldo]] = 42;
|
2020-09-08 08:10:45 +08:00
|
|
|
auto lambda = [x = [[waldo]]](){};
|
|
|
|
}
|
|
|
|
)cpp",
|
2020-09-07 14:28:46 +08:00
|
|
|
R"cpp(// Renaming alias
|
|
|
|
template <typename> class Vector {};
|
2021-01-27 00:16:57 +08:00
|
|
|
using $def[[^X]] = Vector<int>;
|
2020-09-07 14:28:46 +08:00
|
|
|
[[X]] x1;
|
|
|
|
Vector<int> x2;
|
|
|
|
Vector<double> y;
|
|
|
|
)cpp",
|
2018-09-05 18:33:36 +08:00
|
|
|
};
|
2021-01-27 00:16:57 +08:00
|
|
|
for (const char *Test : Tests)
|
|
|
|
checkFindRefs(Test);
|
2018-09-05 18:33:36 +08:00
|
|
|
}
|
|
|
|
|
2021-01-08 18:56:30 +08:00
|
|
|
TEST(FindReferences, IncludeOverrides) {
|
|
|
|
llvm::StringRef Test =
|
|
|
|
R"cpp(
|
|
|
|
class Base {
|
|
|
|
public:
|
2021-01-27 00:16:57 +08:00
|
|
|
virtual void $decl[[f^unc]]() = 0;
|
2021-01-08 18:56:30 +08:00
|
|
|
};
|
|
|
|
class Derived : public Base {
|
|
|
|
public:
|
2021-01-27 00:57:22 +08:00
|
|
|
void [[func]]() override;
|
2021-01-08 18:56:30 +08:00
|
|
|
};
|
|
|
|
void test(Derived* D) {
|
|
|
|
D->[[func]]();
|
|
|
|
})cpp";
|
2021-01-27 00:16:57 +08:00
|
|
|
checkFindRefs(Test, /*UseIndex=*/true);
|
2021-01-08 18:56:30 +08:00
|
|
|
}
|
|
|
|
|
2020-04-02 15:29:16 +08:00
|
|
|
TEST(FindReferences, MainFileReferencesOnly) {
|
|
|
|
llvm::StringRef Test =
|
|
|
|
R"cpp(
|
|
|
|
void test() {
|
|
|
|
int [[fo^o]] = 1;
|
|
|
|
// refs not from main file should not be included.
|
|
|
|
#include "foo.inc"
|
|
|
|
})cpp";
|
|
|
|
|
|
|
|
Annotations Code(Test);
|
|
|
|
auto TU = TestTU::withCode(Code.code());
|
|
|
|
TU.AdditionalFiles["foo.inc"] = R"cpp(
|
|
|
|
foo = 3;
|
|
|
|
)cpp";
|
|
|
|
auto AST = TU.build();
|
|
|
|
|
2021-01-27 00:16:57 +08:00
|
|
|
std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
|
2020-04-02 15:29:16 +08:00
|
|
|
for (const auto &R : Code.ranges())
|
|
|
|
ExpectedLocations.push_back(RangeIs(R));
|
|
|
|
EXPECT_THAT(findReferences(AST, Code.point(), 0).References,
|
|
|
|
ElementsAreArray(ExpectedLocations))
|
|
|
|
<< Test;
|
|
|
|
}
|
|
|
|
|
2018-12-13 21:17:04 +08:00
|
|
|
TEST(FindReferences, ExplicitSymbols) {
|
|
|
|
const char *Tests[] = {
|
|
|
|
R"cpp(
|
2021-01-27 00:16:57 +08:00
|
|
|
struct Foo { Foo* $decl[[self]]() const; };
|
2018-12-13 21:17:04 +08:00
|
|
|
void f() {
|
2019-08-20 22:07:27 +08:00
|
|
|
Foo foo;
|
|
|
|
if (Foo* T = foo.[[^self]]()) {} // Foo member call expr.
|
2018-12-13 21:17:04 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
struct Foo { Foo(int); };
|
|
|
|
Foo f() {
|
2021-01-27 00:16:57 +08:00
|
|
|
int $def[[b]];
|
2019-08-20 22:07:27 +08:00
|
|
|
return [[^b]]; // Foo constructor expr.
|
2018-12-13 21:17:04 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
struct Foo {};
|
|
|
|
void g(Foo);
|
2021-01-27 00:16:57 +08:00
|
|
|
Foo $decl[[f]]();
|
2018-12-13 21:17:04 +08:00
|
|
|
void call() {
|
2019-08-20 22:07:27 +08:00
|
|
|
g([[^f]]()); // Foo constructor expr.
|
2018-12-13 21:17:04 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
|
|
|
|
R"cpp(
|
2021-01-27 00:16:57 +08:00
|
|
|
void $decl[[foo]](int);
|
|
|
|
void $decl[[foo]](double);
|
2018-12-13 21:17:04 +08:00
|
|
|
|
|
|
|
namespace ns {
|
2021-01-27 00:16:57 +08:00
|
|
|
using ::$decl[[fo^o]];
|
2018-12-13 21:17:04 +08:00
|
|
|
}
|
|
|
|
)cpp",
|
2019-08-21 18:54:19 +08:00
|
|
|
|
|
|
|
R"cpp(
|
|
|
|
struct X {
|
|
|
|
operator bool();
|
|
|
|
};
|
|
|
|
|
|
|
|
int test() {
|
2021-01-27 00:16:57 +08:00
|
|
|
X $def[[a]];
|
2019-08-21 18:54:19 +08:00
|
|
|
[[a]].operator bool();
|
|
|
|
if ([[a^]]) {} // ignore implicit conversion-operator AST node
|
|
|
|
}
|
|
|
|
)cpp",
|
2018-12-13 21:17:04 +08:00
|
|
|
};
|
2021-01-27 00:16:57 +08:00
|
|
|
for (const char *Test : Tests)
|
|
|
|
checkFindRefs(Test);
|
2018-12-13 21:17:04 +08:00
|
|
|
}
|
|
|
|
|
2020-01-08 20:57:00 +08:00
|
|
|
TEST(FindReferences, NeedsIndexForSymbols) {
|
2018-09-05 18:33:36 +08:00
|
|
|
const char *Header = "int foo();";
|
|
|
|
Annotations Main("int main() { [[f^oo]](); }");
|
|
|
|
TestTU TU;
|
2020-01-29 03:23:46 +08:00
|
|
|
TU.Code = std::string(Main.code());
|
2018-09-05 18:33:36 +08:00
|
|
|
TU.HeaderCode = Header;
|
|
|
|
auto AST = TU.build();
|
|
|
|
|
|
|
|
// References in main file are returned without index.
|
2019-11-18 18:35:00 +08:00
|
|
|
EXPECT_THAT(
|
|
|
|
findReferences(AST, Main.point(), 0, /*Index=*/nullptr).References,
|
|
|
|
ElementsAre(RangeIs(Main.range())));
|
2018-09-05 18:33:36 +08:00
|
|
|
Annotations IndexedMain(R"cpp(
|
2021-01-27 00:16:57 +08:00
|
|
|
int [[foo]]() { return 42; }
|
2018-09-05 18:33:36 +08:00
|
|
|
)cpp");
|
|
|
|
|
|
|
|
// References from indexed files are included.
|
|
|
|
TestTU IndexedTU;
|
2020-01-29 03:23:46 +08:00
|
|
|
IndexedTU.Code = std::string(IndexedMain.code());
|
2018-09-05 18:33:36 +08:00
|
|
|
IndexedTU.Filename = "Indexed.cpp";
|
|
|
|
IndexedTU.HeaderCode = Header;
|
2019-11-18 18:35:00 +08:00
|
|
|
EXPECT_THAT(
|
|
|
|
findReferences(AST, Main.point(), 0, IndexedTU.index().get()).References,
|
2021-01-27 00:16:57 +08:00
|
|
|
ElementsAre(RangeIs(Main.range()),
|
|
|
|
AllOf(RangeIs(IndexedMain.range()),
|
|
|
|
AttrsAre(ReferencesResult::Declaration |
|
|
|
|
ReferencesResult::Definition))));
|
2019-11-18 18:35:00 +08:00
|
|
|
auto LimitRefs =
|
|
|
|
findReferences(AST, Main.point(), /*Limit*/ 1, IndexedTU.index().get());
|
|
|
|
EXPECT_EQ(1u, LimitRefs.References.size());
|
|
|
|
EXPECT_TRUE(LimitRefs.HasMore);
|
2019-01-15 02:11:09 +08:00
|
|
|
|
2020-01-08 20:57:00 +08:00
|
|
|
// Avoid indexed results for the main file. Use AST for the mainfile.
|
2018-09-05 18:33:36 +08:00
|
|
|
TU.Code = ("\n\n" + Main.code()).str();
|
2019-11-18 18:35:00 +08:00
|
|
|
EXPECT_THAT(findReferences(AST, Main.point(), 0, TU.index().get()).References,
|
2018-09-05 18:33:36 +08:00
|
|
|
ElementsAre(RangeIs(Main.range())));
|
2018-09-11 21:01:49 +08:00
|
|
|
}
|
2018-09-05 18:33:36 +08:00
|
|
|
|
2020-01-08 20:57:00 +08:00
|
|
|
TEST(FindReferences, NeedsIndexForMacro) {
|
|
|
|
const char *Header = "#define MACRO(X) (X+1)";
|
|
|
|
Annotations Main(R"cpp(
|
|
|
|
int main() {
|
|
|
|
int a = [[MA^CRO]](1);
|
|
|
|
}
|
|
|
|
)cpp");
|
|
|
|
TestTU TU;
|
2020-01-29 03:23:46 +08:00
|
|
|
TU.Code = std::string(Main.code());
|
2020-01-08 20:57:00 +08:00
|
|
|
TU.HeaderCode = Header;
|
|
|
|
auto AST = TU.build();
|
|
|
|
|
|
|
|
// References in main file are returned without index.
|
|
|
|
EXPECT_THAT(
|
|
|
|
findReferences(AST, Main.point(), 0, /*Index=*/nullptr).References,
|
|
|
|
ElementsAre(RangeIs(Main.range())));
|
|
|
|
|
|
|
|
Annotations IndexedMain(R"cpp(
|
|
|
|
int indexed_main() {
|
|
|
|
int a = [[MACRO]](1);
|
|
|
|
}
|
|
|
|
)cpp");
|
|
|
|
|
|
|
|
// References from indexed files are included.
|
|
|
|
TestTU IndexedTU;
|
2020-01-29 03:23:46 +08:00
|
|
|
IndexedTU.Code = std::string(IndexedMain.code());
|
2020-01-08 20:57:00 +08:00
|
|
|
IndexedTU.Filename = "Indexed.cpp";
|
|
|
|
IndexedTU.HeaderCode = Header;
|
|
|
|
EXPECT_THAT(
|
|
|
|
findReferences(AST, Main.point(), 0, IndexedTU.index().get()).References,
|
|
|
|
ElementsAre(RangeIs(Main.range()), RangeIs(IndexedMain.range())));
|
|
|
|
auto LimitRefs =
|
|
|
|
findReferences(AST, Main.point(), /*Limit*/ 1, IndexedTU.index().get());
|
|
|
|
EXPECT_EQ(1u, LimitRefs.References.size());
|
|
|
|
EXPECT_TRUE(LimitRefs.HasMore);
|
|
|
|
}
|
|
|
|
|
2018-09-05 18:33:36 +08:00
|
|
|
TEST(FindReferences, NoQueryForLocalSymbols) {
|
|
|
|
struct RecordingIndex : public MemIndex {
|
2019-01-07 23:45:19 +08:00
|
|
|
mutable Optional<llvm::DenseSet<SymbolID>> RefIDs;
|
2019-11-13 21:42:26 +08:00
|
|
|
bool refs(const RefsRequest &Req,
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::function_ref<void(const Ref &)>) const override {
|
2018-09-05 18:33:36 +08:00
|
|
|
RefIDs = Req.IDs;
|
2019-11-13 21:42:26 +08:00
|
|
|
return false;
|
2018-09-05 18:33:36 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Test {
|
|
|
|
StringRef AnnotatedCode;
|
|
|
|
bool WantQuery;
|
|
|
|
} Tests[] = {
|
|
|
|
{"int ^x;", true},
|
|
|
|
// For now we don't assume header structure which would allow skipping.
|
|
|
|
{"namespace { int ^x; }", true},
|
|
|
|
{"static int ^x;", true},
|
|
|
|
// Anything in a function certainly can't be referenced though.
|
|
|
|
{"void foo() { int ^x; }", false},
|
|
|
|
{"void foo() { struct ^x{}; }", false},
|
|
|
|
{"auto lambda = []{ int ^x; };", false},
|
|
|
|
};
|
|
|
|
for (Test T : Tests) {
|
|
|
|
Annotations File(T.AnnotatedCode);
|
|
|
|
RecordingIndex Rec;
|
|
|
|
auto AST = TestTU::withCode(File.code()).build();
|
2019-01-15 02:11:09 +08:00
|
|
|
findReferences(AST, File.point(), 0, &Rec);
|
2018-09-05 18:33:36 +08:00
|
|
|
if (T.WantQuery)
|
2018-10-20 23:30:37 +08:00
|
|
|
EXPECT_NE(Rec.RefIDs, None) << T.AnnotatedCode;
|
2018-09-05 18:33:36 +08:00
|
|
|
else
|
2018-10-20 23:30:37 +08:00
|
|
|
EXPECT_EQ(Rec.RefIDs, None) << T.AnnotatedCode;
|
2018-09-05 18:33:36 +08:00
|
|
|
}
|
2018-09-11 21:01:49 +08:00
|
|
|
}
|
2018-09-05 18:33:36 +08:00
|
|
|
|
2019-09-26 15:27:43 +08:00
|
|
|
TEST(GetNonLocalDeclRefs, All) {
|
|
|
|
struct Case {
|
|
|
|
llvm::StringRef AnnotatedCode;
|
2020-01-29 06:30:02 +08:00
|
|
|
std::vector<std::string> ExpectedDecls;
|
2019-09-26 15:27:43 +08:00
|
|
|
} Cases[] = {
|
|
|
|
{
|
|
|
|
// VarDecl and ParamVarDecl
|
|
|
|
R"cpp(
|
|
|
|
void bar();
|
|
|
|
void ^foo(int baz) {
|
|
|
|
int x = 10;
|
|
|
|
bar();
|
|
|
|
})cpp",
|
|
|
|
{"bar"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Method from class
|
|
|
|
R"cpp(
|
|
|
|
class Foo { public: void foo(); };
|
|
|
|
class Bar {
|
|
|
|
void foo();
|
|
|
|
void bar();
|
|
|
|
};
|
|
|
|
void Bar::^foo() {
|
|
|
|
Foo f;
|
|
|
|
bar();
|
|
|
|
f.foo();
|
|
|
|
})cpp",
|
|
|
|
{"Bar", "Bar::bar", "Foo", "Foo::foo"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Local types
|
|
|
|
R"cpp(
|
|
|
|
void ^foo() {
|
|
|
|
class Foo { public: void foo() {} };
|
|
|
|
class Bar { public: void bar() {} };
|
|
|
|
Foo f;
|
|
|
|
Bar b;
|
|
|
|
b.bar();
|
|
|
|
f.foo();
|
|
|
|
})cpp",
|
|
|
|
{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Template params
|
|
|
|
R"cpp(
|
|
|
|
template <typename T, template<typename> class Q>
|
|
|
|
void ^foo() {
|
|
|
|
T x;
|
|
|
|
Q<T> y;
|
|
|
|
})cpp",
|
|
|
|
{},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
for (const Case &C : Cases) {
|
|
|
|
Annotations File(C.AnnotatedCode);
|
|
|
|
auto AST = TestTU::withCode(File.code()).build();
|
|
|
|
SourceLocation SL = llvm::cantFail(
|
|
|
|
sourceLocationInMainFile(AST.getSourceManager(), File.point()));
|
|
|
|
|
|
|
|
const FunctionDecl *FD =
|
|
|
|
llvm::dyn_cast<FunctionDecl>(&findDecl(AST, [SL](const NamedDecl &ND) {
|
|
|
|
return ND.getLocation() == SL && llvm::isa<FunctionDecl>(ND);
|
|
|
|
}));
|
|
|
|
ASSERT_NE(FD, nullptr);
|
|
|
|
|
|
|
|
auto NonLocalDeclRefs = getNonLocalDeclRefs(AST, FD);
|
|
|
|
std::vector<std::string> Names;
|
|
|
|
for (const Decl *D : NonLocalDeclRefs) {
|
|
|
|
if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))
|
|
|
|
Names.push_back(ND->getQualifiedNameAsString());
|
|
|
|
}
|
2019-10-18 20:07:19 +08:00
|
|
|
EXPECT_THAT(Names, UnorderedElementsAreArray(C.ExpectedDecls))
|
|
|
|
<< File.code();
|
2019-09-26 15:27:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-17 02:08:51 +08:00
|
|
|
TEST(DocumentLinks, All) {
|
|
|
|
Annotations MainCpp(R"cpp(
|
2020-05-04 16:48:19 +08:00
|
|
|
#/*comments*/include /*comments*/ $foo[["foo.h"]] //more comments
|
2019-12-17 02:08:51 +08:00
|
|
|
int end_of_preamble = 0;
|
2020-05-04 16:48:19 +08:00
|
|
|
#include $bar[[<bar.h>]]
|
2019-12-17 02:08:51 +08:00
|
|
|
)cpp");
|
|
|
|
|
|
|
|
TestTU TU;
|
2020-01-29 03:23:46 +08:00
|
|
|
TU.Code = std::string(MainCpp.code());
|
2019-12-17 02:08:51 +08:00
|
|
|
TU.AdditionalFiles = {{"foo.h", ""}, {"bar.h", ""}};
|
2020-05-04 16:48:19 +08:00
|
|
|
TU.ExtraArgs = {"-isystem."};
|
2019-12-17 02:08:51 +08:00
|
|
|
auto AST = TU.build();
|
|
|
|
|
|
|
|
EXPECT_THAT(
|
|
|
|
clangd::getDocumentLinks(AST),
|
|
|
|
ElementsAre(
|
|
|
|
DocumentLink({MainCpp.range("foo"),
|
|
|
|
URIForFile::canonicalize(testPath("foo.h"), "")}),
|
|
|
|
DocumentLink({MainCpp.range("bar"),
|
|
|
|
URIForFile::canonicalize(testPath("bar.h"), "")})));
|
|
|
|
}
|
|
|
|
|
2017-12-21 00:06:05 +08:00
|
|
|
} // namespace
|
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|