Index: clangd/ExpectedTypes.cpp =================================================================== --- clangd/ExpectedTypes.cpp +++ clangd/ExpectedTypes.cpp @@ -8,9 +8,11 @@ #include "ExpectedTypes.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Type.h" #include "clang/Index/USRGeneration.h" #include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" namespace clang { @@ -41,7 +43,13 @@ static llvm::Optional typeOfCompletion(const CodeCompletionResult &R) { - auto *VD = dyn_cast_or_null(R.Declaration); + const NamedDecl *D = R.Declaration; + if (!D) + return llvm::None; + // Templates do not have a type on their own, look at the templated decl. + if (auto *Template = dyn_cast(D)) + D = Template->getTemplatedDecl(); + auto *VD = dyn_cast(D); if (!VD) return llvm::None; // We handle only variables and functions below. auto T = VD->getType(); Index: clangd/unittests/ExpectedTypeTest.cpp =================================================================== --- clangd/unittests/ExpectedTypeTest.cpp +++ clangd/unittests/ExpectedTypeTest.cpp @@ -11,6 +11,7 @@ #include "TestTU.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/StringRef.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -31,16 +32,14 @@ AST = TestTU::withCode(Code).build(); } - const ValueDecl *decl(llvm::StringRef Name) { - return &cast(findDecl(*AST, Name)); - } + const NamedDecl *decl(llvm::StringRef Name) { return &findDecl(*AST, Name); } QualType typeOf(llvm::StringRef Name) { - return decl(Name)->getType().getCanonicalType(); + return cast(decl(Name))->getType().getCanonicalType(); } /// An overload for convenience. - llvm::Optional fromCompletionResult(const ValueDecl *D) { + llvm::Optional fromCompletionResult(const NamedDecl *D) { return OpaqueType::fromCompletionResult( ASTCtx(), CodeCompletionResult(D, CCP_Declaration)); } @@ -148,6 +147,29 @@ EXPECT_EQ(fromCompletionResult(decl("returns_ptr")), IntPtrTy); } +TEST_F(ExpectedTypeConversionTest, Templates) { + build(R"cpp( +template +int* returns_not_dependent(); +template +T* returns_dependent(); + +template +int* var_not_dependent = nullptr; +template +T* var_dependent = nullptr; + +int* int_ptr_; + )cpp"); + + auto IntPtrTy = *OpaqueType::fromType(ASTCtx(), typeOf("int_ptr_")); + EXPECT_EQ(fromCompletionResult(decl("returns_not_dependent")), IntPtrTy); + EXPECT_EQ(fromCompletionResult(decl("returns_dependent")), llvm::None); + + EXPECT_EQ(fromCompletionResult(decl("var_not_dependent")), IntPtrTy); + EXPECT_EQ(fromCompletionResult(decl("var_dependent")), llvm::None); +} + } // namespace } // namespace clangd } // namespace clang