Skip to content

Commit c900824

Browse files
hokeinsam-mccall
authored andcommitted
[clangd] Fix a crash for accessing a null template decl returned by findExplicitReferences.
Summary: Fixes clangd/clangd#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 7d1ee63) Includes some test-only changes from f651c40 to support the cherry-picked tests. Test tweaked slightly as it exhibits a separate bug that was fixed on master.
1 parent 0530e2a commit c900824

File tree

2 files changed

+37
-9
lines changed

2 files changed

+37
-9
lines changed

clang-tools-extra/clangd/FindTarget.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -759,15 +759,17 @@ class ExplicitReferenceCollector
759759
// TemplateArgumentLoc is the only way to get locations for references to
760760
// template template parameters.
761761
bool TraverseTemplateArgumentLoc(TemplateArgumentLoc A) {
762+
llvm::SmallVector<const NamedDecl *, 1> Targets;
762763
switch (A.getArgument().getKind()) {
763764
case TemplateArgument::Template:
764765
case TemplateArgument::TemplateExpansion:
766+
if (const auto *D = A.getArgument()
767+
.getAsTemplateOrTemplatePattern()
768+
.getAsTemplateDecl())
769+
Targets.push_back(D);
765770
reportReference(ReferenceLoc{A.getTemplateQualifierLoc(),
766771
A.getTemplateNameLoc(),
767-
/*IsDecl=*/false,
768-
{A.getArgument()
769-
.getAsTemplateOrTemplatePattern()
770-
.getAsTemplateDecl()}},
772+
/*IsDecl=*/false, Targets},
771773
DynTypedNode::create(A.getArgument()));
772774
break;
773775
case TemplateArgument::Declaration:

clang-tools-extra/clangd/unittests/FindTargetTests.cpp

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -589,12 +589,21 @@ class FindExplicitReferencesTest : public ::testing::Test {
589589
auto *TestDecl = &findDecl(AST, "foo");
590590
if (auto *T = llvm::dyn_cast<FunctionTemplateDecl>(TestDecl))
591591
TestDecl = T->getTemplatedDecl();
592-
auto &Func = llvm::cast<FunctionDecl>(*TestDecl);
593592

594593
std::vector<ReferenceLoc> Refs;
595-
findExplicitReferences(Func.getBody(), [&Refs](ReferenceLoc R) {
596-
Refs.push_back(std::move(R));
597-
});
594+
if (const auto *Func = llvm::dyn_cast<FunctionDecl>(TestDecl))
595+
findExplicitReferences(Func->getBody(), [&Refs](ReferenceLoc R) {
596+
Refs.push_back(std::move(R));
597+
});
598+
else if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(TestDecl))
599+
findExplicitReferences(NS, [&Refs, &NS](ReferenceLoc R) {
600+
// Avoid adding the namespace foo decl to the results.
601+
if (R.Targets.size() == 1 && R.Targets.front() == NS)
602+
return;
603+
Refs.push_back(std::move(R));
604+
});
605+
else
606+
ADD_FAILURE() << "Failed to find ::foo decl for test";
598607

599608
auto &SM = AST.getSourceManager();
600609
llvm::sort(Refs, [&](const ReferenceLoc &L, const ReferenceLoc &R) {
@@ -984,7 +993,24 @@ TEST_F(FindExplicitReferencesTest, All) {
984993
}
985994
)cpp",
986995
"0: targets = {Test}\n"
987-
"1: targets = {a}, decl\n"}};
996+
"1: targets = {a}, decl\n"},
997+
// unknown template name should not crash.
998+
// duplicate $1$2 is fixed on master.
999+
{R"cpp(
1000+
template <template <typename> typename T>
1001+
struct Base {};
1002+
namespace foo {
1003+
template <typename $0^T>
1004+
struct $1^$2^Derive : $3^Base<$4^T::template $5^Unknown> {};
1005+
}
1006+
)cpp",
1007+
"0: targets = {foo::Derive::T}, decl\n"
1008+
"1: targets = {foo::Derive}, decl\n"
1009+
"2: targets = {foo::Derive}, decl\n"
1010+
"3: targets = {Base}\n"
1011+
"4: targets = {foo::Derive::T}\n"
1012+
"5: targets = {}, qualifier = 'T::'\n"},
1013+
};
9881014

9891015
for (const auto &C : Cases) {
9901016
llvm::StringRef ExpectedCode = C.first;

0 commit comments

Comments
 (0)