diff options
author | Haojian Wu <hokein.wu@gmail.com> | 2020-04-22 13:33:02 +0200 |
---|---|---|
committer | Sam McCall <sam.mccall@gmail.com> | 2020-06-10 16:07:41 +0200 |
commit | c90082432021360fae9f838502479b9113854de4 (patch) | |
tree | 4d8c78352dbf5217601fae80ec79561bb2be395a | |
parent | 0530e2a811b08f13e8137c29f047ad6bd11967fa (diff) | |
download | bcm5719-llvm-c90082432021360fae9f838502479b9113854de4.tar.gz bcm5719-llvm-c90082432021360fae9f838502479b9113854de4.zip |
[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.
-rw-r--r-- | clang-tools-extra/clangd/FindTarget.cpp | 10 | ||||
-rw-r--r-- | clang-tools-extra/clangd/unittests/FindTargetTests.cpp | 36 |
2 files changed, 37 insertions, 9 deletions
diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp index 5912464b0ed..7a4f651b362 100644 --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -759,15 +759,17 @@ public: // 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 9c1020b7a18..ae16c608fd3 100644 --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -589,12 +589,21 @@ protected: 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; |