blob: d5077b8da8680a20fc18f5a22c38f48b90fe0b03 [file] [log] [blame]
Richard Smith46dd5bb2014-05-30 22:16:51 +00001//===- unittests/AST/NamedDeclPrinterTest.cpp --- NamedDecl printer tests -===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Richard Smith46dd5bb2014-05-30 22:16:51 +00006//
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"
Ilya Biryukov66482232019-09-25 15:46:04 +000019#include "clang/AST/Decl.h"
20#include "clang/AST/PrettyPrinter.h"
Richard Smith46dd5bb2014-05-30 22:16:51 +000021#include "clang/ASTMatchers/ASTMatchFinder.h"
22#include "clang/Tooling/Tooling.h"
23#include "llvm/ADT/SmallString.h"
Ilya Biryukov66482232019-09-25 15:46:04 +000024#include "llvm/Support/raw_ostream.h"
Richard Smith46dd5bb2014-05-30 22:16:51 +000025#include "gtest/gtest.h"
26
27using namespace clang;
28using namespace ast_matchers;
29using namespace tooling;
30
31namespace {
32
33class PrintMatch : public MatchFinder::MatchCallback {
34 SmallString<1024> Printed;
35 unsigned NumFoundDecls;
Ilya Biryukov66482232019-09-25 15:46:04 +000036 std::function<void(llvm::raw_ostream &OS, const NamedDecl *)> Printer;
Richard Smith46dd5bb2014-05-30 22:16:51 +000037
38public:
Ilya Biryukov66482232019-09-25 15:46:04 +000039 explicit PrintMatch(
40 std::function<void(llvm::raw_ostream &OS, const NamedDecl *)> Printer)
41 : NumFoundDecls(0), Printer(std::move(Printer)) {}
Richard Smith46dd5bb2014-05-30 22:16:51 +000042
Alexander Kornienko34eb2072015-04-11 02:00:23 +000043 void run(const MatchFinder::MatchResult &Result) override {
Richard Smith46dd5bb2014-05-30 22:16:51 +000044 const NamedDecl *ND = Result.Nodes.getNodeAs<NamedDecl>("id");
45 if (!ND)
46 return;
47 NumFoundDecls++;
48 if (NumFoundDecls > 1)
49 return;
50
51 llvm::raw_svector_ostream Out(Printed);
Ilya Biryukov66482232019-09-25 15:46:04 +000052 Printer(Out, ND);
Richard Smith46dd5bb2014-05-30 22:16:51 +000053 }
54
55 StringRef getPrinted() const {
56 return Printed;
57 }
58
59 unsigned getNumFoundDecls() const {
60 return NumFoundDecls;
61 }
62};
63
Ilya Biryukov66482232019-09-25 15:46:04 +000064::testing::AssertionResult PrintedDeclMatches(
65 StringRef Code, const std::vector<std::string> &Args,
66 const DeclarationMatcher &NodeMatch, StringRef ExpectedPrinted,
67 StringRef FileName,
68 std::function<void(llvm::raw_ostream &, const NamedDecl *)> Print) {
69 PrintMatch Printer(std::move(Print));
Richard Smith46dd5bb2014-05-30 22:16:51 +000070 MatchFinder Finder;
71 Finder.addMatcher(NodeMatch, &Printer);
David Blaikie6beb6aa2014-08-10 19:56:51 +000072 std::unique_ptr<FrontendActionFactory> Factory =
73 newFrontendActionFactory(&Finder);
Richard Smith46dd5bb2014-05-30 22:16:51 +000074
75 if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
76 return testing::AssertionFailure()
77 << "Parsing error in \"" << Code.str() << "\"";
78
79 if (Printer.getNumFoundDecls() == 0)
80 return testing::AssertionFailure()
81 << "Matcher didn't find any named declarations";
82
83 if (Printer.getNumFoundDecls() > 1)
84 return testing::AssertionFailure()
85 << "Matcher should match only one named declaration "
86 "(found " << Printer.getNumFoundDecls() << ")";
87
88 if (Printer.getPrinted() != ExpectedPrinted)
89 return ::testing::AssertionFailure()
90 << "Expected \"" << ExpectedPrinted.str() << "\", "
91 "got \"" << Printer.getPrinted().str() << "\"";
92
93 return ::testing::AssertionSuccess();
94}
95
96::testing::AssertionResult
Ilya Biryukov66482232019-09-25 15:46:04 +000097PrintedNamedDeclMatches(StringRef Code, const std::vector<std::string> &Args,
98 bool SuppressUnwrittenScope,
99 const DeclarationMatcher &NodeMatch,
100 StringRef ExpectedPrinted, StringRef FileName) {
101 return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, FileName,
102 [=](llvm::raw_ostream &Out, const NamedDecl *ND) {
103 auto Policy =
104 ND->getASTContext().getPrintingPolicy();
105 Policy.SuppressUnwrittenScope =
106 SuppressUnwrittenScope;
107 ND->printQualifiedName(Out, Policy);
108 });
109}
110
111::testing::AssertionResult
Richard Smith46dd5bb2014-05-30 22:16:51 +0000112PrintedNamedDeclCXX98Matches(StringRef Code, StringRef DeclName,
113 StringRef ExpectedPrinted) {
114 std::vector<std::string> Args(1, "-std=c++98");
Benjamin Krameradcd0262020-01-28 20:23:46 +0100115 return PrintedNamedDeclMatches(
116 Code, Args,
117 /*SuppressUnwrittenScope*/ false,
118 namedDecl(hasName(std::string(DeclName))).bind("id"), ExpectedPrinted,
119 "input.cc");
Richard Smith46dd5bb2014-05-30 22:16:51 +0000120}
121
122::testing::AssertionResult
123PrintedWrittenNamedDeclCXX11Matches(StringRef Code, StringRef DeclName,
124 StringRef ExpectedPrinted) {
125 std::vector<std::string> Args(1, "-std=c++11");
Benjamin Krameradcd0262020-01-28 20:23:46 +0100126 return PrintedNamedDeclMatches(
127 Code, Args,
128 /*SuppressUnwrittenScope*/ true,
129 namedDecl(hasName(std::string(DeclName))).bind("id"), ExpectedPrinted,
130 "input.cc");
Richard Smith46dd5bb2014-05-30 22:16:51 +0000131}
132
David Goldman19d21852019-04-04 20:13:22 +0000133::testing::AssertionResult
134PrintedWrittenPropertyDeclObjCMatches(StringRef Code, StringRef DeclName,
135 StringRef ExpectedPrinted) {
136 std::vector<std::string> Args{"-std=c++11", "-xobjective-c++"};
Benjamin Krameradcd0262020-01-28 20:23:46 +0100137 return PrintedNamedDeclMatches(
138 Code, Args,
139 /*SuppressUnwrittenScope*/ true,
140 objcPropertyDecl(hasName(std::string(DeclName))).bind("id"),
141 ExpectedPrinted, "input.m");
David Goldman19d21852019-04-04 20:13:22 +0000142}
143
Ilya Biryukov66482232019-09-25 15:46:04 +0000144::testing::AssertionResult
145PrintedNestedNameSpecifierMatches(StringRef Code, StringRef DeclName,
146 StringRef ExpectedPrinted) {
147 std::vector<std::string> Args{"-std=c++11"};
Benjamin Krameradcd0262020-01-28 20:23:46 +0100148 return PrintedDeclMatches(
149 Code, Args, namedDecl(hasName(std::string(DeclName))).bind("id"),
150 ExpectedPrinted, "input.cc",
151 [](llvm::raw_ostream &Out, const NamedDecl *D) {
152 D->printNestedNameSpecifier(Out);
153 });
Ilya Biryukov66482232019-09-25 15:46:04 +0000154}
155
Richard Smith46dd5bb2014-05-30 22:16:51 +0000156} // unnamed namespace
157
158TEST(NamedDeclPrinter, TestNamespace1) {
159 ASSERT_TRUE(PrintedNamedDeclCXX98Matches(
160 "namespace { int A; }",
161 "A",
162 "(anonymous namespace)::A"));
163}
164
165TEST(NamedDeclPrinter, TestNamespace2) {
166 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
167 "inline namespace Z { namespace { int A; } }",
168 "A",
169 "A"));
170}
Alexander Kornienko4f355322015-11-09 16:45:17 +0000171
172TEST(NamedDeclPrinter, TestUnscopedUnnamedEnum) {
173 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
174 "enum { A };",
175 "A",
176 "A"));
177}
178
179TEST(NamedDeclPrinter, TestNamedEnum) {
180 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
181 "enum X { A };",
182 "A",
Paul Robinsonf1838482017-12-21 21:47:22 +0000183 "A"));
Alexander Kornienko4f355322015-11-09 16:45:17 +0000184}
185
186TEST(NamedDeclPrinter, TestScopedNamedEnum) {
187 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
188 "enum class X { A };",
189 "A",
190 "X::A"));
191}
192
193TEST(NamedDeclPrinter, TestClassWithUnscopedUnnamedEnum) {
194 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
195 "class X { enum { A }; };",
196 "A",
197 "X::A"));
198}
199
200TEST(NamedDeclPrinter, TestClassWithUnscopedNamedEnum) {
201 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
202 "class X { enum Y { A }; };",
203 "A",
Paul Robinsonf1838482017-12-21 21:47:22 +0000204 "X::A"));
Alexander Kornienko4f355322015-11-09 16:45:17 +0000205}
206
207TEST(NamedDeclPrinter, TestClassWithScopedNamedEnum) {
208 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
209 "class X { enum class Y { A }; };",
210 "A",
211 "X::Y::A"));
212}
Sam McCall34f9d3f2018-02-02 13:34:47 +0000213
214TEST(NamedDeclPrinter, TestLinkageInNamespace) {
215 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
216 "namespace X { extern \"C\" { int A; } }",
217 "A",
218 "X::A"));
219}
David Goldman19d21852019-04-04 20:13:22 +0000220
221TEST(NamedDeclPrinter, TestObjCClassExtension) {
David Goldman4af5d742019-04-05 19:17:24 +0000222 const char *Code =
223R"(
224 @interface Obj
225 @end
David Goldman19d21852019-04-04 20:13:22 +0000226
David Goldman4af5d742019-04-05 19:17:24 +0000227 @interface Obj ()
228 @property(nonatomic) int property;
229 @end
230)";
231 ASSERT_TRUE(PrintedWrittenPropertyDeclObjCMatches(
232 Code,
David Goldman19d21852019-04-04 20:13:22 +0000233 "property",
234 "Obj::property"));
235}
236
237TEST(NamedDeclPrinter, TestObjCClassExtensionWithGetter) {
David Goldman4af5d742019-04-05 19:17:24 +0000238 const char *Code =
239R"(
240 @interface Obj
241 @end
David Goldman19d21852019-04-04 20:13:22 +0000242
David Goldman4af5d742019-04-05 19:17:24 +0000243 @interface Obj ()
244 @property(nonatomic, getter=myPropertyGetter) int property;
245 @end
246)";
247 ASSERT_TRUE(PrintedWrittenPropertyDeclObjCMatches(
248 Code,
David Goldman19d21852019-04-04 20:13:22 +0000249 "property",
250 "Obj::property"));
251}
Ilya Biryukov66482232019-09-25 15:46:04 +0000252
253TEST(NamedDeclPrinter, NestedNameSpecifierSimple) {
254 const char *Code =
255 R"(
256 namespace foo { namespace bar { void func(); } }
257)";
258 ASSERT_TRUE(PrintedNestedNameSpecifierMatches(Code, "func", "foo::bar::"));
259}
260
261TEST(NamedDeclPrinter, NestedNameSpecifierTemplateArgs) {
262 const char *Code =
263 R"(
264 template <class T> struct vector;
265 template <> struct vector<int> { int method(); };
266)";
267 ASSERT_TRUE(
268 PrintedNestedNameSpecifierMatches(Code, "method", "vector<int>::"));
269}