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-exception 6 // 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/None.h" 15 #include "llvm/ADT/StringRef.h" 16 #include "gmock/gmock.h" 17 #include "gtest/gtest.h" 18 19 namespace clang { 20 namespace clangd { 21 namespace { 22 23 using ::testing::Field; 24 using ::testing::Matcher; 25 using ::testing::SizeIs; 26 using ::testing::UnorderedElementsAreArray; 27 28 class ExpectedTypeConversionTest : public ::testing::Test { 29 protected: 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 llvm::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 by 48 /// 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 of 63 // '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[Type->raw()].insert(Name); 70 } 71 return Classes; 72 } 73 74 ASTContext &ASTCtx() { return AST->getASTContext(); } 75 76 private: 77 // Set after calling build(). 78 llvm::Optional<ParsedAST> AST; 79 }; 80 81 TEST_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 // pointers 94 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 112 TEST_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 124 TEST_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 134 TEST_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 150 TEST_F(ExpectedTypeConversionTest, Templates) { 151 build(R"cpp( 152 template <class T> 153 int* returns_not_dependent(); 154 template <class T> 155 T* returns_dependent(); 156 157 template <class T> 158 int* var_not_dependent = nullptr; 159 template <class T> 160 T* var_dependent = nullptr; 161 162 int* 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")), llvm::None); 168 169 EXPECT_EQ(fromCompletionResult(decl("var_not_dependent")), IntPtrTy); 170 EXPECT_EQ(fromCompletionResult(decl("var_dependent")), llvm::None); 171 } 172 173 } // namespace 174 } // namespace clangd 175 } // namespace clang 176