2020-01-21 11:50:57 +01:00
|
|
|
//===-- FindTargetTests.cpp --------------------------*- C++ -*------------===//
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00: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
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "FindTarget.h"
|
|
|
|
|
|
|
|
#include "Selection.h"
|
|
|
|
#include "TestTU.h"
|
2019-09-25 12:40:22 +00:00
|
|
|
#include "clang/AST/Decl.h"
|
2019-09-27 09:39:10 +00:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2019-09-25 12:40:22 +00:00
|
|
|
#include "clang/Basic/SourceLocation.h"
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
2019-09-27 09:39:10 +00:00
|
|
|
#include "llvm/Support/Casting.h"
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include "llvm/Testing/Support/Annotations.h"
|
|
|
|
#include "gmock/gmock.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <initializer_list>
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
// A referenced Decl together with its DeclRelationSet, for assertions.
|
|
|
|
//
|
|
|
|
// There's no great way to assert on the "content" of a Decl in the general case
|
|
|
|
// that's both expressive and unambiguous (e.g. clearly distinguishes between
|
|
|
|
// templated decls and their specializations).
|
|
|
|
//
|
|
|
|
// We use the result of pretty-printing the decl, with the {body} truncated.
|
|
|
|
struct PrintedDecl {
|
|
|
|
PrintedDecl(const char *Name, DeclRelationSet Relations = {})
|
|
|
|
: Name(Name), Relations(Relations) {}
|
[clangd] targetDecl() returns only NamedDecls.
Summary:
While it's perfectly reasonable for non-named decls such as
static_assert to resolve to themselves:
- nothing else ever resolves to them
- features based on references (hover, highlight, find refs etc) tend
to be uninteresting where only trivial references are possible
- returning NamedDecl is a more convenient API (we cast to it in many places)
- this aligns closer to findExplicitReferences/explicitReferenceTargets
This fixes a crash in explicitReferenceTargets: if the target is a
non-named decl then there's an invalid unchecked cast to NamedDecl.
In practice this means when hovering over e.g. a static_assert:
- before ac3f9e4842, we would show a (boring) hover card
- after ac3f9e4842, we would crash
- after this patch, we will show nothing
Reviewers: kadircet, ilya-biryukov
Subscribers: MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D72163
2020-01-03 17:26:33 +01:00
|
|
|
PrintedDecl(const NamedDecl *D, DeclRelationSet Relations = {})
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
: Relations(Relations) {
|
|
|
|
std::string S;
|
|
|
|
llvm::raw_string_ostream OS(S);
|
|
|
|
D->print(OS);
|
|
|
|
llvm::StringRef FirstLine =
|
|
|
|
llvm::StringRef(OS.str()).take_until([](char C) { return C == '\n'; });
|
|
|
|
FirstLine = FirstLine.rtrim(" {");
|
2020-01-28 20:23:46 +01:00
|
|
|
Name = std::string(FirstLine.rtrim(" {"));
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string Name;
|
|
|
|
DeclRelationSet Relations;
|
|
|
|
};
|
|
|
|
bool operator==(const PrintedDecl &L, const PrintedDecl &R) {
|
|
|
|
return std::tie(L.Name, L.Relations) == std::tie(R.Name, R.Relations);
|
|
|
|
}
|
|
|
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const PrintedDecl &D) {
|
|
|
|
return OS << D.Name << " Rel=" << D.Relations;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The test cases in for targetDecl() take the form
|
|
|
|
// - a piece of code (Code = "...")
|
|
|
|
// - Code should have a single AST node marked as a [[range]]
|
|
|
|
// - an EXPECT_DECLS() assertion that verify the type of node selected, and
|
|
|
|
// all the decls that targetDecl() considers it to reference
|
|
|
|
// Despite the name, these cases actually test allTargetDecls() for brevity.
|
|
|
|
class TargetDeclTest : public ::testing::Test {
|
|
|
|
protected:
|
|
|
|
using Rel = DeclRelation;
|
|
|
|
std::string Code;
|
|
|
|
std::vector<const char *> Flags;
|
|
|
|
|
|
|
|
// Asserts that `Code` has a marked selection of a node `NodeType`,
|
|
|
|
// and returns allTargetDecls() as PrintedDecl structs.
|
|
|
|
// Use via EXPECT_DECLS().
|
|
|
|
std::vector<PrintedDecl> assertNodeAndPrintDecls(const char *NodeType) {
|
|
|
|
llvm::Annotations A(Code);
|
|
|
|
auto TU = TestTU::withCode(A.code());
|
|
|
|
TU.ExtraArgs = Flags;
|
|
|
|
auto AST = TU.build();
|
|
|
|
llvm::Annotations::Range R = A.range();
|
2020-02-23 16:34:49 +01:00
|
|
|
SelectionTree Selection(AST.getASTContext(), AST.getTokens(), R.Begin,
|
|
|
|
R.End);
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
const SelectionTree::Node *N = Selection.commonAncestor();
|
|
|
|
if (!N) {
|
|
|
|
ADD_FAILURE() << "No node selected!\n" << Code;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
EXPECT_EQ(N->kind(), NodeType) << Selection;
|
|
|
|
|
|
|
|
std::vector<PrintedDecl> ActualDecls;
|
|
|
|
for (const auto &Entry : allTargetDecls(N->ASTNode))
|
|
|
|
ActualDecls.emplace_back(Entry.first, Entry.second);
|
|
|
|
return ActualDecls;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// This is a macro to preserve line numbers in assertion failures.
|
|
|
|
// It takes the expected decls as varargs to work around comma-in-macro issues.
|
|
|
|
#define EXPECT_DECLS(NodeType, ...) \
|
|
|
|
EXPECT_THAT(assertNodeAndPrintDecls(NodeType), \
|
|
|
|
::testing::UnorderedElementsAreArray( \
|
|
|
|
std::vector<PrintedDecl>({__VA_ARGS__}))) \
|
|
|
|
<< Code
|
|
|
|
using ExpectedDecls = std::vector<PrintedDecl>;
|
|
|
|
|
|
|
|
TEST_F(TargetDeclTest, Exprs) {
|
|
|
|
Code = R"cpp(
|
|
|
|
int f();
|
|
|
|
int x = [[f]]();
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DeclRefExpr", "int f()");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
struct S { S operator+(S) const; };
|
|
|
|
auto X = S() [[+]] S();
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DeclRefExpr", "S operator+(S) const");
|
2019-11-27 16:22:16 +01:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
int foo();
|
|
|
|
int s = foo[[()]];
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CallExpr", "int foo()");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
struct X {
|
|
|
|
void operator()(int n);
|
|
|
|
};
|
|
|
|
void test() {
|
|
|
|
X x;
|
|
|
|
x[[(123)]];
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXOperatorCallExpr", "void operator()(int n)");
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TargetDeclTest, UsingDecl) {
|
|
|
|
Code = R"cpp(
|
|
|
|
namespace foo {
|
|
|
|
int f(int);
|
|
|
|
int f(char);
|
|
|
|
}
|
|
|
|
using foo::f;
|
|
|
|
int x = [[f]](42);
|
|
|
|
)cpp";
|
|
|
|
// f(char) is not referenced!
|
|
|
|
EXPECT_DECLS("DeclRefExpr", {"using foo::f", Rel::Alias},
|
|
|
|
{"int f(int)", Rel::Underlying});
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
namespace foo {
|
|
|
|
int f(int);
|
|
|
|
int f(char);
|
|
|
|
}
|
|
|
|
[[using foo::f]];
|
|
|
|
)cpp";
|
|
|
|
// All overloads are referenced.
|
|
|
|
EXPECT_DECLS("UsingDecl", {"using foo::f", Rel::Alias},
|
|
|
|
{"int f(int)", Rel::Underlying},
|
|
|
|
{"int f(char)", Rel::Underlying});
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
struct X {
|
|
|
|
int foo();
|
|
|
|
};
|
|
|
|
struct Y : X {
|
|
|
|
using X::foo;
|
|
|
|
};
|
|
|
|
int x = Y().[[foo]]();
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("MemberExpr", {"using X::foo", Rel::Alias},
|
|
|
|
{"int foo()", Rel::Underlying});
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TargetDeclTest, ConstructorInitList) {
|
|
|
|
Code = R"cpp(
|
|
|
|
struct X {
|
|
|
|
int a;
|
|
|
|
X() : [[a]](42) {}
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXCtorInitializer", "int a");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
struct X {
|
|
|
|
X() : [[X]](1) {}
|
|
|
|
X(int);
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("RecordTypeLoc", "struct X");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TargetDeclTest, DesignatedInit) {
|
|
|
|
Flags = {"-xc"}; // array designators are a C99 extension.
|
|
|
|
Code = R"c(
|
|
|
|
struct X { int a; };
|
|
|
|
struct Y { int b; struct X c[2]; };
|
|
|
|
struct Y y = { .c[0].[[a]] = 1 };
|
|
|
|
)c";
|
|
|
|
EXPECT_DECLS("DesignatedInitExpr", "int a");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TargetDeclTest, NestedNameSpecifier) {
|
|
|
|
Code = R"cpp(
|
|
|
|
namespace a { namespace b { int c; } }
|
|
|
|
int x = a::[[b::]]c;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("NestedNameSpecifierLoc", "namespace b");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
namespace a { struct X { enum { y }; }; }
|
|
|
|
int x = a::[[X::]]y;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("NestedNameSpecifierLoc", "struct X");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename T>
|
|
|
|
int x = [[T::]]y;
|
|
|
|
)cpp";
|
2020-01-30 14:00:51 +01:00
|
|
|
EXPECT_DECLS("NestedNameSpecifierLoc", "typename T");
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
namespace a { int x; }
|
|
|
|
namespace b = a;
|
|
|
|
int y = [[b]]::x;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("NestedNameSpecifierLoc", {"namespace b = a", Rel::Alias},
|
|
|
|
{"namespace a", Rel::Underlying});
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TargetDeclTest, Types) {
|
|
|
|
Code = R"cpp(
|
|
|
|
struct X{};
|
|
|
|
[[X]] x;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("RecordTypeLoc", "struct X");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
struct S{};
|
|
|
|
typedef S X;
|
|
|
|
[[X]] x;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TypedefTypeLoc", {"typedef S X", Rel::Alias},
|
|
|
|
{"struct S", Rel::Underlying});
|
2020-02-05 09:56:13 +01:00
|
|
|
Code = R"cpp(
|
|
|
|
namespace ns { struct S{}; }
|
|
|
|
typedef ns::S X;
|
|
|
|
[[X]] x;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TypedefTypeLoc", {"typedef ns::S X", Rel::Alias},
|
|
|
|
{"struct S", Rel::Underlying});
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
|
2019-10-13 13:15:27 +00:00
|
|
|
// FIXME: Auto-completion in a template requires disabling delayed template
|
|
|
|
// parsing.
|
|
|
|
Flags = {"-fno-delayed-template-parsing"};
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
Code = R"cpp(
|
|
|
|
template<class T>
|
|
|
|
void foo() { [[T]] x; }
|
|
|
|
)cpp";
|
2020-01-30 14:00:51 +01:00
|
|
|
EXPECT_DECLS("TemplateTypeParmTypeLoc", "class T");
|
2019-10-13 13:15:27 +00:00
|
|
|
Flags.clear();
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
|
2019-10-13 13:15:27 +00:00
|
|
|
// FIXME: Auto-completion in a template requires disabling delayed template
|
|
|
|
// parsing.
|
|
|
|
Flags = {"-fno-delayed-template-parsing"};
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
Code = R"cpp(
|
|
|
|
template<template<typename> class T>
|
|
|
|
void foo() { [[T<int>]] x; }
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TemplateSpecializationTypeLoc", "template <typename> class T");
|
2019-10-13 13:15:27 +00:00
|
|
|
Flags.clear();
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
struct S{};
|
|
|
|
S X;
|
|
|
|
[[decltype]](X) Y;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DecltypeTypeLoc", {"struct S", Rel::Underlying});
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
struct S{};
|
|
|
|
[[auto]] X = S{};
|
|
|
|
)cpp";
|
|
|
|
// FIXME: deduced type missing in AST. https://llvm.org/PR42914
|
|
|
|
EXPECT_DECLS("AutoTypeLoc");
|
2019-12-05 14:27:23 -05:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename... E>
|
|
|
|
struct S {
|
|
|
|
static const int size = sizeof...([[E]]);
|
|
|
|
};
|
|
|
|
)cpp";
|
2020-01-30 14:00:51 +01:00
|
|
|
EXPECT_DECLS("SizeOfPackExpr", "typename ...E");
|
2020-01-21 15:28:06 +01:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename T>
|
|
|
|
class Foo {
|
|
|
|
void f([[Foo]] x);
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("InjectedClassNameTypeLoc", "class Foo");
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TargetDeclTest, ClassTemplate) {
|
|
|
|
Code = R"cpp(
|
|
|
|
// Implicit specialization.
|
|
|
|
template<int x> class Foo{};
|
|
|
|
[[Foo<42>]] B;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TemplateSpecializationTypeLoc",
|
|
|
|
{"template<> class Foo<42>", Rel::TemplateInstantiation},
|
|
|
|
{"class Foo", Rel::TemplatePattern});
|
|
|
|
|
2020-02-20 15:22:07 +01:00
|
|
|
Code = R"cpp(
|
|
|
|
template<typename T> class Foo {};
|
|
|
|
// The "Foo<int>" SpecializationDecl is incomplete, there is no
|
|
|
|
// instantiation happening.
|
|
|
|
void func([[Foo<int>]] *);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TemplateSpecializationTypeLoc",
|
|
|
|
{"class Foo", Rel::TemplatePattern},
|
|
|
|
{"template<> class Foo<int>", Rel::TemplateInstantiation});
|
|
|
|
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
Code = R"cpp(
|
|
|
|
// Explicit specialization.
|
|
|
|
template<int x> class Foo{};
|
|
|
|
template<> class Foo<42>{};
|
|
|
|
[[Foo<42>]] B;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TemplateSpecializationTypeLoc", "template<> class Foo<42>");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
// Partial specialization.
|
|
|
|
template<typename T> class Foo{};
|
|
|
|
template<typename T> class Foo<T*>{};
|
|
|
|
[[Foo<int*>]] B;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TemplateSpecializationTypeLoc",
|
|
|
|
{"template<> class Foo<int *>", Rel::TemplateInstantiation},
|
2019-11-14 14:16:14 +01:00
|
|
|
{"template <typename T> class Foo<T *>", Rel::TemplatePattern});
|
2020-01-02 00:45:01 -05:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
// Class template argument deduction
|
|
|
|
template <typename T>
|
|
|
|
struct Test {
|
|
|
|
Test(T);
|
|
|
|
};
|
|
|
|
void foo() {
|
|
|
|
[[Test]] a(5);
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
Flags.push_back("-std=c++17");
|
|
|
|
EXPECT_DECLS("DeducedTemplateSpecializationTypeLoc",
|
|
|
|
{"struct Test", Rel::TemplatePattern});
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
}
|
|
|
|
|
2020-01-21 16:55:43 -05:00
|
|
|
TEST_F(TargetDeclTest, Concept) {
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename T>
|
|
|
|
concept Fooable = requires (T t) { t.foo(); };
|
|
|
|
|
|
|
|
template <typename T> requires [[Fooable]]<T>
|
|
|
|
void bar(T t) {
|
|
|
|
t.foo();
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
Flags.push_back("-std=c++2a");
|
|
|
|
EXPECT_DECLS(
|
|
|
|
"ConceptSpecializationExpr",
|
|
|
|
// FIXME: Should we truncate the pretty-printed form of a concept decl
|
|
|
|
// somewhere?
|
|
|
|
{"template <typename T> concept Fooable = requires (T t) { t.foo(); };"});
|
|
|
|
}
|
|
|
|
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
TEST_F(TargetDeclTest, FunctionTemplate) {
|
|
|
|
Code = R"cpp(
|
|
|
|
// Implicit specialization.
|
|
|
|
template<typename T> bool foo(T) { return false; };
|
|
|
|
bool x = [[foo]](42);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DeclRefExpr",
|
|
|
|
{"template<> bool foo<int>(int)", Rel::TemplateInstantiation},
|
|
|
|
{"bool foo(T)", Rel::TemplatePattern});
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
// Explicit specialization.
|
|
|
|
template<typename T> bool foo(T) { return false; };
|
|
|
|
template<> bool foo<int>(int) { return false; };
|
|
|
|
bool x = [[foo]](42);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DeclRefExpr", "template<> bool foo<int>(int)");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TargetDeclTest, VariableTemplate) {
|
|
|
|
// Pretty-printer doesn't do a very good job of variable templates :-(
|
|
|
|
Code = R"cpp(
|
|
|
|
// Implicit specialization.
|
|
|
|
template<typename T> int foo;
|
|
|
|
int x = [[foo]]<char>;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DeclRefExpr", {"int foo", Rel::TemplateInstantiation},
|
|
|
|
{"int foo", Rel::TemplatePattern});
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
// Explicit specialization.
|
|
|
|
template<typename T> int foo;
|
|
|
|
template <> bool foo<char>;
|
|
|
|
int x = [[foo]]<char>;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DeclRefExpr", "bool foo");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
// Partial specialization.
|
|
|
|
template<typename T> int foo;
|
|
|
|
template<typename T> bool foo<T*>;
|
|
|
|
bool x = [[foo]]<char*>;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DeclRefExpr", {"bool foo", Rel::TemplateInstantiation},
|
|
|
|
{"bool foo", Rel::TemplatePattern});
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TargetDeclTest, TypeAliasTemplate) {
|
|
|
|
Code = R"cpp(
|
|
|
|
template<typename T, int X> class SmallVector {};
|
|
|
|
template<typename U> using TinyVector = SmallVector<U, 1>;
|
|
|
|
[[TinyVector<int>]] X;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TemplateSpecializationTypeLoc",
|
|
|
|
{"template<> class SmallVector<int, 1>",
|
|
|
|
Rel::TemplateInstantiation | Rel::Underlying},
|
|
|
|
{"class SmallVector", Rel::TemplatePattern | Rel::Underlying},
|
|
|
|
{"using TinyVector = SmallVector<U, 1>",
|
|
|
|
Rel::Alias | Rel::TemplatePattern});
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TargetDeclTest, MemberOfTemplate) {
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename T> struct Foo {
|
|
|
|
int x(T);
|
|
|
|
};
|
|
|
|
int y = Foo<int>().[[x]](42);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("MemberExpr", {"int x(int)", Rel::TemplateInstantiation},
|
|
|
|
{"int x(T)", Rel::TemplatePattern});
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename T> struct Foo {
|
|
|
|
template <typename U>
|
|
|
|
int x(T, U);
|
|
|
|
};
|
|
|
|
int y = Foo<char>().[[x]]('c', 42);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("MemberExpr",
|
|
|
|
{"template<> int x<int>(char, int)", Rel::TemplateInstantiation},
|
|
|
|
{"int x(T, U)", Rel::TemplatePattern});
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TargetDeclTest, Lambda) {
|
|
|
|
Code = R"cpp(
|
|
|
|
void foo(int x = 42) {
|
|
|
|
auto l = [ [[x]] ]{ return x + 1; };
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DeclRefExpr", "int x = 42");
|
|
|
|
|
|
|
|
// It seems like this should refer to another var, with the outer param being
|
|
|
|
// an underlying decl. But it doesn't seem to exist.
|
|
|
|
Code = R"cpp(
|
|
|
|
void foo(int x = 42) {
|
|
|
|
auto l = [x]{ return [[x]] + 1; };
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DeclRefExpr", "int x = 42");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
void foo() {
|
|
|
|
auto l = [x = 1]{ return [[x]] + 1; };
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
// FIXME: why both auto and int?
|
|
|
|
EXPECT_DECLS("DeclRefExpr", "auto int x = 1");
|
|
|
|
}
|
|
|
|
|
2019-10-01 07:27:55 +00:00
|
|
|
TEST_F(TargetDeclTest, OverloadExpr) {
|
2019-10-13 13:15:27 +00:00
|
|
|
// FIXME: Auto-completion in a template requires disabling delayed template
|
|
|
|
// parsing.
|
|
|
|
Flags = {"-fno-delayed-template-parsing"};
|
|
|
|
|
2019-10-01 07:27:55 +00:00
|
|
|
Code = R"cpp(
|
|
|
|
void func(int*);
|
|
|
|
void func(char*);
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void foo(T t) {
|
|
|
|
[[func]](t);
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("UnresolvedLookupExpr", "void func(int *)", "void func(char *)");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
struct X {
|
|
|
|
void func(int*);
|
|
|
|
void func(char*);
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void foo(X x, T t) {
|
|
|
|
x.[[func]](t);
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("UnresolvedMemberExpr", "void func(int *)", "void func(char *)");
|
|
|
|
}
|
|
|
|
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
TEST_F(TargetDeclTest, ObjC) {
|
|
|
|
Flags = {"-xobjective-c"};
|
|
|
|
Code = R"cpp(
|
|
|
|
@interface Foo {}
|
|
|
|
-(void)bar;
|
|
|
|
@end
|
|
|
|
void test(Foo *f) {
|
|
|
|
[f [[bar]] ];
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCMessageExpr", "- (void)bar");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@interface Foo { @public int bar; }
|
|
|
|
@end
|
|
|
|
int test(Foo *f) {
|
|
|
|
return [[f->bar]];
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCIvarRefExpr", "int bar");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@interface Foo {}
|
|
|
|
-(int) x;
|
|
|
|
-(void) setX:(int)x;
|
|
|
|
@end
|
|
|
|
void test(Foo *f) {
|
|
|
|
[[f.x]] = 42;
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCPropertyRefExpr", "- (void)setX:(int)x");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
2020-01-10 10:40:30 +01:00
|
|
|
@interface I {}
|
|
|
|
@property(retain) I* x;
|
|
|
|
@property(retain) I* y;
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
@end
|
2020-01-10 10:40:30 +01:00
|
|
|
void test(I *f) {
|
|
|
|
[[f.x]].y = 0;
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
}
|
|
|
|
)cpp";
|
2020-01-13 19:53:52 +01:00
|
|
|
EXPECT_DECLS("ObjCPropertyRefExpr",
|
|
|
|
"@property(atomic, retain, readwrite) I *x");
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@protocol Foo
|
|
|
|
@end
|
|
|
|
id test() {
|
|
|
|
return [[@protocol(Foo)]];
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCProtocolExpr", "@protocol Foo");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@interface Foo
|
|
|
|
@end
|
|
|
|
void test([[Foo]] *p);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCInterfaceTypeLoc", "@interface Foo");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@protocol Foo
|
|
|
|
@end
|
|
|
|
void test([[id<Foo>]] p);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCObjectTypeLoc", "@protocol Foo");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@class C;
|
|
|
|
@protocol Foo
|
|
|
|
@end
|
|
|
|
void test(C<[[Foo]]> *p);
|
|
|
|
)cpp";
|
|
|
|
// FIXME: there's no AST node corresponding to 'Foo', so we're stuck.
|
|
|
|
EXPECT_DECLS("ObjCObjectTypeLoc");
|
|
|
|
}
|
|
|
|
|
2019-09-25 12:40:22 +00:00
|
|
|
class FindExplicitReferencesTest : public ::testing::Test {
|
|
|
|
protected:
|
|
|
|
struct AllRefs {
|
|
|
|
std::string AnnotatedCode;
|
|
|
|
std::string DumpedReferences;
|
|
|
|
};
|
|
|
|
|
2020-01-21 11:50:57 +01:00
|
|
|
/// Parses \p Code, finds function or namespace '::foo' and annotates its body
|
|
|
|
/// with results of findExplicitReferecnces.
|
2019-09-25 12:40:22 +00:00
|
|
|
/// See actual tests for examples of annotation format.
|
|
|
|
AllRefs annotateReferencesInFoo(llvm::StringRef Code) {
|
|
|
|
TestTU TU;
|
2020-01-28 20:23:46 +01:00
|
|
|
TU.Code = std::string(Code);
|
2019-09-25 12:40:22 +00:00
|
|
|
|
2019-10-13 13:15:27 +00:00
|
|
|
// FIXME: Auto-completion in a template requires disabling delayed template
|
|
|
|
// parsing.
|
|
|
|
TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
|
2020-01-21 13:21:08 -05:00
|
|
|
TU.ExtraArgs.push_back("-std=c++2a");
|
2020-01-10 16:27:12 +01:00
|
|
|
TU.ExtraArgs.push_back("-xobjective-c++");
|
2019-10-13 13:15:27 +00:00
|
|
|
|
2019-09-25 12:40:22 +00:00
|
|
|
auto AST = TU.build();
|
2019-09-27 09:39:10 +00:00
|
|
|
auto *TestDecl = &findDecl(AST, "foo");
|
|
|
|
if (auto *T = llvm::dyn_cast<FunctionTemplateDecl>(TestDecl))
|
|
|
|
TestDecl = T->getTemplatedDecl();
|
2019-09-25 12:40:22 +00:00
|
|
|
|
|
|
|
std::vector<ReferenceLoc> Refs;
|
2020-01-21 11:50:57 +01:00
|
|
|
if (const auto *Func = llvm::dyn_cast<FunctionDecl>(TestDecl))
|
|
|
|
findExplicitReferences(Func->getBody(), [&Refs](ReferenceLoc R) {
|
|
|
|
Refs.push_back(std::move(R));
|
|
|
|
});
|
|
|
|
else if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(TestDecl))
|
|
|
|
findExplicitReferences(NS, [&Refs, &NS](ReferenceLoc R) {
|
|
|
|
// Avoid adding the namespace foo decl to the results.
|
|
|
|
if (R.Targets.size() == 1 && R.Targets.front() == NS)
|
|
|
|
return;
|
|
|
|
Refs.push_back(std::move(R));
|
|
|
|
});
|
|
|
|
else
|
|
|
|
ADD_FAILURE() << "Failed to find ::foo decl for test";
|
2019-09-25 12:40:22 +00:00
|
|
|
|
|
|
|
auto &SM = AST.getSourceManager();
|
|
|
|
llvm::sort(Refs, [&](const ReferenceLoc &L, const ReferenceLoc &R) {
|
|
|
|
return SM.isBeforeInTranslationUnit(L.NameLoc, R.NameLoc);
|
|
|
|
});
|
|
|
|
|
|
|
|
std::string AnnotatedCode;
|
|
|
|
unsigned NextCodeChar = 0;
|
|
|
|
for (unsigned I = 0; I < Refs.size(); ++I) {
|
|
|
|
auto &R = Refs[I];
|
|
|
|
|
|
|
|
SourceLocation Pos = R.NameLoc;
|
|
|
|
assert(Pos.isValid());
|
|
|
|
if (Pos.isMacroID()) // FIXME: figure out how to show macro locations.
|
|
|
|
Pos = SM.getExpansionLoc(Pos);
|
|
|
|
assert(Pos.isFileID());
|
|
|
|
|
|
|
|
FileID File;
|
|
|
|
unsigned Offset;
|
|
|
|
std::tie(File, Offset) = SM.getDecomposedLoc(Pos);
|
|
|
|
if (File == SM.getMainFileID()) {
|
|
|
|
// Print the reference in a source code.
|
|
|
|
assert(NextCodeChar <= Offset);
|
|
|
|
AnnotatedCode += Code.substr(NextCodeChar, Offset - NextCodeChar);
|
|
|
|
AnnotatedCode += "$" + std::to_string(I) + "^";
|
|
|
|
|
|
|
|
NextCodeChar = Offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AnnotatedCode += Code.substr(NextCodeChar);
|
|
|
|
|
|
|
|
std::string DumpedReferences;
|
|
|
|
for (unsigned I = 0; I < Refs.size(); ++I)
|
2020-01-28 20:23:46 +01:00
|
|
|
DumpedReferences += std::string(llvm::formatv("{0}: {1}\n", I, Refs[I]));
|
2019-09-25 12:40:22 +00:00
|
|
|
|
|
|
|
return AllRefs{std::move(AnnotatedCode), std::move(DumpedReferences)};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST_F(FindExplicitReferencesTest, All) {
|
|
|
|
std::pair</*Code*/ llvm::StringRef, /*References*/ llvm::StringRef> Cases[] =
|
2019-12-05 14:27:23 -05:00
|
|
|
{// Simple expressions.
|
|
|
|
{R"cpp(
|
2019-09-25 12:40:22 +00:00
|
|
|
int global;
|
|
|
|
int func();
|
|
|
|
void foo(int param) {
|
|
|
|
$0^global = $1^param + $2^func();
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {global}\n"
|
|
|
|
"1: targets = {param}\n"
|
|
|
|
"2: targets = {func}\n"},
|
|
|
|
{R"cpp(
|
2019-09-25 12:40:22 +00:00
|
|
|
struct X { int a; };
|
|
|
|
void foo(X x) {
|
|
|
|
$0^x.$1^a = 10;
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {x}\n"
|
|
|
|
"1: targets = {X::a}\n"},
|
|
|
|
// Namespaces and aliases.
|
|
|
|
{R"cpp(
|
2019-09-25 12:40:22 +00:00
|
|
|
namespace ns {}
|
|
|
|
namespace alias = ns;
|
|
|
|
void foo() {
|
|
|
|
using namespace $0^ns;
|
|
|
|
using namespace $1^alias;
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {ns}\n"
|
|
|
|
"1: targets = {alias}\n"},
|
|
|
|
// Using declarations.
|
|
|
|
{R"cpp(
|
2019-09-25 12:40:22 +00:00
|
|
|
namespace ns { int global; }
|
|
|
|
void foo() {
|
|
|
|
using $0^ns::$1^global;
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {ns}\n"
|
|
|
|
"1: targets = {ns::global}, qualifier = 'ns::'\n"},
|
|
|
|
// Simple types.
|
|
|
|
{R"cpp(
|
2019-09-25 12:40:22 +00:00
|
|
|
struct Struct { int a; };
|
|
|
|
using Typedef = int;
|
|
|
|
void foo() {
|
2019-10-18 12:07:19 +00:00
|
|
|
$0^Struct $1^x;
|
|
|
|
$2^Typedef $3^y;
|
|
|
|
static_cast<$4^Struct*>(0);
|
2019-09-25 12:40:22 +00:00
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {Struct}\n"
|
|
|
|
"1: targets = {x}, decl\n"
|
|
|
|
"2: targets = {Typedef}\n"
|
|
|
|
"3: targets = {y}, decl\n"
|
|
|
|
"4: targets = {Struct}\n"},
|
|
|
|
// Name qualifiers.
|
|
|
|
{R"cpp(
|
2019-09-25 12:40:22 +00:00
|
|
|
namespace a { namespace b { struct S { typedef int type; }; } }
|
|
|
|
void foo() {
|
2019-10-18 12:07:19 +00:00
|
|
|
$0^a::$1^b::$2^S $3^x;
|
|
|
|
using namespace $4^a::$5^b;
|
|
|
|
$6^S::$7^type $8^y;
|
2019-09-25 12:40:22 +00:00
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {a}\n"
|
|
|
|
"1: targets = {a::b}, qualifier = 'a::'\n"
|
|
|
|
"2: targets = {a::b::S}, qualifier = 'a::b::'\n"
|
|
|
|
"3: targets = {x}, decl\n"
|
|
|
|
"4: targets = {a}\n"
|
|
|
|
"5: targets = {a::b}, qualifier = 'a::'\n"
|
|
|
|
"6: targets = {a::b::S}\n"
|
|
|
|
"7: targets = {a::b::S::type}, qualifier = 'struct S::'\n"
|
|
|
|
"8: targets = {y}, decl\n"},
|
|
|
|
// Simple templates.
|
|
|
|
{R"cpp(
|
2019-09-25 12:40:22 +00:00
|
|
|
template <class T> struct vector { using value_type = T; };
|
|
|
|
template <> struct vector<bool> { using value_type = bool; };
|
|
|
|
void foo() {
|
2019-10-18 12:07:19 +00:00
|
|
|
$0^vector<int> $1^vi;
|
|
|
|
$2^vector<bool> $3^vb;
|
2019-09-25 12:40:22 +00:00
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {vector<int>}\n"
|
|
|
|
"1: targets = {vi}, decl\n"
|
|
|
|
"2: targets = {vector<bool>}\n"
|
|
|
|
"3: targets = {vb}, decl\n"},
|
|
|
|
// Template type aliases.
|
|
|
|
{R"cpp(
|
2019-09-27 17:55:46 +00:00
|
|
|
template <class T> struct vector { using value_type = T; };
|
|
|
|
template <> struct vector<bool> { using value_type = bool; };
|
|
|
|
template <class T> using valias = vector<T>;
|
|
|
|
void foo() {
|
2019-10-18 12:07:19 +00:00
|
|
|
$0^valias<int> $1^vi;
|
|
|
|
$2^valias<bool> $3^vb;
|
2019-09-27 17:55:46 +00:00
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {valias}\n"
|
|
|
|
"1: targets = {vi}, decl\n"
|
|
|
|
"2: targets = {valias}\n"
|
|
|
|
"3: targets = {vb}, decl\n"},
|
2020-01-21 11:50:57 +01:00
|
|
|
// Injected class name.
|
|
|
|
{R"cpp(
|
|
|
|
namespace foo {
|
|
|
|
template <typename $0^T>
|
2020-01-21 15:15:06 +01:00
|
|
|
class $1^Bar {
|
|
|
|
~$2^Bar();
|
|
|
|
void $3^f($4^Bar);
|
2020-01-21 11:50:57 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {foo::Bar::T}, decl\n"
|
|
|
|
"1: targets = {foo::Bar}, decl\n"
|
2020-01-21 15:15:06 +01:00
|
|
|
"2: targets = {foo::Bar}\n"
|
|
|
|
"3: targets = {foo::Bar::f}, decl\n"
|
|
|
|
"4: targets = {foo::Bar}\n"},
|
2019-12-05 14:27:23 -05:00
|
|
|
// MemberExpr should know their using declaration.
|
|
|
|
{R"cpp(
|
2020-01-07 14:44:50 -05:00
|
|
|
struct X { void func(int); };
|
2019-09-25 12:40:22 +00:00
|
|
|
struct Y : X {
|
|
|
|
using X::func;
|
|
|
|
};
|
|
|
|
void foo(Y y) {
|
|
|
|
$0^y.$1^func(1);
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {y}\n"
|
|
|
|
"1: targets = {Y::func}\n"},
|
|
|
|
// DeclRefExpr should know their using declaration.
|
|
|
|
{R"cpp(
|
2019-09-25 12:40:22 +00:00
|
|
|
namespace ns { void bar(int); }
|
|
|
|
using ns::bar;
|
|
|
|
|
|
|
|
void foo() {
|
|
|
|
$0^bar(10);
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {bar}\n"},
|
|
|
|
// References from a macro.
|
|
|
|
{R"cpp(
|
2019-09-25 12:40:22 +00:00
|
|
|
#define FOO a
|
|
|
|
#define BAR b
|
|
|
|
|
|
|
|
void foo(int a, int b) {
|
|
|
|
$0^FOO+$1^BAR;
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {a}\n"
|
|
|
|
"1: targets = {b}\n"},
|
|
|
|
// No references from implicit nodes.
|
|
|
|
{R"cpp(
|
2019-09-25 12:40:22 +00:00
|
|
|
struct vector {
|
|
|
|
int *begin();
|
|
|
|
int *end();
|
|
|
|
};
|
|
|
|
|
|
|
|
void foo() {
|
2019-10-18 12:07:19 +00:00
|
|
|
for (int $0^x : $1^vector()) {
|
|
|
|
$2^x = 10;
|
2019-09-25 12:40:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {x}, decl\n"
|
|
|
|
"1: targets = {vector}\n"
|
|
|
|
"2: targets = {x}\n"},
|
|
|
|
// Handle UnresolvedLookupExpr.
|
2020-02-10 12:11:47 -08:00
|
|
|
// FIXME
|
|
|
|
// This case fails when expensive checks are enabled.
|
|
|
|
// Seems like the order of ns1::func and ns2::func isn't defined.
|
|
|
|
#ifndef EXPENSIVE_CHECKS
|
2019-12-05 14:27:23 -05:00
|
|
|
{R"cpp(
|
2019-09-27 09:39:10 +00:00
|
|
|
namespace ns1 { void func(char*); }
|
|
|
|
namespace ns2 { void func(int*); }
|
|
|
|
using namespace ns1;
|
|
|
|
using namespace ns2;
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void foo(T t) {
|
|
|
|
$0^func($1^t);
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {ns1::func, ns2::func}\n"
|
|
|
|
"1: targets = {t}\n"},
|
2020-02-10 12:11:47 -08:00
|
|
|
#endif
|
2019-12-05 14:27:23 -05:00
|
|
|
// Handle UnresolvedMemberExpr.
|
|
|
|
{R"cpp(
|
2019-09-27 09:39:10 +00:00
|
|
|
struct X {
|
|
|
|
void func(char*);
|
|
|
|
void func(int*);
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void foo(X x, T t) {
|
|
|
|
$0^x.$1^func($2^t);
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {x}\n"
|
|
|
|
"1: targets = {X::func, X::func}\n"
|
|
|
|
"2: targets = {t}\n"},
|
|
|
|
// Type template parameters.
|
|
|
|
{R"cpp(
|
2019-09-27 10:55:53 +00:00
|
|
|
template <class T>
|
|
|
|
void foo() {
|
|
|
|
static_cast<$0^T>(0);
|
|
|
|
$1^T();
|
2019-10-18 12:07:19 +00:00
|
|
|
$2^T $3^t;
|
2019-09-27 10:55:53 +00:00
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {T}\n"
|
|
|
|
"1: targets = {T}\n"
|
|
|
|
"2: targets = {T}\n"
|
|
|
|
"3: targets = {t}, decl\n"},
|
|
|
|
// Non-type template parameters.
|
|
|
|
{R"cpp(
|
2019-09-27 10:55:53 +00:00
|
|
|
template <int I>
|
|
|
|
void foo() {
|
2019-10-18 12:07:19 +00:00
|
|
|
int $0^x = $1^I;
|
2019-09-27 10:55:53 +00:00
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {x}, decl\n"
|
|
|
|
"1: targets = {I}\n"},
|
|
|
|
// Template template parameters.
|
|
|
|
{R"cpp(
|
2019-10-01 10:02:23 +00:00
|
|
|
template <class T> struct vector {};
|
|
|
|
|
|
|
|
template <template<class> class TT, template<class> class ...TP>
|
|
|
|
void foo() {
|
2019-10-18 12:07:19 +00:00
|
|
|
$0^TT<int> $1^x;
|
|
|
|
$2^foo<$3^TT>();
|
2020-01-07 14:44:50 -05:00
|
|
|
$4^foo<$5^vector>();
|
2019-10-18 12:07:19 +00:00
|
|
|
$6^foo<$7^TP...>();
|
2019-10-01 10:02:23 +00:00
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {TT}\n"
|
|
|
|
"1: targets = {x}, decl\n"
|
|
|
|
"2: targets = {foo}\n"
|
|
|
|
"3: targets = {TT}\n"
|
|
|
|
"4: targets = {foo}\n"
|
|
|
|
"5: targets = {vector}\n"
|
|
|
|
"6: targets = {foo}\n"
|
|
|
|
"7: targets = {TP}\n"},
|
|
|
|
// Non-type template parameters with declarations.
|
|
|
|
{R"cpp(
|
2019-10-01 10:02:23 +00:00
|
|
|
int func();
|
|
|
|
template <int(*)()> struct wrapper {};
|
|
|
|
|
|
|
|
template <int(*FuncParam)()>
|
|
|
|
void foo() {
|
2019-10-18 12:07:19 +00:00
|
|
|
$0^wrapper<$1^func> $2^w;
|
|
|
|
$3^FuncParam();
|
2019-10-01 10:02:23 +00:00
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {wrapper<&func>}\n"
|
|
|
|
"1: targets = {func}\n"
|
|
|
|
"2: targets = {w}, decl\n"
|
|
|
|
"3: targets = {FuncParam}\n"},
|
|
|
|
// declaration references.
|
|
|
|
{R"cpp(
|
2019-10-18 12:07:19 +00:00
|
|
|
namespace ns {}
|
|
|
|
class S {};
|
|
|
|
void foo() {
|
|
|
|
class $0^Foo { $1^Foo(); ~$2^Foo(); int $3^field; };
|
|
|
|
int $4^Var;
|
|
|
|
enum $5^E { $6^ABC };
|
|
|
|
typedef int $7^INT;
|
|
|
|
using $8^INT2 = int;
|
|
|
|
namespace $9^NS = $10^ns;
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {Foo}, decl\n"
|
|
|
|
"1: targets = {foo()::Foo::Foo}, decl\n"
|
|
|
|
"2: targets = {Foo}\n"
|
|
|
|
"3: targets = {foo()::Foo::field}, decl\n"
|
|
|
|
"4: targets = {Var}, decl\n"
|
|
|
|
"5: targets = {E}, decl\n"
|
|
|
|
"6: targets = {foo()::ABC}, decl\n"
|
|
|
|
"7: targets = {INT}, decl\n"
|
|
|
|
"8: targets = {INT2}, decl\n"
|
|
|
|
"9: targets = {NS}, decl\n"
|
|
|
|
"10: targets = {ns}\n"},
|
2020-01-21 05:33:39 +01:00
|
|
|
// User-defined conversion operator.
|
|
|
|
{R"cpp(
|
|
|
|
void foo() {
|
|
|
|
class $0^Bar {};
|
|
|
|
class $1^Foo {
|
|
|
|
public:
|
|
|
|
// FIXME: This should have only one reference to Bar.
|
|
|
|
$2^operator $3^$4^Bar();
|
|
|
|
};
|
|
|
|
|
|
|
|
$5^Foo $6^f;
|
|
|
|
$7^f.$8^operator $9^Bar();
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {Bar}, decl\n"
|
|
|
|
"1: targets = {Foo}, decl\n"
|
|
|
|
"2: targets = {foo()::Foo::operator Bar}, decl\n"
|
|
|
|
"3: targets = {Bar}\n"
|
|
|
|
"4: targets = {Bar}\n"
|
|
|
|
"5: targets = {Foo}\n"
|
|
|
|
"6: targets = {f}, decl\n"
|
|
|
|
"7: targets = {f}\n"
|
|
|
|
"8: targets = {foo()::Foo::operator Bar}\n"
|
|
|
|
"9: targets = {Bar}\n"},
|
|
|
|
// Destructor.
|
|
|
|
{R"cpp(
|
|
|
|
void foo() {
|
|
|
|
class $0^Foo {
|
|
|
|
public:
|
|
|
|
~$1^Foo() {}
|
|
|
|
|
|
|
|
void $2^destructMe() {
|
|
|
|
this->~$3^Foo();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
$4^Foo $5^f;
|
|
|
|
$6^f.~ /*...*/ $7^Foo();
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {Foo}, decl\n"
|
|
|
|
// FIXME: It's better to target destructor's FunctionDecl instead of
|
|
|
|
// the type itself (similar to constructor).
|
|
|
|
"1: targets = {Foo}\n"
|
|
|
|
"2: targets = {foo()::Foo::destructMe}, decl\n"
|
|
|
|
"3: targets = {Foo}\n"
|
|
|
|
"4: targets = {Foo}\n"
|
|
|
|
"5: targets = {f}, decl\n"
|
|
|
|
"6: targets = {f}\n"
|
|
|
|
"7: targets = {Foo}\n"},
|
2019-12-05 14:27:23 -05:00
|
|
|
// cxx constructor initializer.
|
|
|
|
{R"cpp(
|
2019-10-21 10:11:30 +02:00
|
|
|
class Base {};
|
|
|
|
void foo() {
|
|
|
|
// member initializer
|
|
|
|
class $0^X {
|
|
|
|
int $1^abc;
|
|
|
|
$2^X(): $3^abc() {}
|
|
|
|
};
|
|
|
|
// base initializer
|
|
|
|
class $4^Derived : public $5^Base {
|
|
|
|
$6^Base $7^B;
|
|
|
|
$8^Derived() : $9^Base() {}
|
|
|
|
};
|
|
|
|
// delegating initializer
|
|
|
|
class $10^Foo {
|
2019-10-28 14:41:06 +01:00
|
|
|
$11^Foo(int);
|
|
|
|
$12^Foo(): $13^Foo(111) {}
|
2019-10-21 10:11:30 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {X}, decl\n"
|
|
|
|
"1: targets = {foo()::X::abc}, decl\n"
|
|
|
|
"2: targets = {foo()::X::X}, decl\n"
|
|
|
|
"3: targets = {foo()::X::abc}\n"
|
|
|
|
"4: targets = {Derived}, decl\n"
|
|
|
|
"5: targets = {Base}\n"
|
|
|
|
"6: targets = {Base}\n"
|
|
|
|
"7: targets = {foo()::Derived::B}, decl\n"
|
|
|
|
"8: targets = {foo()::Derived::Derived}, decl\n"
|
|
|
|
"9: targets = {Base}\n"
|
|
|
|
"10: targets = {Foo}, decl\n"
|
|
|
|
"11: targets = {foo()::Foo::Foo}, decl\n"
|
|
|
|
"12: targets = {foo()::Foo::Foo}, decl\n"
|
|
|
|
"13: targets = {Foo}\n"},
|
|
|
|
// Anonymous entities should not be reported.
|
|
|
|
{
|
|
|
|
R"cpp(
|
2019-10-28 14:41:06 +01:00
|
|
|
void foo() {
|
|
|
|
class {} $0^x;
|
|
|
|
int (*$1^fptr)(int $2^a, int) = nullptr;
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {x}, decl\n"
|
|
|
|
"1: targets = {fptr}, decl\n"
|
|
|
|
"2: targets = {a}, decl\n"},
|
|
|
|
// Namespace aliases should be handled properly.
|
|
|
|
{
|
|
|
|
R"cpp(
|
2020-01-07 14:44:50 -05:00
|
|
|
namespace ns { struct Type {}; }
|
2019-10-31 11:58:57 +01:00
|
|
|
namespace alias = ns;
|
|
|
|
namespace rec_alias = alias;
|
|
|
|
|
|
|
|
void foo() {
|
|
|
|
$0^ns::$1^Type $2^a;
|
|
|
|
$3^alias::$4^Type $5^b;
|
|
|
|
$6^rec_alias::$7^Type $8^c;
|
|
|
|
}
|
|
|
|
)cpp",
|
2019-12-05 14:27:23 -05:00
|
|
|
"0: targets = {ns}\n"
|
|
|
|
"1: targets = {ns::Type}, qualifier = 'ns::'\n"
|
|
|
|
"2: targets = {a}, decl\n"
|
|
|
|
"3: targets = {alias}\n"
|
|
|
|
"4: targets = {ns::Type}, qualifier = 'alias::'\n"
|
|
|
|
"5: targets = {b}, decl\n"
|
|
|
|
"6: targets = {rec_alias}\n"
|
|
|
|
"7: targets = {ns::Type}, qualifier = 'rec_alias::'\n"
|
|
|
|
"8: targets = {c}, decl\n"},
|
|
|
|
// Handle SizeOfPackExpr.
|
|
|
|
{
|
|
|
|
R"cpp(
|
|
|
|
template <typename... E>
|
|
|
|
void foo() {
|
|
|
|
constexpr int $0^size = sizeof...($1^E);
|
|
|
|
};
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {size}, decl\n"
|
2020-01-02 00:45:01 -05:00
|
|
|
"1: targets = {E}\n"},
|
|
|
|
// Class template argument deduction
|
|
|
|
{
|
|
|
|
R"cpp(
|
|
|
|
template <typename T>
|
|
|
|
struct Test {
|
|
|
|
Test(T);
|
|
|
|
};
|
|
|
|
void foo() {
|
|
|
|
$0^Test $1^a(5);
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {Test}\n"
|
2020-01-21 15:15:06 +01:00
|
|
|
"1: targets = {a}, decl\n"},
|
|
|
|
// Templates
|
|
|
|
{R"cpp(
|
|
|
|
namespace foo {
|
|
|
|
template <typename $0^T>
|
|
|
|
class $1^Bar {};
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {foo::Bar::T}, decl\n"
|
|
|
|
"1: targets = {foo::Bar}, decl\n"},
|
|
|
|
// Templates
|
|
|
|
{R"cpp(
|
|
|
|
namespace foo {
|
|
|
|
template <typename $0^T>
|
|
|
|
void $1^func();
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {T}, decl\n"
|
|
|
|
"1: targets = {foo::func}, decl\n"},
|
|
|
|
// Templates
|
|
|
|
{R"cpp(
|
|
|
|
namespace foo {
|
|
|
|
template <typename $0^T>
|
|
|
|
$1^T $2^x;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {foo::T}, decl\n"
|
|
|
|
"1: targets = {foo::T}\n"
|
|
|
|
"2: targets = {foo::x}, decl\n"},
|
|
|
|
// Templates
|
|
|
|
{R"cpp(
|
|
|
|
template<typename T> class vector {};
|
|
|
|
namespace foo {
|
|
|
|
template <typename $0^T>
|
|
|
|
using $1^V = $2^vector<$3^T>;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {foo::T}, decl\n"
|
|
|
|
"1: targets = {foo::V}, decl\n"
|
|
|
|
"2: targets = {vector}\n"
|
2020-01-21 13:21:08 -05:00
|
|
|
"3: targets = {foo::T}\n"},
|
|
|
|
// Concept
|
|
|
|
{
|
|
|
|
R"cpp(
|
|
|
|
template <typename T>
|
|
|
|
concept Drawable = requires (T t) { t.draw(); };
|
|
|
|
|
|
|
|
namespace foo {
|
|
|
|
template <typename $0^T> requires $1^Drawable<$2^T>
|
|
|
|
void $3^bar($4^T $5^t) {
|
|
|
|
$6^t.draw();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {T}, decl\n"
|
|
|
|
"1: targets = {Drawable}\n"
|
|
|
|
"2: targets = {T}\n"
|
|
|
|
"3: targets = {foo::bar}, decl\n"
|
|
|
|
"4: targets = {T}\n"
|
|
|
|
"5: targets = {t}, decl\n"
|
2020-01-10 16:27:12 +01:00
|
|
|
"6: targets = {t}\n"},
|
|
|
|
// Objective-C: properties
|
|
|
|
{
|
|
|
|
R"cpp(
|
|
|
|
@interface I {}
|
|
|
|
@property(retain) I* x;
|
|
|
|
@property(retain) I* y;
|
|
|
|
@end
|
|
|
|
I *f;
|
|
|
|
void foo() {
|
|
|
|
$0^f.$1^x.$2^y = 0;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {f}\n"
|
|
|
|
"1: targets = {I::x}\n"
|
|
|
|
"2: targets = {I::y}\n"},
|
|
|
|
// Objective-C: implicit properties
|
|
|
|
{
|
|
|
|
R"cpp(
|
|
|
|
@interface I {}
|
|
|
|
-(I*)x;
|
|
|
|
-(void)setY:(I*)y;
|
|
|
|
@end
|
|
|
|
I *f;
|
|
|
|
void foo() {
|
|
|
|
$0^f.$1^x.$2^y = 0;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {f}\n"
|
|
|
|
"1: targets = {I::x}\n"
|
2020-02-10 11:53:17 +01:00
|
|
|
"2: targets = {I::setY:}\n"},
|
|
|
|
// Designated initializers.
|
|
|
|
{R"cpp(
|
|
|
|
void foo() {
|
|
|
|
struct $0^Foo {
|
|
|
|
int $1^Bar;
|
|
|
|
};
|
|
|
|
$2^Foo $3^f { .$4^Bar = 42 };
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {Foo}, decl\n"
|
|
|
|
"1: targets = {foo()::Foo::Bar}, decl\n"
|
|
|
|
"2: targets = {Foo}\n"
|
|
|
|
"3: targets = {f}, decl\n"
|
|
|
|
"4: targets = {foo()::Foo::Bar}\n"},
|
|
|
|
{R"cpp(
|
|
|
|
void foo() {
|
|
|
|
struct $0^Baz {
|
|
|
|
int $1^Field;
|
|
|
|
};
|
|
|
|
struct $2^Bar {
|
|
|
|
$3^Baz $4^Foo;
|
|
|
|
};
|
|
|
|
$5^Bar $6^bar { .$7^Foo.$8^Field = 42 };
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {Baz}, decl\n"
|
|
|
|
"1: targets = {foo()::Baz::Field}, decl\n"
|
|
|
|
"2: targets = {Bar}, decl\n"
|
|
|
|
"3: targets = {Baz}\n"
|
|
|
|
"4: targets = {foo()::Bar::Foo}, decl\n"
|
|
|
|
"5: targets = {Bar}\n"
|
|
|
|
"6: targets = {bar}, decl\n"
|
|
|
|
"7: targets = {foo()::Bar::Foo}\n"
|
|
|
|
"8: targets = {foo()::Baz::Field}\n"}};
|
2019-09-25 12:40:22 +00:00
|
|
|
|
|
|
|
for (const auto &C : Cases) {
|
|
|
|
llvm::StringRef ExpectedCode = C.first;
|
|
|
|
llvm::StringRef ExpectedRefs = C.second;
|
|
|
|
|
|
|
|
auto Actual =
|
|
|
|
annotateReferencesInFoo(llvm::Annotations(ExpectedCode).code());
|
|
|
|
EXPECT_EQ(ExpectedCode, Actual.AnnotatedCode);
|
|
|
|
EXPECT_EQ(ExpectedRefs, Actual.DumpedReferences) << ExpectedCode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[clangd] Add targetDecl(), which determines what declaration an AST node refers to.
Summary:
This is the first part of an effort to "unbundle" our libIndex use into separate
concerns (AST traversal, token<->node mapping, node<->decl mapping,
decl<->decl relationshipes).
Currently, clangd relies on libIndex to associate tokens, AST nodes, and decls.
This leads to rather convoluted implementations of e.g. hover and
extract-function, which are not naturally thought of as indexing applications.
The idea is that by decoupling different concerns, we make them easier
to use, test, and combine, and more efficient when only one part is needed.
There are some synergies between e.g. traversal and finding
relationships between decls, hopefully the benefits outweight these.
Reviewers: kadircet, ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, jfb, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66751
llvm-svn: 370746
2019-09-03 11:35:50 +00:00
|
|
|
} // namespace
|
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|