forked from OSchip/llvm-project
[clangd] Improve heuristic resolution of dependent types in TargetFinder
* Try to apply heuristic resolution recursively to the base expression of a CXXDependentScopeMemberExpr. * Try to apply heuristic resolution recursively to the callee expression in a call expression. Fixes https://github.com/clangd/clangd/issues/441 Subscribers: ilya-biryukov, jkorous, arphaman, kadircet, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D82739
This commit is contained in:
parent
8953376478
commit
9946dcd3e9
|
@ -59,24 +59,32 @@ nodeToString(const ast_type_traits::DynTypedNode &N) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function for getMembersReferencedViaDependentName()
|
// Helper function for getMembersReferencedViaDependentName()
|
||||||
// which takes a dependent type `T` and heuristically
|
// which takes a possibly-dependent type `T` and heuristically
|
||||||
// resolves it to a CXXRecordDecl in which we can try name lookup.
|
// resolves it to a CXXRecordDecl in which we can try name lookup.
|
||||||
CXXRecordDecl *resolveTypeToRecordDecl(const Type *T) {
|
CXXRecordDecl *resolveTypeToRecordDecl(const Type *T) {
|
||||||
assert(T);
|
assert(T);
|
||||||
if (const auto *ICNT = T->getAs<InjectedClassNameType>()) {
|
|
||||||
|
if (const auto *RT = T->getAs<RecordType>())
|
||||||
|
return dyn_cast<CXXRecordDecl>(RT->getDecl());
|
||||||
|
|
||||||
|
if (const auto *ICNT = T->getAs<InjectedClassNameType>())
|
||||||
T = ICNT->getInjectedSpecializationType().getTypePtrOrNull();
|
T = ICNT->getInjectedSpecializationType().getTypePtrOrNull();
|
||||||
}
|
if (!T)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
const auto *TST = T->getAs<TemplateSpecializationType>();
|
const auto *TST = T->getAs<TemplateSpecializationType>();
|
||||||
if (!TST)
|
if (!TST)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
const ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>(
|
const ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>(
|
||||||
TST->getTemplateName().getAsTemplateDecl());
|
TST->getTemplateName().getAsTemplateDecl());
|
||||||
if (!TD)
|
if (!TD)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return TD->getTemplatedDecl();
|
return TD->getTemplatedDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a dependent type and a member name, heuristically resolve the
|
// Given a tag-decl type and a member name, heuristically resolve the
|
||||||
// name to one or more declarations.
|
// name to one or more declarations.
|
||||||
// The current heuristic is simply to look up the name in the primary
|
// The current heuristic is simply to look up the name in the primary
|
||||||
// template. This is a heuristic because the template could potentially
|
// template. This is a heuristic because the template could potentially
|
||||||
|
@ -154,6 +162,10 @@ const Type *getPointeeType(const Type *T) {
|
||||||
return FirstArg.getAsType().getTypePtrOrNull();
|
return FirstArg.getAsType().getTypePtrOrNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Forward declaration, needed as this function is mutually recursive
|
||||||
|
// with resolveDependentExprToDecls.
|
||||||
|
const Type *resolveDependentExprToType(const Expr *E);
|
||||||
|
|
||||||
// Try to heuristically resolve a dependent expression `E` to one
|
// Try to heuristically resolve a dependent expression `E` to one
|
||||||
// or more declarations that it likely references.
|
// or more declarations that it likely references.
|
||||||
std::vector<const NamedDecl *> resolveDependentExprToDecls(const Expr *E) {
|
std::vector<const NamedDecl *> resolveDependentExprToDecls(const Expr *E) {
|
||||||
|
@ -163,6 +175,15 @@ std::vector<const NamedDecl *> resolveDependentExprToDecls(const Expr *E) {
|
||||||
if (ME->isArrow()) {
|
if (ME->isArrow()) {
|
||||||
BaseType = getPointeeType(BaseType);
|
BaseType = getPointeeType(BaseType);
|
||||||
}
|
}
|
||||||
|
if (const auto *BT = BaseType->getAs<BuiltinType>()) {
|
||||||
|
// If BaseType is the type of a dependent expression, it's just
|
||||||
|
// represented as BultinType::Dependent which gives us no information. We
|
||||||
|
// can get further by analyzing the depedent expression.
|
||||||
|
Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase();
|
||||||
|
if (Base && BT->getKind() == BuiltinType::Dependent) {
|
||||||
|
BaseType = resolveDependentExprToType(Base);
|
||||||
|
}
|
||||||
|
}
|
||||||
return getMembersReferencedViaDependentName(
|
return getMembersReferencedViaDependentName(
|
||||||
BaseType, [ME](ASTContext &) { return ME->getMember(); },
|
BaseType, [ME](ASTContext &) { return ME->getMember(); },
|
||||||
/*IsNonstaticMember=*/true);
|
/*IsNonstaticMember=*/true);
|
||||||
|
@ -173,9 +194,38 @@ std::vector<const NamedDecl *> resolveDependentExprToDecls(const Expr *E) {
|
||||||
[RE](ASTContext &) { return RE->getDeclName(); },
|
[RE](ASTContext &) { return RE->getDeclName(); },
|
||||||
/*IsNonstaticMember=*/false);
|
/*IsNonstaticMember=*/false);
|
||||||
}
|
}
|
||||||
|
if (const auto *CE = dyn_cast<CallExpr>(E)) {
|
||||||
|
const auto *CalleeType = resolveDependentExprToType(CE->getCallee());
|
||||||
|
if (!CalleeType)
|
||||||
|
return {};
|
||||||
|
if (const auto *FnTypePtr = CalleeType->getAs<PointerType>())
|
||||||
|
CalleeType = FnTypePtr->getPointeeType().getTypePtr();
|
||||||
|
if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) {
|
||||||
|
if (const auto *D =
|
||||||
|
resolveTypeToRecordDecl(FnType->getReturnType().getTypePtr())) {
|
||||||
|
return {D};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (const auto *ME = dyn_cast<MemberExpr>(E)) {
|
||||||
|
return {ME->getMemberDecl()};
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to heuristically resolve the type of a dependent expression `E`.
|
||||||
|
const Type *resolveDependentExprToType(const Expr *E) {
|
||||||
|
std::vector<const NamedDecl *> Decls = resolveDependentExprToDecls(E);
|
||||||
|
if (Decls.size() != 1) // Names an overload set -- just bail.
|
||||||
|
return nullptr;
|
||||||
|
if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) {
|
||||||
|
return TD->getTypeForDecl();
|
||||||
|
} else if (const auto *VD = dyn_cast<ValueDecl>(Decls[0])) {
|
||||||
|
return VD->getType().getTypePtrOrNull();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
const NamedDecl *getTemplatePattern(const NamedDecl *D) {
|
const NamedDecl *getTemplatePattern(const NamedDecl *D) {
|
||||||
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
|
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
|
||||||
if (const auto *Result = CRD->getTemplateInstantiationPattern())
|
if (const auto *Result = CRD->getTemplateInstantiationPattern())
|
||||||
|
@ -235,9 +285,8 @@ const NamedDecl *getTemplatePattern(const NamedDecl *D) {
|
||||||
// and both are lossy. We must know upfront what the caller ultimately wants.
|
// and both are lossy. We must know upfront what the caller ultimately wants.
|
||||||
//
|
//
|
||||||
// FIXME: improve common dependent scope using name lookup in primary templates.
|
// FIXME: improve common dependent scope using name lookup in primary templates.
|
||||||
// e.g. template<typename T> int foo() { return std::vector<T>().size(); }
|
// We currently handle DependentScopeDeclRefExpr and
|
||||||
// formally size() is unresolved, but the primary template is a good guess.
|
// CXXDependentScopeMemberExpr, but some other constructs remain to be handled:
|
||||||
// This affects:
|
|
||||||
// - DependentTemplateSpecializationType,
|
// - DependentTemplateSpecializationType,
|
||||||
// - DependentNameType
|
// - DependentNameType
|
||||||
// - UnresolvedUsingValueDecl
|
// - UnresolvedUsingValueDecl
|
||||||
|
|
|
@ -561,6 +561,74 @@ TEST_F(TargetDeclTest, OverloadExpr) {
|
||||||
EXPECT_DECLS("UnresolvedMemberExpr", "void func(int *)", "void func(char *)");
|
EXPECT_DECLS("UnresolvedMemberExpr", "void func(int *)", "void func(char *)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(TargetDeclTest, DependentExprs) {
|
||||||
|
Flags = {"-fno-delayed-template-parsing"};
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(TargetDeclTest, ObjC) {
|
TEST_F(TargetDeclTest, ObjC) {
|
||||||
Flags = {"-xobjective-c"};
|
Flags = {"-xobjective-c"};
|
||||||
Code = R"cpp(
|
Code = R"cpp(
|
||||||
|
@ -718,36 +786,37 @@ protected:
|
||||||
|
|
||||||
TEST_F(FindExplicitReferencesTest, All) {
|
TEST_F(FindExplicitReferencesTest, All) {
|
||||||
std::pair</*Code*/ llvm::StringRef, /*References*/ llvm::StringRef> Cases[] =
|
std::pair</*Code*/ llvm::StringRef, /*References*/ llvm::StringRef> Cases[] =
|
||||||
{// Simple expressions.
|
{
|
||||||
{R"cpp(
|
// Simple expressions.
|
||||||
|
{R"cpp(
|
||||||
int global;
|
int global;
|
||||||
int func();
|
int func();
|
||||||
void foo(int param) {
|
void foo(int param) {
|
||||||
$0^global = $1^param + $2^func();
|
$0^global = $1^param + $2^func();
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {global}\n"
|
"0: targets = {global}\n"
|
||||||
"1: targets = {param}\n"
|
"1: targets = {param}\n"
|
||||||
"2: targets = {func}\n"},
|
"2: targets = {func}\n"},
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
struct X { int a; };
|
struct X { int a; };
|
||||||
void foo(X x) {
|
void foo(X x) {
|
||||||
$0^x.$1^a = 10;
|
$0^x.$1^a = 10;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {x}\n"
|
"0: targets = {x}\n"
|
||||||
"1: targets = {X::a}\n"},
|
"1: targets = {X::a}\n"},
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
// error-ok: testing with broken code
|
// error-ok: testing with broken code
|
||||||
int bar();
|
int bar();
|
||||||
int foo() {
|
int foo() {
|
||||||
return $0^bar() + $1^bar(42);
|
return $0^bar() + $1^bar(42);
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {bar}\n"
|
"0: targets = {bar}\n"
|
||||||
"1: targets = {bar}\n"},
|
"1: targets = {bar}\n"},
|
||||||
// Namespaces and aliases.
|
// Namespaces and aliases.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
namespace ns {}
|
namespace ns {}
|
||||||
namespace alias = ns;
|
namespace alias = ns;
|
||||||
void foo() {
|
void foo() {
|
||||||
|
@ -755,19 +824,19 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
using namespace $1^alias;
|
using namespace $1^alias;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {ns}\n"
|
"0: targets = {ns}\n"
|
||||||
"1: targets = {alias}\n"},
|
"1: targets = {alias}\n"},
|
||||||
// Using declarations.
|
// Using declarations.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
namespace ns { int global; }
|
namespace ns { int global; }
|
||||||
void foo() {
|
void foo() {
|
||||||
using $0^ns::$1^global;
|
using $0^ns::$1^global;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {ns}\n"
|
"0: targets = {ns}\n"
|
||||||
"1: targets = {ns::global}, qualifier = 'ns::'\n"},
|
"1: targets = {ns::global}, qualifier = 'ns::'\n"},
|
||||||
// Simple types.
|
// Simple types.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
struct Struct { int a; };
|
struct Struct { int a; };
|
||||||
using Typedef = int;
|
using Typedef = int;
|
||||||
void foo() {
|
void foo() {
|
||||||
|
@ -776,13 +845,13 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
static_cast<$4^Struct*>(0);
|
static_cast<$4^Struct*>(0);
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {Struct}\n"
|
"0: targets = {Struct}\n"
|
||||||
"1: targets = {x}, decl\n"
|
"1: targets = {x}, decl\n"
|
||||||
"2: targets = {Typedef}\n"
|
"2: targets = {Typedef}\n"
|
||||||
"3: targets = {y}, decl\n"
|
"3: targets = {y}, decl\n"
|
||||||
"4: targets = {Struct}\n"},
|
"4: targets = {Struct}\n"},
|
||||||
// Name qualifiers.
|
// Name qualifiers.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
namespace a { namespace b { struct S { typedef int type; }; } }
|
namespace a { namespace b { struct S { typedef int type; }; } }
|
||||||
void foo() {
|
void foo() {
|
||||||
$0^a::$1^b::$2^S $3^x;
|
$0^a::$1^b::$2^S $3^x;
|
||||||
|
@ -790,16 +859,16 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$6^S::$7^type $8^y;
|
$6^S::$7^type $8^y;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {a}\n"
|
"0: targets = {a}\n"
|
||||||
"1: targets = {a::b}, qualifier = 'a::'\n"
|
"1: targets = {a::b}, qualifier = 'a::'\n"
|
||||||
"2: targets = {a::b::S}, qualifier = 'a::b::'\n"
|
"2: targets = {a::b::S}, qualifier = 'a::b::'\n"
|
||||||
"3: targets = {x}, decl\n"
|
"3: targets = {x}, decl\n"
|
||||||
"4: targets = {a}\n"
|
"4: targets = {a}\n"
|
||||||
"5: targets = {a::b}, qualifier = 'a::'\n"
|
"5: targets = {a::b}, qualifier = 'a::'\n"
|
||||||
"6: targets = {a::b::S}\n"
|
"6: targets = {a::b::S}\n"
|
||||||
"7: targets = {a::b::S::type}, qualifier = 'struct S::'\n"
|
"7: targets = {a::b::S::type}, qualifier = 'struct S::'\n"
|
||||||
"8: targets = {y}, decl\n"},
|
"8: targets = {y}, decl\n"},
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
void foo() {
|
void foo() {
|
||||||
$0^ten: // PRINT "HELLO WORLD!"
|
$0^ten: // PRINT "HELLO WORLD!"
|
||||||
goto $1^ten;
|
goto $1^ten;
|
||||||
|
@ -816,12 +885,12 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$2^vector<bool> $3^vb;
|
$2^vector<bool> $3^vb;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {vector<int>}\n"
|
"0: targets = {vector<int>}\n"
|
||||||
"1: targets = {vi}, decl\n"
|
"1: targets = {vi}, decl\n"
|
||||||
"2: targets = {vector<bool>}\n"
|
"2: targets = {vector<bool>}\n"
|
||||||
"3: targets = {vb}, decl\n"},
|
"3: targets = {vb}, decl\n"},
|
||||||
// Template type aliases.
|
// Template type aliases.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
template <class T> struct vector { using value_type = T; };
|
template <class T> struct vector { using value_type = T; };
|
||||||
template <> struct vector<bool> { using value_type = bool; };
|
template <> struct vector<bool> { using value_type = bool; };
|
||||||
template <class T> using valias = vector<T>;
|
template <class T> using valias = vector<T>;
|
||||||
|
@ -830,12 +899,12 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$2^valias<bool> $3^vb;
|
$2^valias<bool> $3^vb;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {valias}\n"
|
"0: targets = {valias}\n"
|
||||||
"1: targets = {vi}, decl\n"
|
"1: targets = {vi}, decl\n"
|
||||||
"2: targets = {valias}\n"
|
"2: targets = {valias}\n"
|
||||||
"3: targets = {vb}, decl\n"},
|
"3: targets = {vb}, decl\n"},
|
||||||
// Injected class name.
|
// Injected class name.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
namespace foo {
|
namespace foo {
|
||||||
template <typename $0^T>
|
template <typename $0^T>
|
||||||
class $1^Bar {
|
class $1^Bar {
|
||||||
|
@ -844,13 +913,13 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {foo::Bar::T}, decl\n"
|
"0: targets = {foo::Bar::T}, decl\n"
|
||||||
"1: targets = {foo::Bar}, decl\n"
|
"1: targets = {foo::Bar}, decl\n"
|
||||||
"2: targets = {foo::Bar}\n"
|
"2: targets = {foo::Bar}\n"
|
||||||
"3: targets = {foo::Bar::f}, decl\n"
|
"3: targets = {foo::Bar::f}, decl\n"
|
||||||
"4: targets = {foo::Bar}\n"},
|
"4: targets = {foo::Bar}\n"},
|
||||||
// MemberExpr should know their using declaration.
|
// MemberExpr should know their using declaration.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
struct X { void func(int); };
|
struct X { void func(int); };
|
||||||
struct Y : X {
|
struct Y : X {
|
||||||
using X::func;
|
using X::func;
|
||||||
|
@ -859,10 +928,10 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$0^y.$1^func(1);
|
$0^y.$1^func(1);
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {y}\n"
|
"0: targets = {y}\n"
|
||||||
"1: targets = {Y::func}\n"},
|
"1: targets = {Y::func}\n"},
|
||||||
// DeclRefExpr should know their using declaration.
|
// DeclRefExpr should know their using declaration.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
namespace ns { void bar(int); }
|
namespace ns { void bar(int); }
|
||||||
using ns::bar;
|
using ns::bar;
|
||||||
|
|
||||||
|
@ -870,9 +939,9 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$0^bar(10);
|
$0^bar(10);
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {bar}\n"},
|
"0: targets = {bar}\n"},
|
||||||
// References from a macro.
|
// References from a macro.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
#define FOO a
|
#define FOO a
|
||||||
#define BAR b
|
#define BAR b
|
||||||
|
|
||||||
|
@ -880,10 +949,10 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$0^FOO+$1^BAR;
|
$0^FOO+$1^BAR;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {a}\n"
|
"0: targets = {a}\n"
|
||||||
"1: targets = {b}\n"},
|
"1: targets = {b}\n"},
|
||||||
// No references from implicit nodes.
|
// No references from implicit nodes.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
struct vector {
|
struct vector {
|
||||||
int *begin();
|
int *begin();
|
||||||
int *end();
|
int *end();
|
||||||
|
@ -895,15 +964,15 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {x}, decl\n"
|
"0: targets = {x}, decl\n"
|
||||||
"1: targets = {vector}\n"
|
"1: targets = {vector}\n"
|
||||||
"2: targets = {x}\n"},
|
"2: targets = {x}\n"},
|
||||||
// Handle UnresolvedLookupExpr.
|
// Handle UnresolvedLookupExpr.
|
||||||
// FIXME
|
// FIXME
|
||||||
// This case fails when expensive checks are enabled.
|
// This case fails when expensive checks are enabled.
|
||||||
// Seems like the order of ns1::func and ns2::func isn't defined.
|
// Seems like the order of ns1::func and ns2::func isn't defined.
|
||||||
#ifndef EXPENSIVE_CHECKS
|
#ifndef EXPENSIVE_CHECKS
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
namespace ns1 { void func(char*); }
|
namespace ns1 { void func(char*); }
|
||||||
namespace ns2 { void func(int*); }
|
namespace ns2 { void func(int*); }
|
||||||
using namespace ns1;
|
using namespace ns1;
|
||||||
|
@ -914,11 +983,11 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$0^func($1^t);
|
$0^func($1^t);
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {ns1::func, ns2::func}\n"
|
"0: targets = {ns1::func, ns2::func}\n"
|
||||||
"1: targets = {t}\n"},
|
"1: targets = {t}\n"},
|
||||||
#endif
|
#endif
|
||||||
// Handle UnresolvedMemberExpr.
|
// Handle UnresolvedMemberExpr.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
struct X {
|
struct X {
|
||||||
void func(char*);
|
void func(char*);
|
||||||
void func(int*);
|
void func(int*);
|
||||||
|
@ -929,11 +998,11 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$0^x.$1^func($2^t);
|
$0^x.$1^func($2^t);
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {x}\n"
|
"0: targets = {x}\n"
|
||||||
"1: targets = {X::func, X::func}\n"
|
"1: targets = {X::func, X::func}\n"
|
||||||
"2: targets = {t}\n"},
|
"2: targets = {t}\n"},
|
||||||
// Handle DependentScopeDeclRefExpr.
|
// Handle DependentScopeDeclRefExpr.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
template <class T>
|
template <class T>
|
||||||
struct S {
|
struct S {
|
||||||
static int value;
|
static int value;
|
||||||
|
@ -944,11 +1013,11 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$0^S<$1^T>::$2^value;
|
$0^S<$1^T>::$2^value;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {S}\n"
|
"0: targets = {S}\n"
|
||||||
"1: targets = {T}\n"
|
"1: targets = {T}\n"
|
||||||
"2: targets = {S::value}, qualifier = 'S<T>::'\n"},
|
"2: targets = {S::value}, qualifier = 'S<T>::'\n"},
|
||||||
// Handle CXXDependentScopeMemberExpr.
|
// Handle CXXDependentScopeMemberExpr.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
template <class T>
|
template <class T>
|
||||||
struct S {
|
struct S {
|
||||||
int value;
|
int value;
|
||||||
|
@ -959,10 +1028,10 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$0^t.$1^value;
|
$0^t.$1^value;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {t}\n"
|
"0: targets = {t}\n"
|
||||||
"1: targets = {S::value}\n"},
|
"1: targets = {S::value}\n"},
|
||||||
// Type template parameters.
|
// Type template parameters.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
template <class T>
|
template <class T>
|
||||||
void foo() {
|
void foo() {
|
||||||
static_cast<$0^T>(0);
|
static_cast<$0^T>(0);
|
||||||
|
@ -970,21 +1039,21 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$2^T $3^t;
|
$2^T $3^t;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {T}\n"
|
"0: targets = {T}\n"
|
||||||
"1: targets = {T}\n"
|
"1: targets = {T}\n"
|
||||||
"2: targets = {T}\n"
|
"2: targets = {T}\n"
|
||||||
"3: targets = {t}, decl\n"},
|
"3: targets = {t}, decl\n"},
|
||||||
// Non-type template parameters.
|
// Non-type template parameters.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
template <int I>
|
template <int I>
|
||||||
void foo() {
|
void foo() {
|
||||||
int $0^x = $1^I;
|
int $0^x = $1^I;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {x}, decl\n"
|
"0: targets = {x}, decl\n"
|
||||||
"1: targets = {I}\n"},
|
"1: targets = {I}\n"},
|
||||||
// Template template parameters.
|
// Template template parameters.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
template <class T> struct vector {};
|
template <class T> struct vector {};
|
||||||
|
|
||||||
template <template<class> class TT, template<class> class ...TP>
|
template <template<class> class TT, template<class> class ...TP>
|
||||||
|
@ -995,16 +1064,16 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$6^foo<$7^TP...>();
|
$6^foo<$7^TP...>();
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {TT}\n"
|
"0: targets = {TT}\n"
|
||||||
"1: targets = {x}, decl\n"
|
"1: targets = {x}, decl\n"
|
||||||
"2: targets = {foo}\n"
|
"2: targets = {foo}\n"
|
||||||
"3: targets = {TT}\n"
|
"3: targets = {TT}\n"
|
||||||
"4: targets = {foo}\n"
|
"4: targets = {foo}\n"
|
||||||
"5: targets = {vector}\n"
|
"5: targets = {vector}\n"
|
||||||
"6: targets = {foo}\n"
|
"6: targets = {foo}\n"
|
||||||
"7: targets = {TP}\n"},
|
"7: targets = {TP}\n"},
|
||||||
// Non-type template parameters with declarations.
|
// Non-type template parameters with declarations.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
int func();
|
int func();
|
||||||
template <int(*)()> struct wrapper {};
|
template <int(*)()> struct wrapper {};
|
||||||
|
|
||||||
|
@ -1014,12 +1083,12 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$3^FuncParam();
|
$3^FuncParam();
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {wrapper<&func>}\n"
|
"0: targets = {wrapper<&func>}\n"
|
||||||
"1: targets = {func}\n"
|
"1: targets = {func}\n"
|
||||||
"2: targets = {w}, decl\n"
|
"2: targets = {w}, decl\n"
|
||||||
"3: targets = {FuncParam}\n"},
|
"3: targets = {FuncParam}\n"},
|
||||||
// declaration references.
|
// declaration references.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
namespace ns {}
|
namespace ns {}
|
||||||
class S {};
|
class S {};
|
||||||
void foo() {
|
void foo() {
|
||||||
|
@ -1031,19 +1100,19 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
namespace $9^NS = $10^ns;
|
namespace $9^NS = $10^ns;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {Foo}, decl\n"
|
"0: targets = {Foo}, decl\n"
|
||||||
"1: targets = {foo()::Foo::Foo}, decl\n"
|
"1: targets = {foo()::Foo::Foo}, decl\n"
|
||||||
"2: targets = {Foo}\n"
|
"2: targets = {Foo}\n"
|
||||||
"3: targets = {foo()::Foo::field}, decl\n"
|
"3: targets = {foo()::Foo::field}, decl\n"
|
||||||
"4: targets = {Var}, decl\n"
|
"4: targets = {Var}, decl\n"
|
||||||
"5: targets = {E}, decl\n"
|
"5: targets = {E}, decl\n"
|
||||||
"6: targets = {foo()::ABC}, decl\n"
|
"6: targets = {foo()::ABC}, decl\n"
|
||||||
"7: targets = {INT}, decl\n"
|
"7: targets = {INT}, decl\n"
|
||||||
"8: targets = {INT2}, decl\n"
|
"8: targets = {INT2}, decl\n"
|
||||||
"9: targets = {NS}, decl\n"
|
"9: targets = {NS}, decl\n"
|
||||||
"10: targets = {ns}\n"},
|
"10: targets = {ns}\n"},
|
||||||
// User-defined conversion operator.
|
// User-defined conversion operator.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
void foo() {
|
void foo() {
|
||||||
class $0^Bar {};
|
class $0^Bar {};
|
||||||
class $1^Foo {
|
class $1^Foo {
|
||||||
|
@ -1056,18 +1125,18 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$7^f.$8^operator $9^Bar();
|
$7^f.$8^operator $9^Bar();
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {Bar}, decl\n"
|
"0: targets = {Bar}, decl\n"
|
||||||
"1: targets = {Foo}, decl\n"
|
"1: targets = {Foo}, decl\n"
|
||||||
"2: targets = {foo()::Foo::operator Bar}, decl\n"
|
"2: targets = {foo()::Foo::operator Bar}, decl\n"
|
||||||
"3: targets = {Bar}\n"
|
"3: targets = {Bar}\n"
|
||||||
"4: targets = {Bar}\n"
|
"4: targets = {Bar}\n"
|
||||||
"5: targets = {Foo}\n"
|
"5: targets = {Foo}\n"
|
||||||
"6: targets = {f}, decl\n"
|
"6: targets = {f}, decl\n"
|
||||||
"7: targets = {f}\n"
|
"7: targets = {f}\n"
|
||||||
"8: targets = {foo()::Foo::operator Bar}\n"
|
"8: targets = {foo()::Foo::operator Bar}\n"
|
||||||
"9: targets = {Bar}\n"},
|
"9: targets = {Bar}\n"},
|
||||||
// Destructor.
|
// Destructor.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
void foo() {
|
void foo() {
|
||||||
class $0^Foo {
|
class $0^Foo {
|
||||||
public:
|
public:
|
||||||
|
@ -1082,18 +1151,18 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$6^f.~ /*...*/ $7^Foo();
|
$6^f.~ /*...*/ $7^Foo();
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {Foo}, decl\n"
|
"0: targets = {Foo}, decl\n"
|
||||||
// FIXME: It's better to target destructor's FunctionDecl instead of
|
// FIXME: It's better to target destructor's FunctionDecl instead of
|
||||||
// the type itself (similar to constructor).
|
// the type itself (similar to constructor).
|
||||||
"1: targets = {Foo}\n"
|
"1: targets = {Foo}\n"
|
||||||
"2: targets = {foo()::Foo::destructMe}, decl\n"
|
"2: targets = {foo()::Foo::destructMe}, decl\n"
|
||||||
"3: targets = {Foo}\n"
|
"3: targets = {Foo}\n"
|
||||||
"4: targets = {Foo}\n"
|
"4: targets = {Foo}\n"
|
||||||
"5: targets = {f}, decl\n"
|
"5: targets = {f}, decl\n"
|
||||||
"6: targets = {f}\n"
|
"6: targets = {f}\n"
|
||||||
"7: targets = {Foo}\n"},
|
"7: targets = {Foo}\n"},
|
||||||
// cxx constructor initializer.
|
// cxx constructor initializer.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
class Base {};
|
class Base {};
|
||||||
void foo() {
|
void foo() {
|
||||||
// member initializer
|
// member initializer
|
||||||
|
@ -1113,34 +1182,34 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {X}, decl\n"
|
"0: targets = {X}, decl\n"
|
||||||
"1: targets = {foo()::X::abc}, decl\n"
|
"1: targets = {foo()::X::abc}, decl\n"
|
||||||
"2: targets = {foo()::X::X}, decl\n"
|
"2: targets = {foo()::X::X}, decl\n"
|
||||||
"3: targets = {foo()::X::abc}\n"
|
"3: targets = {foo()::X::abc}\n"
|
||||||
"4: targets = {Derived}, decl\n"
|
"4: targets = {Derived}, decl\n"
|
||||||
"5: targets = {Base}\n"
|
"5: targets = {Base}\n"
|
||||||
"6: targets = {Base}\n"
|
"6: targets = {Base}\n"
|
||||||
"7: targets = {foo()::Derived::B}, decl\n"
|
"7: targets = {foo()::Derived::B}, decl\n"
|
||||||
"8: targets = {foo()::Derived::Derived}, decl\n"
|
"8: targets = {foo()::Derived::Derived}, decl\n"
|
||||||
"9: targets = {Base}\n"
|
"9: targets = {Base}\n"
|
||||||
"10: targets = {Foo}, decl\n"
|
"10: targets = {Foo}, decl\n"
|
||||||
"11: targets = {foo()::Foo::Foo}, decl\n"
|
"11: targets = {foo()::Foo::Foo}, decl\n"
|
||||||
"12: targets = {foo()::Foo::Foo}, decl\n"
|
"12: targets = {foo()::Foo::Foo}, decl\n"
|
||||||
"13: targets = {Foo}\n"},
|
"13: targets = {Foo}\n"},
|
||||||
// Anonymous entities should not be reported.
|
// Anonymous entities should not be reported.
|
||||||
{
|
{
|
||||||
R"cpp(
|
R"cpp(
|
||||||
void foo() {
|
void foo() {
|
||||||
class {} $0^x;
|
class {} $0^x;
|
||||||
int (*$1^fptr)(int $2^a, int) = nullptr;
|
int (*$1^fptr)(int $2^a, int) = nullptr;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {x}, decl\n"
|
"0: targets = {x}, decl\n"
|
||||||
"1: targets = {fptr}, decl\n"
|
"1: targets = {fptr}, decl\n"
|
||||||
"2: targets = {a}, decl\n"},
|
"2: targets = {a}, decl\n"},
|
||||||
// Namespace aliases should be handled properly.
|
// Namespace aliases should be handled properly.
|
||||||
{
|
{
|
||||||
R"cpp(
|
R"cpp(
|
||||||
namespace ns { struct Type {}; }
|
namespace ns { struct Type {}; }
|
||||||
namespace alias = ns;
|
namespace alias = ns;
|
||||||
namespace rec_alias = alias;
|
namespace rec_alias = alias;
|
||||||
|
@ -1151,28 +1220,28 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$6^rec_alias::$7^Type $8^c;
|
$6^rec_alias::$7^Type $8^c;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {ns}\n"
|
"0: targets = {ns}\n"
|
||||||
"1: targets = {ns::Type}, qualifier = 'ns::'\n"
|
"1: targets = {ns::Type}, qualifier = 'ns::'\n"
|
||||||
"2: targets = {a}, decl\n"
|
"2: targets = {a}, decl\n"
|
||||||
"3: targets = {alias}\n"
|
"3: targets = {alias}\n"
|
||||||
"4: targets = {ns::Type}, qualifier = 'alias::'\n"
|
"4: targets = {ns::Type}, qualifier = 'alias::'\n"
|
||||||
"5: targets = {b}, decl\n"
|
"5: targets = {b}, decl\n"
|
||||||
"6: targets = {rec_alias}\n"
|
"6: targets = {rec_alias}\n"
|
||||||
"7: targets = {ns::Type}, qualifier = 'rec_alias::'\n"
|
"7: targets = {ns::Type}, qualifier = 'rec_alias::'\n"
|
||||||
"8: targets = {c}, decl\n"},
|
"8: targets = {c}, decl\n"},
|
||||||
// Handle SizeOfPackExpr.
|
// Handle SizeOfPackExpr.
|
||||||
{
|
{
|
||||||
R"cpp(
|
R"cpp(
|
||||||
template <typename... E>
|
template <typename... E>
|
||||||
void foo() {
|
void foo() {
|
||||||
constexpr int $0^size = sizeof...($1^E);
|
constexpr int $0^size = sizeof...($1^E);
|
||||||
};
|
};
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {size}, decl\n"
|
"0: targets = {size}, decl\n"
|
||||||
"1: targets = {E}\n"},
|
"1: targets = {E}\n"},
|
||||||
// Class template argument deduction
|
// Class template argument deduction
|
||||||
{
|
{
|
||||||
R"cpp(
|
R"cpp(
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Test {
|
struct Test {
|
||||||
Test(T);
|
Test(T);
|
||||||
|
@ -1181,51 +1250,51 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$0^Test $1^a(5);
|
$0^Test $1^a(5);
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {Test}\n"
|
"0: targets = {Test}\n"
|
||||||
"1: targets = {a}, decl\n"},
|
"1: targets = {a}, decl\n"},
|
||||||
// Templates
|
// Templates
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
namespace foo {
|
namespace foo {
|
||||||
template <typename $0^T>
|
template <typename $0^T>
|
||||||
class $1^Bar {};
|
class $1^Bar {};
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {foo::Bar::T}, decl\n"
|
"0: targets = {foo::Bar::T}, decl\n"
|
||||||
"1: targets = {foo::Bar}, decl\n"},
|
"1: targets = {foo::Bar}, decl\n"},
|
||||||
// Templates
|
// Templates
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
namespace foo {
|
namespace foo {
|
||||||
template <typename $0^T>
|
template <typename $0^T>
|
||||||
void $1^func();
|
void $1^func();
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {T}, decl\n"
|
"0: targets = {T}, decl\n"
|
||||||
"1: targets = {foo::func}, decl\n"},
|
"1: targets = {foo::func}, decl\n"},
|
||||||
// Templates
|
// Templates
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
namespace foo {
|
namespace foo {
|
||||||
template <typename $0^T>
|
template <typename $0^T>
|
||||||
$1^T $2^x;
|
$1^T $2^x;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {foo::T}, decl\n"
|
"0: targets = {foo::T}, decl\n"
|
||||||
"1: targets = {foo::T}\n"
|
"1: targets = {foo::T}\n"
|
||||||
"2: targets = {foo::x}, decl\n"},
|
"2: targets = {foo::x}, decl\n"},
|
||||||
// Templates
|
// Templates
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
template<typename T> class vector {};
|
template<typename T> class vector {};
|
||||||
namespace foo {
|
namespace foo {
|
||||||
template <typename $0^T>
|
template <typename $0^T>
|
||||||
using $1^V = $2^vector<$3^T>;
|
using $1^V = $2^vector<$3^T>;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {foo::T}, decl\n"
|
"0: targets = {foo::T}, decl\n"
|
||||||
"1: targets = {foo::V}, decl\n"
|
"1: targets = {foo::V}, decl\n"
|
||||||
"2: targets = {vector}\n"
|
"2: targets = {vector}\n"
|
||||||
"3: targets = {foo::T}\n"},
|
"3: targets = {foo::T}\n"},
|
||||||
// Concept
|
// Concept
|
||||||
{
|
{
|
||||||
R"cpp(
|
R"cpp(
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept Drawable = requires (T t) { t.draw(); };
|
concept Drawable = requires (T t) { t.draw(); };
|
||||||
|
|
||||||
|
@ -1236,17 +1305,17 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {T}, decl\n"
|
"0: targets = {T}, decl\n"
|
||||||
"1: targets = {Drawable}\n"
|
"1: targets = {Drawable}\n"
|
||||||
"2: targets = {T}\n"
|
"2: targets = {T}\n"
|
||||||
"3: targets = {foo::bar}, decl\n"
|
"3: targets = {foo::bar}, decl\n"
|
||||||
"4: targets = {T}\n"
|
"4: targets = {T}\n"
|
||||||
"5: targets = {t}, decl\n"
|
"5: targets = {t}, decl\n"
|
||||||
"6: targets = {t}\n"
|
"6: targets = {t}\n"
|
||||||
"7: targets = {}\n"},
|
"7: targets = {}\n"},
|
||||||
// Objective-C: properties
|
// Objective-C: properties
|
||||||
{
|
{
|
||||||
R"cpp(
|
R"cpp(
|
||||||
@interface I {}
|
@interface I {}
|
||||||
@property(retain) I* x;
|
@property(retain) I* x;
|
||||||
@property(retain) I* y;
|
@property(retain) I* y;
|
||||||
|
@ -1256,12 +1325,12 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$0^f.$1^x.$2^y = 0;
|
$0^f.$1^x.$2^y = 0;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {f}\n"
|
"0: targets = {f}\n"
|
||||||
"1: targets = {I::x}\n"
|
"1: targets = {I::x}\n"
|
||||||
"2: targets = {I::y}\n"},
|
"2: targets = {I::y}\n"},
|
||||||
// Objective-C: implicit properties
|
// Objective-C: implicit properties
|
||||||
{
|
{
|
||||||
R"cpp(
|
R"cpp(
|
||||||
@interface I {}
|
@interface I {}
|
||||||
-(I*)x;
|
-(I*)x;
|
||||||
-(void)setY:(I*)y;
|
-(void)setY:(I*)y;
|
||||||
|
@ -1271,11 +1340,11 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$0^f.$1^x.$2^y = 0;
|
$0^f.$1^x.$2^y = 0;
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {f}\n"
|
"0: targets = {f}\n"
|
||||||
"1: targets = {I::x}\n"
|
"1: targets = {I::x}\n"
|
||||||
"2: targets = {I::setY:}\n"},
|
"2: targets = {I::setY:}\n"},
|
||||||
// Designated initializers.
|
// Designated initializers.
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
void foo() {
|
void foo() {
|
||||||
struct $0^Foo {
|
struct $0^Foo {
|
||||||
int $1^Bar;
|
int $1^Bar;
|
||||||
|
@ -1283,12 +1352,12 @@ TEST_F(FindExplicitReferencesTest, All) {
|
||||||
$2^Foo $3^f { .$4^Bar = 42 };
|
$2^Foo $3^f { .$4^Bar = 42 };
|
||||||
}
|
}
|
||||||
)cpp",
|
)cpp",
|
||||||
"0: targets = {Foo}, decl\n"
|
"0: targets = {Foo}, decl\n"
|
||||||
"1: targets = {foo()::Foo::Bar}, decl\n"
|
"1: targets = {foo()::Foo::Bar}, decl\n"
|
||||||
"2: targets = {Foo}\n"
|
"2: targets = {Foo}\n"
|
||||||
"3: targets = {f}, decl\n"
|
"3: targets = {f}, decl\n"
|
||||||
"4: targets = {foo()::Foo::Bar}\n"},
|
"4: targets = {foo()::Foo::Bar}\n"},
|
||||||
{R"cpp(
|
{R"cpp(
|
||||||
void foo() {
|
void foo() {
|
||||||
struct $0^Baz {
|
struct $0^Baz {
|
||||||
int $1^Field;
|
int $1^Field;
|
||||||
|
|
Loading…
Reference in New Issue