| 1 | //===- unittests/AST/ASTDumperTest.cpp --- Test of AST node dump() methods ===// |
| 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 | // This file contains tests for TypeLoc::dump() and related methods. |
| 10 | // Most of these are lit tests via clang -ast-dump. However some nodes are not |
| 11 | // included in dumps of (TranslationUnit)Decl, but still relevant when dumped |
| 12 | // directly. |
| 13 | // |
| 14 | //===----------------------------------------------------------------------===// |
| 15 | |
| 16 | #include "ASTPrint.h" |
| 17 | #include "clang/AST/ASTContext.h" |
| 18 | #include "clang/AST/Decl.h" |
| 19 | #include "clang/Testing/TestAST.h" |
| 20 | #include "llvm/ADT/StringRef.h" |
| 21 | #include "gmock/gmock.h" |
| 22 | #include "gtest/gtest.h" |
| 23 | |
| 24 | using namespace clang; |
| 25 | using namespace ast_matchers; |
| 26 | |
| 27 | namespace { |
| 28 | using testing::ElementsAre; |
| 29 | using testing::StartsWith; |
| 30 | |
| 31 | std::vector<std::string> dumpTypeLoc(llvm::StringRef Name, ASTContext &Ctx) { |
| 32 | auto Lookup = Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get(Name)); |
| 33 | DeclaratorDecl *D = nullptr; |
| 34 | if ((D = Lookup.find_first<DeclaratorDecl>())) |
| 35 | ; |
| 36 | else if (auto *TD = Lookup.find_first<FunctionTemplateDecl>()) |
| 37 | D = TD->getTemplatedDecl(); |
| 38 | EXPECT_NE(D, nullptr) << Name; |
| 39 | if (!D) |
| 40 | return {}; |
| 41 | EXPECT_NE(D->getTypeSourceInfo(), nullptr); |
| 42 | if (!D->getTypeSourceInfo()) |
| 43 | return {}; |
| 44 | std::string S; |
| 45 | { |
| 46 | llvm::raw_string_ostream OS(S); |
| 47 | D->getTypeSourceInfo()->getTypeLoc().dump(OS, Ctx); |
| 48 | } |
| 49 | // Split result into lines. |
| 50 | std::vector<std::string> Result; |
| 51 | auto Remaining = llvm::StringRef(S).trim(Chars: "\n" ); |
| 52 | while (!Remaining.empty()) { |
| 53 | auto [First, Rest] = Remaining.split(Separator: '\n'); |
| 54 | Result.push_back(x: First.str()); |
| 55 | Remaining = Rest; |
| 56 | } |
| 57 | return Result; |
| 58 | } |
| 59 | |
| 60 | TEST(ASTDumper, TypeLocChain) { |
| 61 | TestAST AST(R"cc( |
| 62 | const int **x; |
| 63 | )cc" ); |
| 64 | EXPECT_THAT( |
| 65 | dumpTypeLoc("x" , AST.context()), |
| 66 | ElementsAre("" |
| 67 | "PointerTypeLoc <input.mm:2:11, col:16> 'const int **'" , |
| 68 | "`-PointerTypeLoc <col:11, col:15> 'const int *'" , |
| 69 | " `-QualifiedTypeLoc <col:11> 'const int'" , |
| 70 | " `-BuiltinTypeLoc <col:11> 'int'" )); |
| 71 | } |
| 72 | |
| 73 | TEST(ASTDumper, AutoType) { |
| 74 | TestInputs Inputs(R"cc( |
| 75 | template <class, class> concept C = true; |
| 76 | C<int> auto str1 = "hello"; |
| 77 | auto str2 = "hello"; |
| 78 | )cc" ); |
| 79 | Inputs.ExtraArgs.push_back(x: "-std=c++20" ); |
| 80 | TestAST AST(Inputs); |
| 81 | EXPECT_THAT( |
| 82 | dumpTypeLoc("str1" , AST.context()), |
| 83 | ElementsAre("" |
| 84 | "AutoTypeLoc <input.mm:3:5, col:12> 'C<int> auto' undeduced" , |
| 85 | StartsWith("|-Concept" ), // |
| 86 | "`-TemplateArgument <col:7> type 'int'" , |
| 87 | StartsWith(" `-BuiltinType" ))); |
| 88 | EXPECT_THAT(dumpTypeLoc("str2" , AST.context()), |
| 89 | ElementsAre("" |
| 90 | "AutoTypeLoc <input.mm:4:5> 'auto' undeduced" )); |
| 91 | } |
| 92 | |
| 93 | |
| 94 | TEST(ASTDumper, FunctionTypeLoc) { |
| 95 | TestAST AST(R"cc( |
| 96 | void x(int, double *y); |
| 97 | |
| 98 | auto trailing() -> int; |
| 99 | |
| 100 | template <class T> int tmpl(T&&); |
| 101 | )cc" ); |
| 102 | EXPECT_THAT( |
| 103 | dumpTypeLoc("x" , AST.context()), |
| 104 | ElementsAre("" |
| 105 | "FunctionProtoTypeLoc <input.mm:2:5, col:26> 'void (int, " |
| 106 | "double *)' cdecl" , |
| 107 | StartsWith("|-ParmVarDecl" ), |
| 108 | "| `-BuiltinTypeLoc <col:12> 'int'" , |
| 109 | StartsWith("|-ParmVarDecl" ), |
| 110 | "| `-PointerTypeLoc <col:17, col:24> 'double *'" , |
| 111 | "| `-BuiltinTypeLoc <col:17> 'double'" , |
| 112 | "`-BuiltinTypeLoc <col:5> 'void'" )); |
| 113 | |
| 114 | EXPECT_THAT(dumpTypeLoc("trailing" , AST.context()), |
| 115 | ElementsAre("" |
| 116 | "FunctionProtoTypeLoc <input.mm:4:5, col:24> " |
| 117 | "'auto () -> int' trailing_return cdecl" , |
| 118 | "`-BuiltinTypeLoc <col:24> 'int'" )); |
| 119 | |
| 120 | EXPECT_THAT( |
| 121 | dumpTypeLoc("tmpl" , AST.context()), |
| 122 | ElementsAre("" |
| 123 | "FunctionProtoTypeLoc <input.mm:6:24, col:36> " |
| 124 | "'int (T &&)' cdecl" , |
| 125 | StartsWith("|-ParmVarDecl" ), |
| 126 | "| `-RValueReferenceTypeLoc <col:33, col:34> 'T &&'" , |
| 127 | "| `-TemplateTypeParmTypeLoc <col:33> 'T' depth 0 index 0" , |
| 128 | StartsWith("| `-TemplateTypeParm" ), |
| 129 | "`-BuiltinTypeLoc <col:24> 'int'" )); |
| 130 | |
| 131 | // Dynamic-exception-spec needs C++14 or earlier. |
| 132 | TestInputs Throws(R"cc( |
| 133 | void throws() throw(int); |
| 134 | )cc" ); |
| 135 | Throws.ExtraArgs.push_back(x: "-std=c++14" ); |
| 136 | AST = TestAST(Throws); |
| 137 | EXPECT_THAT(dumpTypeLoc("throws" , AST.context()), |
| 138 | ElementsAre("" |
| 139 | "FunctionProtoTypeLoc <input.mm:2:5, col:28> " |
| 140 | "'void () throw(int)' exceptionspec_dynamic cdecl" , |
| 141 | // FIXME: include TypeLoc for int |
| 142 | "|-Exceptions: 'int'" , |
| 143 | "`-BuiltinTypeLoc <col:5> 'void'" )); |
| 144 | } |
| 145 | |
| 146 | } // namespace |
| 147 | |