[llvm-branch-commits] [clang-tools-extra] c900824 - [clangd] Fix a crash for accessing a null template decl returned by findExplicitReferences.

Sam McCall via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Jun 10 07:07:57 PDT 2020


Author: Haojian Wu
Date: 2020-06-10T16:07:41+02:00
New Revision: c90082432021360fae9f838502479b9113854de4

URL: https://github.com/llvm/llvm-project/commit/c90082432021360fae9f838502479b9113854de4
DIFF: https://github.com/llvm/llvm-project/commit/c90082432021360fae9f838502479b9113854de4.diff

LOG: [clangd] Fix a crash for accessing a null template decl returned by findExplicitReferences.

Summary: Fixes https://github.com/clangd/clangd/issues/347.

Reviewers: kadircet

Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D78626

(cherry picked from commit 7d1ee639cb9efea364bec90afe4d1161ec624a7f)
Includes some test-only changes from f651c402a221a20f3bc6ea43f70b29326a357010
to support the cherry-picked tests.
Test tweaked slightly as it exhibits a separate bug that was fixed on master.

Added: 
    

Modified: 
    clang-tools-extra/clangd/FindTarget.cpp
    clang-tools-extra/clangd/unittests/FindTargetTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp
index 5912464b0ed0..7a4f651b3620 100644
--- a/clang-tools-extra/clangd/FindTarget.cpp
+++ b/clang-tools-extra/clangd/FindTarget.cpp
@@ -759,15 +759,17 @@ class ExplicitReferenceCollector
   // TemplateArgumentLoc is the only way to get locations for references to
   // template template parameters.
   bool TraverseTemplateArgumentLoc(TemplateArgumentLoc A) {
+    llvm::SmallVector<const NamedDecl *, 1> Targets;
     switch (A.getArgument().getKind()) {
     case TemplateArgument::Template:
     case TemplateArgument::TemplateExpansion:
+      if (const auto *D = A.getArgument()
+                              .getAsTemplateOrTemplatePattern()
+                              .getAsTemplateDecl())
+        Targets.push_back(D);
       reportReference(ReferenceLoc{A.getTemplateQualifierLoc(),
                                    A.getTemplateNameLoc(),
-                                   /*IsDecl=*/false,
-                                   {A.getArgument()
-                                        .getAsTemplateOrTemplatePattern()
-                                        .getAsTemplateDecl()}},
+                                   /*IsDecl=*/false, Targets},
                       DynTypedNode::create(A.getArgument()));
       break;
     case TemplateArgument::Declaration:

diff  --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
index 9c1020b7a189..ae16c608fd33 100644
--- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -589,12 +589,21 @@ class FindExplicitReferencesTest : public ::testing::Test {
     auto *TestDecl = &findDecl(AST, "foo");
     if (auto *T = llvm::dyn_cast<FunctionTemplateDecl>(TestDecl))
       TestDecl = T->getTemplatedDecl();
-    auto &Func = llvm::cast<FunctionDecl>(*TestDecl);
 
     std::vector<ReferenceLoc> Refs;
-    findExplicitReferences(Func.getBody(), [&Refs](ReferenceLoc R) {
-      Refs.push_back(std::move(R));
-    });
+    if (const auto *Func = llvm::dyn_cast<FunctionDecl>(TestDecl))
+      findExplicitReferences(Func->getBody(), [&Refs](ReferenceLoc R) {
+        Refs.push_back(std::move(R));
+      });
+    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));
+      });
+    else
+      ADD_FAILURE() << "Failed to find ::foo decl for test";
 
     auto &SM = AST.getSourceManager();
     llvm::sort(Refs, [&](const ReferenceLoc &L, const ReferenceLoc &R) {
@@ -984,7 +993,24 @@ TEST_F(FindExplicitReferencesTest, All) {
               }
             )cpp",
            "0: targets = {Test}\n"
-           "1: targets = {a}, decl\n"}};
+           "1: targets = {a}, decl\n"},
+      // unknown template name should not crash.
+      // duplicate $1$2 is fixed on master.
+      {R"cpp(
+        template <template <typename> typename T>
+        struct Base {};
+        namespace foo {
+        template <typename $0^T>
+        struct $1^$2^Derive : $3^Base<$4^T::template $5^Unknown> {};
+        }
+      )cpp",
+      "0: targets = {foo::Derive::T}, decl\n"
+      "1: targets = {foo::Derive}, decl\n"
+      "2: targets = {foo::Derive}, decl\n"
+      "3: targets = {Base}\n"
+      "4: targets = {foo::Derive::T}\n"
+      "5: targets = {}, qualifier = 'T::'\n"},
+    };
 
   for (const auto &C : Cases) {
     llvm::StringRef ExpectedCode = C.first;


        


More information about the llvm-branch-commits mailing list