1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
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 | |
24 | using namespace clang; |
25 | using namespace ast_matchers; |
26 | using namespace tooling; |
27 | |
28 | namespace { |
29 | |
30 | class PrintMatch : public MatchFinder::MatchCallback { |
31 | SmallString<1024> Printed; |
32 | unsigned NumFoundDecls; |
33 | bool SuppressUnwrittenScope; |
34 | |
35 | public: |
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 |
63 | PrintedNamedDeclMatches(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<FrontendActionFactory> Factory = |
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 |
95 | PrintedNamedDeclCXX98Matches(StringRef Code, StringRef DeclName, |
96 | StringRef ExpectedPrinted) { |
97 | std::vector<std::string> Args(1, "-std=c++98"); |
98 | return PrintedNamedDeclMatches(Code, |
99 | Args, |
100 | false, |
101 | namedDecl(hasName(DeclName)).bind("id"), |
102 | ExpectedPrinted, |
103 | "input.cc"); |
104 | } |
105 | |
106 | ::testing::AssertionResult |
107 | PrintedWrittenNamedDeclCXX11Matches(StringRef Code, StringRef DeclName, |
108 | StringRef ExpectedPrinted) { |
109 | std::vector<std::string> Args(1, "-std=c++11"); |
110 | return PrintedNamedDeclMatches(Code, |
111 | Args, |
112 | true, |
113 | namedDecl(hasName(DeclName)).bind("id"), |
114 | ExpectedPrinted, |
115 | "input.cc"); |
116 | } |
117 | |
118 | } |
119 | |
120 | TEST(NamedDeclPrinter, TestNamespace1) { |
121 | ASSERT_TRUE(PrintedNamedDeclCXX98Matches( |
122 | "namespace { int A; }", |
123 | "A", |
124 | "(anonymous namespace)::A")); |
125 | } |
126 | |
127 | TEST(NamedDeclPrinter, TestNamespace2) { |
128 | ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( |
129 | "inline namespace Z { namespace { int A; } }", |
130 | "A", |
131 | "A")); |
132 | } |
133 | |
134 | TEST(NamedDeclPrinter, TestUnscopedUnnamedEnum) { |
135 | ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( |
136 | "enum { A };", |
137 | "A", |
138 | "A")); |
139 | } |
140 | |
141 | TEST(NamedDeclPrinter, TestNamedEnum) { |
142 | ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( |
143 | "enum X { A };", |
144 | "A", |
145 | "A")); |
146 | } |
147 | |
148 | TEST(NamedDeclPrinter, TestScopedNamedEnum) { |
149 | ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( |
150 | "enum class X { A };", |
151 | "A", |
152 | "X::A")); |
153 | } |
154 | |
155 | TEST(NamedDeclPrinter, TestClassWithUnscopedUnnamedEnum) { |
156 | ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( |
157 | "class X { enum { A }; };", |
158 | "A", |
159 | "X::A")); |
160 | } |
161 | |
162 | TEST(NamedDeclPrinter, TestClassWithUnscopedNamedEnum) { |
163 | ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( |
164 | "class X { enum Y { A }; };", |
165 | "A", |
166 | "X::A")); |
167 | } |
168 | |
169 | TEST(NamedDeclPrinter, TestClassWithScopedNamedEnum) { |
170 | ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( |
171 | "class X { enum class Y { A }; };", |
172 | "A", |
173 | "X::Y::A")); |
174 | } |
175 | |
176 | TEST(NamedDeclPrinter, TestLinkageInNamespace) { |
177 | ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches( |
178 | "namespace X { extern \"C\" { int A; } }", |
179 | "A", |
180 | "X::A")); |
181 | } |
182 | |