blob: 7d6e0c3dadeabcc906411d5daf13705e03d81ef1 [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
32enum Language { Lang_C, Lang_CXX };
33
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;
81 case Lang_CXX:
82 Args.push_back("-std=c++98");
83 FileName = "input.cc";
84 break;
85 }
86
87 // Default to failure in case callback is never called
88 setFailure("Could not find match");
89 if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
90 return testing::AssertionFailure() << "Parsing error";
91 if (!Verified)
92 return testing::AssertionFailure() << VerifyResult;
93 return testing::AssertionSuccess();
94}
95
96template <typename NodeType>
97void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) {
98 const NodeType *Node = Result.Nodes.getNodeAs<NodeType>("");
99 if (!Node) {
100 setFailure("Matched node has wrong type");
101 } else {
102 // Callback has been called, default to success
103 Verified = true;
104 verify(Result, *Node);
105 }
106}
107
108/// \brief Verify whether a node has the correct source location.
109///
110/// By default, Node.getSourceLocation() is checked. This can be changed
111/// by overriding getLocation().
112template <typename NodeType>
113class LocationVerifier : public MatchVerifier<NodeType> {
114public:
115 void expectLocation(unsigned Line, unsigned Column) {
116 ExpectLine = Line;
117 ExpectColumn = Column;
118 }
119
120protected:
121 void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) {
122 SourceLocation Loc = getLocation(Node);
123 unsigned Line = Result.SourceManager->getSpellingLineNumber(Loc);
124 unsigned Column = Result.SourceManager->getSpellingColumnNumber(Loc);
125 if (Line != ExpectLine || Column != ExpectColumn) {
126 std::string MsgStr;
127 llvm::raw_string_ostream Msg(MsgStr);
128 Msg << "Expected location <" << ExpectLine << ":" << ExpectColumn
129 << ">, found <";
130 Loc.print(Msg, *Result.SourceManager);
131 Msg << '>';
132 this->setFailure(Msg.str());
133 }
134 }
135
136 virtual SourceLocation getLocation(const NodeType &Node) {
137 return Node.getLocation();
138 }
139
140private:
141 unsigned ExpectLine, ExpectColumn;
142};
143
144/// \brief Verify whether a node has the correct source range.
145///
146/// By default, Node.getSourceRange() is checked. This can be changed
147/// by overriding getRange().
148template <typename NodeType>
149class RangeVerifier : public MatchVerifier<NodeType> {
150public:
151 void expectRange(unsigned BeginLine, unsigned BeginColumn,
152 unsigned EndLine, unsigned EndColumn) {
153 ExpectBeginLine = BeginLine;
154 ExpectBeginColumn = BeginColumn;
155 ExpectEndLine = EndLine;
156 ExpectEndColumn = EndColumn;
157 }
158
159protected:
160 void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) {
161 SourceRange R = getRange(Node);
162 SourceLocation Begin = R.getBegin();
163 SourceLocation End = R.getEnd();
164 unsigned BeginLine = Result.SourceManager->getSpellingLineNumber(Begin);
165 unsigned BeginColumn = Result.SourceManager->getSpellingColumnNumber(Begin);
166 unsigned EndLine = Result.SourceManager->getSpellingLineNumber(End);
167 unsigned EndColumn = Result.SourceManager->getSpellingColumnNumber(End);
168 if (BeginLine != ExpectBeginLine || BeginColumn != ExpectBeginColumn ||
169 EndLine != ExpectEndLine || EndColumn != ExpectEndColumn) {
170 std::string MsgStr;
171 llvm::raw_string_ostream Msg(MsgStr);
172 Msg << "Expected range <" << ExpectBeginLine << ":" << ExpectBeginColumn
173 << '-' << ExpectEndLine << ":" << ExpectEndColumn << ">, found <";
174 Begin.print(Msg, *Result.SourceManager);
175 Msg << '-';
176 End.print(Msg, *Result.SourceManager);
177 Msg << '>';
178 this->setFailure(Msg.str());
179 }
180 }
181
182 virtual SourceRange getRange(const NodeType &Node) {
183 return Node.getSourceRange();
184 }
185
186private:
187 unsigned ExpectBeginLine, ExpectBeginColumn, ExpectEndLine, ExpectEndColumn;
188};
189
190TEST(MatchVerifier, ParseError) {
191 LocationVerifier<VarDecl> Verifier;
192 Verifier.expectLocation(1, 1);
193 EXPECT_FALSE(Verifier.match("int i", varDecl()));
194}
195
196TEST(MatchVerifier, NoMatch) {
197 LocationVerifier<VarDecl> Verifier;
198 Verifier.expectLocation(1, 1);
199 EXPECT_FALSE(Verifier.match("int i;", recordDecl()));
200}
201
202TEST(MatchVerifier, WrongType) {
203 LocationVerifier<RecordDecl> Verifier;
204 Verifier.expectLocation(1, 1);
205 EXPECT_FALSE(Verifier.match("int i;", varDecl()));
206}
207
208TEST(LocationVerifier, WrongLocation) {
209 LocationVerifier<VarDecl> Verifier;
210 Verifier.expectLocation(1, 1);
211 EXPECT_FALSE(Verifier.match("int i;", varDecl()));
212}
213
214TEST(RangeVerifier, WrongRange) {
215 RangeVerifier<VarDecl> Verifier;
216 Verifier.expectRange(1, 1, 1, 1);
217 EXPECT_FALSE(Verifier.match("int i;", varDecl()));
218}
219
220class LabelDeclRangeVerifier : public RangeVerifier<LabelStmt> {
221protected:
222 virtual SourceRange getRange(const LabelStmt &Node) {
223 return Node.getDecl()->getSourceRange();
224 }
225};
226
227TEST(LabelDecl, Range) {
228 LabelDeclRangeVerifier Verifier;
229 Verifier.expectRange(1, 12, 1, 12);
230 EXPECT_TRUE(Verifier.match("void f() { l: return; }", labelStmt()));
231}
232
233TEST(LabelStmt, Range) {
234 RangeVerifier<LabelStmt> Verifier;
235 Verifier.expectRange(1, 12, 1, 15);
236 EXPECT_TRUE(Verifier.match("void f() { l: return; }", labelStmt()));
237}
238
239TEST(ParmVarDecl, KNRLocation) {
240 LocationVerifier<ParmVarDecl> Verifier;
241 Verifier.expectLocation(1, 8);
242 EXPECT_TRUE(Verifier.match("void f(i) {}", varDecl(), Lang_C));
243}
244
245TEST(ParmVarDecl, KNRRange) {
246 RangeVerifier<ParmVarDecl> Verifier;
247 Verifier.expectRange(1, 8, 1, 8);
248 EXPECT_TRUE(Verifier.match("void f(i) {}", varDecl(), Lang_C));
249}
250
David Blaikie5a789852012-11-07 17:17:07 +0000251TEST(CXXNewExpr, ArrayRange) {
252 RangeVerifier<CXXNewExpr> Verifier;
253 Verifier.expectRange(1, 12, 1, 22);
254 EXPECT_TRUE(Verifier.match("void f() { new int[10]; }", newExpr()));
255}
256
Manuel Klimek975a9492012-11-06 17:31:40 +0000257} // end namespace ast_matchers
258} // end namespace clang