clang-tools 22.0.0git
DumpASTTests.cpp
Go to the documentation of this file.
1//===-- DumpASTTests.cpp --------------------------------------------------===//
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 "Annotations.h"
10#include "DumpAST.h"
11#include "TestTU.h"
12#include "clang/AST/ASTTypeTraits.h"
13#include "llvm/Support/ScopedPrinter.h"
14#include "gmock/gmock.h"
15#include "gtest/gtest.h"
16
17namespace clang {
18namespace clangd {
19namespace {
20using testing::Contains;
21using testing::Not;
22using testing::SizeIs;
23
24MATCHER_P(withDetail, str, "") { return arg.detail == str; }
25
26TEST(DumpASTTests, BasicInfo) {
27 std::pair</*Code=*/std::string, /*Expected=*/std::string> Cases[] = {
28 {R"cpp(
29float root(int *x) {
30 return *x + 1;
31}
32 )cpp",
33 R"(
34declaration: Function - root
35 type: FunctionProto
36 type: Builtin - float
37 declaration: ParmVar - x
38 type: Pointer
39 type: Builtin - int
40 statement: Compound
41 statement: Return
42 expression: ImplicitCast - IntegralToFloating
43 expression: BinaryOperator - +
44 expression: ImplicitCast - LValueToRValue
45 expression: UnaryOperator - *
46 expression: ImplicitCast - LValueToRValue
47 expression: DeclRef - x
48 expression: IntegerLiteral - 1
49 )"},
50 {R"cpp(
51namespace root {
52struct S { static const int x = 0; ~S(); };
53int y = S::x + root::S().x;
54}
55 )cpp",
56 R"(
57declaration: Namespace - root
58 declaration: CXXRecord - S
59 declaration: Var - x
60 type: Qualified - const
61 type: Builtin - int
62 expression: IntegerLiteral - 0
63 declaration: CXXDestructor
64 type: Record - S
65 type: FunctionProto
66 type: Builtin - void
67 declaration: CXXConstructor
68 declaration: CXXConstructor
69 declaration: Var - y
70 type: Builtin - int
71 expression: ExprWithCleanups
72 expression: BinaryOperator - +
73 expression: ImplicitCast - LValueToRValue
74 expression: DeclRef - x
75 specifier: Type
76 type: Record - S
77 expression: ImplicitCast - LValueToRValue
78 expression: Member - x
79 expression: CXXBindTemporary
80 expression: CXXTemporaryObject - S
81 type: Record - S
82 specifier: Namespace - root::
83 )"},
84 {R"cpp(
85namespace root {
86struct S { static const int x = 0; };
87int y = S::x + root::S().x;
88}
89 )cpp",
90 R"(
91declaration: Namespace - root
92 declaration: CXXRecord - S
93 declaration: Var - x
94 type: Qualified - const
95 type: Builtin - int
96 expression: IntegerLiteral - 0
97 declaration: CXXConstructor
98 declaration: CXXConstructor
99 declaration: CXXConstructor
100 declaration: CXXDestructor
101 declaration: Var - y
102 type: Builtin - int
103 expression: BinaryOperator - +
104 expression: ImplicitCast - LValueToRValue
105 expression: DeclRef - x
106 specifier: Type
107 type: Record - S
108 expression: ImplicitCast - LValueToRValue
109 expression: Member - x
110 expression: CXXTemporaryObject - S
111 type: Record - S
112 specifier: Namespace - root::
113 )"},
114 {R"cpp(
115namespace root {
116template <typename T> int tmpl() {
117 (void)tmpl<unsigned>();
118 return T::value;
119}
120}
121 )cpp",
122 R"(
123declaration: Namespace - root
124 declaration: FunctionTemplate - tmpl
125 declaration: TemplateTypeParm - T
126 declaration: Function - tmpl
127 type: FunctionProto
128 type: Builtin - int
129 statement: Compound
130 expression: CStyleCast - ToVoid
131 type: Builtin - void
132 expression: Call
133 expression: ImplicitCast - FunctionToPointerDecay
134 expression: DeclRef - tmpl
135 template argument: Type
136 type: Builtin - unsigned int
137 statement: Return
138 expression: DependentScopeDeclRef - value
139 specifier: Type
140 type: TemplateTypeParm - T
141 )"},
142 {R"cpp(
143struct Foo { char operator+(int); };
144char root = Foo() + 42;
145 )cpp",
146 R"(
147declaration: Var - root
148 type: Builtin - char
149 expression: ExprWithCleanups
150 expression: CXXOperatorCall
151 expression: ImplicitCast - FunctionToPointerDecay
152 expression: DeclRef - operator+
153 expression: MaterializeTemporary - lvalue
154 expression: CXXTemporaryObject - Foo
155 type: Record - Foo
156 expression: IntegerLiteral - 42
157 )"},
158 {R"cpp(
159struct Bar {
160 int x;
161 int root() const {
162 return x;
163 }
164};
165 )cpp",
166 R"(
167declaration: CXXMethod - root
168 type: FunctionProto
169 type: Builtin - int
170 statement: Compound
171 statement: Return
172 expression: ImplicitCast - LValueToRValue
173 expression: Member - x
174 expression: CXXThis - const, implicit
175 )"},
176 };
177 for (const auto &Case : Cases) {
178 ParsedAST AST = TestTU::withCode(Case.first).build();
179 auto Node = dumpAST(DynTypedNode::create(findUnqualifiedDecl(AST, "root")),
180 AST.getTokens(), AST.getASTContext());
181 EXPECT_EQ(llvm::StringRef(Case.second).trim(),
182 llvm::StringRef(llvm::to_string(Node)).trim());
183 }
184}
185
186TEST(DumpASTTests, Range) {
187 Annotations Case("$var[[$type[[int]] x]];");
188 ParsedAST AST = TestTU::withCode(Case.code()).build();
189 auto Node = dumpAST(DynTypedNode::create(findDecl(AST, "x")), AST.getTokens(),
190 AST.getASTContext());
191 EXPECT_EQ(Node.range, Case.range("var"));
192 ASSERT_THAT(Node.children, SizeIs(1)) << "Expected one child typeloc";
193 EXPECT_EQ(Node.children.front().range, Case.range("type"));
194}
195
196TEST(DumpASTTests, NoRange) {
197 auto TU = TestTU::withHeaderCode("void funcFromHeader();");
198 TU.Code = "int varFromSource;";
199 ParsedAST AST = TU.build();
200 auto Node = dumpAST(
201 DynTypedNode::create(*AST.getASTContext().getTranslationUnitDecl()),
202 AST.getTokens(), AST.getASTContext());
203 ASSERT_THAT(Node.children, Contains(withDetail("varFromSource")));
204 ASSERT_THAT(Node.children, Not(Contains(withDetail("funcFromHeader"))));
205 EXPECT_THAT(Node.arcana, testing::StartsWith("TranslationUnitDecl "));
206 ASSERT_FALSE(Node.range) << "Expected no range for translation unit";
207}
208
209TEST(DumpASTTests, Arcana) {
210 ParsedAST AST = TestTU::withCode("int x;").build();
211 auto Node = dumpAST(DynTypedNode::create(findDecl(AST, "x")), AST.getTokens(),
212 AST.getASTContext());
213 EXPECT_THAT(Node.arcana, testing::StartsWith("VarDecl "));
214 EXPECT_THAT(Node.arcana, testing::EndsWith(" 'int'"));
215 ASSERT_THAT(Node.children, SizeIs(1)) << "Expected one child typeloc";
216 EXPECT_THAT(Node.children.front().arcana, testing::StartsWith("QualType "));
217}
218
219TEST(DumpASTTests, UnbalancedBraces) {
220 // Test that we don't crash while trying to compute a source range for the
221 // node whose ending brace is missing, and also that the source range is
222 // not empty.
223 Annotations Case("/*error-ok*/ $func[[int main() {]]");
224 ParsedAST AST = TestTU::withCode(Case.code()).build();
225 auto Node = dumpAST(DynTypedNode::create(findDecl(AST, "main")),
226 AST.getTokens(), AST.getASTContext());
227 ASSERT_EQ(Node.range, Case.range("func"));
228}
229
230} // namespace
231} // namespace clangd
232} // namespace clang
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges.
Definition Annotations.h:23
Stores and provides access to parsed AST.
Definition ParsedAST.h:46
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:45
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
Definition TestTU.cpp:220
ASTNode dumpAST(const DynTypedNode &N, const syntax::TokenBuffer &Tokens, const ASTContext &Ctx)
Definition DumpAST.cpp:408
MATCHER_P(named, N, "")
TEST(BackgroundQueueTest, Priority)
const NamedDecl & findUnqualifiedDecl(ParsedAST &AST, llvm::StringRef Name)
Definition TestTU.cpp:261
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
ParsedAST build() const
Definition TestTU.cpp:115
static TestTU withHeaderCode(llvm::StringRef HeaderCode)
Definition TestTU.h:42
static TestTU withCode(llvm::StringRef Code)
Definition TestTU.h:36