Skip to content

Commit

Permalink
[clangd] Compute expected type for templates
Browse files Browse the repository at this point in the history
Reviewers: sammccall

Reviewed By: sammccall

Subscribers: MaskRay, jkorous, arphaman, kadircet, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D62515

llvm-svn: 361823
  • Loading branch information
ilya-biryukov committed May 28, 2019
1 parent d5a8637 commit b4a3945
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 6 deletions.
10 changes: 9 additions & 1 deletion clang-tools-extra/clangd/ExpectedTypes.cpp
Expand Up @@ -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 {
Expand Down Expand Up @@ -41,7 +43,13 @@ static const Type *toEquivClass(ASTContext &Ctx, QualType T) {

static llvm::Optional<QualType>
typeOfCompletion(const CodeCompletionResult &R) {
auto *VD = dyn_cast_or_null<ValueDecl>(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<TemplateDecl>(D))
D = Template->getTemplatedDecl();
auto *VD = dyn_cast<ValueDecl>(D);
if (!VD)
return llvm::None; // We handle only variables and functions below.
auto T = VD->getType();
Expand Down
32 changes: 27 additions & 5 deletions clang-tools-extra/clangd/unittests/ExpectedTypeTest.cpp
Expand Up @@ -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"
Expand All @@ -31,16 +32,14 @@ class ExpectedTypeConversionTest : public ::testing::Test {
AST = TestTU::withCode(Code).build();
}

const ValueDecl *decl(llvm::StringRef Name) {
return &cast<ValueDecl>(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<ValueDecl>(decl(Name))->getType().getCanonicalType();
}

/// An overload for convenience.
llvm::Optional<OpaqueType> fromCompletionResult(const ValueDecl *D) {
llvm::Optional<OpaqueType> fromCompletionResult(const NamedDecl *D) {
return OpaqueType::fromCompletionResult(
ASTCtx(), CodeCompletionResult(D, CCP_Declaration));
}
Expand Down Expand Up @@ -148,6 +147,29 @@ TEST_F(ExpectedTypeConversionTest, FunctionReturns) {
EXPECT_EQ(fromCompletionResult(decl("returns_ptr")), IntPtrTy);
}

TEST_F(ExpectedTypeConversionTest, Templates) {
build(R"cpp(
template <class T>
int* returns_not_dependent();
template <class T>
T* returns_dependent();
template <class T>
int* var_not_dependent = nullptr;
template <class T>
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

0 comments on commit b4a3945

Please sign in to comment.