kadircet created this revision. kadircet added a reviewer: ilya-biryukov. Herald added subscribers: cfe-commits, jdoerfert, arphaman, jkorous, MaskRay, ioeric. Herald added a project: clang.
Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D59599 Files: clangd/AST.cpp unittests/clangd/SymbolCollectorTests.cpp 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: This should be fixed in AST to point at specialization. Exercised + // just to make sure we don't crash. + Annotations Header(R"( + template <typename T> struct [[Foo]]; + struct Bar { + friend class Foo<int>; + }; + template <> struct Foo<int> {}; + )"); + runSymbolCollector(Header.code(), /*Main=*/""); + EXPECT_THAT(Symbols, + Contains(AllOf(QName("Foo<int>"), DeclRange(Header.range()), + ForCodeCompletion(true)))); +} + } // namespace } // namespace clangd } // namespace clang 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,19 @@ if (auto Args = getTemplateSpecializationArgLocs(ND)) printTemplateArgumentList(OS, *Args, Policy); else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) { - if (auto STL = Cls->getTypeAsWritten() - ->getTypeLoc() - .getAs<TemplateSpecializationTypeLoc>()) { - llvm::SmallVector<TemplateArgumentLoc, 8> ArgLocs; - ArgLocs.reserve(STL.getNumArgs()); - for (unsigned I = 0; I < STL.getNumArgs(); ++I) - ArgLocs.push_back(STL.getArgLoc(I)); - printTemplateArgumentList(OS, ArgLocs, Policy); + if (auto *TSI = Cls->getTypeAsWritten()) { + if (auto STL = TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>()) { + llvm::SmallVector<TemplateArgumentLoc, 8> 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: Cls->getTypeAsWritten might return null in some cases, e.g. + // clang sees first sees a friend declaration and then the specialization. + // In that case fall back to TemplateArguments without Location info, + 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: This should be fixed in AST to point at specialization. Exercised + // just to make sure we don't crash. + Annotations Header(R"( + template <typename T> struct [[Foo]]; + struct Bar { + friend class Foo<int>; + }; + template <> struct Foo<int> {}; + )"); + runSymbolCollector(Header.code(), /*Main=*/""); + EXPECT_THAT(Symbols, + Contains(AllOf(QName("Foo<int>"), DeclRange(Header.range()), + ForCodeCompletion(true)))); +} + } // namespace } // namespace clangd } // namespace clang 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,19 @@ if (auto Args = getTemplateSpecializationArgLocs(ND)) printTemplateArgumentList(OS, *Args, Policy); else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) { - if (auto STL = Cls->getTypeAsWritten() - ->getTypeLoc() - .getAs<TemplateSpecializationTypeLoc>()) { - llvm::SmallVector<TemplateArgumentLoc, 8> ArgLocs; - ArgLocs.reserve(STL.getNumArgs()); - for (unsigned I = 0; I < STL.getNumArgs(); ++I) - ArgLocs.push_back(STL.getArgLoc(I)); - printTemplateArgumentList(OS, ArgLocs, Policy); + if (auto *TSI = Cls->getTypeAsWritten()) { + if (auto STL = TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>()) { + llvm::SmallVector<TemplateArgumentLoc, 8> 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: Cls->getTypeAsWritten might return null in some cases, e.g. + // clang sees first sees a friend declaration and then the specialization. + // In that case fall back to TemplateArguments without Location info, + printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy); } } OS.flush();
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits