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; };
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: CXXConstructor
64 declaration: CXXConstructor
65 declaration: CXXConstructor
66 declaration: CXXDestructor
67 declaration: Var - y
68 type: Builtin - int
69 expression: ExprWithCleanups
70 expression: BinaryOperator - +
71 expression: ImplicitCast - LValueToRValue
72 expression: DeclRef - x
73 specifier: TypeSpec
74 type: Record - S
75 expression: ImplicitCast - LValueToRValue
76 expression: Member - x
77 expression: MaterializeTemporary - rvalue
78 expression: CXXTemporaryObject - S
79 type: Elaborated
80 specifier: Namespace - root::
81 type: Record - S
82 )"},
83 {R"cpp(
84namespace root {
85template <typename T> int tmpl() {
86 (void)tmpl<unsigned>();
87 return T::value;
88}
89}
90 )cpp",
91 R"(
92declaration: Namespace - root
93 declaration: FunctionTemplate - tmpl
94 declaration: TemplateTypeParm - T
95 declaration: Function - tmpl
96 type: FunctionProto
97 type: Builtin - int
98 statement: Compound
99 expression: CStyleCast - ToVoid
100 type: Builtin - void
101 expression: Call
102 expression: ImplicitCast - FunctionToPointerDecay
103 expression: DeclRef - tmpl
104 template argument: Type
105 type: Builtin - unsigned int
106 statement: Return
107 expression: DependentScopeDeclRef - value
108 specifier: TypeSpec
109 type: TemplateTypeParm - T
110 )"},
111 {R"cpp(
112struct Foo { char operator+(int); };
113char root = Foo() + 42;
114 )cpp",
115 R"(
116declaration: Var - root
117 type: Builtin - char
118 expression: ExprWithCleanups
119 expression: CXXOperatorCall
120 expression: ImplicitCast - FunctionToPointerDecay
121 expression: DeclRef - operator+
122 expression: MaterializeTemporary - lvalue
123 expression: CXXTemporaryObject - Foo
124 type: Elaborated
125 type: Record - Foo
126 expression: IntegerLiteral - 42
127 )"},
128 {R"cpp(
129struct Bar {
130 int x;
131 int root() const {
132 return x;
133 }
134};
135 )cpp",
136 R"(
137declaration: CXXMethod - root
138 type: FunctionProto
139 type: Builtin - int
140 statement: Compound
141 statement: Return
142 expression: ImplicitCast - LValueToRValue
143 expression: Member - x
144 expression: CXXThis - const, implicit
145 )"},
146 };
147 for (const auto &Case : Cases) {
148 ParsedAST AST = TestTU::withCode(Code: Case.first).build();
149 auto Node = dumpAST(DynTypedNode::create(Node: findUnqualifiedDecl(AST, Name: "root")),
150 Tokens: AST.getTokens(), AST.getASTContext());
151 EXPECT_EQ(llvm::StringRef(Case.second).trim(),
152 llvm::StringRef(llvm::to_string(Node)).trim());
153 }
154}
155
156TEST(DumpASTTests, Range) {
157 Annotations Case("$var[[$type[[int]] x]];");
158 ParsedAST AST = TestTU::withCode(Code: Case.code()).build();
159 auto Node = dumpAST(DynTypedNode::create(Node: findDecl(AST, QName: "x")), Tokens: AST.getTokens(),
160 AST.getASTContext());
161 EXPECT_EQ(Node.range, Case.range("var"));
162 ASSERT_THAT(Node.children, SizeIs(1)) << "Expected one child typeloc";
163 EXPECT_EQ(Node.children.front().range, Case.range("type"));
164}
165
166TEST(DumpASTTests, NoRange) {
167 auto TU = TestTU::withHeaderCode(HeaderCode: "void funcFromHeader();");
168 TU.Code = "int varFromSource;";
169 ParsedAST AST = TU.build();
170 auto Node = dumpAST(
171 DynTypedNode::create(Node: *AST.getASTContext().getTranslationUnitDecl()),
172 Tokens: AST.getTokens(), AST.getASTContext());
173 ASSERT_THAT(Node.children, Contains(withDetail("varFromSource")));
174 ASSERT_THAT(Node.children, Not(Contains(withDetail("funcFromHeader"))));
175 EXPECT_THAT(Node.arcana, testing::StartsWith("TranslationUnitDecl "));
176 ASSERT_FALSE(Node.range) << "Expected no range for translation unit";
177}
178
179TEST(DumpASTTests, Arcana) {
180 ParsedAST AST = TestTU::withCode(Code: "int x;").build();
181 auto Node = dumpAST(DynTypedNode::create(Node: findDecl(AST, QName: "x")), Tokens: AST.getTokens(),
182 AST.getASTContext());
183 EXPECT_THAT(Node.arcana, testing::StartsWith("VarDecl "));
184 EXPECT_THAT(Node.arcana, testing::EndsWith(" 'int'"));
185 ASSERT_THAT(Node.children, SizeIs(1)) << "Expected one child typeloc";
186 EXPECT_THAT(Node.children.front().arcana, testing::StartsWith("QualType "));
187}
188
189TEST(DumpASTTests, UnbalancedBraces) {
190 // Test that we don't crash while trying to compute a source range for the
191 // node whose ending brace is missing, and also that the source range is
192 // not empty.
193 Annotations Case("/*error-ok*/ $func[[int main() {]]");
194 ParsedAST AST = TestTU::withCode(Code: Case.code()).build();
195 auto Node = dumpAST(DynTypedNode::create(Node: findDecl(AST, QName: "main")),
196 Tokens: AST.getTokens(), AST.getASTContext());
197 ASSERT_EQ(Node.range, Case.range("func"));
198}
199
200} // namespace
201} // namespace clangd
202} // namespace clang
203

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