[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
This commit is contained in:
Haojian Wu 2018-12-13 13:17:04 +00:00
parent e58e0903e2
commit bf28533726
2 changed files with 57 additions and 12 deletions

View File

@ -139,21 +139,19 @@ public:
SourceLocation Loc,
index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
if (Loc == SearchedLocation) {
// Check whether the E has an implicit AST node (e.g. ImplicitCastExpr).
auto hasImplicitExpr = [](const Expr *E) {
if (!E || E->child_begin() == E->child_end())
auto isImplicitExpr = [](const Expr *E) {
if (!E)
return false;
// Use the first child is good enough for most cases -- normally the
// expression returned by handleDeclOccurence contains exactly one
// child expression.
const auto *FirstChild = *E->child_begin();
return isa<ExprWithCleanups>(FirstChild) ||
isa<MaterializeTemporaryExpr>(FirstChild) ||
isa<CXXBindTemporaryExpr>(FirstChild) ||
isa<ImplicitCastExpr>(FirstChild);
// We assume that a constructor expression is implict (was inserted by
// clang) if it has an invalid paren/brace location, since such
// experssion is impossible to write down.
if (const auto *CtorExpr = dyn_cast<CXXConstructExpr>(E))
return CtorExpr->getNumArgs() > 0 &&
CtorExpr->getParenOrBraceRange().isInvalid();
return isa<ImplicitCastExpr>(E);
};
bool IsExplicit = !hasImplicitExpr(ASTNode.OrigE);
bool IsExplicit = !isImplicitExpr(ASTNode.OrigE);
// Find and add definition declarations (for GoToDefinition).
// We don't use parameter `D`, as Parameter `D` is the canonical
// declaration, which is the first declaration of a redeclarable

View File

@ -1225,6 +1225,53 @@ TEST(FindReferences, WithinAST) {
}
}
TEST(FindReferences, ExplicitSymbols) {
const char *Tests[] = {
R"cpp(
struct Foo { Foo* [self]() const; };
void f() {
if (Foo* T = foo.[^self]()) {} // Foo member call expr.
}
)cpp",
R"cpp(
struct Foo { Foo(int); };
Foo f() {
int [b];
return [^b]; // Foo constructor expr.
}
)cpp",
R"cpp(
struct Foo {};
void g(Foo);
Foo [f]();
void call() {
g([^f]()); // Foo constructor expr.
}
)cpp",
R"cpp(
void [foo](int);
void [foo](double);
namespace ns {
using ::[fo^o];
}
)cpp",
};
for (const char *Test : Tests) {
Annotations T(Test);
auto AST = TestTU::withCode(T.code()).build();
std::vector<Matcher<Location>> ExpectedLocations;
for (const auto &R : T.ranges())
ExpectedLocations.push_back(RangeIs(R));
EXPECT_THAT(findReferences(AST, T.point()),
ElementsAreArray(ExpectedLocations))
<< Test;
}
}
TEST(FindReferences, NeedsIndex) {
const char *Header = "int foo();";
Annotations Main("int main() { [[f^oo]](); }");