RecursiveASTVisitorTest.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. //===- unittest/Tooling/RecursiveASTVisitorTest.cpp -----------------------===//
  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. #include "clang/AST/ASTConsumer.h"
  10. #include "clang/AST/RecursiveASTVisitor.h"
  11. #include "clang/Frontend/FrontendAction.h"
  12. #include "clang/Frontend/CompilerInstance.h"
  13. #include "clang/Tooling/Tooling.h"
  14. #include "gtest/gtest.h"
  15. namespace clang {
  16. /// \brief Base class for sipmle RecursiveASTVisitor based tests.
  17. ///
  18. /// This is a drop-in replacement for RecursiveASTVisitor itself, with the
  19. /// additional capability of running it over a snippet of code.
  20. ///
  21. /// Visits template instantiations by default.
  22. ///
  23. /// FIXME: Put into a common location.
  24. template <typename T>
  25. class TestVisitor : public clang::RecursiveASTVisitor<T> {
  26. public:
  27. /// \brief Runs the current AST visitor over the given code.
  28. bool runOver(StringRef Code) {
  29. return tooling::runToolOnCode(new TestAction(this), Code);
  30. }
  31. bool shouldVisitTemplateInstantiations() const {
  32. return true;
  33. }
  34. protected:
  35. clang::ASTContext *Context;
  36. private:
  37. class FindConsumer : public clang::ASTConsumer {
  38. public:
  39. FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}
  40. virtual void HandleTranslationUnit(clang::ASTContext &Context) {
  41. Visitor->TraverseDecl(Context.getTranslationUnitDecl());
  42. }
  43. private:
  44. TestVisitor *Visitor;
  45. };
  46. class TestAction : public clang::ASTFrontendAction {
  47. public:
  48. TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
  49. virtual clang::ASTConsumer* CreateASTConsumer(
  50. clang::CompilerInstance& compiler, llvm::StringRef dummy) {
  51. Visitor->Context = &compiler.getASTContext();
  52. /// TestConsumer will be deleted by the framework calling us.
  53. return new FindConsumer(Visitor);
  54. }
  55. private:
  56. TestVisitor *Visitor;
  57. };
  58. };
  59. /// \brief A RecursiveASTVisitor for testing the RecursiveASTVisitor itself.
  60. ///
  61. /// Allows simple creation of test visitors running matches on only a small
  62. /// subset of the Visit* methods.
  63. template <typename T>
  64. class ExpectedLocationVisitor : public TestVisitor<T> {
  65. public:
  66. ExpectedLocationVisitor()
  67. : ExpectedLine(0), ExpectedColumn(0), Found(false) {}
  68. ~ExpectedLocationVisitor() {
  69. EXPECT_TRUE(Found)
  70. << "Expected \"" << ExpectedMatch << "\" at " << ExpectedLine
  71. << ":" << ExpectedColumn << PartialMatches;
  72. }
  73. /// \brief Expect 'Match' to occur at the given 'Line' and 'Column'.
  74. void ExpectMatch(Twine Match, unsigned Line, unsigned Column) {
  75. ExpectedMatch = Match.str();
  76. ExpectedLine = Line;
  77. ExpectedColumn = Column;
  78. }
  79. protected:
  80. /// \brief Convenience method to simplify writing test visitors.
  81. ///
  82. /// Sets 'Found' to true if 'Name' and 'Location' match the expected
  83. /// values. If only a partial match is found, record the information
  84. /// to produce nice error output when a test fails.
  85. ///
  86. /// Implementations are required to call this with appropriate values
  87. /// for 'Name' during visitation.
  88. void Match(StringRef Name, SourceLocation Location) {
  89. FullSourceLoc FullLocation = this->Context->getFullLoc(Location);
  90. if (Name == ExpectedMatch &&
  91. FullLocation.isValid() &&
  92. FullLocation.getSpellingLineNumber() == ExpectedLine &&
  93. FullLocation.getSpellingColumnNumber() == ExpectedColumn) {
  94. EXPECT_TRUE(!Found);
  95. Found = true;
  96. } else if (Name == ExpectedMatch ||
  97. (FullLocation.isValid() &&
  98. FullLocation.getSpellingLineNumber() == ExpectedLine &&
  99. FullLocation.getSpellingColumnNumber() == ExpectedColumn)) {
  100. // If we did not match, record information about partial matches.
  101. llvm::raw_string_ostream Stream(PartialMatches);
  102. Stream << ", partial match: \"" << Name << "\" at ";
  103. Location.print(Stream, this->Context->getSourceManager());
  104. }
  105. }
  106. std::string ExpectedMatch;
  107. unsigned ExpectedLine;
  108. unsigned ExpectedColumn;
  109. std::string PartialMatches;
  110. bool Found;
  111. };
  112. class TypeLocVisitor : public ExpectedLocationVisitor<TypeLocVisitor> {
  113. public:
  114. bool VisitTypeLoc(TypeLoc TypeLocation) {
  115. Match(TypeLocation.getType().getAsString(), TypeLocation.getBeginLoc());
  116. return true;
  117. }
  118. };
  119. class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> {
  120. public:
  121. bool VisitDeclRefExpr(DeclRefExpr *Reference) {
  122. Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
  123. return true;
  124. }
  125. };
  126. class CXXMemberCallVisitor
  127. : public ExpectedLocationVisitor<CXXMemberCallVisitor> {
  128. public:
  129. bool VisitCXXMemberCallExpr(CXXMemberCallExpr *Call) {
  130. Match(Call->getMethodDecl()->getQualifiedNameAsString(),
  131. Call->getLocStart());
  132. return true;
  133. }
  134. };
  135. class NamedDeclVisitor
  136. : public ExpectedLocationVisitor<NamedDeclVisitor> {
  137. public:
  138. bool VisitNamedDecl(NamedDecl *Decl) {
  139. std::string NameWithTemplateArgs;
  140. Decl->getNameForDiagnostic(NameWithTemplateArgs,
  141. Decl->getASTContext().getPrintingPolicy(),
  142. true);
  143. Match(NameWithTemplateArgs, Decl->getLocation());
  144. return true;
  145. }
  146. };
  147. TEST(RecursiveASTVisitor, VisitsBaseClassDeclarations) {
  148. TypeLocVisitor Visitor;
  149. Visitor.ExpectMatch("class X", 1, 30);
  150. EXPECT_TRUE(Visitor.runOver("class X {}; class Y : public X {};"));
  151. }
  152. TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfForwardDeclaredClass) {
  153. TypeLocVisitor Visitor;
  154. Visitor.ExpectMatch("class X", 3, 18);
  155. EXPECT_TRUE(Visitor.runOver(
  156. "class Y;\n"
  157. "class X {};\n"
  158. "class Y : public X {};"));
  159. }
  160. TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersWithIncompleteInnerClass) {
  161. TypeLocVisitor Visitor;
  162. Visitor.ExpectMatch("class X", 2, 18);
  163. EXPECT_TRUE(Visitor.runOver(
  164. "class X {};\n"
  165. "class Y : public X { class Z; };"));
  166. }
  167. TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfSelfReferentialType) {
  168. TypeLocVisitor Visitor;
  169. Visitor.ExpectMatch("X<class Y>", 2, 18);
  170. EXPECT_TRUE(Visitor.runOver(
  171. "template<typename T> class X {};\n"
  172. "class Y : public X<Y> {};"));
  173. }
  174. TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
  175. DeclRefExprVisitor Visitor;
  176. Visitor.ExpectMatch("x", 2, 3);
  177. EXPECT_TRUE(Visitor.runOver(
  178. "void x(); template <void (*T)()> class X {};\nX<x> y;"));
  179. }
  180. TEST(RecursiveASTVisitor, VisitsCallExpr) {
  181. DeclRefExprVisitor Visitor;
  182. Visitor.ExpectMatch("x", 1, 22);
  183. EXPECT_TRUE(Visitor.runOver(
  184. "void x(); void y() { x(); }"));
  185. }
  186. TEST(RecursiveASTVisitor, VisitsCallInTemplateInstantiation) {
  187. CXXMemberCallVisitor Visitor;
  188. Visitor.ExpectMatch("Y::x", 3, 3);
  189. EXPECT_TRUE(Visitor.runOver(
  190. "struct Y { void x(); };\n"
  191. "template<typename T> void y(T t) {\n"
  192. " t.x();\n"
  193. "}\n"
  194. "void foo() { y<Y>(Y()); }"));
  195. }
  196. TEST(RecursiveASTVisitor, VisitsCallInNestedFunctionTemplateInstantiation) {
  197. CXXMemberCallVisitor Visitor;
  198. Visitor.ExpectMatch("Y::x", 4, 5);
  199. EXPECT_TRUE(Visitor.runOver(
  200. "struct Y { void x(); };\n"
  201. "template<typename T> struct Z {\n"
  202. " template<typename U> static void f() {\n"
  203. " T().x();\n"
  204. " }\n"
  205. "};\n"
  206. "void foo() { Z<Y>::f<int>(); }"));
  207. }
  208. TEST(RecursiveASTVisitor, VisitsCallInNestedClassTemplateInstantiation) {
  209. CXXMemberCallVisitor Visitor;
  210. Visitor.ExpectMatch("A::x", 5, 7);
  211. EXPECT_TRUE(Visitor.runOver(
  212. "template <typename T1> struct X {\n"
  213. " template <typename T2> struct Y {\n"
  214. " void f() {\n"
  215. " T2 y;\n"
  216. " y.x();\n"
  217. " }\n"
  218. " };\n"
  219. "};\n"
  220. "struct A { void x(); };\n"
  221. "int main() {\n"
  222. " (new X<A>::Y<A>())->f();\n"
  223. "}"));
  224. }
  225. /* FIXME: According to Richard Smith this is a bug in the AST.
  226. TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
  227. DeclRefExprVisitor Visitor;
  228. Visitor.ExpectMatch("x", 3, 43);
  229. EXPECT_TRUE(Visitor.runOver(
  230. "template <typename T> void x();\n"
  231. "template <void (*T)()> class X {};\n"
  232. "template <typename T> class Y : public X< x<T> > {};\n"
  233. "Y<int> y;"));
  234. }
  235. */
  236. TEST(RecursiveASTVisitor, VisitsCallInPartialTemplateSpecialization) {
  237. CXXMemberCallVisitor Visitor;
  238. Visitor.ExpectMatch("A::x", 6, 20);
  239. EXPECT_TRUE(Visitor.runOver(
  240. "template <typename T1> struct X {\n"
  241. " template <typename T2, bool B> struct Y { void g(); };\n"
  242. "};\n"
  243. "template <typename T1> template <typename T2>\n"
  244. "struct X<T1>::Y<T2, true> {\n"
  245. " void f() { T2 y; y.x(); }\n"
  246. "};\n"
  247. "struct A { void x(); };\n"
  248. "int main() {\n"
  249. " (new X<A>::Y<A, true>())->f();\n"
  250. "}\n"));
  251. }
  252. TEST(RecursiveASTVisitor, VisitsPartialTemplateSpecialization) {
  253. // From cfe-commits/Week-of-Mon-20100830/033998.html
  254. // Contrary to the approach sugggested in that email, we visit all
  255. // specializations when we visit the primary template. Visiting them when we
  256. // visit the associated specialization is problematic for specializations of
  257. // template members of class templates.
  258. NamedDeclVisitor Visitor;
  259. Visitor.ExpectMatch("A<bool>", 1, 26);
  260. Visitor.ExpectMatch("A<char *>", 2, 26);
  261. EXPECT_TRUE(Visitor.runOver(
  262. "template <class T> class A {};\n"
  263. "template <class T> class A<T*> {};\n"
  264. "A<bool> ab;\n"
  265. "A<char*> acp;\n"));
  266. }
  267. TEST(RecursiveASTVisitor, VisitsUndefinedClassTemplateSpecialization) {
  268. NamedDeclVisitor Visitor;
  269. Visitor.ExpectMatch("A<int>", 1, 29);
  270. EXPECT_TRUE(Visitor.runOver(
  271. "template<typename T> struct A;\n"
  272. "A<int> *p;\n"));
  273. }
  274. TEST(RecursiveASTVisitor, VisitsNestedUndefinedClassTemplateSpecialization) {
  275. NamedDeclVisitor Visitor;
  276. Visitor.ExpectMatch("A<int>::B<char>", 2, 31);
  277. EXPECT_TRUE(Visitor.runOver(
  278. "template<typename T> struct A {\n"
  279. " template<typename U> struct B;\n"
  280. "};\n"
  281. "A<int>::B<char> *p;\n"));
  282. }
  283. TEST(RecursiveASTVisitor, VisitsUndefinedFunctionTemplateSpecialization) {
  284. NamedDeclVisitor Visitor;
  285. Visitor.ExpectMatch("A<int>", 1, 26);
  286. EXPECT_TRUE(Visitor.runOver(
  287. "template<typename T> int A();\n"
  288. "int k = A<int>();\n"));
  289. }
  290. TEST(RecursiveASTVisitor, VisitsNestedUndefinedFunctionTemplateSpecialization) {
  291. NamedDeclVisitor Visitor;
  292. Visitor.ExpectMatch("A<int>::B<char>", 2, 35);
  293. EXPECT_TRUE(Visitor.runOver(
  294. "template<typename T> struct A {\n"
  295. " template<typename U> static int B();\n"
  296. "};\n"
  297. "int k = A<int>::B<char>();\n"));
  298. }
  299. TEST(RecursiveASTVisitor, NoRecursionInSelfFriend) {
  300. // From cfe-commits/Week-of-Mon-20100830/033977.html
  301. NamedDeclVisitor Visitor;
  302. Visitor.ExpectMatch("vector_iterator<int>", 2, 7);
  303. EXPECT_TRUE(Visitor.runOver(
  304. "template<typename Container>\n"
  305. "class vector_iterator {\n"
  306. " template <typename C> friend class vector_iterator;\n"
  307. "};\n"
  308. "vector_iterator<int> it_int;\n"));
  309. }
  310. } // end namespace clang