blob: 1042312e8a7307f04eb2c639d9fabfbd7ba47de7 [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 Kramer4e3f4f02020-01-29 10:52:25 +0100115 return PrintedNamedDeclMatches(Code, Args,
116 /*SuppressUnwrittenScope*/ false,
117 namedDecl(hasName(DeclName)).bind("id"),
118 ExpectedPrinted, "input.cc");
Richard Smith46dd5bb2014-05-30 22:16:51 +0000119}
120
121::testing::AssertionResult
122PrintedWrittenNamedDeclCXX11Matches(StringRef Code, StringRef DeclName,
123 StringRef ExpectedPrinted) {
124 std::vector<std::string> Args(1, "-std=c++11");
Benjamin Kramer4e3f4f02020-01-29 10:52:25 +0100125 return PrintedNamedDeclMatches(Code, Args,
126 /*SuppressUnwrittenScope*/ true,
127 namedDecl(hasName(DeclName)).bind("id"),
128 ExpectedPrinted, "input.cc");
Richard Smith46dd5bb2014-05-30 22:16:51 +0000129}
130
David Goldman19d21852019-04-04 20:13:22 +0000131::testing::AssertionResult
132PrintedWrittenPropertyDeclObjCMatches(StringRef Code, StringRef DeclName,
133 StringRef ExpectedPrinted) {
134 std::vector<std::string> Args{"-std=c++11", "-xobjective-c++"};
Benjamin Kramer4e3f4f02020-01-29 10:52:25 +0100135 return PrintedNamedDeclMatches(Code, Args,
136 /*SuppressUnwrittenScope*/ true,
137 objcPropertyDecl(hasName(DeclName)).bind("id"),
138 ExpectedPrinted, "input.m");
David Goldman19d21852019-04-04 20:13:22 +0000139}
140
Ilya Biryukov66482232019-09-25 15:46:04 +0000141::testing::AssertionResult
142PrintedNestedNameSpecifierMatches(StringRef Code, StringRef DeclName,
143 StringRef ExpectedPrinted) {
144 std::vector<std::string> Args{"-std=c++11"};
Benjamin Kramer4e3f4f02020-01-29 10:52:25 +0100145 return PrintedDeclMatches(Code, Args, namedDecl(hasName(DeclName)).bind("id"),
146 ExpectedPrinted, "input.cc",
147 [](llvm::raw_ostream &Out, const NamedDecl *D) {
148 D->printNestedNameSpecifier(Out);
149 });
Ilya Biryukov66482232019-09-25 15:46:04 +0000150}
151
Richard Smith46dd5bb2014-05-30 22:16:51 +0000152} // unnamed namespace
153
154TEST(NamedDeclPrinter, TestNamespace1) {
155 ASSERT_TRUE(PrintedNamedDeclCXX98Matches(
156 "namespace { int A; }",
157 "A",
158 "(anonymous namespace)::A"));
159}
160
161TEST(NamedDeclPrinter, TestNamespace2) {
162 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
163 "inline namespace Z { namespace { int A; } }",
164 "A",
165 "A"));
166}
Alexander Kornienko4f355322015-11-09 16:45:17 +0000167
168TEST(NamedDeclPrinter, TestUnscopedUnnamedEnum) {
169 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
170 "enum { A };",
171 "A",
172 "A"));
173}
174
175TEST(NamedDeclPrinter, TestNamedEnum) {
176 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
177 "enum X { A };",
178 "A",
Paul Robinsonf1838482017-12-21 21:47:22 +0000179 "A"));
Alexander Kornienko4f355322015-11-09 16:45:17 +0000180}
181
182TEST(NamedDeclPrinter, TestScopedNamedEnum) {
183 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
184 "enum class X { A };",
185 "A",
186 "X::A"));
187}
188
189TEST(NamedDeclPrinter, TestClassWithUnscopedUnnamedEnum) {
190 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
191 "class X { enum { A }; };",
192 "A",
193 "X::A"));
194}
195
196TEST(NamedDeclPrinter, TestClassWithUnscopedNamedEnum) {
197 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
198 "class X { enum Y { A }; };",
199 "A",
Paul Robinsonf1838482017-12-21 21:47:22 +0000200 "X::A"));
Alexander Kornienko4f355322015-11-09 16:45:17 +0000201}
202
203TEST(NamedDeclPrinter, TestClassWithScopedNamedEnum) {
204 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
205 "class X { enum class Y { A }; };",
206 "A",
207 "X::Y::A"));
208}
Sam McCall34f9d3f2018-02-02 13:34:47 +0000209
210TEST(NamedDeclPrinter, TestLinkageInNamespace) {
211 ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
212 "namespace X { extern \"C\" { int A; } }",
213 "A",
214 "X::A"));
215}
David Goldman19d21852019-04-04 20:13:22 +0000216
217TEST(NamedDeclPrinter, TestObjCClassExtension) {
David Goldman4af5d742019-04-05 19:17:24 +0000218 const char *Code =
219R"(
220 @interface Obj
221 @end
David Goldman19d21852019-04-04 20:13:22 +0000222
David Goldman4af5d742019-04-05 19:17:24 +0000223 @interface Obj ()
224 @property(nonatomic) int property;
225 @end
226)";
227 ASSERT_TRUE(PrintedWrittenPropertyDeclObjCMatches(
228 Code,
David Goldman19d21852019-04-04 20:13:22 +0000229 "property",
230 "Obj::property"));
231}
232
Haojian Wu6f565992020-05-19 15:10:10 +0200233TEST(NamedDeclPrinter, TestInstanceObjCClassExtension) {
234 const char *Code =
235R"(
236@interface ObjC
237@end
238@interface ObjC () {
239 char data; // legal with non-fragile ABI.
240}
241@end
242)";
243
244 std::vector<std::string> Args{
245 "-std=c++11", "-xobjective-c++",
246 "-fobjc-runtime=macosx" /*force to use non-fragile ABI*/};
247 ASSERT_TRUE(PrintedNamedDeclMatches(Code, Args,
248 /*SuppressUnwrittenScope*/ true,
249 namedDecl(hasName("data")).bind("id"),
250 // not "::data"
251 "ObjC::data", "input.mm"));
252}
253
David Goldman19d21852019-04-04 20:13:22 +0000254TEST(NamedDeclPrinter, TestObjCClassExtensionWithGetter) {
David Goldman4af5d742019-04-05 19:17:24 +0000255 const char *Code =
256R"(
257 @interface Obj
258 @end
David Goldman19d21852019-04-04 20:13:22 +0000259
David Goldman4af5d742019-04-05 19:17:24 +0000260 @interface Obj ()
261 @property(nonatomic, getter=myPropertyGetter) int property;
262 @end
263)";
264 ASSERT_TRUE(PrintedWrittenPropertyDeclObjCMatches(
265 Code,
David Goldman19d21852019-04-04 20:13:22 +0000266 "property",
267 "Obj::property"));
268}
Ilya Biryukov66482232019-09-25 15:46:04 +0000269
270TEST(NamedDeclPrinter, NestedNameSpecifierSimple) {
271 const char *Code =
272 R"(
273 namespace foo { namespace bar { void func(); } }
274)";
275 ASSERT_TRUE(PrintedNestedNameSpecifierMatches(Code, "func", "foo::bar::"));
276}
277
278TEST(NamedDeclPrinter, NestedNameSpecifierTemplateArgs) {
279 const char *Code =
280 R"(
281 template <class T> struct vector;
282 template <> struct vector<int> { int method(); };
283)";
284 ASSERT_TRUE(
285 PrintedNestedNameSpecifierMatches(Code, "method", "vector<int>::"));
286}