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