summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHaojian Wu <hokein.wu@gmail.com>2020-04-22 13:33:02 +0200
committerSam McCall <sam.mccall@gmail.com>2020-06-10 16:07:41 +0200
commitc90082432021360fae9f838502479b9113854de4 (patch)
tree4d8c78352dbf5217601fae80ec79561bb2be395a
parent0530e2a811b08f13e8137c29f047ad6bd11967fa (diff)
downloadbcm5719-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.cpp10
-rw-r--r--clang-tools-extra/clangd/unittests/FindTargetTests.cpp36
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;
OpenPOWER on IntegriCloud