clang-tools  10.0.0
ExpectedTypeTest.cpp
Go to the documentation of this file.
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) {
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
ParsedAST build() const
Definition: TestTU.cpp:22
std::string Code
static llvm::Optional< OpaqueType > fromType(ASTContext &Ctx, QualType Type)
Construct an instance from a clang::QualType.
Documents should not be synced at all.
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
static constexpr llvm::StringLiteral Name
static TestTU withCode(llvm::StringRef Code)
Definition: TestTU.h:33
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
NodeType Type
static llvm::Optional< OpaqueType > fromCompletionResult(ASTContext &Ctx, const CodeCompletionResult &R)
Create a type from a code completion result.
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
Definition: TestTU.cpp:118