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"
|
2023-01-12 13:40:47 -08:00
|
|
|
#include "llvm/Testing/Annotations/Annotations.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 "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;
|
2020-03-31 23:09:28 +02:00
|
|
|
std::vector<std::string> Flags;
|
[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
|
|
|
|
|
|
|
// 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 20:03:00 +01:00
|
|
|
auto Selection = SelectionTree::createRight(
|
|
|
|
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;
|
2021-01-18 02:58:43 -05:00
|
|
|
for (const auto &Entry :
|
|
|
|
allTargetDecls(N->ASTNode, AST.getHeuristicResolver()))
|
[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
|
|
|
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)");
|
2020-04-08 11:03:50 +02:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
void test() {
|
|
|
|
goto [[label]];
|
|
|
|
label:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("GotoStmt", "label:");
|
|
|
|
Code = R"cpp(
|
|
|
|
void test() {
|
|
|
|
[[label]]:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("LabelStmt", "label:");
|
[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-10-12 13:22:13 +02:00
|
|
|
TEST_F(TargetDeclTest, RecoveryForC) {
|
|
|
|
Flags = {"-xc", "-Xclang", "-frecovery-ast"};
|
|
|
|
Code = R"cpp(
|
|
|
|
// error-ok: testing behavior on broken code
|
|
|
|
// int f();
|
|
|
|
int f(int);
|
|
|
|
int x = [[f]]();
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DeclRefExpr", "int f(int)");
|
|
|
|
}
|
|
|
|
|
2020-03-31 16:09:49 +02:00
|
|
|
TEST_F(TargetDeclTest, Recovery) {
|
|
|
|
Code = R"cpp(
|
|
|
|
// error-ok: testing behavior on broken code
|
|
|
|
int f();
|
|
|
|
int f(int, int);
|
|
|
|
int x = [[f]](42);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("UnresolvedLookupExpr", "int f()", "int f(int, int)");
|
|
|
|
}
|
|
|
|
|
2020-05-19 15:21:50 +02:00
|
|
|
TEST_F(TargetDeclTest, RecoveryType) {
|
|
|
|
Code = R"cpp(
|
|
|
|
// error-ok: testing behavior on broken code
|
|
|
|
struct S { int member; };
|
|
|
|
S overloaded(int);
|
|
|
|
void foo() {
|
|
|
|
// No overload matches, but we have recovery-expr with the correct type.
|
|
|
|
overloaded().[[member]];
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("MemberExpr", "int member");
|
|
|
|
}
|
|
|
|
|
[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!
|
2020-10-07 10:01:04 +02:00
|
|
|
EXPECT_DECLS("DeclRefExpr", {"using foo::f", Rel::Alias}, {"int f(int)"});
|
[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 foo {
|
|
|
|
int f(int);
|
|
|
|
int f(char);
|
|
|
|
}
|
|
|
|
[[using foo::f]];
|
|
|
|
)cpp";
|
|
|
|
// All overloads are referenced.
|
2020-10-07 10:01:04 +02:00
|
|
|
EXPECT_DECLS("UsingDecl", {"using foo::f", Rel::Alias}, {"int f(int)"},
|
|
|
|
{"int f(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
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
struct X {
|
|
|
|
int foo();
|
|
|
|
};
|
|
|
|
struct Y : X {
|
|
|
|
using X::foo;
|
|
|
|
};
|
|
|
|
int x = Y().[[foo]]();
|
|
|
|
)cpp";
|
2020-10-07 10:01:04 +02:00
|
|
|
EXPECT_DECLS("MemberExpr", {"using X::foo", Rel::Alias}, {"int foo()"});
|
2020-03-12 19:27:18 -04:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename T>
|
|
|
|
struct Base {
|
|
|
|
void waldo() {}
|
|
|
|
};
|
|
|
|
template <typename T>
|
|
|
|
struct Derived : Base<T> {
|
|
|
|
using Base<T>::[[waldo]];
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("UnresolvedUsingValueDecl", {"using Base<T>::waldo", Rel::Alias},
|
2020-10-07 10:01:04 +02:00
|
|
|
{"void waldo()"});
|
2022-04-06 13:03:21 +02:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
namespace ns {
|
|
|
|
template<typename T> class S {};
|
|
|
|
}
|
|
|
|
|
|
|
|
using ns::S;
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
using A = [[S]]<T>;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TemplateSpecializationTypeLoc", {"using ns::S", Rel::Alias},
|
|
|
|
{"template <typename T> class S"},
|
|
|
|
{"class S", Rel::TemplatePattern});
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
namespace ns {
|
|
|
|
template<typename T> class S {};
|
|
|
|
}
|
|
|
|
|
|
|
|
using ns::S;
|
|
|
|
template <template <typename> class T> class X {};
|
|
|
|
using B = X<[[S]]>;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TemplateArgumentLoc", {"using ns::S", Rel::Alias},
|
|
|
|
{"template <typename T> class S"});
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
namespace ns {
|
|
|
|
template<typename T> class S { public: S(T); };
|
|
|
|
}
|
|
|
|
|
|
|
|
using ns::S;
|
|
|
|
[[S]] s(123);
|
|
|
|
)cpp";
|
|
|
|
Flags.push_back("-std=c++17"); // For CTAD feature.
|
|
|
|
EXPECT_DECLS("DeducedTemplateSpecializationTypeLoc",
|
|
|
|
{"using ns::S", Rel::Alias}, {"template <typename T> class S"},
|
|
|
|
{"class S", Rel::TemplatePattern});
|
2022-05-16 14:46:09 +02:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
template<typename T>
|
|
|
|
class Foo { public: class foo {}; };
|
|
|
|
template <class T> class A : public Foo<T> {
|
|
|
|
using typename Foo<T>::foo;
|
|
|
|
[[foo]] abc;
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("UnresolvedUsingTypeLoc",
|
|
|
|
{"using typename Foo<T>::foo", Rel::Alias});
|
2022-10-08 04:32:15 +02:00
|
|
|
|
|
|
|
// Using enum.
|
|
|
|
Flags.push_back("-std=c++20");
|
|
|
|
Code = R"cpp(
|
|
|
|
namespace ns { enum class A { X }; }
|
|
|
|
[[using enum ns::A]];
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("UsingEnumDecl", "enum class A : int");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
namespace ns { enum class A { X }; }
|
|
|
|
using enum ns::A;
|
|
|
|
auto m = [[X]];
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DeclRefExpr", "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
|
|
|
}
|
|
|
|
|
2021-01-26 18:59:29 +00:00
|
|
|
TEST_F(TargetDeclTest, BaseSpecifier) {
|
|
|
|
Code = R"cpp(
|
|
|
|
struct X {};
|
|
|
|
struct Y : [[private]] X {};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXBaseSpecifier", "struct X");
|
|
|
|
Code = R"cpp(
|
|
|
|
struct X {};
|
|
|
|
struct Y : [[private X]] {};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXBaseSpecifier", "struct X");
|
|
|
|
Code = R"cpp(
|
|
|
|
struct X {};
|
|
|
|
struct Y : private [[X]] {};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("RecordTypeLoc", "struct 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
|
|
|
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
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
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
|
|
|
|
2021-10-12 16:52:09 +02:00
|
|
|
Code = R"cpp(
|
|
|
|
template<template<typename> class ...T>
|
|
|
|
class C {
|
|
|
|
C<[[T...]]> foo;
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TemplateArgumentLoc", {"template <typename> class ...T"});
|
|
|
|
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
|
|
|
|
2020-08-09 20:37:43 -04:00
|
|
|
Code = R"cpp(
|
|
|
|
// Template template argument.
|
|
|
|
template<typename T> struct Vector {};
|
|
|
|
template <template <typename> class Container>
|
|
|
|
struct A {};
|
|
|
|
A<[[Vector]]> a;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TemplateArgumentLoc", {"template <typename T> struct Vector"});
|
|
|
|
|
2020-07-19 02:26:49 -04:00
|
|
|
Flags.push_back("-std=c++17"); // for CTAD tests
|
|
|
|
|
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";
|
|
|
|
EXPECT_DECLS("DeducedTemplateSpecializationTypeLoc",
|
|
|
|
{"struct Test", Rel::TemplatePattern});
|
2020-07-19 02:26:49 -04:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
// Deduction guide
|
|
|
|
template <typename T>
|
|
|
|
struct Test {
|
|
|
|
template <typename I>
|
|
|
|
Test(I, I);
|
|
|
|
};
|
|
|
|
template <typename I>
|
|
|
|
[[Test]](I, I) -> Test<typename I::type>;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXDeductionGuideDecl", {"template <typename T> struct Test"});
|
[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) {
|
2020-08-03 03:21:01 -04:00
|
|
|
Flags.push_back("-std=c++20");
|
|
|
|
|
|
|
|
// FIXME: Should we truncate the pretty-printed form of a concept decl
|
|
|
|
// somewhere?
|
|
|
|
|
2020-01-21 16:55:43 -05:00
|
|
|
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";
|
|
|
|
EXPECT_DECLS(
|
|
|
|
"ConceptSpecializationExpr",
|
2021-06-30 17:11:32 -07:00
|
|
|
{"template <typename T> concept Fooable = requires (T t) { t.foo(); }"});
|
2020-08-03 03:21:01 -04:00
|
|
|
|
|
|
|
// trailing requires clause
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename T>
|
|
|
|
concept Fooable = true;
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void foo() requires [[Fooable]]<T>;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ConceptSpecializationExpr",
|
2021-06-30 17:11:32 -07:00
|
|
|
{"template <typename T> concept Fooable = true"});
|
2020-07-26 22:45:24 -04:00
|
|
|
|
|
|
|
// constrained-parameter
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename T>
|
|
|
|
concept Fooable = true;
|
|
|
|
|
|
|
|
template <[[Fooable]] T>
|
|
|
|
void bar(T t);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ConceptSpecializationExpr",
|
2021-06-30 17:11:32 -07:00
|
|
|
{"template <typename T> concept Fooable = true"});
|
2020-07-26 22:45:24 -04:00
|
|
|
|
|
|
|
// partial-concept-id
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename T, typename U>
|
|
|
|
concept Fooable = true;
|
|
|
|
|
|
|
|
template <[[Fooable]]<int> T>
|
|
|
|
void bar(T t);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ConceptSpecializationExpr",
|
2021-06-30 17:11:32 -07:00
|
|
|
{"template <typename T, typename U> concept Fooable = true"});
|
2020-01-21 16:55:43 -05:00
|
|
|
}
|
|
|
|
|
2022-04-04 02:29:21 -04:00
|
|
|
TEST_F(TargetDeclTest, Coroutine) {
|
|
|
|
Flags.push_back("-std=c++20");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
2023-02-20 10:26:41 +08:00
|
|
|
namespace std {
|
2022-04-04 02:29:21 -04:00
|
|
|
template <typename, typename...> struct coroutine_traits;
|
|
|
|
template <typename> struct coroutine_handle {
|
|
|
|
template <typename U>
|
|
|
|
coroutine_handle(coroutine_handle<U>&&) noexcept;
|
|
|
|
static coroutine_handle from_address(void* __addr) noexcept;
|
|
|
|
};
|
2023-02-20 10:26:41 +08:00
|
|
|
} // namespace std
|
2022-04-04 02:29:21 -04:00
|
|
|
|
|
|
|
struct executor {};
|
|
|
|
struct awaitable {};
|
|
|
|
struct awaitable_frame {
|
|
|
|
awaitable get_return_object();
|
|
|
|
void return_void();
|
|
|
|
void unhandled_exception();
|
|
|
|
struct result_t {
|
|
|
|
~result_t();
|
|
|
|
bool await_ready() const noexcept;
|
2023-02-20 10:26:41 +08:00
|
|
|
void await_suspend(std::coroutine_handle<void>) noexcept;
|
2022-04-04 02:29:21 -04:00
|
|
|
void await_resume() const noexcept;
|
|
|
|
};
|
|
|
|
result_t initial_suspend() noexcept;
|
|
|
|
result_t final_suspend() noexcept;
|
|
|
|
result_t await_transform(executor) noexcept;
|
|
|
|
};
|
|
|
|
|
2023-02-20 10:26:41 +08:00
|
|
|
namespace std {
|
2022-04-04 02:29:21 -04:00
|
|
|
template <>
|
|
|
|
struct coroutine_traits<awaitable> {
|
|
|
|
typedef awaitable_frame promise_type;
|
|
|
|
};
|
2023-02-20 10:26:41 +08:00
|
|
|
} // namespace std
|
2022-04-04 02:29:21 -04:00
|
|
|
|
|
|
|
awaitable foo() {
|
|
|
|
co_await [[executor]]();
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("RecordTypeLoc", "struct executor");
|
|
|
|
}
|
|
|
|
|
2023-06-20 13:25:56 +02:00
|
|
|
TEST_F(TargetDeclTest, RewrittenBinaryOperator) {
|
|
|
|
Flags.push_back("-std=c++20");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
namespace std {
|
|
|
|
struct strong_ordering {
|
|
|
|
int n;
|
|
|
|
constexpr operator int() const { return n; }
|
|
|
|
static const strong_ordering equal, greater, less;
|
|
|
|
};
|
|
|
|
constexpr strong_ordering strong_ordering::equal = {0};
|
|
|
|
constexpr strong_ordering strong_ordering::greater = {1};
|
|
|
|
constexpr strong_ordering strong_ordering::less = {-1};
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Foo
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
auto operator<=>(const Foo&) const = default;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool x = (Foo(1) [[!=]] Foo(2));
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXRewrittenBinaryOperator",
|
|
|
|
{"std::strong_ordering operator<=>(const Foo &) const = default",
|
|
|
|
Rel::TemplatePattern},
|
|
|
|
{"bool operator==(const Foo &) const noexcept = default",
|
|
|
|
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
|
|
|
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) {
|
2020-07-25 21:52:33 +02:00
|
|
|
Flags.push_back("--target=x86_64-pc-linux-gnu");
|
2019-10-13 13:15:27 +00:00
|
|
|
|
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 *)");
|
2020-07-25 21:52:33 +02:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
struct X {
|
|
|
|
static void *operator new(unsigned long);
|
|
|
|
};
|
|
|
|
auto* k = [[new]] X();
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXNewExpr", "static void *operator new(unsigned long)");
|
|
|
|
Code = R"cpp(
|
|
|
|
void *operator new(unsigned long);
|
|
|
|
auto* k = [[new]] int();
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXNewExpr", "void *operator new(unsigned long)");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
struct X {
|
|
|
|
static void operator delete(void *) noexcept;
|
|
|
|
};
|
|
|
|
void k(X* x) {
|
|
|
|
[[delete]] x;
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXDeleteExpr", "static void operator delete(void *) noexcept");
|
|
|
|
Code = R"cpp(
|
|
|
|
void operator delete(void *) noexcept;
|
|
|
|
void k(int* x) {
|
|
|
|
[[delete]] x;
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXDeleteExpr", "void operator delete(void *) noexcept");
|
2019-10-01 07:27:55 +00:00
|
|
|
}
|
|
|
|
|
2020-07-08 02:51:34 -04:00
|
|
|
TEST_F(TargetDeclTest, DependentExprs) {
|
|
|
|
// Heuristic resolution of method of dependent field
|
|
|
|
Code = R"cpp(
|
|
|
|
struct A { void foo() {} };
|
|
|
|
template <typename T>
|
|
|
|
struct B {
|
|
|
|
A a;
|
|
|
|
void bar() {
|
|
|
|
this->a.[[foo]]();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
|
|
|
|
|
|
|
|
// Similar to above but base expression involves a function call.
|
|
|
|
Code = R"cpp(
|
|
|
|
struct A {
|
|
|
|
void foo() {}
|
|
|
|
};
|
|
|
|
struct B {
|
|
|
|
A getA();
|
|
|
|
};
|
|
|
|
template <typename T>
|
|
|
|
struct C {
|
|
|
|
B c;
|
|
|
|
void bar() {
|
|
|
|
this->c.getA().[[foo]]();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
|
|
|
|
|
|
|
|
// Similar to above but uses a function pointer.
|
|
|
|
Code = R"cpp(
|
|
|
|
struct A {
|
|
|
|
void foo() {}
|
|
|
|
};
|
|
|
|
struct B {
|
|
|
|
using FPtr = A(*)();
|
|
|
|
FPtr fptr;
|
|
|
|
};
|
|
|
|
template <typename T>
|
|
|
|
struct C {
|
|
|
|
B c;
|
|
|
|
void bar() {
|
|
|
|
this->c.fptr().[[foo]]();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
|
|
|
|
|
|
|
|
// Base expression involves a member access into this.
|
|
|
|
Code = R"cpp(
|
|
|
|
struct Bar {
|
|
|
|
int aaaa;
|
|
|
|
};
|
|
|
|
template <typename T> struct Foo {
|
|
|
|
Bar func(int);
|
|
|
|
void test() {
|
|
|
|
func(1).[[aaaa]];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXDependentScopeMemberExpr", "int aaaa");
|
2020-07-29 13:58:12 +02:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
class Foo {
|
|
|
|
public:
|
|
|
|
static Foo k(int);
|
|
|
|
template <typename T> T convert() const;
|
|
|
|
};
|
|
|
|
template <typename T>
|
|
|
|
void test() {
|
|
|
|
Foo::k(T()).template [[convert]]<T>();
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXDependentScopeMemberExpr",
|
|
|
|
"template <typename T> T convert() const");
|
2023-06-09 02:39:28 -04:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename T>
|
|
|
|
struct Waldo {
|
|
|
|
void find();
|
|
|
|
};
|
|
|
|
template <typename T>
|
|
|
|
using Wally = Waldo<T>;
|
|
|
|
template <typename T>
|
|
|
|
void foo(Wally<T> w) {
|
|
|
|
w.[[find]]();
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void find()");
|
2023-06-09 02:39:28 -04:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename T>
|
|
|
|
struct Waldo {
|
|
|
|
void find();
|
|
|
|
};
|
|
|
|
template <typename T>
|
|
|
|
struct MetaWaldo {
|
|
|
|
using Type = Waldo<T>;
|
|
|
|
};
|
|
|
|
template <typename T>
|
|
|
|
void foo(typename MetaWaldo<T>::Type w) {
|
|
|
|
w.[[find]]();
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void find()");
|
2023-06-12 04:05:10 -04:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
struct Waldo {
|
|
|
|
void find();
|
|
|
|
};
|
|
|
|
template <typename T>
|
|
|
|
using Wally = Waldo;
|
|
|
|
template <typename>
|
|
|
|
struct S : Wally<int> {
|
|
|
|
void Foo() { this->[[find]](); }
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void find()");
|
2020-07-08 02:51:34 -04:00
|
|
|
}
|
|
|
|
|
2020-09-29 03:19:59 -04:00
|
|
|
TEST_F(TargetDeclTest, DependentTypes) {
|
|
|
|
// Heuristic resolution of dependent type name
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename>
|
|
|
|
struct A { struct B {}; };
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void foo(typename A<T>::[[B]]);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DependentNameTypeLoc", "struct B");
|
|
|
|
|
|
|
|
// Heuristic resolution of dependent type name which doesn't get a TypeLoc
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename>
|
|
|
|
struct A { struct B { struct C {}; }; };
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void foo(typename A<T>::[[B]]::C);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("NestedNameSpecifierLoc", "struct B");
|
|
|
|
|
|
|
|
// Heuristic resolution of dependent type name whose qualifier is also
|
|
|
|
// dependent
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename>
|
|
|
|
struct A { struct B { struct C {}; }; };
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void foo(typename A<T>::B::[[C]]);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DependentNameTypeLoc", "struct C");
|
|
|
|
|
|
|
|
// Heuristic resolution of dependent template name
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename>
|
|
|
|
struct A {
|
|
|
|
template <typename> struct B {};
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void foo(typename A<T>::template [[B]]<int>);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DependentTemplateSpecializationTypeLoc",
|
|
|
|
"template <typename> struct B");
|
|
|
|
}
|
|
|
|
|
2021-01-10 20:41:50 -05:00
|
|
|
TEST_F(TargetDeclTest, TypedefCascade) {
|
|
|
|
Code = R"cpp(
|
|
|
|
struct C {
|
|
|
|
using type = int;
|
|
|
|
};
|
|
|
|
struct B {
|
|
|
|
using type = C::type;
|
|
|
|
};
|
|
|
|
struct A {
|
|
|
|
using type = B::type;
|
|
|
|
};
|
|
|
|
A::[[type]] waldo;
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TypedefTypeLoc",
|
|
|
|
{"using type = int", Rel::Alias | Rel::Underlying},
|
|
|
|
{"using type = C::type", Rel::Alias | Rel::Underlying},
|
|
|
|
{"using type = B::type", Rel::Alias});
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TargetDeclTest, RecursiveTemplate) {
|
|
|
|
Flags.push_back("-std=c++20"); // the test case uses concepts
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
template <typename T>
|
|
|
|
concept Leaf = false;
|
|
|
|
|
|
|
|
template <typename Tree>
|
|
|
|
struct descend_left {
|
|
|
|
using type = typename descend_left<typename Tree::left>::[[type]];
|
|
|
|
};
|
|
|
|
|
|
|
|
template <Leaf Tree>
|
|
|
|
struct descend_left<Tree> {
|
|
|
|
using type = typename Tree::value;
|
|
|
|
};
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("DependentNameTypeLoc",
|
|
|
|
{"using type = typename descend_left<typename Tree::left>::type",
|
|
|
|
Rel::Alias | 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
|
|
|
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
|
|
|
|
2020-10-16 14:14:37 -04:00
|
|
|
Code = R"cpp(
|
|
|
|
@interface MYObject
|
|
|
|
@end
|
|
|
|
@interface Interface
|
|
|
|
@property(retain) [[MYObject]] *x;
|
|
|
|
@end
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCInterfaceTypeLoc", "@interface MYObject");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@interface MYObject2
|
|
|
|
@end
|
|
|
|
@interface Interface
|
|
|
|
@property(retain, nonnull) [[MYObject2]] *x;
|
|
|
|
@end
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCInterfaceTypeLoc", "@interface MYObject2");
|
|
|
|
|
[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");
|
|
|
|
|
2020-07-09 14:29:15 -04:00
|
|
|
Code = R"cpp(// Don't consider implicit interface as the target.
|
|
|
|
@implementation [[Implicit]]
|
|
|
|
@end
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCImplementationDecl", "@implementation Implicit");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@interface Foo
|
|
|
|
@end
|
|
|
|
@implementation [[Foo]]
|
|
|
|
@end
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCImplementationDecl", "@interface Foo");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@interface Foo
|
|
|
|
@end
|
|
|
|
@interface Foo (Ext)
|
|
|
|
@end
|
|
|
|
@implementation [[Foo]] (Ext)
|
|
|
|
@end
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCCategoryImplDecl", "@interface Foo(Ext)");
|
|
|
|
|
2023-06-26 12:25:56 -04:00
|
|
|
Code = R"cpp(
|
|
|
|
@interface Foo
|
|
|
|
@end
|
|
|
|
@interface Foo (Ext)
|
|
|
|
@end
|
|
|
|
@implementation Foo ([[Ext]])
|
|
|
|
@end
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCCategoryImplDecl", "@interface Foo(Ext)");
|
|
|
|
|
[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(
|
2022-02-09 15:01:17 -05:00
|
|
|
void test(id</*error-ok*/[[InvalidProtocol]]> p);
|
[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";
|
2022-02-09 15:01:17 -05:00
|
|
|
EXPECT_DECLS("ParmVarDecl", "id p");
|
[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
|
|
|
|
2021-03-19 16:23:15 -04:00
|
|
|
Code = R"cpp(
|
|
|
|
@class C;
|
|
|
|
@protocol Foo
|
|
|
|
@end
|
|
|
|
void test([[C]]<Foo> *p);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCInterfaceTypeLoc", "@class 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
|
|
|
Code = R"cpp(
|
|
|
|
@class C;
|
|
|
|
@protocol Foo
|
|
|
|
@end
|
|
|
|
void test(C<[[Foo]]> *p);
|
|
|
|
)cpp";
|
2022-02-09 15:01:17 -05:00
|
|
|
EXPECT_DECLS("ObjCProtocolLoc", "@protocol Foo");
|
2021-03-19 16:23:15 -04:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@class C;
|
|
|
|
@protocol Foo
|
|
|
|
@end
|
|
|
|
@protocol Bar
|
|
|
|
@end
|
|
|
|
void test(C<[[Foo]], Bar> *p);
|
|
|
|
)cpp";
|
2022-02-09 15:01:17 -05:00
|
|
|
EXPECT_DECLS("ObjCProtocolLoc", "@protocol Foo");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@class C;
|
|
|
|
@protocol Foo
|
|
|
|
@end
|
|
|
|
@protocol Bar
|
|
|
|
@end
|
|
|
|
void test(C<Foo, [[Bar]]> *p);
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCProtocolLoc", "@protocol Bar");
|
2021-04-06 13:31:09 -04:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@interface Foo
|
|
|
|
+ (id)sharedInstance;
|
|
|
|
@end
|
|
|
|
@implementation Foo
|
|
|
|
+ (id)sharedInstance { return 0; }
|
|
|
|
@end
|
|
|
|
void test() {
|
|
|
|
id value = [[Foo]].sharedInstance;
|
|
|
|
}
|
|
|
|
)cpp";
|
2021-04-30 12:14:32 -04:00
|
|
|
EXPECT_DECLS("ObjCInterfaceTypeLoc", "@interface Foo");
|
2021-04-06 13:31:09 -04:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@interface Foo
|
|
|
|
+ (id)sharedInstance;
|
|
|
|
@end
|
|
|
|
@implementation Foo
|
|
|
|
+ (id)sharedInstance { return 0; }
|
|
|
|
@end
|
|
|
|
void test() {
|
|
|
|
id value = Foo.[[sharedInstance]];
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("ObjCPropertyRefExpr", "+ (id)sharedInstance");
|
2021-08-23 10:30:49 -04:00
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@interface Foo
|
|
|
|
+ ([[id]])sharedInstance;
|
|
|
|
@end
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TypedefTypeLoc");
|
|
|
|
|
|
|
|
Code = R"cpp(
|
|
|
|
@interface Foo
|
|
|
|
+ ([[instancetype]])sharedInstance;
|
|
|
|
@end
|
|
|
|
)cpp";
|
|
|
|
EXPECT_DECLS("TypedefTypeLoc");
|
[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-09-25 12:40:22 +00:00
|
|
|
class FindExplicitReferencesTest : public ::testing::Test {
|
|
|
|
protected:
|
|
|
|
struct AllRefs {
|
|
|
|
std::string AnnotatedCode;
|
|
|
|
std::string DumpedReferences;
|
|
|
|
};
|
|
|
|
|
2023-06-26 12:25:56 -04:00
|
|
|
TestTU newTU(llvm::StringRef Code) {
|
2019-09-25 12:40:22 +00:00
|
|
|
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.
|
2020-06-03 14:53:59 +02:00
|
|
|
TU.ExtraArgs.push_back("-std=c++20");
|
2020-01-10 16:27:12 +01:00
|
|
|
TU.ExtraArgs.push_back("-xobjective-c++");
|
2019-10-13 13:15:27 +00:00
|
|
|
|
2023-06-26 12:25:56 -04:00
|
|
|
return TU;
|
|
|
|
}
|
2019-09-25 12:40:22 +00:00
|
|
|
|
2023-06-26 12:25:56 -04:00
|
|
|
AllRefs annotatedReferences(llvm::StringRef Code, ParsedAST &AST,
|
|
|
|
std::vector<ReferenceLoc> Refs) {
|
2019-09-25 12:40:22 +00:00
|
|
|
auto &SM = AST.getSourceManager();
|
2023-06-27 09:37:12 +02:00
|
|
|
llvm::stable_sort(Refs, [&](const ReferenceLoc &L, const ReferenceLoc &R) {
|
2019-09-25 12:40:22 +00:00
|
|
|
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)};
|
|
|
|
}
|
2023-06-26 12:25:56 -04:00
|
|
|
|
|
|
|
/// Parses \p Code, and annotates its body with results of
|
|
|
|
/// findExplicitReferences on all top level decls.
|
|
|
|
/// See actual tests for examples of annotation format.
|
|
|
|
AllRefs annotateAllReferences(llvm::StringRef Code) {
|
|
|
|
TestTU TU = newTU(Code);
|
|
|
|
auto AST = TU.build();
|
|
|
|
|
|
|
|
std::vector<ReferenceLoc> Refs;
|
|
|
|
for (auto *TopLevel : AST.getLocalTopLevelDecls())
|
|
|
|
findExplicitReferences(
|
|
|
|
TopLevel, [&Refs](ReferenceLoc R) { Refs.push_back(std::move(R)); },
|
|
|
|
AST.getHeuristicResolver());
|
|
|
|
return annotatedReferences(Code, AST, std::move(Refs));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Parses \p Code, finds function or namespace '::foo' and annotates its body
|
|
|
|
/// with results of findExplicitReferences.
|
|
|
|
/// See actual tests for examples of annotation format.
|
|
|
|
AllRefs annotateReferencesInFoo(llvm::StringRef Code) {
|
|
|
|
TestTU TU = newTU(Code);
|
|
|
|
auto AST = TU.build();
|
|
|
|
auto *TestDecl = &findDecl(AST, "foo");
|
|
|
|
if (auto *T = llvm::dyn_cast<FunctionTemplateDecl>(TestDecl))
|
|
|
|
TestDecl = T->getTemplatedDecl();
|
|
|
|
|
|
|
|
std::vector<ReferenceLoc> Refs;
|
|
|
|
if (const auto *Func = llvm::dyn_cast<FunctionDecl>(TestDecl))
|
|
|
|
findExplicitReferences(
|
|
|
|
Func->getBody(),
|
|
|
|
[&Refs](ReferenceLoc R) { Refs.push_back(std::move(R)); },
|
|
|
|
AST.getHeuristicResolver());
|
|
|
|
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));
|
|
|
|
},
|
|
|
|
AST.getHeuristicResolver());
|
|
|
|
else if (const auto *OC = llvm::dyn_cast<ObjCContainerDecl>(TestDecl))
|
|
|
|
findExplicitReferences(
|
|
|
|
OC, [&Refs](ReferenceLoc R) { Refs.push_back(std::move(R)); },
|
|
|
|
AST.getHeuristicResolver());
|
|
|
|
else
|
|
|
|
ADD_FAILURE() << "Failed to find ::foo decl for test";
|
|
|
|
|
|
|
|
return annotatedReferences(Code, AST, std::move(Refs));
|
|
|
|
}
|
2019-09-25 12:40:22 +00:00
|
|
|
};
|
|
|
|
|
2023-06-26 12:25:56 -04:00
|
|
|
TEST_F(FindExplicitReferencesTest, AllRefsInFoo) {
|
2019-09-25 12:40:22 +00:00
|
|
|
std::pair</*Code*/ llvm::StringRef, /*References*/ llvm::StringRef> Cases[] =
|
2021-04-26 17:58:35 -04: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",
|
2021-04-26 17:58:35 -04: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",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {x}\n"
|
|
|
|
"1: targets = {X::a}\n"},
|
|
|
|
{R"cpp(
|
2020-03-31 16:09:49 +02:00
|
|
|
// error-ok: testing with broken code
|
|
|
|
int bar();
|
|
|
|
int foo() {
|
|
|
|
return $0^bar() + $1^bar(42);
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {bar}\n"
|
|
|
|
"1: targets = {bar}\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",
|
2021-04-26 17:58:35 -04: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",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {ns}\n"
|
|
|
|
"1: targets = {ns::global}, qualifier = 'ns::'\n"},
|
2022-09-20 21:39:47 +02:00
|
|
|
// Using enum declarations.
|
|
|
|
{R"cpp(
|
|
|
|
namespace ns { enum class A {}; }
|
|
|
|
void foo() {
|
|
|
|
using enum $0^ns::$1^A;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {ns}\n"
|
|
|
|
"1: targets = {ns::A}, qualifier = 'ns::'\n"},
|
2021-04-26 17:58:35 -04:00
|
|
|
// 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",
|
2021-04-26 17:58:35 -04: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",
|
2021-04-26 17:58:35 -04: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"},
|
|
|
|
{R"cpp(
|
2020-05-19 00:45:27 +02:00
|
|
|
void foo() {
|
|
|
|
$0^ten: // PRINT "HELLO WORLD!"
|
|
|
|
goto $1^ten;
|
|
|
|
}
|
|
|
|
)cpp",
|
2020-07-19 02:26:49 -04:00
|
|
|
"0: targets = {ten}, decl\n"
|
|
|
|
"1: targets = {ten}\n"},
|
2019-12-05 14:27:23 -05:00
|
|
|
// 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",
|
2021-04-26 17:58:35 -04: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",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {valias}\n"
|
|
|
|
"1: targets = {vi}, decl\n"
|
|
|
|
"2: targets = {valias}\n"
|
|
|
|
"3: targets = {vb}, decl\n"},
|
|
|
|
// Injected class name.
|
|
|
|
{R"cpp(
|
2020-01-21 11:50:57 +01:00
|
|
|
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",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {foo::Bar::T}, decl\n"
|
|
|
|
"1: targets = {foo::Bar}, decl\n"
|
|
|
|
"2: targets = {foo::Bar}\n"
|
|
|
|
"3: targets = {foo::Bar::f}, decl\n"
|
|
|
|
"4: targets = {foo::Bar}\n"},
|
|
|
|
// 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",
|
2021-04-26 17:58:35 -04: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",
|
2021-04-26 17:58:35 -04: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",
|
2021-04-26 17:58:35 -04: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",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {x}, decl\n"
|
|
|
|
"1: targets = {vector}\n"
|
|
|
|
"2: targets = {x}\n"},
|
2022-01-18 11:03:20 +01:00
|
|
|
// Handle UnresolvedLookupExpr.
|
2021-04-26 17:58:35 -04: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",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {ns1::func, ns2::func}\n"
|
|
|
|
"1: targets = {t}\n"},
|
|
|
|
// 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",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {x}\n"
|
|
|
|
"1: targets = {X::func, X::func}\n"
|
|
|
|
"2: targets = {t}\n"},
|
|
|
|
// Handle DependentScopeDeclRefExpr.
|
|
|
|
{R"cpp(
|
2020-03-19 15:42:10 -04:00
|
|
|
template <class T>
|
|
|
|
struct S {
|
|
|
|
static int value;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void foo() {
|
|
|
|
$0^S<$1^T>::$2^value;
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {S}\n"
|
|
|
|
"1: targets = {T}\n"
|
|
|
|
"2: targets = {S::value}, qualifier = 'S<T>::'\n"},
|
|
|
|
// Handle CXXDependentScopeMemberExpr.
|
|
|
|
{R"cpp(
|
2020-03-19 15:42:10 -04:00
|
|
|
template <class T>
|
|
|
|
struct S {
|
|
|
|
int value;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void foo(S<T> t) {
|
|
|
|
$0^t.$1^value;
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {t}\n"
|
|
|
|
"1: targets = {S::value}\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",
|
2021-04-26 17:58:35 -04: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",
|
2021-04-26 17:58:35 -04: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",
|
2021-04-26 17:58:35 -04: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",
|
2021-04-26 17:58:35 -04: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",
|
2021-04-26 17:58:35 -04: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"},
|
|
|
|
// User-defined conversion operator.
|
|
|
|
{R"cpp(
|
2020-01-21 05:33:39 +01:00
|
|
|
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",
|
2021-04-26 17:58:35 -04:00
|
|
|
"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(
|
2020-01-21 05:33:39 +01:00
|
|
|
void foo() {
|
|
|
|
class $0^Foo {
|
|
|
|
public:
|
|
|
|
~$1^Foo() {}
|
|
|
|
|
|
|
|
void $2^destructMe() {
|
|
|
|
this->~$3^Foo();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
$4^Foo $5^f;
|
|
|
|
$6^f.~ /*...*/ $7^Foo();
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"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"},
|
|
|
|
// 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",
|
2021-04-26 17:58:35 -04: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() {
|
[clang] Implement ElaboratedType sugaring for types written bare
Without this patch, clang will not wrap in an ElaboratedType node types written
without a keyword and nested name qualifier, which goes against the intent that
we should produce an AST which retains enough details to recover how things are
written.
The lack of this sugar is incompatible with the intent of the type printer
default policy, which is to print types as written, but to fall back and print
them fully qualified when they are desugared.
An ElaboratedTypeLoc without keyword / NNS uses no storage by itself, but still
requires pointer alignment due to pre-existing bug in the TypeLoc buffer
handling.
---
Troubleshooting list to deal with any breakage seen with this patch:
1) The most likely effect one would see by this patch is a change in how
a type is printed. The type printer will, by design and default,
print types as written. There are customization options there, but
not that many, and they mainly apply to how to print a type that we
somehow failed to track how it was written. This patch fixes a
problem where we failed to distinguish between a type
that was written without any elaborated-type qualifiers,
such as a 'struct'/'class' tags and name spacifiers such as 'std::',
and one that has been stripped of any 'metadata' that identifies such,
the so called canonical types.
Example:
```
namespace foo {
struct A {};
A a;
};
```
If one were to print the type of `foo::a`, prior to this patch, this
would result in `foo::A`. This is how the type printer would have,
by default, printed the canonical type of A as well.
As soon as you add any name qualifiers to A, the type printer would
suddenly start accurately printing the type as written. This patch
will make it print it accurately even when written without
qualifiers, so we will just print `A` for the initial example, as
the user did not really write that `foo::` namespace qualifier.
2) This patch could expose a bug in some AST matcher. Matching types
is harder to get right when there is sugar involved. For example,
if you want to match a type against being a pointer to some type A,
then you have to account for getting a type that is sugar for a
pointer to A, or being a pointer to sugar to A, or both! Usually
you would get the second part wrong, and this would work for a
very simple test where you don't use any name qualifiers, but
you would discover is broken when you do. The usual fix is to
either use the matcher which strips sugar, which is annoying
to use as for example if you match an N level pointer, you have
to put N+1 such matchers in there, beginning to end and between
all those levels. But in a lot of cases, if the property you want
to match is present in the canonical type, it's easier and faster
to just match on that... This goes with what is said in 1), if
you want to match against the name of a type, and you want
the name string to be something stable, perhaps matching on
the name of the canonical type is the better choice.
3) This patch could expose a bug in how you get the source range of some
TypeLoc. For some reason, a lot of code is using getLocalSourceRange(),
which only looks at the given TypeLoc node. This patch introduces a new,
and more common TypeLoc node which contains no source locations on itself.
This is not an inovation here, and some other, more rare TypeLoc nodes could
also have this property, but if you use getLocalSourceRange on them, it's not
going to return any valid locations, because it doesn't have any. The right fix
here is to always use getSourceRange() or getBeginLoc/getEndLoc which will dive
into the inner TypeLoc to get the source range if it doesn't find it on the
top level one. You can use getLocalSourceRange if you are really into
micro-optimizations and you have some outside knowledge that the TypeLocs you are
dealing with will always include some source location.
4) Exposed a bug somewhere in the use of the normal clang type class API, where you
have some type, you want to see if that type is some particular kind, you try a
`dyn_cast` such as `dyn_cast<TypedefType>` and that fails because now you have an
ElaboratedType which has a TypeDefType inside of it, which is what you wanted to match.
Again, like 2), this would usually have been tested poorly with some simple tests with
no qualifications, and would have been broken had there been any other kind of type sugar,
be it an ElaboratedType or a TemplateSpecializationType or a SubstTemplateParmType.
The usual fix here is to use `getAs` instead of `dyn_cast`, which will look deeper
into the type. Or use `getAsAdjusted` when dealing with TypeLocs.
For some reason the API is inconsistent there and on TypeLocs getAs behaves like a dyn_cast.
5) It could be a bug in this patch perhaps.
Let me know if you need any help!
Signed-off-by: Matheus Izvekov <mizvekov@gmail.com>
Differential Revision: https://reviews.llvm.org/D112374
2021-10-11 18:15:36 +02:00
|
|
|
$0^class {} $1^x;
|
|
|
|
int (*$2^fptr)(int $3^a, int) = nullptr;
|
2019-10-28 14:41:06 +01:00
|
|
|
}
|
|
|
|
)cpp",
|
2022-10-14 08:17:16 -04:00
|
|
|
"0: targets = {(unnamed)}\n"
|
[clang] Implement ElaboratedType sugaring for types written bare
Without this patch, clang will not wrap in an ElaboratedType node types written
without a keyword and nested name qualifier, which goes against the intent that
we should produce an AST which retains enough details to recover how things are
written.
The lack of this sugar is incompatible with the intent of the type printer
default policy, which is to print types as written, but to fall back and print
them fully qualified when they are desugared.
An ElaboratedTypeLoc without keyword / NNS uses no storage by itself, but still
requires pointer alignment due to pre-existing bug in the TypeLoc buffer
handling.
---
Troubleshooting list to deal with any breakage seen with this patch:
1) The most likely effect one would see by this patch is a change in how
a type is printed. The type printer will, by design and default,
print types as written. There are customization options there, but
not that many, and they mainly apply to how to print a type that we
somehow failed to track how it was written. This patch fixes a
problem where we failed to distinguish between a type
that was written without any elaborated-type qualifiers,
such as a 'struct'/'class' tags and name spacifiers such as 'std::',
and one that has been stripped of any 'metadata' that identifies such,
the so called canonical types.
Example:
```
namespace foo {
struct A {};
A a;
};
```
If one were to print the type of `foo::a`, prior to this patch, this
would result in `foo::A`. This is how the type printer would have,
by default, printed the canonical type of A as well.
As soon as you add any name qualifiers to A, the type printer would
suddenly start accurately printing the type as written. This patch
will make it print it accurately even when written without
qualifiers, so we will just print `A` for the initial example, as
the user did not really write that `foo::` namespace qualifier.
2) This patch could expose a bug in some AST matcher. Matching types
is harder to get right when there is sugar involved. For example,
if you want to match a type against being a pointer to some type A,
then you have to account for getting a type that is sugar for a
pointer to A, or being a pointer to sugar to A, or both! Usually
you would get the second part wrong, and this would work for a
very simple test where you don't use any name qualifiers, but
you would discover is broken when you do. The usual fix is to
either use the matcher which strips sugar, which is annoying
to use as for example if you match an N level pointer, you have
to put N+1 such matchers in there, beginning to end and between
all those levels. But in a lot of cases, if the property you want
to match is present in the canonical type, it's easier and faster
to just match on that... This goes with what is said in 1), if
you want to match against the name of a type, and you want
the name string to be something stable, perhaps matching on
the name of the canonical type is the better choice.
3) This patch could expose a bug in how you get the source range of some
TypeLoc. For some reason, a lot of code is using getLocalSourceRange(),
which only looks at the given TypeLoc node. This patch introduces a new,
and more common TypeLoc node which contains no source locations on itself.
This is not an inovation here, and some other, more rare TypeLoc nodes could
also have this property, but if you use getLocalSourceRange on them, it's not
going to return any valid locations, because it doesn't have any. The right fix
here is to always use getSourceRange() or getBeginLoc/getEndLoc which will dive
into the inner TypeLoc to get the source range if it doesn't find it on the
top level one. You can use getLocalSourceRange if you are really into
micro-optimizations and you have some outside knowledge that the TypeLocs you are
dealing with will always include some source location.
4) Exposed a bug somewhere in the use of the normal clang type class API, where you
have some type, you want to see if that type is some particular kind, you try a
`dyn_cast` such as `dyn_cast<TypedefType>` and that fails because now you have an
ElaboratedType which has a TypeDefType inside of it, which is what you wanted to match.
Again, like 2), this would usually have been tested poorly with some simple tests with
no qualifications, and would have been broken had there been any other kind of type sugar,
be it an ElaboratedType or a TemplateSpecializationType or a SubstTemplateParmType.
The usual fix here is to use `getAs` instead of `dyn_cast`, which will look deeper
into the type. Or use `getAsAdjusted` when dealing with TypeLocs.
For some reason the API is inconsistent there and on TypeLocs getAs behaves like a dyn_cast.
5) It could be a bug in this patch perhaps.
Let me know if you need any help!
Signed-off-by: Matheus Izvekov <mizvekov@gmail.com>
Differential Revision: https://reviews.llvm.org/D112374
2021-10-11 18:15:36 +02:00
|
|
|
"1: targets = {x}, decl\n"
|
|
|
|
"2: targets = {fptr}, decl\n"
|
|
|
|
"3: targets = {a}, decl\n"},
|
2021-04-26 17:58:35 -04:00
|
|
|
// 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",
|
2021-04-26 17:58:35 -04: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(
|
2019-12-05 14:27:23 -05:00
|
|
|
template <typename... E>
|
|
|
|
void foo() {
|
|
|
|
constexpr int $0^size = sizeof...($1^E);
|
|
|
|
};
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {size}, decl\n"
|
|
|
|
"1: targets = {E}\n"},
|
|
|
|
// Class template argument deduction
|
|
|
|
{
|
|
|
|
R"cpp(
|
2020-01-02 00:45:01 -05:00
|
|
|
template <typename T>
|
|
|
|
struct Test {
|
|
|
|
Test(T);
|
|
|
|
};
|
|
|
|
void foo() {
|
|
|
|
$0^Test $1^a(5);
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {Test}\n"
|
|
|
|
"1: targets = {a}, decl\n"},
|
|
|
|
// Templates
|
|
|
|
{R"cpp(
|
2020-01-21 15:15:06 +01:00
|
|
|
namespace foo {
|
|
|
|
template <typename $0^T>
|
|
|
|
class $1^Bar {};
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {foo::Bar::T}, decl\n"
|
|
|
|
"1: targets = {foo::Bar}, decl\n"},
|
|
|
|
// Templates
|
|
|
|
{R"cpp(
|
2020-01-21 15:15:06 +01:00
|
|
|
namespace foo {
|
|
|
|
template <typename $0^T>
|
|
|
|
void $1^func();
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {T}, decl\n"
|
|
|
|
"1: targets = {foo::func}, decl\n"},
|
|
|
|
// Templates
|
|
|
|
{R"cpp(
|
2020-01-21 15:15:06 +01:00
|
|
|
namespace foo {
|
|
|
|
template <typename $0^T>
|
|
|
|
$1^T $2^x;
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {foo::T}, decl\n"
|
|
|
|
"1: targets = {foo::T}\n"
|
|
|
|
"2: targets = {foo::x}, decl\n"},
|
|
|
|
// Templates
|
|
|
|
{R"cpp(
|
2020-01-21 15:15:06 +01:00
|
|
|
template<typename T> class vector {};
|
|
|
|
namespace foo {
|
|
|
|
template <typename $0^T>
|
|
|
|
using $1^V = $2^vector<$3^T>;
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {foo::T}, decl\n"
|
|
|
|
"1: targets = {foo::V}, decl\n"
|
|
|
|
"2: targets = {vector}\n"
|
|
|
|
"3: targets = {foo::T}\n"},
|
|
|
|
// Concept
|
|
|
|
{
|
|
|
|
R"cpp(
|
2020-01-21 13:21:08 -05:00
|
|
|
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) {
|
2020-03-19 15:42:10 -04:00
|
|
|
$6^t.$7^draw();
|
2020-01-21 13:21:08 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"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"
|
|
|
|
"6: targets = {t}\n"
|
|
|
|
"7: targets = {}\n"},
|
2021-05-03 16:18:57 -04:00
|
|
|
// Objective-C: instance variables
|
|
|
|
{
|
|
|
|
R"cpp(
|
|
|
|
@interface I {
|
|
|
|
@public
|
|
|
|
I *_z;
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
I *f;
|
|
|
|
void foo() {
|
|
|
|
$0^f->$1^_z = 0;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {f}\n"
|
|
|
|
"1: targets = {I::_z}\n"},
|
2021-04-26 17:58:35 -04:00
|
|
|
// Objective-C: properties
|
|
|
|
{
|
|
|
|
R"cpp(
|
2020-01-10 16:27:12 +01:00
|
|
|
@interface I {}
|
|
|
|
@property(retain) I* x;
|
|
|
|
@property(retain) I* y;
|
|
|
|
@end
|
|
|
|
I *f;
|
|
|
|
void foo() {
|
|
|
|
$0^f.$1^x.$2^y = 0;
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {f}\n"
|
|
|
|
"1: targets = {I::x}\n"
|
|
|
|
"2: targets = {I::y}\n"},
|
|
|
|
// Objective-C: implicit properties
|
|
|
|
{
|
|
|
|
R"cpp(
|
2020-01-10 16:27:12 +01:00
|
|
|
@interface I {}
|
|
|
|
-(I*)x;
|
|
|
|
-(void)setY:(I*)y;
|
|
|
|
@end
|
|
|
|
I *f;
|
|
|
|
void foo() {
|
|
|
|
$0^f.$1^x.$2^y = 0;
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {f}\n"
|
|
|
|
"1: targets = {I::x}\n"
|
|
|
|
"2: targets = {I::setY:}\n"},
|
2021-04-06 13:31:09 -04:00
|
|
|
// Objective-C: class properties
|
|
|
|
{
|
|
|
|
R"cpp(
|
|
|
|
@interface I {}
|
|
|
|
@property(class) I *x;
|
|
|
|
@end
|
|
|
|
id local;
|
|
|
|
void foo() {
|
|
|
|
$0^I.$1^x = 0;
|
|
|
|
$2^local = $3^I.$4^x;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {I}\n"
|
|
|
|
"1: targets = {I::setX:}\n"
|
|
|
|
"2: targets = {local}\n"
|
|
|
|
"3: targets = {I}\n"
|
|
|
|
"4: targets = {I::x}\n"},
|
|
|
|
// Objective-C: implicit class properties
|
|
|
|
{
|
|
|
|
R"cpp(
|
|
|
|
@interface I {}
|
|
|
|
+(I*)x;
|
|
|
|
+(void)setX:(I*)x;
|
|
|
|
@end
|
|
|
|
id local;
|
|
|
|
void foo() {
|
|
|
|
$0^I.$1^x = 0;
|
|
|
|
$2^local = $3^I.$4^x;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {I}\n"
|
|
|
|
"1: targets = {I::setX:}\n"
|
|
|
|
"2: targets = {local}\n"
|
|
|
|
"3: targets = {I}\n"
|
|
|
|
"4: targets = {I::x}\n"},
|
2021-04-26 17:58:35 -04:00
|
|
|
{// Objective-C: methods
|
|
|
|
R"cpp(
|
2021-02-27 22:08:07 +01:00
|
|
|
@interface I
|
|
|
|
-(void) a:(int)x b:(int)y;
|
|
|
|
@end
|
|
|
|
void foo(I *i) {
|
|
|
|
[$0^i $1^a:1 b:2];
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {i}\n"
|
|
|
|
"1: targets = {I::a:b:}\n"},
|
|
|
|
{// Objective-C: protocols
|
|
|
|
R"cpp(
|
2021-02-27 22:08:07 +01:00
|
|
|
@interface I
|
|
|
|
@end
|
|
|
|
@protocol P
|
|
|
|
@end
|
|
|
|
void foo() {
|
2021-03-19 16:23:15 -04:00
|
|
|
$0^I<$1^P> *$2^x;
|
2021-02-27 22:08:07 +01:00
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"0: targets = {I}\n"
|
2021-03-19 16:23:15 -04:00
|
|
|
"1: targets = {P}\n"
|
|
|
|
"2: targets = {x}, decl\n"},
|
2021-02-27 22:08:07 +01:00
|
|
|
|
2021-04-26 17:58:35 -04:00
|
|
|
// Designated initializers.
|
|
|
|
{R"cpp(
|
2020-02-10 11:53:17 +01:00
|
|
|
void foo() {
|
|
|
|
struct $0^Foo {
|
|
|
|
int $1^Bar;
|
|
|
|
};
|
|
|
|
$2^Foo $3^f { .$4^Bar = 42 };
|
|
|
|
}
|
|
|
|
)cpp",
|
2021-04-26 17:58:35 -04:00
|
|
|
"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(
|
2020-02-10 11:53:17 +01:00
|
|
|
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"
|
2020-04-15 00:16:10 +02:00
|
|
|
"8: targets = {foo()::Baz::Field}\n"},
|
2020-07-19 02:26:49 -04:00
|
|
|
{R"cpp(
|
2020-04-15 00:16:10 +02:00
|
|
|
template<typename T>
|
|
|
|
void crash(T);
|
|
|
|
template<typename T>
|
|
|
|
void foo() {
|
|
|
|
$0^crash({.$1^x = $2^T()});
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {crash}\n"
|
|
|
|
"1: targets = {}\n"
|
2020-07-19 02:26:49 -04:00
|
|
|
"2: targets = {T}\n"},
|
|
|
|
// unknown template name should not crash.
|
|
|
|
{R"cpp(
|
2020-04-22 13:33:02 +02:00
|
|
|
template <template <typename> typename T>
|
|
|
|
struct Base {};
|
|
|
|
namespace foo {
|
|
|
|
template <typename $0^T>
|
|
|
|
struct $1^Derive : $2^Base<$3^T::template $4^Unknown> {};
|
|
|
|
}
|
|
|
|
)cpp",
|
2020-07-19 02:26:49 -04:00
|
|
|
"0: targets = {foo::Derive::T}, decl\n"
|
|
|
|
"1: targets = {foo::Derive}, decl\n"
|
|
|
|
"2: targets = {Base}\n"
|
|
|
|
"3: targets = {foo::Derive::T}\n"
|
|
|
|
"4: targets = {}, qualifier = 'T::'\n"},
|
|
|
|
// deduction guide
|
|
|
|
{R"cpp(
|
|
|
|
namespace foo {
|
|
|
|
template <typename $0^T>
|
|
|
|
struct $1^Test {
|
|
|
|
template <typename $2^I>
|
|
|
|
$3^Test($4^I);
|
|
|
|
};
|
|
|
|
template <typename $5^I>
|
|
|
|
$6^Test($7^I) -> $8^Test<typename $9^I::$10^type>;
|
|
|
|
}
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {T}, decl\n"
|
|
|
|
"1: targets = {foo::Test}, decl\n"
|
|
|
|
"2: targets = {I}, decl\n"
|
|
|
|
"3: targets = {foo::Test::Test<T>}, decl\n"
|
|
|
|
"4: targets = {I}\n"
|
|
|
|
"5: targets = {I}, decl\n"
|
|
|
|
"6: targets = {foo::Test}\n"
|
|
|
|
"7: targets = {I}\n"
|
|
|
|
"8: targets = {foo::Test}\n"
|
|
|
|
"9: targets = {I}\n"
|
|
|
|
"10: targets = {}, qualifier = 'I::'\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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-26 12:25:56 -04:00
|
|
|
TEST_F(FindExplicitReferencesTest, AllRefs) {
|
|
|
|
std::pair</*Code*/ llvm::StringRef, /*References*/ llvm::StringRef> Cases[] =
|
|
|
|
{{R"cpp(
|
|
|
|
@interface $0^MyClass
|
|
|
|
@end
|
|
|
|
@implementation $1^$2^MyClass
|
|
|
|
@end
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {MyClass}, decl\n"
|
|
|
|
"1: targets = {MyClass}\n"
|
|
|
|
"2: targets = {MyClass}, decl\n"},
|
|
|
|
{R"cpp(
|
|
|
|
@interface $0^MyClass
|
|
|
|
@end
|
|
|
|
@interface $1^MyClass ($2^Category)
|
|
|
|
@end
|
|
|
|
@implementation $3^MyClass ($4^$5^Category)
|
|
|
|
@end
|
|
|
|
)cpp",
|
|
|
|
"0: targets = {MyClass}, decl\n"
|
|
|
|
"1: targets = {MyClass}\n"
|
|
|
|
"2: targets = {Category}, decl\n"
|
|
|
|
"3: targets = {MyClass}\n"
|
|
|
|
"4: targets = {Category}\n"
|
|
|
|
"5: targets = {Category}, decl\n"}};
|
|
|
|
|
|
|
|
for (const auto &C : Cases) {
|
|
|
|
llvm::StringRef ExpectedCode = C.first;
|
|
|
|
llvm::StringRef ExpectedRefs = C.second;
|
|
|
|
|
|
|
|
auto Actual = annotateAllReferences(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
|