Clang Project

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