233 lines · cpp
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-exception6//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 - root35 type: FunctionProto36 type: Builtin - float37 declaration: ParmVar - x38 type: Pointer39 type: Builtin - int40 statement: Compound41 statement: Return42 expression: ImplicitCast - IntegralToFloating43 expression: BinaryOperator - +44 expression: ImplicitCast - LValueToRValue45 expression: UnaryOperator - *46 expression: ImplicitCast - LValueToRValue47 expression: DeclRef - x48 expression: IntegerLiteral - 149 )"},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 - root58 declaration: CXXRecord - S59 declaration: Var - x60 type: Qualified - const61 type: Builtin - int62 expression: IntegerLiteral - 063 declaration: CXXDestructor64 type: Record - S65 type: FunctionProto66 type: Builtin - void67 declaration: CXXConstructor68 declaration: CXXConstructor69 declaration: Var - y70 type: Builtin - int71 expression: ExprWithCleanups72 expression: BinaryOperator - +73 expression: ImplicitCast - LValueToRValue74 expression: DeclRef - x75 specifier: Type76 type: Record - S77 expression: ImplicitCast - LValueToRValue78 expression: Member - x79 expression: CXXBindTemporary80 expression: CXXTemporaryObject - S81 type: Record - S82 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 - root92 declaration: CXXRecord - S93 declaration: Var - x94 type: Qualified - const95 type: Builtin - int96 expression: IntegerLiteral - 097 declaration: CXXConstructor98 declaration: CXXConstructor99 declaration: CXXConstructor100 declaration: CXXDestructor101 declaration: Var - y102 type: Builtin - int103 expression: BinaryOperator - +104 expression: ImplicitCast - LValueToRValue105 expression: DeclRef - x106 specifier: Type107 type: Record - S108 expression: ImplicitCast - LValueToRValue109 expression: Member - x110 expression: CXXTemporaryObject - S111 type: Record - S112 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 - root124 declaration: FunctionTemplate - tmpl125 declaration: TemplateTypeParm - T126 declaration: Function - tmpl127 type: FunctionProto128 type: Builtin - int129 statement: Compound130 expression: CStyleCast - ToVoid131 type: Builtin - void132 expression: Call133 expression: ImplicitCast - FunctionToPointerDecay134 expression: DeclRef - tmpl135 template argument: Type136 type: Builtin - unsigned int137 statement: Return138 expression: DependentScopeDeclRef - value139 specifier: Type140 type: TemplateTypeParm - T141 )"},142 {R"cpp(143struct Foo { char operator+(int); };144char root = Foo() + 42;145 )cpp",146 R"(147declaration: Var - root148 type: Builtin - char149 expression: ExprWithCleanups150 expression: CXXOperatorCall151 expression: ImplicitCast - FunctionToPointerDecay152 expression: DeclRef - operator+153 expression: MaterializeTemporary - lvalue154 expression: CXXTemporaryObject - Foo155 type: Record - Foo156 expression: IntegerLiteral - 42157 )"},158 {R"cpp(159struct Bar {160 int x;161 int root() const {162 return x;163 }164};165 )cpp",166 R"(167declaration: CXXMethod - root168 type: FunctionProto169 type: Builtin - int170 statement: Compound171 statement: Return172 expression: ImplicitCast - LValueToRValue173 expression: Member - x174 expression: CXXThis - const, implicit175 )"},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 the221 // node whose ending brace is missing, and also that the source range is222 // 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} // namespace231} // namespace clangd232} // namespace clang233