From bf285337262a65c114922cf7fc17c1cdc0b31dd8 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 13 Dec 2018 13:17:04 +0000 Subject: [PATCH] [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 --- clang-tools-extra/clangd/XRefs.cpp | 22 ++++----- .../unittests/clangd/XRefsTests.cpp | 47 +++++++++++++++++++ 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index 13308ea3c836..bdae8a3501ef 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -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(FirstChild) || - isa(FirstChild) || - isa(FirstChild) || - isa(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(E)) + return CtorExpr->getNumArgs() > 0 && + CtorExpr->getParenOrBraceRange().isInvalid(); + return isa(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 diff --git a/clang-tools-extra/unittests/clangd/XRefsTests.cpp b/clang-tools-extra/unittests/clangd/XRefsTests.cpp index 423083990e74..ffb0d051f051 100644 --- a/clang-tools-extra/unittests/clangd/XRefsTests.cpp +++ b/clang-tools-extra/unittests/clangd/XRefsTests.cpp @@ -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> 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]](); }");