Index: clangd/AST.cpp =================================================================== --- clangd/AST.cpp +++ clangd/AST.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" @@ -82,14 +83,17 @@ if (auto Args = getTemplateSpecializationArgLocs(ND)) printTemplateArgumentList(OS, *Args, Policy); else if (auto *Cls = llvm::dyn_cast(&ND)) { - if (auto STL = Cls->getTypeAsWritten() - ->getTypeLoc() - .getAs()) { - llvm::SmallVector ArgLocs; - ArgLocs.reserve(STL.getNumArgs()); - for (unsigned I = 0; I < STL.getNumArgs(); ++I) - ArgLocs.push_back(STL.getArgLoc(I)); - printTemplateArgumentList(OS, ArgLocs, Policy); + if (const TypeSourceInfo *TSI = Cls->getTypeAsWritten()) { + if (auto STL = TSI->getTypeLoc().getAs()) { + llvm::SmallVector ArgLocs; + ArgLocs.reserve(STL.getNumArgs()); + for (unsigned I = 0; I < STL.getNumArgs(); ++I) + ArgLocs.push_back(STL.getArgLoc(I)); + printTemplateArgumentList(OS, ArgLocs, Policy); + } + } else { + // FIXME: Fix cases when getTypeAsWritten returns null, e.g. friend decls. + printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy); } } OS.flush(); Index: unittests/clangd/SymbolCollectorTests.cpp =================================================================== --- unittests/clangd/SymbolCollectorTests.cpp +++ unittests/clangd/SymbolCollectorTests.cpp @@ -1222,6 +1222,22 @@ EXPECT_THAT(Symbols, Contains(QName("std::foo"))); } +TEST_F(SymbolCollectorTest, TemplateSpecForwardDecl) { + // FIXME: getTypeAsWritten returns null for friend decls, this should be fixed + // in AST. Testing just to make sure we don't crash. + Annotations Header(R"( + template struct [[Foo]]; + struct Bar { + friend class Foo; + }; + template <> struct Foo {}; + )"); + runSymbolCollector(Header.code(), /*Main=*/""); + EXPECT_THAT(Symbols, + Contains(AllOf(QName("Foo"), DeclRange(Header.range()), + ForCodeCompletion(true)))); +} + } // namespace } // namespace clangd } // namespace clang