diff options
Diffstat (limited to 'unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp')
-rw-r--r-- | unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp b/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp new file mode 100644 index 0000000..6af5906 --- /dev/null +++ b/unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp @@ -0,0 +1,224 @@ +//===- unittest/Tooling/RecursiveASTVisitorTestExprVisitor.cpp ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TestVisitor.h" +#include <stack> + +using namespace clang; + +namespace { + +class ParenExprVisitor : public ExpectedLocationVisitor<ParenExprVisitor> { +public: + bool VisitParenExpr(ParenExpr *Parens) { + Match("", Parens->getExprLoc()); + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) { + ParenExprVisitor Visitor; + Visitor.ExpectMatch("", 1, 9); + EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n")); +} + +class TemplateArgumentLocTraverser + : public ExpectedLocationVisitor<TemplateArgumentLocTraverser> { +public: + bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) { + std::string ArgStr; + llvm::raw_string_ostream Stream(ArgStr); + const TemplateArgument &Arg = ArgLoc.getArgument(); + + Arg.print(Context->getPrintingPolicy(), Stream); + Match(Stream.str(), ArgLoc.getLocation()); + return ExpectedLocationVisitor<TemplateArgumentLocTraverser>:: + TraverseTemplateArgumentLoc(ArgLoc); + } +}; + +TEST(RecursiveASTVisitor, VisitsClassTemplateTemplateParmDefaultArgument) { + TemplateArgumentLocTraverser Visitor; + Visitor.ExpectMatch("X", 2, 40); + EXPECT_TRUE(Visitor.runOver( + "template<typename T> class X;\n" + "template<template <typename> class T = X> class Y;\n" + "template<template <typename> class T> class Y {};\n")); +} + +class CXXBoolLiteralExprVisitor + : public ExpectedLocationVisitor<CXXBoolLiteralExprVisitor> { +public: + bool VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *BE) { + if (BE->getValue()) + Match("true", BE->getLocation()); + else + Match("false", BE->getLocation()); + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsClassTemplateNonTypeParmDefaultArgument) { + CXXBoolLiteralExprVisitor Visitor; + Visitor.ExpectMatch("true", 2, 19); + EXPECT_TRUE(Visitor.runOver( + "template<bool B> class X;\n" + "template<bool B = true> class Y;\n" + "template<bool B> class Y {};\n")); +} + +// A visitor that visits implicit declarations and matches constructors. +class ImplicitCtorVisitor + : public ExpectedLocationVisitor<ImplicitCtorVisitor> { +public: + bool shouldVisitImplicitCode() const { return true; } + + bool VisitCXXConstructorDecl(CXXConstructorDecl* Ctor) { + if (Ctor->isImplicit()) { // Was not written in source code + if (const CXXRecordDecl* Class = Ctor->getParent()) { + Match(Class->getName(), Ctor->getLocation()); + } + } + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsImplicitCopyConstructors) { + ImplicitCtorVisitor Visitor; + Visitor.ExpectMatch("Simple", 2, 8); + // Note: Clang lazily instantiates implicit declarations, so we need + // to use them in order to force them to appear in the AST. + EXPECT_TRUE(Visitor.runOver( + "struct WithCtor { WithCtor(); }; \n" + "struct Simple { Simple(); WithCtor w; }; \n" + "int main() { Simple s; Simple t(s); }\n")); +} + +/// \brief A visitor that optionally includes implicit code and matches +/// CXXConstructExpr. +/// +/// The name recorded for the match is the name of the class whose constructor +/// is invoked by the CXXConstructExpr, not the name of the class whose +/// constructor the CXXConstructExpr is contained in. +class ConstructExprVisitor + : public ExpectedLocationVisitor<ConstructExprVisitor> { +public: + ConstructExprVisitor() : ShouldVisitImplicitCode(false) {} + + bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; } + + void setShouldVisitImplicitCode(bool NewValue) { + ShouldVisitImplicitCode = NewValue; + } + + bool VisitCXXConstructExpr(CXXConstructExpr* Expr) { + if (const CXXConstructorDecl* Ctor = Expr->getConstructor()) { + if (const CXXRecordDecl* Class = Ctor->getParent()) { + Match(Class->getName(), Expr->getLocation()); + } + } + return true; + } + + private: + bool ShouldVisitImplicitCode; +}; + +TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) { + ConstructExprVisitor Visitor; + Visitor.setShouldVisitImplicitCode(true); + Visitor.ExpectMatch("WithCtor", 2, 8); + // Simple has a constructor that implicitly initializes 'w'. Test + // that a visitor that visits implicit code visits that initialization. + // Note: Clang lazily instantiates implicit declarations, so we need + // to use them in order to force them to appear in the AST. + EXPECT_TRUE(Visitor.runOver( + "struct WithCtor { WithCtor(); }; \n" + "struct Simple { WithCtor w; }; \n" + "int main() { Simple s; }\n")); +} + +// The same as CanVisitImplicitMemberInitializations, but checking that the +// visits are omitted when the visitor does not include implicit code. +TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) { + ConstructExprVisitor Visitor; + Visitor.setShouldVisitImplicitCode(false); + Visitor.DisallowMatch("WithCtor", 2, 8); + // Simple has a constructor that implicitly initializes 'w'. Test + // that a visitor that skips implicit code skips that initialization. + // Note: Clang lazily instantiates implicit declarations, so we need + // to use them in order to force them to appear in the AST. + EXPECT_TRUE(Visitor.runOver( + "struct WithCtor { WithCtor(); }; \n" + "struct Simple { WithCtor w; }; \n" + "int main() { Simple s; }\n")); +} + +class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> { +public: + bool VisitDeclRefExpr(DeclRefExpr *Reference) { + Match(Reference->getNameInfo().getAsString(), Reference->getLocation()); + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("x", 2, 3); + EXPECT_TRUE(Visitor.runOver( + "void x(); template <void (*T)()> class X {};\nX<x> y;")); +} + +TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtRange) { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("x", 2, 25); + Visitor.ExpectMatch("x", 2, 30); + EXPECT_TRUE(Visitor.runOver( + "int x[5];\n" + "void f() { for (int i : x) { x[0] = 1; } }", + DeclRefExprVisitor::Lang_CXX11)); +} + +TEST(RecursiveASTVisitor, VisitsCallExpr) { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("x", 1, 22); + EXPECT_TRUE(Visitor.runOver( + "void x(); void y() { x(); }")); +} + +/* FIXME: According to Richard Smith this is a bug in the AST. +TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("x", 3, 43); + EXPECT_TRUE(Visitor.runOver( + "template <typename T> void x();\n" + "template <void (*T)()> class X {};\n" + "template <typename T> class Y : public X< x<T> > {};\n" + "Y<int> y;")); +} +*/ + +TEST(RecursiveASTVisitor, VisitsExtension) { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("s", 1, 24); + EXPECT_TRUE(Visitor.runOver( + "int s = __extension__ (s);\n")); +} + +TEST(RecursiveASTVisitor, VisitsCopyExprOfBlockDeclCapture) { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("x", 3, 24); + EXPECT_TRUE(Visitor.runOver("void f(int(^)(int)); \n" + "void g() { \n" + " f([&](int x){ return x; }); \n" + "}", + DeclRefExprVisitor::Lang_OBJCXX11)); +} + +} // end anonymous namespace |