clang-tools 24.0.0git
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 "clang/Sema/CodeCompleteConsumer.h"
15#include "llvm/ADT/StringRef.h"
16#include "gmock/gmock.h"
17#include "gtest/gtest.h"
18#include <optional>
19
20namespace clang {
21namespace clangd {
22namespace {
23
24using ::testing::Field;
25using ::testing::Matcher;
26using ::testing::SizeIs;
27using ::testing::UnorderedElementsAreArray;
28
29class ExpectedTypeConversionTest : public ::testing::Test {
30protected:
31 void build(llvm::StringRef Code) {
32 assert(!AST && "AST built twice");
33 AST = TestTU::withCode(Code).build();
34 }
35
36 const NamedDecl *decl(llvm::StringRef Name) { return &findDecl(*AST, Name); }
37
38 QualType typeOf(llvm::StringRef Name) {
39 return cast<ValueDecl>(decl(Name))->getType().getCanonicalType();
40 }
41
42 /// An overload for convenience.
43 std::optional<OpaqueType> fromCompletionResult(const NamedDecl *D) {
45 astCtx(), CodeCompletionResult(D, CCP_Declaration));
46 }
47
48 /// A set of DeclNames whose type match each other computed by
49 /// OpaqueType::fromCompletionResult.
50 using EquivClass = std::set<std::string>;
51
52 Matcher<std::map<std::string, EquivClass>>
53 classesAre(llvm::ArrayRef<EquivClass> Classes) {
54 using MapEntry = std::map<std::string, EquivClass>::value_type;
55
56 std::vector<Matcher<MapEntry>> Elements;
57 Elements.reserve(Classes.size());
58 for (auto &Cls : Classes)
59 Elements.push_back(Field(&MapEntry::second, Cls));
60 return UnorderedElementsAreArray(Elements);
61 }
62
63 // Groups \p Decls into equivalence classes based on the result of
64 // 'OpaqueType::fromCompletionResult'.
65 std::map<std::string, EquivClass>
66 buildEquivClasses(llvm::ArrayRef<llvm::StringRef> DeclNames) {
67 std::map<std::string, EquivClass> Classes;
68 for (llvm::StringRef Name : DeclNames) {
69 auto Type = OpaqueType::fromType(astCtx(), typeOf(Name));
70 Classes[std::string(Type->raw())].insert(std::string(Name));
71 }
72 return Classes;
73 }
74
75 ASTContext &astCtx() { return AST->getASTContext(); }
76
77private:
78 // Set after calling build().
79 std::optional<ParsedAST> AST;
80};
81
82TEST_F(ExpectedTypeConversionTest, BasicTypes) {
83 build(R"cpp(
84 // ints.
85 bool b;
86 int i;
87 unsigned int ui;
88 long long ll;
89
90 // floats.
91 float f;
92 double d;
93
94 // pointers
95 int* iptr;
96 bool* bptr;
97
98 // user-defined types.
99 struct X {};
100 X user_type;
101 )cpp");
102
103 EXPECT_THAT(buildEquivClasses({"b", "i", "ui", "ll", "f", "d", "iptr", "bptr",
104 "user_type"}),
105 classesAre({{"b"},
106 {"i", "ui", "ll"},
107 {"f", "d"},
108 {"iptr"},
109 {"bptr"},
110 {"user_type"}}));
111}
112
113TEST_F(ExpectedTypeConversionTest, ReferencesDontMatter) {
114 build(R"cpp(
115 int noref;
116 int & ref = noref;
117 const int & const_ref = noref;
118 int && rv_ref = 10;
119 )cpp");
120
121 EXPECT_THAT(buildEquivClasses({"noref", "ref", "const_ref", "rv_ref"}),
122 SizeIs(1));
123}
124
125TEST_F(ExpectedTypeConversionTest, ArraysDecay) {
126 build(R"cpp(
127 int arr[2];
128 int (&arr_ref)[2] = arr;
129 int *ptr;
130 )cpp");
131
132 EXPECT_THAT(buildEquivClasses({"arr", "arr_ref", "ptr"}), SizeIs(1));
133}
134
135TEST_F(ExpectedTypeConversionTest, FunctionReturns) {
136 build(R"cpp(
137 int returns_int();
138 int* returns_ptr();
139
140 int int_;
141 int* int_ptr;
142 )cpp");
143
144 OpaqueType IntTy = *OpaqueType::fromType(astCtx(), typeOf("int_"));
145 EXPECT_EQ(fromCompletionResult(decl("returns_int")), IntTy);
146
147 OpaqueType IntPtrTy = *OpaqueType::fromType(astCtx(), typeOf("int_ptr"));
148 EXPECT_EQ(fromCompletionResult(decl("returns_ptr")), IntPtrTy);
149}
150
151TEST_F(ExpectedTypeConversionTest, Templates) {
152 build(R"cpp(
153template <class T>
154int* returns_not_dependent();
155template <class T>
156T* returns_dependent();
157
158template <class T>
159int* var_not_dependent = nullptr;
160template <class T>
161T* var_dependent = nullptr;
162
163int* int_ptr_;
164 )cpp");
165
166 auto IntPtrTy = *OpaqueType::fromType(astCtx(), typeOf("int_ptr_"));
167 EXPECT_EQ(fromCompletionResult(decl("returns_not_dependent")), IntPtrTy);
168 EXPECT_EQ(fromCompletionResult(decl("returns_dependent")), std::nullopt);
169
170 EXPECT_EQ(fromCompletionResult(decl("var_not_dependent")), IntPtrTy);
171 EXPECT_EQ(fromCompletionResult(decl("var_dependent")), std::nullopt);
172}
173
174} // namespace
175} // namespace clangd
176} // namespace clang
A representation of a type that can be computed based on clang AST and compared for equality.
static std::optional< OpaqueType > fromCompletionResult(ASTContext &Ctx, const CodeCompletionResult &R)
Create a type from a code completion result.
static std::optional< OpaqueType > fromType(ASTContext &Ctx, QualType Type)
Construct an instance from a clang::QualType.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:44
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
Definition TestTU.cpp:220
@ Type
An inlay hint that for a type annotation.
Definition Protocol.h:1745
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
ParsedAST build() const
Definition TestTU.cpp:115
static TestTU withCode(llvm::StringRef Code)
Definition TestTU.h:36