blob: dec833d15d8026ca2e7548df20701d9f93d4a66e [file] [log] [blame]
Manuel Klimek975a9492012-11-06 17:31:40 +00001//===- unittest/AST/SourceLocationTest.cpp - AST source loc unit 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 SourceLocation and SourceRange fields
11// in AST nodes.
12//
13// FIXME: In the long-term, when we test more than source locations, we may
14// want to have a unit test file for an AST node (or group of related nodes),
15// rather than a unit test file for source locations for all AST nodes.
16//
17//===----------------------------------------------------------------------===//
18
19#include "clang/AST/ASTContext.h"
20#include "clang/ASTMatchers/ASTMatchers.h"
21#include "clang/ASTMatchers/ASTMatchFinder.h"
22#include "clang/Tooling/Tooling.h"
23#include "gtest/gtest.h"
24
25namespace clang {
26namespace ast_matchers {
27
28using clang::tooling::newFrontendActionFactory;
29using clang::tooling::runToolOnCodeWithArgs;
30using clang::tooling::FrontendActionFactory;
31
Abramo Bagnara4c5750e2012-11-08 14:44:42 +000032enum Language { Lang_C, Lang_C89, Lang_CXX };
Manuel Klimek975a9492012-11-06 17:31:40 +000033
34/// \brief Base class for verifying some property of nodes found by a matcher.
35///
36/// FIXME: This class should be shared with other AST tests.
37template <typename NodeType>
38class MatchVerifier : public MatchFinder::MatchCallback {
39public:
40 template <typename MatcherType>
41 testing::AssertionResult match(const std::string &Code,
42 const MatcherType &AMatcher) {
43 return match(Code, AMatcher, Lang_CXX);
44 }
45
46 template <typename MatcherType>
47 testing::AssertionResult match(const std::string &Code,
48 const MatcherType &AMatcher, Language L);
49
50protected:
51 virtual void run(const MatchFinder::MatchResult &Result);
52 virtual void verify(const MatchFinder::MatchResult &Result,
53 const NodeType &Node) = 0;
54
55 void setFailure(const Twine &Result) {
56 Verified = false;
57 VerifyResult = Result.str();
58 }
59
60private:
61 bool Verified;
62 std::string VerifyResult;
63};
64
65/// \brief Runs a matcher over some code, and returns the result of the
66/// verifier for the matched node.
67template <typename NodeType> template <typename MatcherType>
68testing::AssertionResult MatchVerifier<NodeType>::match(
69 const std::string &Code, const MatcherType &AMatcher, Language L) {
70 MatchFinder Finder;
71 Finder.addMatcher(AMatcher.bind(""), this);
72 OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
73
74 std::vector<std::string> Args;
75 StringRef FileName;
76 switch (L) {
77 case Lang_C:
78 Args.push_back("-std=c99");
79 FileName = "input.c";
80 break;
Abramo Bagnara4c5750e2012-11-08 14:44:42 +000081 case Lang_C89:
82 Args.push_back("-std=c89");
83 FileName = "input.c";
84 break;
Manuel Klimek975a9492012-11-06 17:31:40 +000085 case Lang_CXX:
86 Args.push_back("-std=c++98");
87 FileName = "input.cc";
88 break;
89 }
90
91 // Default to failure in case callback is never called
92 setFailure("Could not find match");
93 if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
94 return testing::AssertionFailure() << "Parsing error";
95 if (!Verified)
96 return testing::AssertionFailure() << VerifyResult;
97 return testing::AssertionSuccess();
98}
99
100template <typename NodeType>
101void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) {
102 const NodeType *Node = Result.Nodes.getNodeAs<NodeType>("");
103 if (!Node) {
104 setFailure("Matched node has wrong type");
105 } else {
106 // Callback has been called, default to success
107 Verified = true;
108 verify(Result, *Node);
109 }
110}
111
112/// \brief Verify whether a node has the correct source location.
113///
114/// By default, Node.getSourceLocation() is checked. This can be changed
115/// by overriding getLocation().
116template <typename NodeType>
117class LocationVerifier : public MatchVerifier<NodeType> {
118public:
119 void expectLocation(unsigned Line, unsigned Column) {
120 ExpectLine = Line;
121 ExpectColumn = Column;
122 }
123
124protected:
125 void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) {
126 SourceLocation Loc = getLocation(Node);
127 unsigned Line = Result.SourceManager->getSpellingLineNumber(Loc);
128 unsigned Column = Result.SourceManager->getSpellingColumnNumber(Loc);
129 if (Line != ExpectLine || Column != ExpectColumn) {
130 std::string MsgStr;
131 llvm::raw_string_ostream Msg(MsgStr);
132 Msg << "Expected location <" << ExpectLine << ":" << ExpectColumn
133 << ">, found <";
134 Loc.print(Msg, *Result.SourceManager);
135 Msg << '>';
136 this->setFailure(Msg.str());
137 }
138 }
139
140 virtual SourceLocation getLocation(const NodeType &Node) {
141 return Node.getLocation();
142 }
143
144private:
145 unsigned ExpectLine, ExpectColumn;
146};
147
148/// \brief Verify whether a node has the correct source range.
149///
150/// By default, Node.getSourceRange() is checked. This can be changed
151/// by overriding getRange().
152template <typename NodeType>
153class RangeVerifier : public MatchVerifier<NodeType> {
154public:
155 void expectRange(unsigned BeginLine, unsigned BeginColumn,
156 unsigned EndLine, unsigned EndColumn) {
157 ExpectBeginLine = BeginLine;
158 ExpectBeginColumn = BeginColumn;
159 ExpectEndLine = EndLine;
160 ExpectEndColumn = EndColumn;
161 }
162
163protected:
164 void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) {
165 SourceRange R = getRange(Node);
166 SourceLocation Begin = R.getBegin();
167 SourceLocation End = R.getEnd();
168 unsigned BeginLine = Result.SourceManager->getSpellingLineNumber(Begin);
169 unsigned BeginColumn = Result.SourceManager->getSpellingColumnNumber(Begin);
170 unsigned EndLine = Result.SourceManager->getSpellingLineNumber(End);
171 unsigned EndColumn = Result.SourceManager->getSpellingColumnNumber(End);
172 if (BeginLine != ExpectBeginLine || BeginColumn != ExpectBeginColumn ||
173 EndLine != ExpectEndLine || EndColumn != ExpectEndColumn) {
174 std::string MsgStr;
175 llvm::raw_string_ostream Msg(MsgStr);
176 Msg << "Expected range <" << ExpectBeginLine << ":" << ExpectBeginColumn
177 << '-' << ExpectEndLine << ":" << ExpectEndColumn << ">, found <";
178 Begin.print(Msg, *Result.SourceManager);
179 Msg << '-';
180 End.print(Msg, *Result.SourceManager);
181 Msg << '>';
182 this->setFailure(Msg.str());
183 }
184 }
185
186 virtual SourceRange getRange(const NodeType &Node) {
187 return Node.getSourceRange();
188 }
189
190private:
191 unsigned ExpectBeginLine, ExpectBeginColumn, ExpectEndLine, ExpectEndColumn;
192};
193
194TEST(MatchVerifier, ParseError) {
195 LocationVerifier<VarDecl> Verifier;
196 Verifier.expectLocation(1, 1);
197 EXPECT_FALSE(Verifier.match("int i", varDecl()));
198}
199
200TEST(MatchVerifier, NoMatch) {
201 LocationVerifier<VarDecl> Verifier;
202 Verifier.expectLocation(1, 1);
203 EXPECT_FALSE(Verifier.match("int i;", recordDecl()));
204}
205
206TEST(MatchVerifier, WrongType) {
207 LocationVerifier<RecordDecl> Verifier;
208 Verifier.expectLocation(1, 1);
209 EXPECT_FALSE(Verifier.match("int i;", varDecl()));
210}
211
212TEST(LocationVerifier, WrongLocation) {
213 LocationVerifier<VarDecl> Verifier;
214 Verifier.expectLocation(1, 1);
215 EXPECT_FALSE(Verifier.match("int i;", varDecl()));
216}
217
218TEST(RangeVerifier, WrongRange) {
219 RangeVerifier<VarDecl> Verifier;
220 Verifier.expectRange(1, 1, 1, 1);
221 EXPECT_FALSE(Verifier.match("int i;", varDecl()));
222}
223
224class LabelDeclRangeVerifier : public RangeVerifier<LabelStmt> {
225protected:
226 virtual SourceRange getRange(const LabelStmt &Node) {
227 return Node.getDecl()->getSourceRange();
228 }
229};
230
231TEST(LabelDecl, Range) {
232 LabelDeclRangeVerifier Verifier;
233 Verifier.expectRange(1, 12, 1, 12);
234 EXPECT_TRUE(Verifier.match("void f() { l: return; }", labelStmt()));
235}
236
237TEST(LabelStmt, Range) {
238 RangeVerifier<LabelStmt> Verifier;
239 Verifier.expectRange(1, 12, 1, 15);
240 EXPECT_TRUE(Verifier.match("void f() { l: return; }", labelStmt()));
241}
242
243TEST(ParmVarDecl, KNRLocation) {
244 LocationVerifier<ParmVarDecl> Verifier;
245 Verifier.expectLocation(1, 8);
246 EXPECT_TRUE(Verifier.match("void f(i) {}", varDecl(), Lang_C));
247}
248
249TEST(ParmVarDecl, KNRRange) {
250 RangeVerifier<ParmVarDecl> Verifier;
251 Verifier.expectRange(1, 8, 1, 8);
252 EXPECT_TRUE(Verifier.match("void f(i) {}", varDecl(), Lang_C));
253}
254
David Blaikie5a789852012-11-07 17:17:07 +0000255TEST(CXXNewExpr, ArrayRange) {
256 RangeVerifier<CXXNewExpr> Verifier;
257 Verifier.expectRange(1, 12, 1, 22);
258 EXPECT_TRUE(Verifier.match("void f() { new int[10]; }", newExpr()));
259}
260
David Blaikiec2fc67e2012-11-08 22:53:48 +0000261TEST(CXXNewExpr, ParenRange) {
262 RangeVerifier<CXXNewExpr> Verifier;
263 Verifier.expectRange(1, 12, 1, 20);
264 EXPECT_TRUE(Verifier.match("void f() { new int(); }", newExpr()));
265}
266
Abramo Bagnara13fd6842012-11-08 13:52:58 +0000267TEST(MemberExpr, ImplicitMemberRange) {
268 RangeVerifier<MemberExpr> Verifier;
269 Verifier.expectRange(2, 30, 2, 30);
270 EXPECT_TRUE(Verifier.match("struct S { operator int() const; };\n"
271 "int foo(const S& s) { return s; }",
272 memberExpr()));
273}
274
Abramo Bagnara4c5750e2012-11-08 14:44:42 +0000275TEST(VarDecl, VMTypeFixedVarDeclRange) {
276 RangeVerifier<VarDecl> Verifier;
277 Verifier.expectRange(1, 1, 1, 23);
278 EXPECT_TRUE(Verifier.match("int a[(int)(void*)1234];",
279 varDecl(), Lang_C89));
280}
281
282TEST(CXXConstructorDecl, NoRetFunTypeLocRange) {
283 RangeVerifier<CXXConstructorDecl> Verifier;
284 Verifier.expectRange(1, 11, 1, 13);
285 EXPECT_TRUE(Verifier.match("class C { C(); };", functionDecl()));
286}
287
Manuel Klimek975a9492012-11-06 17:31:40 +0000288} // end namespace ast_matchers
289} // end namespace clang