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 17 namespace clang { 18 namespace clangd { 19 namespace { 20 using testing::Contains; 21 using testing::Not; 22 using testing::SizeIs; 23 24 MATCHER_P(withDetail, str, "") { return arg.detail == str; } 25 26 TEST(DumpASTTests, BasicInfo) { 27 std::pair</*Code=*/std::string, /*Expected=*/std::string> Cases[] = { 28 {R"cpp( 29 float root(int *x) { 30 return *x + 1; 31 } 32 )cpp", 33 R"( 34 declaration: 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( 51 namespace root { 52 struct S { static const int x = 0; ~S(); }; 53 int y = S::x + root::S().x; 54 } 55 )cpp", 56 R"( 57 declaration: 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: TypeSpec 76 type: Record - S 77 expression: ImplicitCast - LValueToRValue 78 expression: Member - x 79 expression: CXXBindTemporary 80 expression: CXXTemporaryObject - S 81 type: Elaborated 82 specifier: Namespace - root:: 83 type: Record - S 84 )"}, 85 {R"cpp( 86 namespace root { 87 struct S { static const int x = 0; }; 88 int y = S::x + root::S().x; 89 } 90 )cpp", 91 R"( 92 declaration: Namespace - root 93 declaration: CXXRecord - S 94 declaration: Var - x 95 type: Qualified - const 96 type: Builtin - int 97 expression: IntegerLiteral - 0 98 declaration: CXXConstructor 99 declaration: CXXConstructor 100 declaration: CXXConstructor 101 declaration: CXXDestructor 102 declaration: Var - y 103 type: Builtin - int 104 expression: BinaryOperator - + 105 expression: ImplicitCast - LValueToRValue 106 expression: DeclRef - x 107 specifier: TypeSpec 108 type: Record - S 109 expression: ImplicitCast - LValueToRValue 110 expression: Member - x 111 expression: CXXTemporaryObject - S 112 type: Elaborated 113 specifier: Namespace - root:: 114 type: Record - S 115 )"}, 116 {R"cpp( 117 namespace root { 118 template <typename T> int tmpl() { 119 (void)tmpl<unsigned>(); 120 return T::value; 121 } 122 } 123 )cpp", 124 R"( 125 declaration: Namespace - root 126 declaration: FunctionTemplate - tmpl 127 declaration: TemplateTypeParm - T 128 declaration: Function - tmpl 129 type: FunctionProto 130 type: Builtin - int 131 statement: Compound 132 expression: CStyleCast - ToVoid 133 type: Builtin - void 134 expression: Call 135 expression: ImplicitCast - FunctionToPointerDecay 136 expression: DeclRef - tmpl 137 template argument: Type 138 type: Builtin - unsigned int 139 statement: Return 140 expression: DependentScopeDeclRef - value 141 specifier: TypeSpec 142 type: TemplateTypeParm - T 143 )"}, 144 {R"cpp( 145 struct Foo { char operator+(int); }; 146 char root = Foo() + 42; 147 )cpp", 148 R"( 149 declaration: Var - root 150 type: Builtin - char 151 expression: ExprWithCleanups 152 expression: CXXOperatorCall 153 expression: ImplicitCast - FunctionToPointerDecay 154 expression: DeclRef - operator+ 155 expression: MaterializeTemporary - lvalue 156 expression: CXXTemporaryObject - Foo 157 type: Elaborated 158 type: Record - Foo 159 expression: IntegerLiteral - 42 160 )"}, 161 {R"cpp( 162 struct Bar { 163 int x; 164 int root() const { 165 return x; 166 } 167 }; 168 )cpp", 169 R"( 170 declaration: CXXMethod - root 171 type: FunctionProto 172 type: Builtin - int 173 statement: Compound 174 statement: Return 175 expression: ImplicitCast - LValueToRValue 176 expression: Member - x 177 expression: CXXThis - const, implicit 178 )"}, 179 }; 180 for (const auto &Case : Cases) { 181 ParsedAST AST = TestTU::withCode(Case.first).build(); 182 auto Node = dumpAST(DynTypedNode::create(findUnqualifiedDecl(AST, "root")), 183 AST.getTokens(), AST.getASTContext()); 184 EXPECT_EQ(llvm::StringRef(Case.second).trim(), 185 llvm::StringRef(llvm::to_string(Node)).trim()); 186 } 187 } 188 189 TEST(DumpASTTests, Range) { 190 Annotations Case("$var[[$type[[int]] x]];"); 191 ParsedAST AST = TestTU::withCode(Case.code()).build(); 192 auto Node = dumpAST(DynTypedNode::create(findDecl(AST, "x")), AST.getTokens(), 193 AST.getASTContext()); 194 EXPECT_EQ(Node.range, Case.range("var")); 195 ASSERT_THAT(Node.children, SizeIs(1)) << "Expected one child typeloc"; 196 EXPECT_EQ(Node.children.front().range, Case.range("type")); 197 } 198 199 TEST(DumpASTTests, NoRange) { 200 auto TU = TestTU::withHeaderCode("void funcFromHeader();"); 201 TU.Code = "int varFromSource;"; 202 ParsedAST AST = TU.build(); 203 auto Node = dumpAST( 204 DynTypedNode::create(*AST.getASTContext().getTranslationUnitDecl()), 205 AST.getTokens(), AST.getASTContext()); 206 ASSERT_THAT(Node.children, Contains(withDetail("varFromSource"))); 207 ASSERT_THAT(Node.children, Not(Contains(withDetail("funcFromHeader")))); 208 EXPECT_THAT(Node.arcana, testing::StartsWith("TranslationUnitDecl ")); 209 ASSERT_FALSE(Node.range) << "Expected no range for translation unit"; 210 } 211 212 TEST(DumpASTTests, Arcana) { 213 ParsedAST AST = TestTU::withCode("int x;").build(); 214 auto Node = dumpAST(DynTypedNode::create(findDecl(AST, "x")), AST.getTokens(), 215 AST.getASTContext()); 216 EXPECT_THAT(Node.arcana, testing::StartsWith("VarDecl ")); 217 EXPECT_THAT(Node.arcana, testing::EndsWith(" 'int'")); 218 ASSERT_THAT(Node.children, SizeIs(1)) << "Expected one child typeloc"; 219 EXPECT_THAT(Node.children.front().arcana, testing::StartsWith("QualType ")); 220 } 221 222 TEST(DumpASTTests, UnbalancedBraces) { 223 // Test that we don't crash while trying to compute a source range for the 224 // node whose ending brace is missing, and also that the source range is 225 // not empty. 226 Annotations Case("/*error-ok*/ $func[[int main() {]]"); 227 ParsedAST AST = TestTU::withCode(Case.code()).build(); 228 auto Node = dumpAST(DynTypedNode::create(findDecl(AST, "main")), 229 AST.getTokens(), AST.getASTContext()); 230 ASSERT_EQ(Node.range, Case.range("func")); 231 } 232 233 } // namespace 234 } // namespace clangd 235 } // namespace clang 236