Skip to content

Commit bf28533

Browse files
committedDec 13, 2018
[clangd] Refine the way of checking a declaration is referenced by the written code.
Summary: The previous solution (checking the AST) is not a reliable way to determine whether a declaration is explicitly referenced by the source code, we are still missing a few cases. Reviewers: ilya-biryukov Subscribers: ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits Differential Revision: https://reviews.llvm.org/D55191 llvm-svn: 349033
1 parent e58e090 commit bf28533

File tree

2 files changed

+57
-12
lines changed

2 files changed

+57
-12
lines changed
 

‎clang-tools-extra/clangd/XRefs.cpp

+10-12
Original file line numberDiff line numberDiff line change
@@ -139,21 +139,19 @@ class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
139139
SourceLocation Loc,
140140
index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
141141
if (Loc == SearchedLocation) {
142-
// Check whether the E has an implicit AST node (e.g. ImplicitCastExpr).
143-
auto hasImplicitExpr = [](const Expr *E) {
144-
if (!E || E->child_begin() == E->child_end())
142+
auto isImplicitExpr = [](const Expr *E) {
143+
if (!E)
145144
return false;
146-
// Use the first child is good enough for most cases -- normally the
147-
// expression returned by handleDeclOccurence contains exactly one
148-
// child expression.
149-
const auto *FirstChild = *E->child_begin();
150-
return isa<ExprWithCleanups>(FirstChild) ||
151-
isa<MaterializeTemporaryExpr>(FirstChild) ||
152-
isa<CXXBindTemporaryExpr>(FirstChild) ||
153-
isa<ImplicitCastExpr>(FirstChild);
145+
// We assume that a constructor expression is implict (was inserted by
146+
// clang) if it has an invalid paren/brace location, since such
147+
// experssion is impossible to write down.
148+
if (const auto *CtorExpr = dyn_cast<CXXConstructExpr>(E))
149+
return CtorExpr->getNumArgs() > 0 &&
150+
CtorExpr->getParenOrBraceRange().isInvalid();
151+
return isa<ImplicitCastExpr>(E);
154152
};
155153

156-
bool IsExplicit = !hasImplicitExpr(ASTNode.OrigE);
154+
bool IsExplicit = !isImplicitExpr(ASTNode.OrigE);
157155
// Find and add definition declarations (for GoToDefinition).
158156
// We don't use parameter `D`, as Parameter `D` is the canonical
159157
// declaration, which is the first declaration of a redeclarable

‎clang-tools-extra/unittests/clangd/XRefsTests.cpp

+47
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,53 @@ TEST(FindReferences, WithinAST) {
12251225
}
12261226
}
12271227

1228+
TEST(FindReferences, ExplicitSymbols) {
1229+
const char *Tests[] = {
1230+
R"cpp(
1231+
struct Foo { Foo* [self]() const; };
1232+
void f() {
1233+
if (Foo* T = foo.[^self]()) {} // Foo member call expr.
1234+
}
1235+
)cpp",
1236+
1237+
R"cpp(
1238+
struct Foo { Foo(int); };
1239+
Foo f() {
1240+
int [b];
1241+
return [^b]; // Foo constructor expr.
1242+
}
1243+
)cpp",
1244+
1245+
R"cpp(
1246+
struct Foo {};
1247+
void g(Foo);
1248+
Foo [f]();
1249+
void call() {
1250+
g([^f]()); // Foo constructor expr.
1251+
}
1252+
)cpp",
1253+
1254+
R"cpp(
1255+
void [foo](int);
1256+
void [foo](double);
1257+
1258+
namespace ns {
1259+
using ::[fo^o];
1260+
}
1261+
)cpp",
1262+
};
1263+
for (const char *Test : Tests) {
1264+
Annotations T(Test);
1265+
auto AST = TestTU::withCode(T.code()).build();
1266+
std::vector<Matcher<Location>> ExpectedLocations;
1267+
for (const auto &R : T.ranges())
1268+
ExpectedLocations.push_back(RangeIs(R));
1269+
EXPECT_THAT(findReferences(AST, T.point()),
1270+
ElementsAreArray(ExpectedLocations))
1271+
<< Test;
1272+
}
1273+
}
1274+
12281275
TEST(FindReferences, NeedsIndex) {
12291276
const char *Header = "int foo();";
12301277
Annotations Main("int main() { [[f^oo]](); }");

0 commit comments

Comments
 (0)
Please sign in to comment.