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/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&: *AST, QName: Name); }
36
37 QualType typeOf(llvm::StringRef Name) {
38 return cast<ValueDecl>(Val: decl(Name))->getType().getCanonicalType();
39 }
40
41 /// An overload for convenience.
42 std::optional<OpaqueType> fromCompletionResult(const NamedDecl *D) {
43 return OpaqueType::fromCompletionResult(
44 Ctx&: astCtx(), R: 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(n: Classes.size());
57 for (auto &Cls : Classes)
58 Elements.push_back(x: Field(field: &MapEntry::second, matcher: Cls));
59 return UnorderedElementsAreArray(container: 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(Ctx&: astCtx(), Type: typeOf(Name));
69 Classes[std::string(Type->raw())].insert(x: 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(Code: 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
112TEST_F(ExpectedTypeConversionTest, ReferencesDontMatter) {
113 build(Code: 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(Code: 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(Code: 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(Ctx&: astCtx(), Type: typeOf(Name: "int_"));
144 EXPECT_EQ(fromCompletionResult(decl("returns_int")), IntTy);
145
146 OpaqueType IntPtrTy = *OpaqueType::fromType(Ctx&: astCtx(), Type: typeOf(Name: "int_ptr"));
147 EXPECT_EQ(fromCompletionResult(decl("returns_ptr")), IntPtrTy);
148}
149
150TEST_F(ExpectedTypeConversionTest, Templates) {
151 build(Code: 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(Ctx&: astCtx(), Type: typeOf(Name: "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} // namespace
174} // namespace clangd
175} // namespace clang
176

source code of clang-tools-extra/clangd/unittests/ExpectedTypeTest.cpp