268 lines · cpp
1//===- unittests/AST/NamedDeclPrinterTest.cpp --- NamedDecl printer tests -===//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// This file contains tests for NamedDecl::printQualifiedName().10//11// These tests have a coding convention:12// * declaration to be printed is named 'A' unless it should have some special13// name (e.g., 'operator+');14// * additional helper declarations are 'Z', 'Y', 'X' and so on.15//16//===----------------------------------------------------------------------===//17 18#include "ASTPrint.h"19#include "clang/AST/ASTContext.h"20#include "clang/AST/Decl.h"21#include "clang/AST/PrettyPrinter.h"22#include "clang/ASTMatchers/ASTMatchFinder.h"23#include "clang/Tooling/Tooling.h"24#include "llvm/ADT/SmallString.h"25#include "llvm/Support/raw_ostream.h"26#include "gtest/gtest.h"27 28using namespace clang;29using namespace ast_matchers;30using namespace tooling;31 32namespace {33 34class PrintMatch : public MatchFinder::MatchCallback {35 SmallString<1024> Printed;36 unsigned NumFoundDecls;37 std::function<void(llvm::raw_ostream &OS, const NamedDecl *)> Printer;38 39public:40 explicit PrintMatch(41 std::function<void(llvm::raw_ostream &OS, const NamedDecl *)> Printer)42 : NumFoundDecls(0), Printer(std::move(Printer)) {}43 44 void run(const MatchFinder::MatchResult &Result) override {45 const NamedDecl *ND = Result.Nodes.getNodeAs<NamedDecl>("id");46 if (!ND)47 return;48 NumFoundDecls++;49 if (NumFoundDecls > 1)50 return;51 52 llvm::raw_svector_ostream Out(Printed);53 Printer(Out, ND);54 }55 56 StringRef getPrinted() const {57 return Printed;58 }59 60 unsigned getNumFoundDecls() const {61 return NumFoundDecls;62 }63};64 65::testing::AssertionResult PrintedDeclMatches(66 StringRef Code, const std::vector<std::string> &Args,67 const DeclarationMatcher &NodeMatch, StringRef ExpectedPrinted,68 StringRef FileName,69 std::function<void(llvm::raw_ostream &, const NamedDecl *)> Print) {70 return PrintedNodeMatches<NamedDecl>(71 Code, Args, NodeMatch, ExpectedPrinted, FileName,72 [Print](llvm::raw_ostream &Out, const ASTContext *Context,73 const NamedDecl *ND,74 PrintingPolicyAdjuster PolicyAdjuster) { Print(Out, ND); });75}76 77::testing::AssertionResult78PrintedNamedDeclMatches(StringRef Code, const std::vector<std::string> &Args,79 bool SuppressUnwrittenScope,80 const DeclarationMatcher &NodeMatch,81 StringRef ExpectedPrinted, StringRef FileName) {82 return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, FileName,83 [=](llvm::raw_ostream &Out, const NamedDecl *ND) {84 auto Policy =85 ND->getASTContext().getPrintingPolicy();86 Policy.SuppressUnwrittenScope =87 SuppressUnwrittenScope;88 ND->printQualifiedName(Out, Policy);89 });90}91 92::testing::AssertionResult93PrintedNamedDeclCXX98Matches(StringRef Code, StringRef DeclName,94 StringRef ExpectedPrinted) {95 std::vector<std::string> Args(1, "-std=c++98");96 return PrintedNamedDeclMatches(Code, Args,97 /*SuppressUnwrittenScope*/ false,98 namedDecl(hasName(DeclName)).bind("id"),99 ExpectedPrinted, "input.cc");100}101 102::testing::AssertionResult103PrintedWrittenNamedDeclCXX11Matches(StringRef Code, StringRef DeclName,104 StringRef ExpectedPrinted) {105 std::vector<std::string> Args(1, "-std=c++11");106 return PrintedNamedDeclMatches(Code, Args,107 /*SuppressUnwrittenScope*/ true,108 namedDecl(hasName(DeclName)).bind("id"),109 ExpectedPrinted, "input.cc");110}111 112::testing::AssertionResult113PrintedWrittenPropertyDeclObjCMatches(StringRef Code, StringRef DeclName,114 StringRef ExpectedPrinted) {115 std::vector<std::string> Args{"-std=c++11", "-xobjective-c++"};116 return PrintedNamedDeclMatches(Code, Args,117 /*SuppressUnwrittenScope*/ true,118 objcPropertyDecl(hasName(DeclName)).bind("id"),119 ExpectedPrinted, "input.m");120}121 122::testing::AssertionResult123PrintedNestedNameSpecifierMatches(StringRef Code, StringRef DeclName,124 StringRef ExpectedPrinted) {125 std::vector<std::string> Args{"-std=c++11"};126 return PrintedDeclMatches(Code, Args, namedDecl(hasName(DeclName)).bind("id"),127 ExpectedPrinted, "input.cc",128 [](llvm::raw_ostream &Out, const NamedDecl *D) {129 D->printNestedNameSpecifier(Out);130 });131}132 133} // unnamed namespace134 135TEST(NamedDeclPrinter, TestNamespace1) {136 ASSERT_TRUE(PrintedNamedDeclCXX98Matches(137 "namespace { int A; }",138 "A",139 "(anonymous namespace)::A"));140}141 142TEST(NamedDeclPrinter, TestNamespace2) {143 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(144 "inline namespace Z { namespace { int A; } }",145 "A",146 "A"));147}148 149TEST(NamedDeclPrinter, TestUnscopedUnnamedEnum) {150 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(151 "enum { A };",152 "A",153 "A"));154}155 156TEST(NamedDeclPrinter, TestNamedEnum) {157 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(158 "enum X { A };",159 "A",160 "A"));161}162 163TEST(NamedDeclPrinter, TestScopedNamedEnum) {164 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(165 "enum class X { A };",166 "A",167 "X::A"));168}169 170TEST(NamedDeclPrinter, TestClassWithUnscopedUnnamedEnum) {171 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(172 "class X { enum { A }; };",173 "A",174 "X::A"));175}176 177TEST(NamedDeclPrinter, TestClassWithUnscopedNamedEnum) {178 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(179 "class X { enum Y { A }; };",180 "A",181 "X::A"));182}183 184TEST(NamedDeclPrinter, TestClassWithScopedNamedEnum) {185 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(186 "class X { enum class Y { A }; };",187 "A",188 "X::Y::A"));189}190 191TEST(NamedDeclPrinter, TestLinkageInNamespace) {192 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(193 "namespace X { extern \"C\" { int A; } }",194 "A",195 "X::A"));196}197 198TEST(NamedDeclPrinter, TestObjCClassExtension) {199 const char *Code =200R"(201 @interface Obj202 @end203 204 @interface Obj ()205 @property(nonatomic) int property;206 @end207)";208 ASSERT_TRUE(PrintedWrittenPropertyDeclObjCMatches(209 Code,210 "property",211 "Obj::property"));212}213 214TEST(NamedDeclPrinter, TestInstanceObjCClassExtension) {215 const char *Code =216R"(217@interface ObjC218@end219@interface ObjC () {220 char data; // legal with non-fragile ABI.221}222@end223)";224 225 std::vector<std::string> Args{226 "-std=c++11", "-xobjective-c++",227 "-fobjc-runtime=macosx" /*force to use non-fragile ABI*/};228 ASSERT_TRUE(PrintedNamedDeclMatches(Code, Args,229 /*SuppressUnwrittenScope*/ true,230 namedDecl(hasName("data")).bind("id"),231 // not "::data"232 "ObjC::data", "input.mm"));233}234 235TEST(NamedDeclPrinter, TestObjCClassExtensionWithGetter) {236 const char *Code =237R"(238 @interface Obj239 @end240 241 @interface Obj ()242 @property(nonatomic, getter=myPropertyGetter) int property;243 @end244)";245 ASSERT_TRUE(PrintedWrittenPropertyDeclObjCMatches(246 Code,247 "property",248 "Obj::property"));249}250 251TEST(NamedDeclPrinter, NestedNameSpecifierSimple) {252 const char *Code =253 R"(254 namespace foo { namespace bar { void func(); } }255)";256 ASSERT_TRUE(PrintedNestedNameSpecifierMatches(Code, "func", "foo::bar::"));257}258 259TEST(NamedDeclPrinter, NestedNameSpecifierTemplateArgs) {260 const char *Code =261 R"(262 template <class T> struct vector;263 template <> struct vector<int> { int method(); };264)";265 ASSERT_TRUE(266 PrintedNestedNameSpecifierMatches(Code, "method", "vector<int>::"));267}268