176 lines · cpp
1//===-- ExpectedTypeTest.cpp -----------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "ExpectedTypes.h"10#include "ParsedAST.h"11#include "TestTU.h"12#include "clang/AST/ASTContext.h"13#include "clang/AST/Decl.h"14#include "llvm/ADT/StringRef.h"15#include "gmock/gmock.h"16#include "gtest/gtest.h"17#include <optional>18 19namespace clang {20namespace clangd {21namespace {22 23using ::testing::Field;24using ::testing::Matcher;25using ::testing::SizeIs;26using ::testing::UnorderedElementsAreArray;27 28class ExpectedTypeConversionTest : public ::testing::Test {29protected:30 void build(llvm::StringRef Code) {31 assert(!AST && "AST built twice");32 AST = TestTU::withCode(Code).build();33 }34 35 const NamedDecl *decl(llvm::StringRef Name) { return &findDecl(*AST, Name); }36 37 QualType typeOf(llvm::StringRef Name) {38 return cast<ValueDecl>(decl(Name))->getType().getCanonicalType();39 }40 41 /// An overload for convenience.42 std::optional<OpaqueType> fromCompletionResult(const NamedDecl *D) {43 return OpaqueType::fromCompletionResult(44 astCtx(), CodeCompletionResult(D, CCP_Declaration));45 }46 47 /// A set of DeclNames whose type match each other computed by48 /// OpaqueType::fromCompletionResult.49 using EquivClass = std::set<std::string>;50 51 Matcher<std::map<std::string, EquivClass>>52 classesAre(llvm::ArrayRef<EquivClass> Classes) {53 using MapEntry = std::map<std::string, EquivClass>::value_type;54 55 std::vector<Matcher<MapEntry>> Elements;56 Elements.reserve(Classes.size());57 for (auto &Cls : Classes)58 Elements.push_back(Field(&MapEntry::second, Cls));59 return UnorderedElementsAreArray(Elements);60 }61 62 // Groups \p Decls into equivalence classes based on the result of63 // 'OpaqueType::fromCompletionResult'.64 std::map<std::string, EquivClass>65 buildEquivClasses(llvm::ArrayRef<llvm::StringRef> DeclNames) {66 std::map<std::string, EquivClass> Classes;67 for (llvm::StringRef Name : DeclNames) {68 auto Type = OpaqueType::fromType(astCtx(), typeOf(Name));69 Classes[std::string(Type->raw())].insert(std::string(Name));70 }71 return Classes;72 }73 74 ASTContext &astCtx() { return AST->getASTContext(); }75 76private:77 // Set after calling build().78 std::optional<ParsedAST> AST;79};80 81TEST_F(ExpectedTypeConversionTest, BasicTypes) {82 build(R"cpp(83 // ints.84 bool b;85 int i;86 unsigned int ui;87 long long ll;88 89 // floats.90 float f;91 double d;92 93 // pointers94 int* iptr;95 bool* bptr;96 97 // user-defined types.98 struct X {};99 X user_type;100 )cpp");101 102 EXPECT_THAT(buildEquivClasses({"b", "i", "ui", "ll", "f", "d", "iptr", "bptr",103 "user_type"}),104 classesAre({{"b"},105 {"i", "ui", "ll"},106 {"f", "d"},107 {"iptr"},108 {"bptr"},109 {"user_type"}}));110}111 112TEST_F(ExpectedTypeConversionTest, ReferencesDontMatter) {113 build(R"cpp(114 int noref;115 int & ref = noref;116 const int & const_ref = noref;117 int && rv_ref = 10;118 )cpp");119 120 EXPECT_THAT(buildEquivClasses({"noref", "ref", "const_ref", "rv_ref"}),121 SizeIs(1));122}123 124TEST_F(ExpectedTypeConversionTest, ArraysDecay) {125 build(R"cpp(126 int arr[2];127 int (&arr_ref)[2] = arr;128 int *ptr;129 )cpp");130 131 EXPECT_THAT(buildEquivClasses({"arr", "arr_ref", "ptr"}), SizeIs(1));132}133 134TEST_F(ExpectedTypeConversionTest, FunctionReturns) {135 build(R"cpp(136 int returns_int();137 int* returns_ptr();138 139 int int_;140 int* int_ptr;141 )cpp");142 143 OpaqueType IntTy = *OpaqueType::fromType(astCtx(), typeOf("int_"));144 EXPECT_EQ(fromCompletionResult(decl("returns_int")), IntTy);145 146 OpaqueType IntPtrTy = *OpaqueType::fromType(astCtx(), typeOf("int_ptr"));147 EXPECT_EQ(fromCompletionResult(decl("returns_ptr")), IntPtrTy);148}149 150TEST_F(ExpectedTypeConversionTest, Templates) {151 build(R"cpp(152template <class T>153int* returns_not_dependent();154template <class T>155T* returns_dependent();156 157template <class T>158int* var_not_dependent = nullptr;159template <class T>160T* var_dependent = nullptr;161 162int* int_ptr_;163 )cpp");164 165 auto IntPtrTy = *OpaqueType::fromType(astCtx(), typeOf("int_ptr_"));166 EXPECT_EQ(fromCompletionResult(decl("returns_not_dependent")), IntPtrTy);167 EXPECT_EQ(fromCompletionResult(decl("returns_dependent")), std::nullopt);168 169 EXPECT_EQ(fromCompletionResult(decl("var_not_dependent")), IntPtrTy);170 EXPECT_EQ(fromCompletionResult(decl("var_dependent")), std::nullopt);171}172 173} // namespace174} // namespace clangd175} // namespace clang176