1 | //===- unittests/AST/ASTDumperTest.cpp --- Test of AST node dump() methods ===// |
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 | // This file contains tests for TypeLoc::dump() and related methods. |
10 | // Most of these are lit tests via clang -ast-dump. However some nodes are not |
11 | // included in dumps of (TranslationUnit)Decl, but still relevant when dumped |
12 | // directly. |
13 | // |
14 | //===----------------------------------------------------------------------===// |
15 | |
16 | #include "ASTPrint.h" |
17 | #include "clang/AST/ASTContext.h" |
18 | #include "clang/AST/Decl.h" |
19 | #include "clang/Testing/TestAST.h" |
20 | #include "llvm/ADT/StringRef.h" |
21 | #include "gmock/gmock.h" |
22 | #include "gtest/gtest.h" |
23 | |
24 | using namespace clang; |
25 | using namespace ast_matchers; |
26 | |
27 | namespace { |
28 | using testing::ElementsAre; |
29 | using testing::StartsWith; |
30 | |
31 | std::vector<std::string> dumpTypeLoc(llvm::StringRef Name, ASTContext &Ctx) { |
32 | auto Lookup = Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get(Name)); |
33 | DeclaratorDecl *D = nullptr; |
34 | if ((D = Lookup.find_first<DeclaratorDecl>())) |
35 | ; |
36 | else if (auto *TD = Lookup.find_first<FunctionTemplateDecl>()) |
37 | D = TD->getTemplatedDecl(); |
38 | EXPECT_NE(D, nullptr) << Name; |
39 | if (!D) |
40 | return {}; |
41 | EXPECT_NE(D->getTypeSourceInfo(), nullptr); |
42 | if (!D->getTypeSourceInfo()) |
43 | return {}; |
44 | std::string S; |
45 | { |
46 | llvm::raw_string_ostream OS(S); |
47 | D->getTypeSourceInfo()->getTypeLoc().dump(OS, Ctx); |
48 | } |
49 | // Split result into lines. |
50 | std::vector<std::string> Result; |
51 | auto Remaining = llvm::StringRef(S).trim(Chars: "\n" ); |
52 | while (!Remaining.empty()) { |
53 | auto [First, Rest] = Remaining.split(Separator: '\n'); |
54 | Result.push_back(x: First.str()); |
55 | Remaining = Rest; |
56 | } |
57 | return Result; |
58 | } |
59 | |
60 | TEST(ASTDumper, TypeLocChain) { |
61 | TestAST AST(R"cc( |
62 | const int **x; |
63 | )cc" ); |
64 | EXPECT_THAT( |
65 | dumpTypeLoc("x" , AST.context()), |
66 | ElementsAre("" |
67 | "PointerTypeLoc <input.mm:2:11, col:16> 'const int **'" , |
68 | "`-PointerTypeLoc <col:11, col:15> 'const int *'" , |
69 | " `-QualifiedTypeLoc <col:11> 'const int'" , |
70 | " `-BuiltinTypeLoc <col:11> 'int'" )); |
71 | } |
72 | |
73 | TEST(ASTDumper, AutoType) { |
74 | TestInputs Inputs(R"cc( |
75 | template <class, class> concept C = true; |
76 | C<int> auto str1 = "hello"; |
77 | auto str2 = "hello"; |
78 | )cc" ); |
79 | Inputs.ExtraArgs.push_back(x: "-std=c++20" ); |
80 | TestAST AST(Inputs); |
81 | EXPECT_THAT( |
82 | dumpTypeLoc("str1" , AST.context()), |
83 | ElementsAre("" |
84 | "AutoTypeLoc <input.mm:3:5, col:12> 'C<int> auto' undeduced" , |
85 | StartsWith("|-Concept" ), // |
86 | "`-TemplateArgument <col:7> type 'int'" , |
87 | StartsWith(" `-BuiltinType" ))); |
88 | EXPECT_THAT(dumpTypeLoc("str2" , AST.context()), |
89 | ElementsAre("" |
90 | "AutoTypeLoc <input.mm:4:5> 'auto' undeduced" )); |
91 | } |
92 | |
93 | |
94 | TEST(ASTDumper, FunctionTypeLoc) { |
95 | TestAST AST(R"cc( |
96 | void x(int, double *y); |
97 | |
98 | auto trailing() -> int; |
99 | |
100 | template <class T> int tmpl(T&&); |
101 | )cc" ); |
102 | EXPECT_THAT( |
103 | dumpTypeLoc("x" , AST.context()), |
104 | ElementsAre("" |
105 | "FunctionProtoTypeLoc <input.mm:2:5, col:26> 'void (int, " |
106 | "double *)' cdecl" , |
107 | StartsWith("|-ParmVarDecl" ), |
108 | "| `-BuiltinTypeLoc <col:12> 'int'" , |
109 | StartsWith("|-ParmVarDecl" ), |
110 | "| `-PointerTypeLoc <col:17, col:24> 'double *'" , |
111 | "| `-BuiltinTypeLoc <col:17> 'double'" , |
112 | "`-BuiltinTypeLoc <col:5> 'void'" )); |
113 | |
114 | EXPECT_THAT(dumpTypeLoc("trailing" , AST.context()), |
115 | ElementsAre("" |
116 | "FunctionProtoTypeLoc <input.mm:4:5, col:24> " |
117 | "'auto () -> int' trailing_return cdecl" , |
118 | "`-BuiltinTypeLoc <col:24> 'int'" )); |
119 | |
120 | EXPECT_THAT( |
121 | dumpTypeLoc("tmpl" , AST.context()), |
122 | ElementsAre("" |
123 | "FunctionProtoTypeLoc <input.mm:6:24, col:36> " |
124 | "'int (T &&)' cdecl" , |
125 | StartsWith("|-ParmVarDecl" ), |
126 | "| `-RValueReferenceTypeLoc <col:33, col:34> 'T &&'" , |
127 | "| `-TemplateTypeParmTypeLoc <col:33> 'T' depth 0 index 0" , |
128 | StartsWith("| `-TemplateTypeParm" ), |
129 | "`-BuiltinTypeLoc <col:24> 'int'" )); |
130 | |
131 | // Dynamic-exception-spec needs C++14 or earlier. |
132 | TestInputs Throws(R"cc( |
133 | void throws() throw(int); |
134 | )cc" ); |
135 | Throws.ExtraArgs.push_back(x: "-std=c++14" ); |
136 | AST = TestAST(Throws); |
137 | EXPECT_THAT(dumpTypeLoc("throws" , AST.context()), |
138 | ElementsAre("" |
139 | "FunctionProtoTypeLoc <input.mm:2:5, col:28> " |
140 | "'void () throw(int)' exceptionspec_dynamic cdecl" , |
141 | // FIXME: include TypeLoc for int |
142 | "|-Exceptions: 'int'" , |
143 | "`-BuiltinTypeLoc <col:5> 'void'" )); |
144 | } |
145 | |
146 | } // namespace |
147 | |