1//===- unittests/AST/NamedDeclPrinterTest.cpp --- NamedDecl printer tests -===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains tests for NamedDecl::printQualifiedName().
11//
12// These tests have a coding convention:
13// * declaration to be printed is named 'A' unless it should have some special
14// name (e.g., 'operator+');
15// * additional helper declarations are 'Z', 'Y', 'X' and so on.
16//
17//===----------------------------------------------------------------------===//
18
19#include "clang/AST/ASTContext.h"
20#include "clang/ASTMatchers/ASTMatchFinder.h"
21#include "clang/Tooling/Tooling.h"
22#include "llvm/ADT/SmallString.h"
23#include "gtest/gtest.h"
24
25using namespace clang;
26using namespace ast_matchers;
27using namespace tooling;
28
29namespace {
30
31class PrintMatch : public MatchFinder::MatchCallback {
32  SmallString<1024> Printed;
33  unsigned NumFoundDecls;
34  bool SuppressUnwrittenScope;
35
36public:
37  explicit PrintMatch(bool suppressUnwrittenScope)
38    : NumFoundDecls(0), SuppressUnwrittenScope(suppressUnwrittenScope) {}
39
40  void run(const MatchFinder::MatchResult &Result) override {
41    const NamedDecl *ND = Result.Nodes.getNodeAs<NamedDecl>("id");
42    if (!ND)
43      return;
44    NumFoundDecls++;
45    if (NumFoundDecls > 1)
46      return;
47
48    llvm::raw_svector_ostream Out(Printed);
49    PrintingPolicy Policy = Result.Context->getPrintingPolicy();
50    Policy.SuppressUnwrittenScope = SuppressUnwrittenScope;
51    ND->printQualifiedName(Out, Policy);
52  }
53
54  StringRef getPrinted() const {
55    return Printed;
56  }
57
58  unsigned getNumFoundDecls() const {
59    return NumFoundDecls;
60  }
61};
62
63::testing::AssertionResult
64PrintedNamedDeclMatches(StringRef Code, const std::vector<std::string> &Args,
65                        bool SuppressUnwrittenScope,
66                        const DeclarationMatcher &NodeMatch,
67                        StringRef ExpectedPrinted, StringRef FileName) {
68  PrintMatch Printer(SuppressUnwrittenScope);
69  MatchFinder Finder;
70  Finder.addMatcher(NodeMatch, &Printer);
71  std::unique_ptr<FrontendActionFactory> Factory =
72      newFrontendActionFactory(&Finder);
73
74  if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
75    return testing::AssertionFailure()
76        << "Parsing error in \"" << Code.str() << "\"";
77
78  if (Printer.getNumFoundDecls() == 0)
79    return testing::AssertionFailure()
80        << "Matcher didn't find any named declarations";
81
82  if (Printer.getNumFoundDecls() > 1)
83    return testing::AssertionFailure()
84        << "Matcher should match only one named declaration "
85           "(found " << Printer.getNumFoundDecls() << ")";
86
87  if (Printer.getPrinted() != ExpectedPrinted)
88    return ::testing::AssertionFailure()
89        << "Expected \"" << ExpectedPrinted.str() << "\", "
90           "got \"" << Printer.getPrinted().str() << "\"";
91
92  return ::testing::AssertionSuccess();
93}
94
95::testing::AssertionResult
96PrintedNamedDeclCXX98Matches(StringRef Code, StringRef DeclName,
97                             StringRef ExpectedPrinted) {
98  std::vector<std::string> Args(1, "-std=c++98");
99  return PrintedNamedDeclMatches(Code,
100                                 Args,
101                                 /*SuppressUnwrittenScope*/ false,
102                                 namedDecl(hasName(DeclName)).bind("id"),
103                                 ExpectedPrinted,
104                                 "input.cc");
105}
106
107::testing::AssertionResult
108PrintedWrittenNamedDeclCXX11Matches(StringRef Code, StringRef DeclName,
109                                    StringRef ExpectedPrinted) {
110  std::vector<std::string> Args(1, "-std=c++11");
111  return PrintedNamedDeclMatches(Code,
112                                 Args,
113                                 /*SuppressUnwrittenScope*/ true,
114                                 namedDecl(hasName(DeclName)).bind("id"),
115                                 ExpectedPrinted,
116                                 "input.cc");
117}
118
119} // unnamed namespace
120
121TEST(NamedDeclPrinter, TestNamespace1) {
122  ASSERT_TRUE(PrintedNamedDeclCXX98Matches(
123    "namespace { int A; }",
124    "A",
125    "(anonymous namespace)::A"));
126}
127
128TEST(NamedDeclPrinter, TestNamespace2) {
129  ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
130    "inline namespace Z { namespace { int A; } }",
131    "A",
132    "A"));
133}
134
135TEST(NamedDeclPrinter, TestUnscopedUnnamedEnum) {
136  ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
137    "enum { A };",
138    "A",
139    "A"));
140}
141
142TEST(NamedDeclPrinter, TestNamedEnum) {
143  ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
144    "enum X { A };",
145    "A",
146    "X::A"));
147}
148
149TEST(NamedDeclPrinter, TestScopedNamedEnum) {
150  ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
151    "enum class X { A };",
152    "A",
153    "X::A"));
154}
155
156TEST(NamedDeclPrinter, TestClassWithUnscopedUnnamedEnum) {
157  ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
158    "class X { enum { A }; };",
159    "A",
160    "X::A"));
161}
162
163TEST(NamedDeclPrinter, TestClassWithUnscopedNamedEnum) {
164  ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
165    "class X { enum Y { A }; };",
166    "A",
167    "X::Y::A"));
168}
169
170TEST(NamedDeclPrinter, TestClassWithScopedNamedEnum) {
171  ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
172    "class X { enum class Y { A }; };",
173    "A",
174    "X::Y::A"));
175}
176