//===- unittests/AST/DeclPrinterTest.cpp --- Declaration printer tests ----===// // // 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 Decl::print() and related methods. // // Search this file for WRONG to see test cases that are producing something // completely wrong, invalid C++ or just misleading. // // These tests have a coding convention: // * declaration to be printed is named 'A' unless it should have some special // name (e.g., 'operator+'); // * additional helper declarations are 'Z', 'Y', 'X' and so on. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "gtest/gtest.h" using namespace clang; using namespace ast_matchers; using namespace tooling; namespace { using PrintingPolicyModifier = void (*)(PrintingPolicy &policy); void PrintDecl(raw_ostream &Out, const ASTContext *Context, const Decl *D, PrintingPolicyModifier PolicyModifier) { PrintingPolicy Policy = Context->getPrintingPolicy(); Policy.TerseOutput = true; Policy.Indentation = 0; if (PolicyModifier) PolicyModifier(Policy); D->print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ false); } class PrintMatch : public MatchFinder::MatchCallback { SmallString<1024> Printed; unsigned NumFoundDecls; PrintingPolicyModifier PolicyModifier; public: PrintMatch(PrintingPolicyModifier PolicyModifier) : NumFoundDecls(0), PolicyModifier(PolicyModifier) {} void run(const MatchFinder::MatchResult &Result) override { const Decl *D = Result.Nodes.getNodeAs("id"); if (!D || D->isImplicit()) return; NumFoundDecls++; if (NumFoundDecls > 1) return; llvm::raw_svector_ostream Out(Printed); PrintDecl(Out, Result.Context, D, PolicyModifier); } StringRef getPrinted() const { return Printed; } unsigned getNumFoundDecls() const { return NumFoundDecls; } }; ::testing::AssertionResult PrintedDeclMatches(StringRef Code, const std::vector &Args, const DeclarationMatcher &NodeMatch, StringRef ExpectedPrinted, StringRef FileName, PrintingPolicyModifier PolicyModifier = nullptr, bool AllowError = false) { PrintMatch Printer(PolicyModifier); MatchFinder Finder; Finder.addMatcher(NodeMatch, &Printer); std::unique_ptr Factory( newFrontendActionFactory(&Finder)); if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName) && !AllowError) return testing::AssertionFailure() << "Parsing error in \"" << Code.str() << "\""; if (Printer.getNumFoundDecls() == 0) return testing::AssertionFailure() << "Matcher didn't find any declarations"; if (Printer.getNumFoundDecls() > 1) return testing::AssertionFailure() << "Matcher should match only one declaration " "(found " << Printer.getNumFoundDecls() << ")"; if (Printer.getPrinted() != ExpectedPrinted) return ::testing::AssertionFailure() << "Expected \"" << ExpectedPrinted.str() << "\", " "got \"" << Printer.getPrinted().str() << "\""; return ::testing::AssertionSuccess(); } ::testing::AssertionResult PrintedDeclCXX98Matches(StringRef Code, StringRef DeclName, StringRef ExpectedPrinted, PrintingPolicyModifier PolicyModifier = nullptr) { std::vector Args(1, "-std=c++98"); return PrintedDeclMatches(Code, Args, namedDecl(hasName(DeclName)).bind("id"), ExpectedPrinted, "input.cc", PolicyModifier); } ::testing::AssertionResult PrintedDeclCXX98Matches(StringRef Code, const DeclarationMatcher &NodeMatch, StringRef ExpectedPrinted, PrintingPolicyModifier PolicyModifier = nullptr) { std::vector Args(1, "-std=c++98"); return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, "input.cc", PolicyModifier); } ::testing::AssertionResult PrintedDeclCXX11Matches(StringRef Code, StringRef DeclName, StringRef ExpectedPrinted) { std::vector Args(1, "-std=c++11"); return PrintedDeclMatches(Code, Args, namedDecl(hasName(DeclName)).bind("id"), ExpectedPrinted, "input.cc"); } ::testing::AssertionResult PrintedDeclCXX11Matches( StringRef Code, const DeclarationMatcher &NodeMatch, StringRef ExpectedPrinted) { std::vector Args(1, "-std=c++11"); return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, "input.cc"); } ::testing::AssertionResult PrintedDeclCXX11nonMSCMatches( StringRef Code, const DeclarationMatcher &NodeMatch, StringRef ExpectedPrinted) { std::vector Args{"-std=c++11", "-fno-delayed-template-parsing"}; return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, "input.cc"); } ::testing::AssertionResult PrintedDeclCXX17Matches(StringRef Code, const DeclarationMatcher &NodeMatch, StringRef ExpectedPrinted, PrintingPolicyModifier PolicyModifier = nullptr) { std::vector Args{"-std=c++17", "-fno-delayed-template-parsing"}; return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, "input.cc", PolicyModifier); } ::testing::AssertionResult PrintedDeclC11Matches(StringRef Code, const DeclarationMatcher &NodeMatch, StringRef ExpectedPrinted, PrintingPolicyModifier PolicyModifier = nullptr) { std::vector Args(1, "-std=c11"); return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, "input.c", PolicyModifier); } ::testing::AssertionResult PrintedDeclObjCMatches(StringRef Code, const DeclarationMatcher &NodeMatch, StringRef ExpectedPrinted, bool AllowError = false) { std::vector Args(1, ""); return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, "input.m", /*PolicyModifier=*/nullptr, AllowError); } } // unnamed namespace TEST(DeclPrinter, TestTypedef1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "typedef int A;", "A", "typedef int A")); // Should be: with semicolon } TEST(DeclPrinter, TestTypedef2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "typedef const char *A;", "A", "typedef const char *A")); // Should be: with semicolon } TEST(DeclPrinter, TestTypedef3) { ASSERT_TRUE(PrintedDeclCXX98Matches( "template class X {};" "typedef X A;", "A", "typedef X A")); // Should be: with semicolon } TEST(DeclPrinter, TestTypedef4) { ASSERT_TRUE(PrintedDeclCXX98Matches( "namespace X { class Y {}; }" "typedef X::Y A;", "A", "typedef X::Y A")); // Should be: with semicolon } TEST(DeclPrinter, TestNamespace1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "namespace A { int B; }", "A", "namespace A {\n}")); // Should be: with { ... } } TEST(DeclPrinter, TestNamespace2) { ASSERT_TRUE(PrintedDeclCXX11Matches( "inline namespace A { int B; }", "A", "inline namespace A {\n}")); // Should be: with { ... } } TEST(DeclPrinter, TestNamespaceAlias1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "namespace Z { }" "namespace A = Z;", "A", "namespace A = Z")); // Should be: with semicolon } TEST(DeclPrinter, TestNamespaceAlias2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "namespace X { namespace Y {} }" "namespace A = X::Y;", "A", "namespace A = X::Y")); // Should be: with semicolon } TEST(DeclPrinter, TestNamespaceUnnamed) { ASSERT_TRUE(PrintedDeclCXX17Matches( "namespace { int X; }", namespaceDecl(has(varDecl(hasName("X")))).bind("id"), "namespace {\nint X;\n}", [](PrintingPolicy &Policy) { Policy.TerseOutput = false; })); } TEST(DeclPrinter, TestNamespaceUsingDirective) { ASSERT_TRUE(PrintedDeclCXX17Matches( "namespace X { namespace A {} }" "using namespace X::A;", usingDirectiveDecl().bind("id"), "using namespace X::A", [](PrintingPolicy &Policy) { Policy.TerseOutput = false; })); } TEST(DeclPrinter, TestEnumDecl1) { ASSERT_TRUE(PrintedDeclCXX17Matches( "enum A { a0, a1, a2 };", enumDecl(hasName("A")).bind("id"), "enum A {\na0,\na1,\na2\n}", [](PrintingPolicy &Policy) { Policy.TerseOutput = false; })); } TEST(DeclPrinter, TestEnumDecl2) { ASSERT_TRUE(PrintedDeclCXX17Matches( "enum A { a0 = -1, a1, a2 = 1 };", enumDecl(hasName("A")).bind("id"), "enum A {\na0 = -1,\na1,\na2 = 1\n}", [](PrintingPolicy &Policy) { Policy.TerseOutput = false; })); } TEST(DeclPrinter, TestEnumDecl3) { ASSERT_TRUE(PrintedDeclCXX17Matches( "enum { a0, a1, a2 };", enumDecl(has(enumConstantDecl(hasName("a0")))).bind("id"), "enum {\na0,\na1,\na2\n}", [](PrintingPolicy &Policy) { Policy.TerseOutput = false; })); } TEST(DeclPrinter, TestEnumDecl4) { ASSERT_TRUE(PrintedDeclCXX17Matches( "enum class A { a0, a1, a2 };", enumDecl(hasName("A")).bind("id"), "enum class A : int {\na0,\na1,\na2\n}", [](PrintingPolicy &Policy) { Policy.TerseOutput = false; })); } TEST(DeclPrinter, TestRecordDecl1) { ASSERT_TRUE(PrintedDeclC11Matches( "struct A { int a; };", recordDecl(hasName("A")).bind("id"), "struct A {\nint a;\n}", [](PrintingPolicy &Policy) { Policy.TerseOutput = false; })); } TEST(DeclPrinter, TestRecordDecl2) { ASSERT_TRUE(PrintedDeclC11Matches( "struct A { struct { int i; }; };", recordDecl(hasName("A")).bind("id"), "struct A {\nstruct {\nint i;\n};\n}", [](PrintingPolicy &Policy) { Policy.TerseOutput = false; })); } TEST(DeclPrinter, TestRecordDecl3) { ASSERT_TRUE(PrintedDeclC11Matches( "union { int A; } u;", recordDecl(has(fieldDecl(hasName("A")))).bind("id"), "union {\nint A;\n}", [](PrintingPolicy &Policy) { Policy.TerseOutput = false; })); } TEST(DeclPrinter, TestCXXRecordDecl1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "class A { int a; };", "A", "class A {}")); } TEST(DeclPrinter, TestCXXRecordDecl2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct A { int a; };", "A", "struct A {}")); } TEST(DeclPrinter, TestCXXRecordDecl3) { ASSERT_TRUE(PrintedDeclCXX98Matches( "union A { int a; };", "A", "union A {}")); } TEST(DeclPrinter, TestCXXRecordDecl4) { ASSERT_TRUE(PrintedDeclCXX98Matches( "class Z { int a; };" "class A : Z { int b; };", "A", "class A : Z {}")); } TEST(DeclPrinter, TestCXXRecordDecl5) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct Z { int a; };" "struct A : Z { int b; };", "A", "struct A : Z {}")); } TEST(DeclPrinter, TestCXXRecordDecl6) { ASSERT_TRUE(PrintedDeclCXX98Matches( "class Z { int a; };" "class A : public Z { int b; };", "A", "class A : public Z {}")); } TEST(DeclPrinter, TestCXXRecordDecl7) { ASSERT_TRUE(PrintedDeclCXX98Matches( "class Z { int a; };" "class A : protected Z { int b; };", "A", "class A : protected Z {}")); } TEST(DeclPrinter, TestCXXRecordDecl8) { ASSERT_TRUE(PrintedDeclCXX98Matches( "class Z { int a; };" "class A : private Z { int b; };", "A", "class A : private Z {}")); } TEST(DeclPrinter, TestCXXRecordDecl9) { ASSERT_TRUE(PrintedDeclCXX98Matches( "class Z { int a; };" "class A : virtual Z { int b; };", "A", "class A : virtual Z {}")); } TEST(DeclPrinter, TestCXXRecordDecl10) { ASSERT_TRUE(PrintedDeclCXX98Matches( "class Z { int a; };" "class A : virtual public Z { int b; };", "A", "class A : virtual public Z {}")); } TEST(DeclPrinter, TestCXXRecordDecl11) { ASSERT_TRUE(PrintedDeclCXX98Matches( "class Z { int a; };" "class Y : virtual public Z { int b; };" "class A : virtual public Z, private Y { int c; };", "A", "class A : virtual public Z, private Y {}")); } TEST(DeclPrinter, TestFunctionDecl1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "void A();", "A", "void A()")); } TEST(DeclPrinter, TestFreeFunctionDecl_FullyQualifiedName) { ASSERT_TRUE(PrintedDeclCXX98Matches( "void A();", "A", "void A()", [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; })); } TEST(DeclPrinter, TestFreeFunctionDeclInNamespace_FullyQualifiedName) { ASSERT_TRUE(PrintedDeclCXX98Matches( "namespace X { void A(); };", "A", "void X::A()", [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; })); } TEST(DeclPrinter, TestMemberFunction_FullyQualifiedName) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct X { void A(); };", "A", "void X::A()", [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; })); } TEST(DeclPrinter, TestMemberFunctionInNamespace_FullyQualifiedName) { ASSERT_TRUE(PrintedDeclCXX98Matches( "namespace Z { struct X { void A(); }; }", "A", "void Z::X::A()", [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; })); } TEST(DeclPrinter, TestMemberFunctionOutside_FullyQualifiedName) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct X { void A(); };" "void X::A() {}", functionDecl(hasName("A"), isDefinition()).bind("id"), "void X::A()", [](PrintingPolicy &Policy){ Policy.FullyQualifiedName = true; })); } TEST(DeclPrinter, TestFunctionDecl2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "void A() {}", "A", "void A()")); } TEST(DeclPrinter, TestFunctionDecl3) { ASSERT_TRUE(PrintedDeclCXX98Matches( "void Z();" "void A() { Z(); }", "A", "void A()")); } TEST(DeclPrinter, TestFunctionDecl4) { ASSERT_TRUE(PrintedDeclCXX98Matches( "extern void A();", "A", "extern void A()")); } TEST(DeclPrinter, TestFunctionDecl5) { ASSERT_TRUE(PrintedDeclCXX98Matches( "static void A();", "A", "static void A()")); } TEST(DeclPrinter, TestFunctionDecl6) { ASSERT_TRUE(PrintedDeclCXX98Matches( "inline void A();", "A", "inline void A()")); } TEST(DeclPrinter, TestFunctionDecl7) { ASSERT_TRUE(PrintedDeclCXX11Matches( "constexpr int A(int a);", "A", "constexpr int A(int a)")); } TEST(DeclPrinter, TestFunctionDecl8) { ASSERT_TRUE(PrintedDeclCXX98Matches( "void A(int a);", "A", "void A(int a)")); } TEST(DeclPrinter, TestFunctionDecl9) { ASSERT_TRUE(PrintedDeclCXX98Matches( "void A(...);", "A", "void A(...)")); } TEST(DeclPrinter, TestFunctionDecl10) { ASSERT_TRUE(PrintedDeclCXX98Matches( "void A(int a, ...);", "A", "void A(int a, ...)")); } TEST(DeclPrinter, TestFunctionDecl11) { ASSERT_TRUE(PrintedDeclCXX98Matches( "typedef long ssize_t;" "typedef int *pInt;" "void A(int a, pInt b, ssize_t c);", "A", "void A(int a, pInt b, ssize_t c)")); } TEST(DeclPrinter, TestFunctionDecl12) { ASSERT_TRUE(PrintedDeclCXX98Matches( "void A(int a, int b = 0);", "A", "void A(int a, int b = 0)")); } TEST(DeclPrinter, TestFunctionDecl13) { ASSERT_TRUE(PrintedDeclCXX98Matches( "void (*A(int a))(int b);", "A", "void (*A(int a))(int)")); // Should be: with parameter name (?) } TEST(DeclPrinter, TestFunctionDecl14) { ASSERT_TRUE(PrintedDeclCXX98Matches( "template" "void A(T t) { }" "template<>" "void A(int N) { }", functionDecl(hasName("A"), isExplicitTemplateSpecialization()).bind("id"), "template<> void A(int N)")); } TEST(DeclPrinter, TestCXXConstructorDecl1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct A {" " A();" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A()")); } TEST(DeclPrinter, TestCXXConstructorDecl2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct A {" " A(int a);" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A(int a)")); } TEST(DeclPrinter, TestCXXConstructorDecl3) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct A {" " A(const A &a);" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A(const A &a)")); } TEST(DeclPrinter, TestCXXConstructorDecl4) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct A {" " A(const A &a, int = 0);" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A(const A &a, int = 0)")); } TEST(DeclPrinter, TestCXXConstructorDeclWithMemberInitializer) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct A {" " int m;" " A() : m(2) {}" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A()")); } TEST(DeclPrinter, TestCXXConstructorDeclWithMemberInitializer_NoTerseOutput) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct A {" " int m;" " A() : m(2) {}" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A() : m(2) {\n}\n", [](PrintingPolicy &Policy){ Policy.TerseOutput = false; })); } TEST(DeclPrinter, TestCXXConstructorDecl5) { ASSERT_TRUE(PrintedDeclCXX11Matches( "struct A {" " A(const A &&a);" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A(const A &&a)")); } TEST(DeclPrinter, TestCXXConstructorDecl6) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct A {" " explicit A(int a);" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "explicit A(int a)")); } TEST(DeclPrinter, TestCXXConstructorDecl7) { ASSERT_TRUE(PrintedDeclCXX11Matches( "struct A {" " constexpr A();" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "constexpr A()")); } TEST(DeclPrinter, TestCXXConstructorDecl8) { ASSERT_TRUE(PrintedDeclCXX11Matches( "struct A {" " A() = default;" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A() = default")); } TEST(DeclPrinter, TestCXXConstructorDecl9) { ASSERT_TRUE(PrintedDeclCXX11Matches( "struct A {" " A() = delete;" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A() = delete")); } TEST(DeclPrinter, TestCXXConstructorDecl10) { ASSERT_TRUE(PrintedDeclCXX11Matches( "template" "struct A {" " A(const A &a);" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A(const A &a)")); } TEST(DeclPrinter, TestCXXConstructorDecl11) { ASSERT_TRUE(PrintedDeclCXX11nonMSCMatches( "template" "struct A : public T... {" " A(T&&... ts) : T(ts)... {}" "};", cxxConstructorDecl(ofClass(hasName("A"))).bind("id"), "A(T &&...ts)")); } TEST(DeclPrinter, TestCXXDestructorDecl1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct A {" " ~A();" "};", cxxDestructorDecl(ofClass(hasName("A"))).bind("id"), "~A()")); } TEST(DeclPrinter, TestCXXDestructorDecl2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct A {" " virtual ~A();" "};", cxxDestructorDecl(ofClass(hasName("A"))).bind("id"), "virtual ~A()")); } TEST(DeclPrinter, TestCXXConversionDecl1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct A {" " operator int();" "};", cxxMethodDecl(ofClass(hasName("A"))).bind("id"), "operator int()")); } TEST(DeclPrinter, TestCXXConversionDecl2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct A {" " operator bool();" "};", cxxMethodDecl(ofClass(hasName("A"))).bind("id"), "operator bool()")); } TEST(DeclPrinter, TestCXXConversionDecl3) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct Z {};" "struct A {" " operator Z();" "};", cxxMethodDecl(ofClass(hasName("A"))).bind("id"), "operator Z()")); } TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction1) { ASSERT_TRUE(PrintedDeclCXX11Matches( "namespace std { typedef decltype(sizeof(int)) size_t; }" "struct Z {" " void *operator new(std::size_t);" "};", cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), "void *operator new(std::size_t)")); } TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction2) { ASSERT_TRUE(PrintedDeclCXX11Matches( "namespace std { typedef decltype(sizeof(int)) size_t; }" "struct Z {" " void *operator new[](std::size_t);" "};", cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), "void *operator new[](std::size_t)")); } TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction3) { ASSERT_TRUE(PrintedDeclCXX11Matches( "struct Z {" " void operator delete(void *);" "};", cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), "void operator delete(void *) noexcept")); // Should be: without noexcept? } TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction4) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct Z {" " void operator delete(void *);" "};", cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), "void operator delete(void *)")); } TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction5) { ASSERT_TRUE(PrintedDeclCXX11Matches( "struct Z {" " void operator delete[](void *);" "};", cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), "void operator delete[](void *) noexcept")); // Should be: without noexcept? } TEST(DeclPrinter, TestCXXMethodDecl_Operator1) { const char *OperatorNames[] = { "+", "-", "*", "/", "%", "^", "&", "|", "=", "<", ">", "+=", "-=", "*=", "/=", "%=", "^=", "&=", "|=", "<<", ">>", ">>=", "<<=", "==", "!=", "<=", ">=", "&&", "||", ",", "->*", "()", "[]" }; for (unsigned i = 0, e = llvm::array_lengthof(OperatorNames); i != e; ++i) { SmallString<128> Code; Code.append("struct Z { void operator"); Code.append(OperatorNames[i]); Code.append("(Z z); };"); SmallString<128> Expected; Expected.append("void operator"); Expected.append(OperatorNames[i]); Expected.append("(Z z)"); ASSERT_TRUE(PrintedDeclCXX98Matches( Code, cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), Expected)); } } TEST(DeclPrinter, TestCXXMethodDecl_Operator2) { const char *OperatorNames[] = { "~", "!", "++", "--", "->" }; for (unsigned i = 0, e = llvm::array_lengthof(OperatorNames); i != e; ++i) { SmallString<128> Code; Code.append("struct Z { void operator"); Code.append(OperatorNames[i]); Code.append("(); };"); SmallString<128> Expected; Expected.append("void operator"); Expected.append(OperatorNames[i]); Expected.append("()"); ASSERT_TRUE(PrintedDeclCXX98Matches( Code, cxxMethodDecl(ofClass(hasName("Z"))).bind("id"), Expected)); } } TEST(DeclPrinter, TestCXXMethodDecl1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct Z {" " void A(int a);" "};", "A", "void A(int a)")); } TEST(DeclPrinter, TestCXXMethodDecl2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct Z {" " virtual void A(int a);" "};", "A", "virtual void A(int a)")); } TEST(DeclPrinter, TestCXXMethodDecl3) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct Z {" " virtual void A(int a);" "};" "struct ZZ : Z {" " void A(int a);" "};", "ZZ::A", "void A(int a)")); // TODO: should we print "virtual"? } TEST(DeclPrinter, TestCXXMethodDecl4) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct Z {" " inline void A(int a);" "};", "A", "inline void A(int a)")); } TEST(DeclPrinter, TestCXXMethodDecl5) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct Z {" " virtual void A(int a) = 0;" "};", "A", "virtual void A(int a) = 0")); } TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct Z {" " void A(int a) const;" "};", "A", "void A(int a) const")); } TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct Z {" " void A(int a) volatile;" "};", "A", "void A(int a) volatile")); } TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier3) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct Z {" " void A(int a) const volatile;" "};", "A", "void A(int a) const volatile")); } TEST(DeclPrinter, TestCXXMethodDecl_RefQualifier1) { ASSERT_TRUE(PrintedDeclCXX11Matches( "struct Z {" " void A(int a) &;" "};", "A", "void A(int a) &")); } TEST(DeclPrinter, TestCXXMethodDecl_RefQualifier2) { ASSERT_TRUE(PrintedDeclCXX11Matches( "struct Z {" " void A(int a) &&;" "};", "A", "void A(int a) &&")); } TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct Z {" " void A(int a) throw();" "};", "A", "void A(int a) throw()")); } TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "struct Z {" " void A(int a) throw(int);" "};", "A", "void A(int a) throw(int)")); } TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification3) { ASSERT_TRUE(PrintedDeclCXX98Matches( "class ZZ {};" "struct Z {" " void A(int a) throw(ZZ, int);" "};", "A", "void A(int a) throw(ZZ, int)")); } TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification4) { ASSERT_TRUE(PrintedDeclCXX11Matches( "struct Z {" " void A(int a) noexcept;" "};", "A", "void A(int a) noexcept")); } TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification5) { ASSERT_TRUE(PrintedDeclCXX11Matches( "struct Z {" " void A(int a) noexcept(true);" "};", "A", "void A(int a) noexcept(trueA(int a) noexcept(true)")); // WRONG; Should be: "void A(int a) noexcept(true);" } TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification6) { ASSERT_TRUE(PrintedDeclCXX11Matches( "struct Z {" " void A(int a) noexcept(1 < 2);" "};", "A", "void A(int a) noexcept(1 < 2A(int a) noexcept(1 < 2)")); // WRONG; Should be: "void A(int a) noexcept(1 < 2);" } TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification7) { ASSERT_TRUE(PrintedDeclCXX11Matches( "template" "struct Z {" " void A(int a) noexcept(N < 2);" "};", "A", "void A(int a) noexcept(N < 2A(int a) noexcept(N < 2)")); // WRONG; Should be: "void A(int a) noexcept(N < 2);" } TEST(DeclPrinter, TestVarDecl1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "char *const (*(*A)[5])(int);", "A", "char *const (*(*A)[5])(int)")); // Should be: with semicolon } TEST(DeclPrinter, TestVarDecl2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "void (*A)() throw(int);", "A", "void (*A)() throw(int)")); // Should be: with semicolon } TEST(DeclPrinter, TestVarDecl3) { ASSERT_TRUE(PrintedDeclCXX11Matches( "void (*A)() noexcept;", "A", "void (*A)() noexcept")); // Should be: with semicolon } TEST(DeclPrinter, TestFieldDecl1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "template" "struct Z { T A; };", "A", "T A")); // Should be: with semicolon } TEST(DeclPrinter, TestFieldDecl2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "template" "struct Z { int A[N]; };", "A", "int A[N]")); // Should be: with semicolon } TEST(DeclPrinter, TestClassTemplateDecl1) { ASSERT_TRUE(PrintedDeclCXX98Matches( "template" "struct A { T a; };", classTemplateDecl(hasName("A")).bind("id"), "template struct A {}")); } TEST(DeclPrinter, TestClassTemplateDecl2) { ASSERT_TRUE(PrintedDeclCXX98Matches( "template" "struct A { T a; };", classTemplateDecl(hasName("A")).bind("id"), "template struct A {}")); } TEST(DeclPrinter, TestClassTemplateDecl3) { ASSERT_TRUE(PrintedDeclCXX98Matches( "template" "struct A { T a; };", classTemplateDecl(hasName("A")).bind("id"), "template struct A {}")); } TEST(DeclPrinter, TestClassTemplateDecl4) { ASSERT_TRUE(PrintedDeclCXX98Matches( "template" "struct A { T a; U b; };", classTemplateDecl(hasName("A")).bind("id"), "template struct A {}")); } TEST(DeclPrinter, TestClassTemplateDecl5) { ASSERT_TRUE(PrintedDeclCXX98Matches( "template" "struct A { int a[N]; };", classTemplateDecl(hasName("A")).bind("id"), "template struct A {}")); } TEST(DeclPrinter, TestClassTemplateDecl6) { ASSERT_TRUE(PrintedDeclCXX98Matches( "template" "struct A { int a[N]; };", classTemplateDecl(hasName("A")).bind("id"), "template struct A {}")); } TEST(DeclPrinter, TestClassTemplateDecl7) { ASSERT_TRUE(PrintedDeclCXX98Matches( "typedef int MyInt;" "template" "struct A { int a[N]; };", classTemplateDecl(hasName("A")).bind("id"), "template struct A {}")); } TEST(DeclPrinter, TestClassTemplateDecl8) { ASSERT_TRUE(PrintedDeclCXX98Matches( "template class T> struct A { };", classTemplateDecl(hasName("A")).bind("id"), "template