//===- unittests/AST/ASTDumperTest.cpp --- Test of AST node dump() methods ===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains tests for TypeLoc::dump() and related methods. // Most of these are lit tests via clang -ast-dump. However some nodes are not // included in dumps of (TranslationUnit)Decl, but still relevant when dumped // directly. // //===----------------------------------------------------------------------===// #include "ASTPrint.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/Testing/TestAST.h" #include "llvm/ADT/StringRef.h" #include "gmock/gmock.h" #include "gtest/gtest.h" using namespace clang; using namespace ast_matchers; namespace { using testing::ElementsAre; using testing::StartsWith; std::vector dumpTypeLoc(llvm::StringRef Name, ASTContext &Ctx) { auto Lookup = Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get(Name)); DeclaratorDecl *D = nullptr; if ((D = Lookup.find_first())) ; else if (auto *TD = Lookup.find_first()) D = TD->getTemplatedDecl(); EXPECT_NE(D, nullptr) << Name; if (!D) return {}; EXPECT_NE(D->getTypeSourceInfo(), nullptr); if (!D->getTypeSourceInfo()) return {}; std::string S; { llvm::raw_string_ostream OS(S); D->getTypeSourceInfo()->getTypeLoc().dump(OS, Ctx); } // Split result into lines. std::vector Result; auto Remaining = llvm::StringRef(S).trim("\n"); while (!Remaining.empty()) { auto [First, Rest] = Remaining.split('\n'); Result.push_back(First.str()); Remaining = Rest; } return Result; } TEST(ASTDumper, TypeLocChain) { TestAST AST(R"cc( const int **x; )cc"); EXPECT_THAT( dumpTypeLoc("x", AST.context()), ElementsAre("" "PointerTypeLoc 'const int **'", "`-PointerTypeLoc 'const int *'", " `-QualifiedTypeLoc 'const int'", " `-BuiltinTypeLoc 'int'")); } TEST(ASTDumper, AutoType) { TestInputs Inputs(R"cc( template concept C = true; C auto str1 = "hello"; auto str2 = "hello"; )cc"); Inputs.ExtraArgs.push_back("-std=c++20"); TestAST AST(Inputs); EXPECT_THAT( dumpTypeLoc("str1", AST.context()), ElementsAre("" "AutoTypeLoc 'C auto' undeduced", StartsWith("|-Concept"), // "`-TemplateArgument type 'int'", StartsWith(" `-BuiltinType"))); EXPECT_THAT(dumpTypeLoc("str2", AST.context()), ElementsAre("" "AutoTypeLoc 'auto' undeduced")); } TEST(ASTDumper, FunctionTypeLoc) { TestAST AST(R"cc( void x(int, double *y); auto trailing() -> int; template int tmpl(T&&); )cc"); EXPECT_THAT( dumpTypeLoc("x", AST.context()), ElementsAre("" "FunctionProtoTypeLoc 'void (int, " "double *)' cdecl", StartsWith("|-ParmVarDecl"), "| `-BuiltinTypeLoc 'int'", StartsWith("|-ParmVarDecl"), "| `-PointerTypeLoc 'double *'", "| `-BuiltinTypeLoc 'double'", "`-BuiltinTypeLoc 'void'")); EXPECT_THAT(dumpTypeLoc("trailing", AST.context()), ElementsAre("" "FunctionProtoTypeLoc " "'auto () -> int' trailing_return cdecl", "`-BuiltinTypeLoc 'int'")); EXPECT_THAT( dumpTypeLoc("tmpl", AST.context()), ElementsAre("" "FunctionProtoTypeLoc " "'int (T &&)' cdecl", StartsWith("|-ParmVarDecl"), "| `-RValueReferenceTypeLoc 'T &&'", "| `-TemplateTypeParmTypeLoc 'T' depth 0 index 0", StartsWith("| `-TemplateTypeParm"), "`-BuiltinTypeLoc 'int'")); // Dynamic-exception-spec needs C++14 or earlier. TestInputs Throws(R"cc( void throws() throw(int); )cc"); Throws.ExtraArgs.push_back("-std=c++14"); AST = TestAST(Throws); EXPECT_THAT(dumpTypeLoc("throws", AST.context()), ElementsAre("" "FunctionProtoTypeLoc " "'void () throw(int)' exceptionspec_dynamic cdecl", // FIXME: include TypeLoc for int "|-Exceptions: 'int'", "`-BuiltinTypeLoc 'void'")); } } // namespace