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 "llvm/Support/ScopedPrinter.h"
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
15 
16 namespace clang {
17 namespace clangd {
18 namespace {
19 using testing::Contains;
20 using testing::Not;
21 using testing::SizeIs;
22 
23 MATCHER_P(WithDetail, str, "") { return arg.detail == str; }
24 
TEST(DumpASTTests,BasicInfo)25 TEST(DumpASTTests, BasicInfo) {
26   std::pair</*Code=*/std::string, /*Expected=*/std::string> Cases[] = {
27       {R"cpp(
28 float root(int *x) {
29   return *x + 1;
30 }
31       )cpp",
32        R"(
33 declaration: Function - root
34   type: FunctionProto
35     type: Builtin - float
36     declaration: ParmVar - x
37       type: Pointer
38         type: Builtin - int
39   statement: Compound
40     statement: Return
41       expression: ImplicitCast - IntegralToFloating
42         expression: BinaryOperator - +
43           expression: ImplicitCast - LValueToRValue
44             expression: UnaryOperator - *
45               expression: ImplicitCast - LValueToRValue
46                 expression: DeclRef - x
47           expression: IntegerLiteral - 1
48       )"},
49       {R"cpp(
50 namespace root {
51 struct S { static const int x = 0; };
52 int y = S::x + root::S().x;
53 }
54       )cpp",
55        R"(
56 declaration: Namespace - root
57   declaration: CXXRecord - S
58     declaration: Var - x
59       type: Qualified - const
60         type: Builtin - int
61       expression: IntegerLiteral - 0
62     declaration: CXXConstructor
63     declaration: CXXConstructor
64     declaration: CXXConstructor
65     declaration: CXXDestructor
66   declaration: Var - y
67     type: Builtin - int
68     expression: ExprWithCleanups
69       expression: BinaryOperator - +
70         expression: ImplicitCast - LValueToRValue
71           expression: DeclRef - x
72             specifier: TypeSpec
73               type: Record - S
74         expression: ImplicitCast - LValueToRValue
75           expression: Member - x
76             expression: MaterializeTemporary - rvalue
77               expression: CXXTemporaryObject - S
78                 type: Elaborated
79                   specifier: Namespace - root::
80                   type: Record - S
81       )"},
82       {R"cpp(
83 namespace root {
84 template <typename T> int tmpl() {
85   (void)tmpl<unsigned>();
86   return T::value;
87 }
88 }
89       )cpp",
90        R"(
91 declaration: Namespace - root
92   declaration: FunctionTemplate - tmpl
93     declaration: TemplateTypeParm - T
94     declaration: Function - tmpl
95       type: FunctionProto
96         type: Builtin - int
97       statement: Compound
98         expression: CStyleCast - ToVoid
99           type: Builtin - void
100           expression: Call
101             expression: ImplicitCast - FunctionToPointerDecay
102               expression: DeclRef - tmpl
103                 template argument: Type
104                   type: Builtin - unsigned int
105         statement: Return
106           expression: DependentScopeDeclRef - value
107             specifier: TypeSpec
108               type: TemplateTypeParm - T
109       )"},
110       {R"cpp(
111 struct Foo { char operator+(int); };
112 char root = Foo() + 42;
113       )cpp",
114        R"(
115 declaration: Var - root
116   type: Builtin - char
117   expression: ExprWithCleanups
118     expression: CXXOperatorCall
119       expression: ImplicitCast - FunctionToPointerDecay
120         expression: DeclRef - operator+
121       expression: MaterializeTemporary - lvalue
122         expression: CXXTemporaryObject - Foo
123           type: Record - Foo
124       expression: IntegerLiteral - 42
125       )"},
126       {R"cpp(
127 struct Bar {
128   int x;
129   int root() const {
130     return x;
131   }
132 };
133       )cpp",
134        R"(
135 declaration: CXXMethod - root
136   type: FunctionProto
137     type: Builtin - int
138   statement: Compound
139     statement: Return
140       expression: ImplicitCast - LValueToRValue
141         expression: Member - x
142           expression: CXXThis - const, implicit
143       )"},
144   };
145   for (const auto &Case : Cases) {
146     ParsedAST AST = TestTU::withCode(Case.first).build();
147     auto Node = dumpAST(DynTypedNode::create(findUnqualifiedDecl(AST, "root")),
148                         AST.getTokens(), AST.getASTContext());
149     EXPECT_EQ(llvm::StringRef(Case.second).trim(),
150               llvm::StringRef(llvm::to_string(Node)).trim());
151   }
152 }
153 
TEST(DumpASTTests,Range)154 TEST(DumpASTTests, Range) {
155   Annotations Case("$var[[$type[[int]] x]];");
156   ParsedAST AST = TestTU::withCode(Case.code()).build();
157   auto Node = dumpAST(DynTypedNode::create(findDecl(AST, "x")), AST.getTokens(),
158                       AST.getASTContext());
159   EXPECT_EQ(Node.range, Case.range("var"));
160   ASSERT_THAT(Node.children, SizeIs(1)) << "Expected one child typeloc";
161   EXPECT_EQ(Node.children.front().range, Case.range("type"));
162 }
163 
TEST(DumpASTTests,NoRange)164 TEST(DumpASTTests, NoRange) {
165   auto TU = TestTU::withHeaderCode("void funcFromHeader();");
166   TU.Code = "int varFromSource;";
167   ParsedAST AST = TU.build();
168   auto Node = dumpAST(
169       DynTypedNode::create(*AST.getASTContext().getTranslationUnitDecl()),
170       AST.getTokens(), AST.getASTContext());
171   ASSERT_THAT(Node.children, Contains(WithDetail("varFromSource")));
172   ASSERT_THAT(Node.children, Not(Contains(WithDetail("funcFromHeader"))));
173   EXPECT_THAT(Node.arcana, testing::StartsWith("TranslationUnitDecl "));
174   ASSERT_FALSE(Node.range.hasValue())
175       << "Expected no range for translation unit";
176 }
177 
TEST(DumpASTTests,Arcana)178 TEST(DumpASTTests, Arcana) {
179   ParsedAST AST = TestTU::withCode("int x;").build();
180   auto Node = dumpAST(DynTypedNode::create(findDecl(AST, "x")), AST.getTokens(),
181                       AST.getASTContext());
182   EXPECT_THAT(Node.arcana, testing::StartsWith("VarDecl "));
183   EXPECT_THAT(Node.arcana, testing::EndsWith(" 'int'"));
184   ASSERT_THAT(Node.children, SizeIs(1)) << "Expected one child typeloc";
185   EXPECT_THAT(Node.children.front().arcana, testing::StartsWith("QualType "));
186 }
187 
188 } // namespace
189 } // namespace clangd
190 } // namespace clang
191