diff options
-rw-r--r-- | examples/Tooling/CMakeLists.txt | 1 | ||||
-rw-r--r-- | examples/Tooling/RemoveCStrCalls/CMakeLists.txt | 5 | ||||
-rw-r--r-- | examples/Tooling/RemoveCStrCalls/RemoveCStrCalls.cpp | 229 | ||||
-rwxr-xr-x | examples/Tooling/replace.py | 50 | ||||
-rw-r--r-- | include/clang/Tooling/ASTMatchers.h | 1736 | ||||
-rw-r--r-- | include/clang/Tooling/Tooling.h | 4 | ||||
-rw-r--r-- | include/clang/Tooling/VariadicFunction.h | 1398 | ||||
-rw-r--r-- | lib/Tooling/ASTMatchers.cpp | 564 | ||||
-rw-r--r-- | lib/Tooling/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Tooling/Tooling.cpp | 60 | ||||
-rw-r--r-- | test/Tooling/remove-cstr-calls.cpp | 20 | ||||
-rw-r--r-- | unittests/CMakeLists.txt | 5 | ||||
-rw-r--r-- | unittests/Tooling/ASTMatchersTest.cpp | 1602 |
13 files changed, 5643 insertions, 32 deletions
diff --git a/examples/Tooling/CMakeLists.txt b/examples/Tooling/CMakeLists.txt index 257d3ea8ea..01132b858a 100644 --- a/examples/Tooling/CMakeLists.txt +++ b/examples/Tooling/CMakeLists.txt @@ -4,3 +4,4 @@ add_clang_executable(clang-check ClangCheck.cpp ) +add_subdirectory(RemoveCStrCalls) diff --git a/examples/Tooling/RemoveCStrCalls/CMakeLists.txt b/examples/Tooling/RemoveCStrCalls/CMakeLists.txt new file mode 100644 index 0000000000..66debc9288 --- /dev/null +++ b/examples/Tooling/RemoveCStrCalls/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_USED_LIBS clangTooling clangBasic clangAST) + +add_clang_executable(remove-cstr-calls + RemoveCStrCalls.cpp + ) diff --git a/examples/Tooling/RemoveCStrCalls/RemoveCStrCalls.cpp b/examples/Tooling/RemoveCStrCalls/RemoveCStrCalls.cpp new file mode 100644 index 0000000000..6de9dd986a --- /dev/null +++ b/examples/Tooling/RemoveCStrCalls/RemoveCStrCalls.cpp @@ -0,0 +1,229 @@ +//===- examples/Tooling/RemoveCStrCalls.cpp - Redundant c_str call removal ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a tool that prints replacements that remove redundant +// calls of c_str() on strings. +// +// Usage: +// remove-cstr-calls <cmake-output-dir> <file1> <file2> ... +// +// Where <cmake-output-dir> is a CMake build directory in which a file named +// compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in +// CMake to get this output). +// +// <file1> ... specify the paths of files in the CMake source tree. This path +// is looked up in the compile command database. If the path of a file is +// absolute, it needs to point into CMake's source tree. If the path is +// relative, the current working directory needs to be in the CMake source +// tree and the file must be in a subdirectory of the current working +// directory. "./" prefixes in the relative files will be automatically +// removed, but the rest of a relative path must be a suffix of a path in +// the compile command line database. +// +// For example, to use remove-cstr-calls on all files in a subtree of the +// source tree, use: +// +// /path/in/subtree $ find . -name '*.cpp'| +// xargs remove-cstr-calls /path/to/source +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Lex/Lexer.h" +#include "clang/Tooling/ASTMatchers.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" + +using namespace clang::tooling::match; + +// FIXME: Pull out helper methods in here into more fitting places. + +// Returns the text that makes up 'node' in the source. +// Returns an empty string if the text cannot be found. +template <typename T> +std::string GetText(const clang::SourceManager &SourceManager, const T &Node) { + clang::SourceLocation StartSpellingLocatino = + SourceManager.getSpellingLoc(Node.getLocStart()); + clang::SourceLocation EndSpellingLocation = + SourceManager.getSpellingLoc(Node.getLocEnd()); + if (!StartSpellingLocatino.isValid() || !EndSpellingLocation.isValid()) { + return std::string(); + } + bool Invalid = true; + const char *Text = + SourceManager.getCharacterData(StartSpellingLocatino, &Invalid); + if (Invalid) { + return std::string(); + } + std::pair<clang::FileID, unsigned> Start = + SourceManager.getDecomposedLoc(StartSpellingLocatino); + std::pair<clang::FileID, unsigned> End = + SourceManager.getDecomposedLoc(clang::Lexer::getLocForEndOfToken( + EndSpellingLocation, 0, SourceManager, clang::LangOptions())); + if (Start.first != End.first) { + // Start and end are in different files. + return std::string(); + } + if (End.second < Start.second) { + // Shuffling text with macros may cause this. + return std::string(); + } + return std::string(Text, End.second - Start.second); +} + +// Returns the position of the spelling location of a node inside a file. +// The format is: +// "<start_line>:<start_column>:<end_line>:<end_column>" +template <typename T1> +void PrintPosition( + llvm::raw_ostream &OS, + const clang::SourceManager &SourceManager, const T1 &Node) { + clang::SourceLocation StartSpellingLocation = + SourceManager.getSpellingLoc(Node.getLocStart()); + clang::SourceLocation EndSpellingLocation = + SourceManager.getSpellingLoc(Node.getLocEnd()); + clang::PresumedLoc Start = + SourceManager.getPresumedLoc(StartSpellingLocation); + clang::SourceLocation EndToken = clang::Lexer::getLocForEndOfToken( + EndSpellingLocation, 1, SourceManager, clang::LangOptions()); + clang::PresumedLoc End = SourceManager.getPresumedLoc(EndToken); + OS << Start.getLine() << ":" << Start.getColumn() << ":" + << End.getLine() << ":" << End.getColumn(); +} + +class ReportPosition : public clang::tooling::MatchFinder::MatchCallback { + public: + virtual void Run(const clang::tooling::MatchFinder::MatchResult &Result) { + llvm::outs() << "Found!\n"; + } +}; + +// Return true if expr needs to be put in parens when it is an +// argument of a prefix unary operator, e.g. when it is a binary or +// ternary operator syntactically. +bool NeedParensAfterUnaryOperator(const clang::Expr &ExprNode) { + if (llvm::dyn_cast<clang::BinaryOperator>(&ExprNode) || + llvm::dyn_cast<clang::ConditionalOperator>(&ExprNode)) { + return true; + } + if (const clang::CXXOperatorCallExpr *op = + llvm::dyn_cast<clang::CXXOperatorCallExpr>(&ExprNode)) { + return op->getNumArgs() == 2 && + op->getOperator() != clang::OO_PlusPlus && + op->getOperator() != clang::OO_MinusMinus && + op->getOperator() != clang::OO_Call && + op->getOperator() != clang::OO_Subscript; + } + return false; +} + +// Format a pointer to an expression: prefix with '*' but simplify +// when it already begins with '&'. Return empty string on failure. +std::string FormatDereference(const clang::SourceManager &SourceManager, + const clang::Expr &ExprNode) { + if (const clang::UnaryOperator *Op = + llvm::dyn_cast<clang::UnaryOperator>(&ExprNode)) { + if (Op->getOpcode() == clang::UO_AddrOf) { + // Strip leading '&'. + return GetText(SourceManager, *Op->getSubExpr()->IgnoreParens()); + } + } + const std::string Text = GetText(SourceManager, ExprNode); + if (Text.empty()) return std::string(); + // Add leading '*'. + if (NeedParensAfterUnaryOperator(ExprNode)) { + return std::string("*(") + Text + ")"; + } + return std::string("*") + Text; +} + +class FixCStrCall : public clang::tooling::MatchFinder::MatchCallback { + public: + virtual void Run(const clang::tooling::MatchFinder::MatchResult &Result) { + const clang::CallExpr *Call = + Result.Nodes.GetStmtAs<clang::CallExpr>("call"); + const clang::Expr *Arg = + Result.Nodes.GetStmtAs<clang::Expr>("arg"); + const bool Arrow = + Result.Nodes.GetStmtAs<clang::MemberExpr>("member")->isArrow(); + // Replace the "call" node with the "arg" node, prefixed with '*' + // if the call was using '->' rather than '.'. + const std::string ArgText = Arrow ? + FormatDereference(*Result.SourceManager, *Arg) : + GetText(*Result.SourceManager, *Arg); + if (ArgText.empty()) return; + + llvm::outs() << + Result.SourceManager->getBufferName(Call->getLocStart(), NULL) << ":"; + PrintPosition(llvm::outs(), *Result.SourceManager, *Call); + llvm::outs() << ":" << ArgText << "\n"; + } +}; + +const char *StringConstructor = + "::std::basic_string<char, std::char_traits<char>, std::allocator<char> >" + "::basic_string"; + +const char *StringCStrMethod = + "::std::basic_string<char, std::char_traits<char>, std::allocator<char> >" + "::c_str"; + +int main(int argc, char **argv) { + clang::tooling::ClangTool Tool(argc, argv); + clang::tooling::MatchFinder finder; + finder.AddMatcher( + ConstructorCall( + HasDeclaration(Method(HasName(StringConstructor))), + ArgumentCountIs(2), + // The first argument must have the form x.c_str() or p->c_str() + // where the method is string::c_str(). We can use the copy + // constructor of string instead (or the compiler might share + // the string object). + HasArgument( + 0, + Id("call", Call( + Callee(Id("member", MemberExpression())), + Callee(Method(HasName(StringCStrMethod))), + On(Id("arg", Expression()))))), + // The second argument is the alloc object which must not be + // present explicitly. + HasArgument( + 1, + DefaultArgument())), new FixCStrCall); + finder.AddMatcher( + ConstructorCall( + // Implicit constructors of these classes are overloaded + // wrt. string types and they internally make a StringRef + // referring to the argument. Passing a string directly to + // them is preferred to passing a char pointer. + HasDeclaration(Method(AnyOf( + HasName("::llvm::StringRef::StringRef"), + HasName("::llvm::Twine::Twine")))), + ArgumentCountIs(1), + // The only argument must have the form x.c_str() or p->c_str() + // where the method is string::c_str(). StringRef also has + // a constructor from string which is more efficient (avoids + // strlen), so we can construct StringRef from the string + // directly. + HasArgument( + 0, + Id("call", Call( + Callee(Id("member", MemberExpression())), + Callee(Method(HasName(StringCStrMethod))), + On(Id("arg", Expression())))))), + new FixCStrCall); + return Tool.Run(finder.NewFrontendActionFactory()); +} + diff --git a/examples/Tooling/replace.py b/examples/Tooling/replace.py new file mode 100755 index 0000000000..a738dea70c --- /dev/null +++ b/examples/Tooling/replace.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python + +#===- replace.py - Applying code rewrites --------------------*- python -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# +# +# This script applies the rewrites generated by replace-cstr-calls on a source +# tree. +# +# Usage: +# ./replace.py < /path/to/replace-cstr-calls-output +# +#===------------------------------------------------------------------------===# + +import fileinput +import re +import sys + +for line in sys.stdin.readlines(): + # The format is: + # <file>:<start_line>:<start_column>:<end_line>:<end_column>:<replacement> + # FIXME: This currently does not support files with colons, we'll need to + # figure out a format when we implement more refactoring support. + match = re.match(r'(.*):(\d+):(\d+):(\d+):(\d+):(.*)$', line) + if match is not None: + file_name = match.group(1) + start_line, start_column = int(match.group(2)), int(match.group(3)) + end_line, end_column = int(match.group(4)), int(match.group(5)) + replacement = match.group(6) + if start_line != end_line: + print ('Skipping match "%s": only single line ' + + 'replacements are supported') % line.strip() + continue + try: + replace_file = fileinput.input(file_name, inplace=1) + for replace_line in replace_file: + # FIXME: Looping over the file for each replacement is both inefficient + # and incorrect if replacements add or remove lines. + if replace_file.lineno() == start_line: + sys.stdout.write(replace_line[:start_column-1] + replacement + + replace_line[end_column:]) + else: + sys.stdout.write(replace_line) + except OSError, e: + print 'Cannot open %s for editing' % file_name diff --git a/include/clang/Tooling/ASTMatchers.h b/include/clang/Tooling/ASTMatchers.h new file mode 100644 index 0000000000..08b687dfe9 --- /dev/null +++ b/include/clang/Tooling/ASTMatchers.h @@ -0,0 +1,1736 @@ +//===--- ASTMatchers.h - Structural query framework -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a framework of AST matchers that can be used to express +// structural queries on the AST representing C++ code. +// +// The general idea is to construct a matcher expression that describes a +// subtree match on the AST. Next, a callback that is executed every time the +// expression matches is registered, and the matcher is run over the AST of +// some code. Matched subexpressions can be bound to string IDs and easily +// be accessed from the registered callback. The callback can than use the +// AST nodes that the subexpressions matched on to output information about +// the match or construct changes that can be applied to the code. +// +// Example: +// class HandleMatch : public clang::tooling::MatchFinder::MatchCallback { +// public: +// virtual void Run(const clang::tooling::MatchFinder::MatchResult &Result) { +// const clang::CXXRecordDecl *Class = +// Result.Nodes.GetDeclAs<clang::CXXRecordDecl>("id"); +// ... +// } +// }; +// +// int main(int argc, char **argv) { +// ClangTool Tool(argc, argv); +// MatchFinder finder; +// finder.AddMatcher(Id("id", Class(HasName("::a_namespace::AClass"))), +// new HandleMatch); +// return Tool.Run(finder.NewFrontendActionFactory()); +// } +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_AST_MATCHERS_H +#define LLVM_CLANG_TOOLING_AST_MATCHERS_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/Stmt.h" +#include "clang/Tooling/VariadicFunction.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/type_traits.h" +#include <assert.h> +#include <stdint.h> +#include <map> +#include <string> +#include <utility> +#include <vector> + +/// FIXME: Move into the llvm support library. +template <bool> struct CompileAssert {}; +#define COMPILE_ASSERT(Expr, Msg) \ + typedef CompileAssert<(bool(Expr))> Msg[bool(Expr) ? 1 : -1] + +namespace clang { + +class FrontendAction; +class SourceManager; + +namespace tooling { + +class FrontendActionFactory; +class BoundNodesBuilder; + +/// Contains a mapping from IDs to nodes bound to those IDs and provides +/// convenient access to those nodes. +class BoundNodes { + public: + BoundNodes() {} + + /// Create BoundNodes from a pre-filled map of bindings. + BoundNodes(const std::map<std::string, const clang::Decl*> &DeclBindings, + const std::map<std::string, const clang::Stmt*> &StmtBindings) + : DeclBindings(DeclBindings), StmtBindings(StmtBindings) {} + + /// Returns the node bound to the specified id if the id was bound to a node + /// and that node can be converted into the specified type. Returns NULL + /// otherwise. + /// FIXME: We'll need one of those for every base type. + template <typename T> + const T *GetDeclAs(const std::string &ID) const { + return GetNodeAs<T>(DeclBindings, ID); + } + template <typename T> + const T *GetStmtAs(const std::string &ID) const { + return GetNodeAs<T>(StmtBindings, ID); + } + + /// Adds all bound nodes to bound_nodes_builder. + void CopyTo(BoundNodesBuilder *CopyToBuilder) const; + + private: + template <typename T, typename MapT> + const T *GetNodeAs(const MapT &Bindings, const std::string &ID) const { + typename MapT::const_iterator It = Bindings.find(ID); + if (It == Bindings.end()) { + return NULL; + } + return llvm::dyn_cast<T>(It->second); + } + + std::map<std::string, const clang::Decl*> DeclBindings; + std::map<std::string, const clang::Stmt*> StmtBindings; +}; // class BoundNodes + +/// Creates BoundNodes objects. +class BoundNodesBuilder { + public: + BoundNodesBuilder() {} + + /// Add a binding from 'ID' to 'Node'. + /// FIXME: Add overloads for all AST base types. + void SetBinding(const std::string &ID, const clang::Decl *Node) { + DeclBindings[ID] = Node; + } + void SetBinding(const std::string &ID, const clang::Stmt *Node) { + StmtBindings[ID] = Node; + } + + /// Returns a BoundNodes object containing all current bindings. + BoundNodes Build() const { + return BoundNodes(DeclBindings, StmtBindings); + } + + private: + BoundNodesBuilder(const BoundNodesBuilder&); // DO NOT IMPLEMENT + void operator=(const BoundNodesBuilder&); // DO NOT IMPLEMENT + + std::map<std::string, const clang::Decl*> DeclBindings; + std::map<std::string, const clang::Stmt*> StmtBindings; +}; + +inline void BoundNodes::CopyTo(BoundNodesBuilder *CopyToBuilder) const { + for (std::map<std::string, const clang::Decl*>::const_iterator + It = DeclBindings.begin(), End = DeclBindings.end(); + It != End; ++It) { + CopyToBuilder->SetBinding(It->first, It->second); + } + /// FIXME: Pull out method. + for (std::map<std::string, const clang::Stmt*>::const_iterator + It = StmtBindings.begin(), End = StmtBindings.end(); + It != End; ++It) { + CopyToBuilder->SetBinding(It->first, It->second); + } +} + +class ASTMatchFinder; + +/// Generic interface for matchers on an AST node of type T. Implement +/// this if your matcher may need to inspect the children or +/// descendants of the node or bind matched nodes to names. If you are +/// writing a simple matcher that only inspects properties of the +/// current node and doesn't care about its children or descendants, +/// implement SingleNodeMatcherInterface instead. +template <typename T> +class MatcherInterface : public llvm::RefCountedBaseVPTR { + public: + virtual ~MatcherInterface() {} + + /// Returns true if 'Node' can be matched. + /// May bind 'Node' to an ID via 'Builder', or recurse into + /// the AST via 'Finder'. + virtual bool Matches( + const T &Node, + ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const = 0; +}; + +/// Interface for matchers that only evaluate properties on a single node. +template <typename T> +class SingleNodeMatcherInterface : public MatcherInterface<T> { + public: + /// Returns true if the matcher matches the provided node. A subclass + /// must implement this instead of Matches(). + virtual bool MatchesNode(const T &Node) const = 0; + + private: + /// Implements MatcherInterface::Matches. + virtual bool Matches(const T &Node, + ASTMatchFinder * /* Finder */, + BoundNodesBuilder * /* Builder */) const { + return MatchesNode(Node); + } +}; + +/// Wrapper of a MatcherInterface<T> *that allows copying. +/// +/// A Matcher<Base> can be used anywhere a Matcher<Derived> is +/// required. This establishes an is-a relationship which is reverse +/// to the AST hierarchy. In other words, Matcher<T> is contravariant +/// with respect to T. The relationship is built via a type conversion +/// operator rather than a type hierarchy to be able to templatize the +/// type hierarchy instead of spelling it out. +template <typename T> +class Matcher { + public: + /// Takes ownership of the provided implementation pointer. + explicit Matcher(MatcherInterface<T> *Implementation) + : Implementation(Implementation) {} + + /// Forwards the call to the underlying MatcherInterface<T> pointer. + bool Matches( + const T &Node, + ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + return Implementation->Matches(Node, Finder, Builder); + } + + /// Implicitly converts this object to a Matcher<Derived>; requires + /// Derived to be derived from T. + template <typename Derived> + operator Matcher<Derived>() const { + return Matcher<Derived>(new ImplicitCastMatcher<Derived>(*this)); + } + + /// Returns an ID that uniquely identifies the matcher. + uint64_t GetID() const { + /// FIXME: Document the requirements this imposes on matcher + /// implementations (no new() implementation_ during a Matches()). + return reinterpret_cast<uint64_t>(Implementation.getPtr()); + } + + private: + /// Allows conversion from Matcher<T> to Matcher<Derived> if Derived + /// is derived from T. + template <typename Derived> + class ImplicitCastMatcher : public MatcherInterface<Derived> { + public: + explicit ImplicitCastMatcher(const Matcher<T> &From) + : From(From) {} + + virtual bool Matches( + const Derived &Node, + ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + return From.Matches(Node, Finder, Builder); + } + + private: + const Matcher<T> From; + }; + + llvm::IntrusiveRefCntPtr< MatcherInterface<T> > Implementation; +}; // class Matcher + +/// A convenient helper for creating a Matcher<T> without specifying +/// the template type argument. +template <typename T> +inline Matcher<T> MakeMatcher(MatcherInterface<T> *Implementation) { + return Matcher<T>(Implementation); +} + +/// Matches declarations for QualType and CallExpr. Type argument +/// DeclMatcherT is required by PolymorphicMatcherWithParam1 but not +/// actually used. +template <typename T, typename DeclMatcherT> +class HasDeclarationMatcher : public MatcherInterface<T> { + COMPILE_ASSERT((llvm::is_same< DeclMatcherT, Matcher<clang::Decl> >::value), + instantiated_with_wrong_types); + public: + explicit HasDeclarationMatcher(const Matcher<clang::Decl> &InnerMatcher) + : InnerMatcher(InnerMatcher) {} + + virtual bool Matches( + const T &Node, + ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + return MatchesSpecialized(Node, Finder, Builder); + } + + private: + /// Extracts the CXXRecordDecl of a QualType and returns whether the inner + /// matcher matches on it. + bool MatchesSpecialized( + const clang::QualType &Node, ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + /// FIXME: Add other ways to convert... + clang::CXXRecordDecl *NodeAsRecordDecl = Node->getAsCXXRecordDecl(); + return NodeAsRecordDecl != NULL && + InnerMatcher.Matches(*NodeAsRecordDecl, Finder, Builder); + } + + /// Extracts the Decl of the callee of a CallExpr and returns whether the + /// inner matcher matches on it. + bool MatchesSpecialized( + const clang::CallExpr &Node, ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + const clang::Decl *NodeAsDecl = Node.getCalleeDecl(); + return NodeAsDecl != NULL && + InnerMatcher.Matches(*NodeAsDecl, Finder, Builder); + } + + /// Extracts the Decl of the constructor call and returns whether the inner + /// matcher matches on it. + bool MatchesSpecialized( + const clang::CXXConstructExpr &Node, ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + const clang::Decl *NodeAsDecl = Node.getConstructor(); + return NodeAsDecl != NULL && + InnerMatcher.Matches(*NodeAsDecl, Finder, Builder); + } + + const Matcher<clang::Decl> InnerMatcher; +}; + +/// IsBaseType<T>::value is true if T is a "base" type in the AST +/// node class hierarchies (i.e. if T is Decl, Stmt, or QualType). +template <typename T> +struct IsBaseType { + static const bool value = (llvm::is_same<T, clang::Decl>::value || + llvm::is_same<T, clang::Stmt>::value || + llvm::is_same<T, clang::QualType>::value); +}; +template <typename T> +const bool IsBaseType<T>::value; + +/// Interface that can match any AST base node type and contains default +/// implementations returning false. +class UntypedBaseMatcher { + public: + virtual ~UntypedBaseMatcher() {} + + virtual bool Matches( + const clang::Decl &DeclNode, ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + return false; + } + virtual bool Matches( + const clang::QualType &TypeNode, ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + return false; + } + virtual bool Matches( + const clang::Stmt &StmtNode, ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + return false; + } + + /// Returns a unique ID for the matcher. + virtual uint64_t GetID() const = 0; +}; + +/// An UntypedBaseMatcher that overwrites the Matches(...) method for node +/// type T. T must be an AST base type. +template <typename T> +class TypedBaseMatcher : public UntypedBaseMatcher { + COMPILE_ASSERT(IsBaseType<T>::value, + typed_base_matcher_can_only_be_used_with_base_type); + public: + explicit TypedBaseMatcher(const Matcher<T> &InnerMatcher) + : InnerMatcher(InnerMatcher) {} + + using UntypedBaseMatcher::Matches; + /// Implements UntypedBaseMatcher::Matches. Since T is guaranteed to + /// be a "base" AST node type, this method is guaranteed to override + /// one of the Matches() methods from UntypedBaseMatcher. + virtual bool Matches(const T &Node, + ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + return InnerMatcher.Matches(Node, Finder, Builder); + } + + /// Implements UntypedBaseMatcher::GetID. + virtual uint64_t GetID() const { + return InnerMatcher.GetID(); + } + + private: + Matcher<T> InnerMatcher; +}; + +/// Interface that allows matchers to traverse the AST. +/// This provides two entry methods for each base node type in the AST: +/// - MatchesChildOf: +/// Matches a matcher on every child node of the given node. Returns true +/// if at least one child node could be matched. +/// - MatchesDescendantOf: +/// Matches a matcher on all descendant nodes of the given node. Returns true +/// if at least one descendant matched. +class ASTMatchFinder { + public: + /// Defines how we descend a level in the AST when we pass + /// through expressions. + enum TraversalMethod { + /// Will traverse any child nodes. + kAsIs, + /// Will not traverse implicit casts and parentheses. + kIgnoreImplicitCastsAndParentheses + }; + + virtual ~ASTMatchFinder() {} + + /// Returns true if the given class is directly or indirectly derived + /// from a base type with the given name. A class is considered to + /// be also derived from itself. + virtual bool ClassIsDerivedFrom(const clang::CXXRecordDecl *Declaration, + const std::string &BaseName) const = 0; + + // FIXME: Implement for other base nodes. + virtual bool MatchesChildOf(const clang::Decl &DeclNode, + const UntypedBaseMatcher &BaseMatcher, + BoundNodesBuilder *Builder, + TraversalMethod Traverse) = 0; + virtual bool MatchesChildOf(const clang::Stmt &StmtNode, + const UntypedBaseMatcher &BaseMatcher, + BoundNodesBuilder *Builder, + TraversalMethod Traverse) = 0; + + virtual bool MatchesDescendantOf(const clang::Decl &DeclNode, + const UntypedBaseMatcher &BaseMatcher, + BoundNodesBuilder *Builder) = 0; + virtual bool MatchesDescendantOf(const clang::Stmt &StmtNode, + const UntypedBaseMatcher &BaseMatcher, + BoundNodesBuilder *Builder) = 0; +}; + +/// Converts a Matcher<T> to a matcher of desired type To by "adapting" +/// a To into a T. The ArgumentAdapterT argument specifies how the +/// adaptation is done. For example: +/// +/// ArgumentAdaptingMatcher<DynCastMatcher, T>(InnerMatcher); +/// returns a matcher that can be used where a Matcher<To> is required, if +/// To and T are in the same type hierarchy, and thus dyn_cast can be +/// called to convert a To to a T. +/// +/// FIXME: Make sure all our applications of this class actually require +/// knowledge about the inner type. DynCastMatcher obviously does, but the +/// Has *matchers require the inner type solely for COMPILE_ASSERT purposes. +template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, + typename T> +class ArgumentAdaptingMatcher { + public: + explicit ArgumentAdaptingMatcher(const Matcher<T> &InnerMatcher) + : InnerMatcher(InnerMatcher) {} + + template <typename To> + operator Matcher<To>() const { + return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher)); + } + + private: + const Matcher<T> InnerMatcher; +}; + +/// A PolymorphicMatcherWithParamN<MatcherT, P1, ..., PN> object can be +/// created from N parameters p1, ..., pN (of type P1, ..., PN) and +/// used as a Matcher<T> where a MatcherT<T, P1, ..., PN>(p1, ..., pN) +/// can be constructed. +/// +/// For example: +/// - PolymorphicMatcherWithParam0<IsDefinitionMatcher>() +/// creates an object that can be used as a Matcher<T> for any type T +/// where an IsDefinitionMatcher<T>() can be constructed. +/// - PolymorphicMatcherWithParam1<ValueEqualsMatcher, int>(42) +/// creates an object that can be used as a Matcher<T> for any type T +/// where a ValueEqualsMatcher<T, int>(42) can be constructed. +template <template <typename T> class MatcherT> +class PolymorphicMatcherWithParam0 { + public: + template <typename T> + operator Matcher<T>() const { + return Matcher<T>(new MatcherT<T>()); + } +}; + +template <template <typename T, typename P1> class MatcherT, + typename P1> +class PolymorphicMatcherWithParam1 { + public: + explicit PolymorphicMatcherWithParam1(const P1 &Param1) + : Param1(Param1) {} + + template <typename T> + operator Matcher<T>() const { + return Matcher<T>(new MatcherT<T, P1>(Param1)); + } + + private: + const P1 Param1; +}; + +template <template <typename T, typename P1, typename P2> class MatcherT, + typename P1, typename P2> +class PolymorphicMatcherWithParam2 { + public: + PolymorphicMatcherWithParam2(const P1 &Param1, const P2 &Param2) + : Param1(Param1), Param2(Param2) {} + + template <typename T> + operator Matcher<T>() const { + return Matcher<T>(new MatcherT<T, P1, P2>(Param1, Param2)); + } + + private: + const P1 Param1; + const P2 Param2; +}; + +// FIXME: Alternatively we could also create a IsAMatcher or something +// that checks that a dyn_cast is possible. This is purely needed for the +// difference between calling for example: +// Class() +// and +// Class(SomeMatcher) +// In the second case we need the correct type we were dyn_cast'ed to in order +// to get the right type for the inner matcher. In the first case we don't need +// that, but we use the type conversion anyway and insert a TrueMatcher. +template <typename T> +class TrueMatcher : public SingleNodeMatcherInterface<T> { + public: + virtual bool MatchesNode(const T &Node) const { + return true; + } +}; + +/// Provides a MatcherInterface<T> for a Matcher<To> that matches if T is +/// dyn_cast'able into To and the given Matcher<To> matches on the dyn_cast'ed +/// node. +template <typename T, typename To> +class DynCastMatcher : public MatcherInterface<T> { + public: + explicit DynCastMatcher(const Matcher<To> &InnerMatcher) + : InnerMatcher(InnerMatcher) {} + + virtual bool Matches(const T &Node, + ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + const To *InnerMatchValue = llvm::dyn_cast<To>(&Node); + return InnerMatchValue != NULL && + InnerMatcher.Matches(*InnerMatchValue, Finder, Builder); + } + + private: + const Matcher<To> InnerMatcher; +}; + +/// Enables the user to pass a Matcher<clang::CXXMemberCallExpr> to Call(). +/// FIXME: Alternatives are using more specific methods than Call, like +/// MemberCall, or not using VariadicFunction for Call and overloading it. +template <> +template <> +inline Matcher<clang::CXXMemberCallExpr>:: +operator Matcher<clang::CallExpr>() const { + return MakeMatcher( + new DynCastMatcher<clang::CallExpr, clang::CXXMemberCallExpr>(*this)); +} + +/// Matcher<T> that wraps an inner Matcher<T> and binds the matched node to +/// an ID if the inner matcher matches on the node. +template <typename T> +class IdMatcher : public MatcherInterface<T> { + public: + /// Creates an IdMatcher that binds to 'ID' if 'InnerMatcher' matches the node. + IdMatcher(const std::string &ID, const Matcher<T> &InnerMatcher) + : ID(ID), InnerMatcher(InnerMatcher) {} + + virtual bool Matches( + const T &Node, + ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + bool Result = InnerMatcher.Matches(Node, Finder, Builder); + if (Result) { + Builder->SetBinding(ID, &Node); + } + return Result; + } + + private: + const std::string ID; + const Matcher<T> InnerMatcher; +}; + +/// Matches nodes of type T that have child nodes of type ChildT for +/// which a specified child matcher matches. ChildT must be an AST base +/// type. +template <typename T, typename ChildT> +class HasMatcher : public MatcherInterface<T> { + COMPILE_ASSERT(IsBaseType<ChildT>::value, has_only_accepts_base_type_matcher); + public: + explicit HasMatcher(const Matcher<ChildT> &ChildMatcher) + : ChildMatcher(ChildMatcher) {} + + virtual bool Matches(const T &Node, + ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + return Finder->MatchesChildOf( + Node, ChildMatcher, Builder, + ASTMatchFinder::kIgnoreImplicitCastsAndParentheses); + } + + private: + const TypedBaseMatcher<ChildT> ChildMatcher; +}; + +/// Matches nodes of type T if the given Matcher<T> does not match. +/// Type argument MatcherT is required by PolymorphicMatcherWithParam1 +/// but not actually used. It will always be instantiated with a type +/// convertible to Matcher<T>. +template <typename T, typename MatcherT> +class NotMatcher : public MatcherInterface<T> { + public: + explicit NotMatcher(const Matcher<T> &InnerMatcher) + : InnerMatcher(InnerMatcher) {} + + virtual bool Matches( + const T &Node, + ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + return !InnerMatcher.Matches(Node, Finder, Builder); + } + + private: + const Matcher<T> InnerMatcher; +}; + +/// Matches nodes of type T for which both provided matchers +/// match. Type arguments MatcherT1 and MatcherT2 are required by +/// PolymorphicMatcherWithParam2 but not actually used. They will +/// always be instantiated with types convertible to Matcher<T>. +template <typename T, typename MatcherT1, typename MatcherT2> +class AllOfMatcher : public MatcherInterface<T> { + public: + AllOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2) + : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {} + + virtual bool Matches( + const T &Node, + ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + return InnerMatcher1.Matches(Node, Finder, Builder) && + InnerMatcher2.Matches(Node, Finder, Builder); + } + + private: + const Matcher<T> InnerMatcher1; + const Matcher<T> InnerMatcher2; +}; + +/// Matches nodes of type T for which at least one of the two provided +/// matchers matches. Type arguments MatcherT1 and MatcherT2 are +/// required by PolymorphicMatcherWithParam2 but not actually +/// used. They will always be instantiated with types convertible to +/// Matcher<T>. +template <typename T, typename MatcherT1, typename MatcherT2> +class AnyOfMatcher : public MatcherInterface<T> { + public: + AnyOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2) + : InnerMatcher1(InnerMatcher1), InnertMatcher2(InnerMatcher2) {} + + virtual bool Matches( + const T &Node, + ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + return InnerMatcher1.Matches(Node, Finder, Builder) || + InnertMatcher2.Matches(Node, Finder, Builder); + } + + private: + const Matcher<T> InnerMatcher1; + const Matcher<T> InnertMatcher2; +}; + +/// Creates a Matcher<T> that matches if +/// T is dyn_cast'able into InnerT and all inner matchers match. +template<typename T, typename InnerT> +Matcher<T> MakeDynCastAllOfComposite( + const Matcher<InnerT> *const InnerMatchers[], int Count) { + if (Count == 0) { + return ArgumentAdaptingMatcher<DynCastMatcher, InnerT>( + MakeMatcher(new TrueMatcher<InnerT>)); + } + Matcher<InnerT> InnerMatcher = *InnerMatchers[Count-1]; + for (int I = Count-2; I >= 0; --I) { + InnerMatcher = MakeMatcher( + new AllOfMatcher<InnerT, Matcher<InnerT>, Matcher<InnerT> >( + *InnerMatchers[I], InnerMatcher)); + } + return ArgumentAdaptingMatcher<DynCastMatcher, InnerT>(InnerMatcher); +} + +/// Matches nodes of type T that have at least one descendant node of +/// type DescendantT for which the given inner matcher matches. +/// DescendantT must be an AST base type. +template <typename T, typename DescendantT> +class HasDescendantMatcher : public MatcherInterface<T> { + COMPILE_ASSERT(IsBaseType<DescendantT>::value, + has_descendant_only_accepts_base_type_matcher); + public: + explicit HasDescendantMatcher(const Matcher<DescendantT> &DescendantMatcher) + : DescendantMatcher(DescendantMatcher) {} + + virtual bool Matches( + const T &Node, + ASTMatchFinder *Finder, + BoundNodesBuilder *Builder) const { + return Finder->MatchesDescendantOf( + Node, DescendantMatcher, Builder); + } + + private: + const TypedBaseMatcher<DescendantT> DescendantMatcher; +}; + +/// Matches on nodes that have a getValue() method if getValue() equals the +/// value the ValueEqualsMatcher was constructed with. +template <typename T, typename ValueT> +class ValueEqualsMatcher : public SingleNodeMatcherInterface<T> { + COMPILE_ASSERT((llvm::is_base_of<clang::CharacterLiteral, T>::value) || + (llvm::is_base_of<clang::CXXBoolLiteralExpr, T>::value) || + (llvm::is_base_of<clang::FloatingLiteral, T>::value) || + (llvm::is_base_of<clang::IntegerLiteral, T>::value), + the_node_must_have_a_getValue_method); + public: + explicit ValueEqualsMatcher(const ValueT &ExpectedValue) + : ExpectedValue(ExpectedValue) {} + + virtual bool MatchesNode(const T &Node) const { + return Node.getValue() == ExpectedValue; + } + + private: + const ValueT ExpectedValue; +}; + +template <typename T> +class IsDefinitionMatcher : public SingleNodeMatcherInterface<T> { + COMPILE_ASSERT((llvm::is_base_of<clang::TagDecl, T>::value) || + (llvm::is_base_of<clang::VarDecl, T>::value) || + (llvm::is_base_of<clang::FunctionDecl, T>::value), + is_definition_requires_isThisDeclarationADefinition_method); + public: + virtual bool MatchesNode(const T &Node) const { + return Node.isThisDeclarationADefinition(); + } +}; + +class IsArrowMatcher : public SingleNodeMatcherInterface<clang::MemberExpr> { + public: + virtual bool MatchesNode(const clang::MemberExpr &Node) const { + return Node.isArrow(); + } +}; + +/// A VariadicDynCastAllOfMatcher<SourceT, TargetT> object is a +/// variadic functor that takes a list of Matcher<TargetT> and returns +/// a Matcher<SourceT> that dyn_casts its argument to TargetT. +template <typename SourceT, typename TargetT> +class VariadicDynCastAllOfMatcher + : public internal::VariadicFunction< + Matcher<SourceT>, Matcher<TargetT>, + MakeDynCastAllOfComposite<SourceT, TargetT> > { + public: + VariadicDynCastAllOfMatcher() {} +}; + +/// AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) { ... } +/// +/// defines a single-parameter function named DefineMatcher() that returns a +/// Matcher<Type> object. The code between the curly braces has access +/// to the following variables: +/// +/// Node: the AST node being matched; its type is Type. +/// Param: the parameter passed to the function; its type +/// is ParamType. +/// Finder: an ASTMatchFinder*. +/// Builder: a BoundNodesBuilder*. +/// +/// The code should return true if 'Node' matches. +#define AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) \ + class matcher_internal_##DefineMatcher##Matcher \ + : public MatcherInterface<Type> { \ + public: \ + explicit matcher_internal_##DefineMatcher##Matcher( \ + const ParamType &A##Param) : Param(A##Param) {} \ + virtual bool Matches( \ + const Type &Node, ASTMatchFinder *Finder, \ + BoundNodesBuilder *Builder) const; \ + private: \ + const ParamType Param; \ + }; \ + inline Matcher<Type> DefineMatcher(const ParamType &Param) { \ + return MakeMatcher(new matcher_internal_##DefineMatcher##Matcher(Param)); \ + } \ + inline bool matcher_internal_##DefineMatcher##Matcher::Matches( \ + const Type &Node, ASTMatchFinder *Finder, \ + BoundNodesBuilder *Builder) const + +/// AST_MATCHER_P2(Type, DefineMatcher, ParamType1, Param1, ParamType2, Param2) +/// { ... } +/// +/// defines a two-parameter function named DefineMatcher() that returns a +/// Matcher<Type> object. The code between the curly braces has access +/// to the following variables: +/// +/// Node: the AST node being matched; its type is Type. +/// Param1, Param2: the parameters passed to the function; their types +/// are ParamType1 and ParamType2. +/// Finder: an ASTMatchFinder*. +/// Builder: a BoundNodesBuilder*. +/// +/// The code should return true if 'Node' matches. +#define AST_MATCHER_P2( \ + Type, DefineMatcher, ParamType1, Param1, ParamType2, Param2) \ + class matcher_internal_##DefineMatcher##Matcher \ + : public MatcherInterface<Type> { \ + public: \ + matcher_internal_##DefineMatcher##Matcher( \ + const ParamType1 &A##Param1, const ParamType2 &A##Param2) \ + : Param1(A##Param1), Param2(A##Param2) {} \ + virtual bool Matches( \ + const Type &Node, ASTMatchFinder *Finder, \ + BoundNodesBuilder *Builder) const; \ + private: \ + const ParamType1 Param1; \ + const ParamType2 Param2; \ + }; \ + inline Matcher<Type> DefineMatcher( \ + const ParamType1 &Param1, const ParamType2 &Param2) { \ + return MakeMatcher(new matcher_internal_##DefineMatcher##Matcher( \ + Param1, Param2)); \ + } \ + inline bool matcher_internal_##DefineMatcher##Matcher::Matches( \ + const Type &Node, ASTMatchFinder *Finder, \ + BoundNodesBuilder *Builder) const + +/// AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) { ... } +/// +/// defines a single-parameter function named DefineMatcher() that is +/// polymorphic in the return type. The variables are the same as for +/// AST_MATCHER_P, with the addition of NodeType, which specifies the node type +/// of the matcher Matcher<NodeType> returned by the function matcher(). +/// +/// FIXME: Pull out common code with above macro? +#define AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) \ + template <typename NodeType, typename ParamT> \ + class matcher_internal_##DefineMatcher##Matcher \ + : public MatcherInterface<NodeType> { \ + public: \ + explicit matcher_internal_##DefineMatcher##Matcher( \ + const ParamType &A##Param) : Param(A##Param) {} \ + virtual bool Matches( \ + const NodeType &Node, ASTMatchFinder *Finder, \ + BoundNodesBuilder *Builder) const; \ + private: \ + const ParamType Param; \ + }; \ + inline PolymorphicMatcherWithParam1< \ + matcher_internal_##DefineMatcher##Matcher, \ + ParamType > \ + DefineMatcher(const ParamType &Param) { \ + return PolymorphicMatcherWithParam1< \ + matcher_internal_##DefineMatcher##Matcher, \ + ParamType >(Param); \ + } \ + template <typename NodeType, typename ParamT> \ + bool matcher_internal_##DefineMatcher##Matcher<NodeType, ParamT>::Matches( \ + const NodeType &Node, ASTMatchFinder *Finder, \ + BoundNodesBuilder *Builder) const + +/// AST_POLYMORPHIC_MATCHER_P2( +/// DefineMatcher, ParamType1, Param1, ParamType2, Param2) { ... } +/// +/// defines a two-parameter function named matcher() that is polymorphic in +/// the return type. The variables are the same as for AST_MATCHER_P2, with the +/// addition of NodeType, which specifies the node type of the matcher +/// Matcher<NodeType> returned by the function DefineMatcher(). +#define AST_POLYMORPHIC_MATCHER_P2( \ + DefineMatcher, ParamType1, Param1, ParamType2, Param2) \ + template <typename NodeType, typename ParamT1, typename ParamT2> \ + class matcher_internal_##DefineMatcher##Matcher \ + : public MatcherInterface<NodeType> { \ + public: \ + matcher_internal_##DefineMatcher##Matcher( \ + const ParamType1 &A##Param1, const ParamType2 &A##Param2) \ + : Param1(A##Param1), Param2(A##Param2) {} \ + virtual bool Matches( \ + const NodeType &Node, ASTMatchFinder *Finder, \ + BoundNodesBuilder *Builder) const; \ + private: \ + const ParamType1 Param1; \ + const ParamType2 Param2; \ + }; \ + inline PolymorphicMatcherWithParam2< \ + matcher_internal_##DefineMatcher##Matcher, \ + ParamType1, ParamType2 > \ + DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) { \ + return PolymorphicMatcherWithParam2< \ + matcher_internal_##DefineMatcher##Matcher, \ + ParamType1, ParamType2 >( \ + Param1, Param2); \ + } \ + template <typename NodeType, typename ParamT1, typename ParamT2> \ + bool matcher_internal_##DefineMatcher##Matcher< \ + NodeType, ParamT1, ParamT2>::Matches( \ + const NodeType &Node, ASTMatchFinder *Finder, \ + BoundNodesBuilder *Builder) const + +namespace match { + +typedef Matcher<clang::Decl> DeclarationMatcher; +typedef Matcher<clang::QualType> TypeMatcher; +typedef Matcher<clang::Stmt> StatementMatcher; + +/// Matches C++ class declarations. +/// +/// Example matches X, Z +/// class X; +/// template<class T> class Z {}; +const VariadicDynCastAllOfMatcher<clang::Decl, clang::CXXRecordDecl> Class; + +/// Matches method declarations. +/// +/// Example matches y +/// class X { void y() }; +const VariadicDynCastAllOfMatcher<clang::Decl, clang::CXXMethodDecl> Method; + +/// Matches variable declarations. +/// +/// Example matches a +/// int a; +const VariadicDynCastAllOfMatcher<clang::Decl, clang::VarDecl> Variable; + +/// Matches member expressions. +/// +/// Given +/// class Y { +/// void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; } +/// int a; static int b; +/// }; +/// MemberExpression() +/// matches this->x, x, y.x, a, this->b +const VariadicDynCastAllOfMatcher<clang::Stmt, clang::MemberExpr> +MemberExpression; + +/// Matches call expressions. +/// +/// Example matches x.y() +/// X x; +/// x.y(); +const VariadicDynCastAllOfMatcher<clang::Stmt, clang::CallExpr> Call; + +/// Matches constructor call expressions (including implicit ones). +/// +/// Example matches string(ptr, n) and ptr within arguments of f +/// (matcher = ConstructorCall()) +/// void f(const string &a, const string &b); +/// char *ptr; +/// int n; +/// f(string(ptr, n), ptr); +const VariadicDynCastAllOfMatcher<clang::Stmt, clang::CXXConstructExpr> +ConstructorCall; + +/// Matches the value of a default argument at the call site. +/// +/// Example matches the CXXDefaultArgExpr placeholder inserted for the +/// default value of the second parameter in the call expression f(42) +/// (matcher = DefaultArgument()) +/// void f(int x, int y = 0); +/// f(42); +const VariadicDynCastAllOfMatcher<clang::Stmt, clang::CXXDefaultArgExpr> +DefaultArgument; + +/// Matches overloaded operator calls. +/// Note that if an operator isn't overloaded, it won't match. Instead, use +/// BinaryOperator matcher. +/// Currently it does not match operators such as new delete. +/// FIXME: figure out why these do not match? +/// +/// Example matches both operator<<((o << b), c) and operator<<(o, b) +/// (matcher = OverloadedOperatorCall()) +/// ostream &operator<< (ostream &out, int i) { }; +/// ostream &o; int b = 1, c = 1; +/// o << b << c; +const VariadicDynCastAllOfMatcher<clang::Stmt, clang::CXXOperatorCallExpr> +OverloadedOperatorCall; + +/// Matches expressions. +/// +/// Example matches x() +/// void f() { x(); } +const VariadicDynCastAllOfMatcher<clang::Stmt, clang::Expr> Expression; + +/// Matches expressions that refer to declarations. +/// +/// Example matches x in if (x) +/// bool x; +/// if (x) {} +const VariadicDynCastAllOfMatcher<clang::Stmt, clang::DeclRefExpr> +DeclarationReference; + +/// Matches if statements. +/// +/// Example matches 'if (x) {}' +/// if (x) {} +const VariadicDynCastAllOfMatcher<clang::Stmt, clang::IfStmt> If; + +/// Matches for statements. +/// +/// Example matches 'for (;;) {}' +/// for (;;) {} +const VariadicDynCastAllOfMatcher<clang::Stmt, clang::ForStmt> For; + +/// Matches compound statements. +/// +/// Example matches '{}' and '{{}}'in 'for (;;) {{}}' +/// for (;;) {{}} +const VariadicDynCastAllOfMatcher<clang::Stmt, clang::CompoundStmt> +CompoundStatement; + +/// Matches bool literals. +/// +/// Example matches true +/// true +const VariadicDynCastAllOfMatcher<clang::Expr, clang::CXXBoolLiteralExpr> +BoolLiteral; + +/// Matches string literals (also matches wide string literals). +/// +/// Example matches "abcd", L"abcd" +/// char *s = "abcd"; wchar_t *ws = L"abcd" +const VariadicDynCastAllOfMatcher<clang::Expr, clang::StringLiteral> +StringLiteral; + +/// Matches character literals (also matches wchar_t). +/// Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral), +/// though. +/// +/// Example matches 'a', L'a' +/// char ch = 'a'; wchar_t chw = L'a'; +const VariadicDynCastAllOfMatcher<clang::Expr, clang::CharacterLiteral> +CharacterLiteral; + +/// Matches integer literals of all sizes / encodings. +/// Not matching character-encoded integers such as L'a'. +/// +/// Example matches 1, 1L, 0x1, 1U +const VariadicDynCastAllOfMatcher<clang::Expr, clang::IntegerLiteral> +IntegerLiteral; + +/// Matches binary operator expressions. +/// +/// Example matches a || b +/// !(a || b) +const VariadicDynCastAllOfMatcher<clang::Stmt, clang::BinaryOperator> +BinaryOperator; + +/// Matches unary operator expressions. +/// +/// Example matches !a +/// !a || b +const VariadicDynCastAllOfMatcher<clang::Stmt, clang::UnaryOperator> +UnaryOperator; + +/// Matches conditional operator expressions. +/// +/// Example matches a ? b : c +/// (a ? b : c) + 42 +const VariadicDynCastAllOfMatcher<clang::Stmt, clang::ConditionalOperator> +ConditionalOperator; + +template<typename C1, typename C2> +PolymorphicMatcherWithParam2<AnyOfMatcher, C1, C2> +AnyOf(const C1 &P1, const C2 &P2) { + return PolymorphicMatcherWithParam2< AnyOfMatcher, C1, C2 >(P1, P2); +} + +template<typename C1, typename C2, typename C3> +PolymorphicMatcherWithParam2<AnyOfMatcher, C1, + PolymorphicMatcherWithParam2<AnyOfMatcher, C2, C3> > +AnyOf(const C1 &P1, const C2 &P2, const C3 &P3) { + return AnyOf(P1, AnyOf(P2, P3)); +} + +template<typename C1, typename C2, typename C3, typename C4> +PolymorphicMatcherWithParam2<AnyOfMatcher, C1, + PolymorphicMatcherWithParam2<AnyOfMatcher, C2, + PolymorphicMatcherWithParam2<AnyOfMatcher, C3, C4> > > +AnyOf(const C1 &P1, const C2 &P2, const C3 &P3, const C4 &P4) { + return AnyOf(P1, AnyOf(P2, AnyOf(P3, P4))); +} + +template<typename C1, typename C2> +PolymorphicMatcherWithParam2<AllOfMatcher, C1, C2> +AllOf(const C1 &P1, const C2 &P2) { + return PolymorphicMatcherWithParam2<AllOfMatcher, C1, C2>(P1, P2); +} + +/// Matches NamedDecl nodes that have the specified name. Supports specifying +/// enclosing namespaces or classes by prefixing the name with '<enclosing>::'. +/// Does not match typedefs of an underlying type with the given name. +/// +/// Example matches X (name == "X") +/// class X; +/// +/// Example matches X (name is one of "::a::b::X", "a::b::X", "b::X", "X") +/// namespace a { namespace b { class X; } } +AST_MATCHER_P(clang::NamedDecl, HasName, std::string, Name) { + assert(!Name.empty()); + const std::string FullNameString = "::" + Node.getQualifiedNameAsString(); + const llvm::StringRef FullName = FullNameString; + const llvm::StringRef Pattern = Name; + if (Pattern.startswith("::")) { + return FullName == Pattern; + } else { + return FullName.endswith(("::" + Pattern).str()); + } +} + +/// Matches overloaded operator name given in strings without the "operator" +/// prefix, such as "<<", for OverloadedOperatorCall's. +/// +/// Example matches a << b +/// (matcher == OverloadedOperatorCall(HasOverloadedOperatorName("<<"))) +/// a << b; +/// c && d; // assuming both operator<< +/// // and operator&& are overloaded somewhere. +AST_MATCHER_P(clang::CXXOperatorCallExpr, + HasOverloadedOperatorName, std::string, Name) { + return clang::getOperatorSpelling(Node.getOperator()) == Name; +} + +/// Matches C++ classes that are directly or indirectly derived from +/// the given base class. Note that a class is considered to be also +/// derived from itself. The parameter specified the name of the base +/// type (either a class or a typedef), and does not allow structural +/// matches for namespaces or template type parameters. +/// +/// Example matches X, Y, Z, C (base == "X") +/// class X; // A class is considered to be derived from itself. +/// class Y : public X {}; // directly derived +/// class Z : public Y {}; // indirectly derived +/// typedef X A; +/// typedef A B; +/// class C : public B {}; // derived from a typedef of X +/// +/// In the following example, Bar matches IsDerivedFrom("X"): +/// class Foo; +/// typedef Foo X; +/// class Bar : public Foo {}; // derived from a type that X is a typedef of +AST_MATCHER_P(clang::CXXRecordDecl, IsDerivedFrom, std::string, Base) { + assert(!Base.empty()); + return Finder->ClassIsDerivedFrom(&Node, Base); +} + +/// Matches AST nodes that have child AST nodes that match the provided matcher. +/// +/// Example matches X, Y (matcher = Class(Has(Class(HasName("X"))) +/// class X {}; // Matches X, because X::X is a class of name X inside X. +/// class Y { class X {}; }; +/// class Z { class Y { class X {}; }; }; // Does not match Z. +/// +/// ChildT must be an AST base type. +template <typename ChildT> +ArgumentAdaptingMatcher<HasMatcher, ChildT> Has( + const Matcher<ChildT> &ChildMatcher) { + return ArgumentAdaptingMatcher<HasMatcher, ChildT>(ChildMatcher); +} + +/// Matches AST nodes that have descendant AST nodes that match the provided +/// matcher. +/// +/// Example matches X, Y, Z (matcher = Class(HasDescendant(Class(HasName("X"))))) +/// class X {}; // Matches X, because X::X is a class of name X inside X. +/// class Y { class X {}; }; +/// class Z { class Y { class X {}; }; }; +/// +/// DescendantT must be an AST base type. +template <typename DescendantT> +ArgumentAdaptingMatcher<HasDescendantMatcher, DescendantT> HasDescendant( + const Matcher<DescendantT> &DescendantMatcher) { + return ArgumentAdaptingMatcher<HasDescendantMatcher, DescendantT>( + DescendantMatcher); +} + +/// Matches if the provided matcher does not match. +/// +/// Example matches Y (matcher = Class(Not(HasName("X")))) +/// class X {}; +/// class Y {}; +template <typename M> +PolymorphicMatcherWithParam1<NotMatcher, M> Not(const M &InnerMatcher) { + return PolymorphicMatcherWithParam1<NotMatcher, M>(InnerMatcher); +} + +/// If the provided matcher matches a node, binds the node to 'id'. +/// FIXME: Add example for accessing it. +template <typename T> +Matcher<T> Id(const std::string &ID, const Matcher<T> &InnerMatcher) { + return Matcher<T>(new IdMatcher<T>(ID, InnerMatcher)); +} + +/// Matches a type if the declaration of the type matches the given matcher. +inline PolymorphicMatcherWithParam1< HasDeclarationMatcher, + Matcher<clang::Decl> > + HasDeclaration(const Matcher<clang::Decl> &InnerMatcher) { + return PolymorphicMatcherWithParam1< HasDeclarationMatcher, + Matcher<clang::Decl> >(InnerMatcher); +} + +/// Matches on the implicit object argument of a member call expression. +/// +/// Example matches y.x() (matcher = Call(On(HasType(Class(HasName("Y")))))) +/// class Y { public: void x(); }; +/// void z() { Y y; y.x(); }", +/// +/// FIXME: Overload to allow directly matching types? +AST_MATCHER_P( + clang::CXXMemberCallExpr, On, Matcher<clang::Expr>, InnerMatcher) { + const clang::Expr *ExprNode = const_cast<clang::CXXMemberCallExpr&>(Node) + .getImplicitObjectArgument() + ->IgnoreParenImpCasts(); + return (ExprNode != NULL && + InnerMatcher.Matches(*ExprNode, Finder, Builder)); +} + +/// Matches if the call expression's callee expression matches. +/// +/// Given +/// class Y { void x() { this->x(); x(); Y y; y.x(); } }; +/// void f() { f(); } +/// Call(Callee(Expression())) +/// matches this->x(), x(), y.x(), f() +/// with Callee(...) +/// matching this->x, x, y.x, f respectively +/// +/// Note: Callee cannot take the more general Matcher<clang::Expr> because +/// this introduces ambiguous overloads with calls to Callee taking a +/// Matcher<clang::Decl>, as the matcher hierarchy is purely implemented in +/// terms of implicit casts. +AST_MATCHER_P(clang::CallExpr, Callee, Matcher<clang::Stmt>, InnerMatcher) { + const clang::Expr *ExprNode = Node.getCallee(); + return (ExprNode != NULL && + InnerMatcher.Matches(*ExprNode, Finder, Builder)); +} + +/// Matches if the call expression's callee's declaration matches the given +/// matcher. +/// +/// Example matches y.x() (matcher = Call(Callee(Method(HasName("x"))))) +/// class Y { public: void x(); }; +/// void z() { Y y; y.x(); +inline Matcher<clang::CallExpr> Callee( + const Matcher<clang::Decl> &InnerMatcher) { + return Matcher<clang::CallExpr>(HasDeclaration(InnerMatcher)); +} + +/// Matches if the expression's or declaration's type matches a type matcher. +/// +/// Example matches x (matcher = Expression(HasType( +/// HasDeclaration(Class(HasName("X")))))) +/// and z (matcher = Variable(HasType( +/// HasDeclaration(Class(HasName("X")))))) +/// class X {}; +/// void y(X &x) { x; X z; } +AST_POLYMORPHIC_MATCHER_P(HasType, Matcher<clang::QualType>, InnerMatcher) { + COMPILE_ASSERT((llvm::is_base_of<clang::Expr, NodeType>::value || + llvm::is_base_of<clang::ValueDecl, NodeType>::value), + instantiated_with_wrong_types); + return InnerMatcher.Matches(Node.getType(), Finder, Builder); +} + +/// Overloaded to match the declaration of the expression's or value +/// declaration's type. +/// In case of a value declaration (for example a variable declaration), +/// this resolves one layer of indirection. For example, in the value declaration +/// "X x;", Class(HasName("X")) matches the declaration of X, while +/// Variable(HasType(Class(HasName("X")))) matches the declaration of x." +/// +/// Example matches x (matcher = Expression(HasType(Class(HasName("X"))))) +/// and z (matcher = Variable(HasType(Class(HasName("X"))))) +/// class X {}; +/// void y(X &x) { x; X z; } +inline PolymorphicMatcherWithParam1<matcher_internal_HasTypeMatcher, + Matcher<clang::QualType> > +HasType(const Matcher<clang::Decl> &InnerMatcher) { + return HasType(Matcher<clang::QualType>(HasDeclaration(InnerMatcher))); +} + +/// Matches if the matched type is a pointer type and the pointee type matches +/// the specified matcher. +/// +/// Example matches y->x() +/// (matcher = Call(On(HasType(PointsTo(Class(HasName("Y"))))))) +/// class Y { public: void x(); }; +/// void z() { Y *y; y->x(); } +AST_MATCHER_P( + clang::QualType, PointsTo, Matcher<clang::QualType>, InnerMatcher) { + return (Node->isPointerType() && + InnerMatcher.Matches(Node->getPointeeType(), Finder, Builder)); +} + +/// Overloaded to match the pointee type's declaration. +inline Matcher<clang::QualType> PointsTo( + const Matcher<clang::Decl> &InnerMatcher) { + return PointsTo(Matcher<clang::QualType>(HasDeclaration(InnerMatcher))); +} + +/// Matches if the matched type is a reference type and the referenced type +/// matches the specified matcher. +/// +/// Example matches X &x and const X &y +/// (matcher = Variable(HasType(References(Class(HasName("X")))))) +/// class X { +/// void a(X b) { +/// X &x = b; +/// const X &y = b; +/// }; +AST_MATCHER_P( + clang::QualType, References, Matcher<clang::QualType>, InnerMatcher) { + return (Node->isReferenceType() && + InnerMatcher.Matches(Node->getPointeeType(), Finder, Builder)); +} + +/// Overloaded to match the referenced type's declaration. +inline Matcher<clang::QualType> References( + const Matcher<clang::Decl> &InnerMatcher) { + return References(Matcher<clang::QualType>(HasDeclaration(InnerMatcher))); +} + +AST_MATCHER_P(clang::CXXMemberCallExpr, OnImplicitObjectArgument, + Matcher<clang::Expr>, InnerMatcher) { + const clang::Expr *ExprNode = + const_cast<clang::CXXMemberCallExpr&>(Node).getImplicitObjectArgument(); + return (ExprNode != NULL && + InnerMatcher.Matches(*ExprNode, Finder, Builder)); +} + +/// Matches if the expression's type either matches the specified matcher, or +/// is a pointer to a type that matches the InnerMatcher. +inline Matcher<clang::CallExpr> ThisPointerType( + const Matcher<clang::QualType> &InnerMatcher) { + return OnImplicitObjectArgument( + AnyOf(HasType(InnerMatcher), HasType(PointsTo(InnerMatcher)))); +} + +/// Overloaded to match the type's declaration. +inline Matcher<clang::CallExpr> ThisPointerType( + const Matcher<clang::Decl> &InnerMatcher) { + return OnImplicitObjectArgument( + AnyOf(HasType(InnerMatcher), HasType(PointsTo(InnerMatcher)))); +} + +/// Matches a DeclRefExpr that refers to a declaration that matches the specified +/// matcher. +/// +/// Example matches x in if(x) +/// (matcher = DeclarationReference(To(Variable(HasName("x"))))) +/// bool x; +/// if (x) {} +AST_MATCHER_P(clang::DeclRefExpr, To, Matcher<clang::Decl>, InnerMatcher) { + const clang::Decl *DeclNode = Node.getDecl(); + return (DeclNode != NULL && + InnerMatcher.Matches(*DeclNode, Finder, Builder)); +} + +/// Matches a variable declaration that has an initializer expression that +/// matches the given matcher. +/// +/// Example matches x (matcher = Variable(HasInitializer(Call()))) +/// bool y() { return true; } +/// bool x = y(); +AST_MATCHER_P( + clang::VarDecl, HasInitializer, Matcher<clang::Expr>, InnerMatcher) { + const clang::Expr *Initializer = Node.getAnyInitializer(); + return (Initializer != NULL && + InnerMatcher.Matches(*Initializer, Finder, Builder)); +} + +/// Checks that a call expression or a constructor call expression has +/// a specific number of arguments (including absent default arguments). +/// +/// Example matches f(0, 0) (matcher = Call(ArgumentCountIs(2))) +/// void f(int x, int y); +/// f(0, 0); +AST_POLYMORPHIC_MATCHER_P(ArgumentCountIs, unsigned, N) { + COMPILE_ASSERT((llvm::is_base_of<clang::CallExpr, NodeType>::value || + llvm::is_base_of<clang::CXXConstructExpr, NodeType>::value), + instantiated_with_wrong_types); + return Node.getNumArgs() == N; +} + +/// Matches the n'th argument of a call expression or a constructor +/// call expression. +/// +/// Example matches y in x(y) +/// (matcher = Call(HasArgument(0, DeclarationReference()))) +/// void x(int) { int y; x(y); } +AST_POLYMORPHIC_MATCHER_P2( + HasArgument, unsigned, N, Matcher<clang::Expr>, InnerMatcher) { + COMPILE_ASSERT((llvm::is_base_of<clang::CallExpr, NodeType>::value || + llvm::is_base_of<clang::CXXConstructExpr, NodeType>::value), + instantiated_with_wrong_types); + assert(N >= 0); + return (N < Node.getNumArgs() && + InnerMatcher.Matches( + *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder)); +} + +/// Matches any argument of a call expression or a constructor call expression. +/// +/// Given +/// void x(int, int, int) { int y; x(1, y, 42); } +/// Call(HasAnyArgument(DeclarationReference())) +/// matches x(1, y, 42) +/// with HasAnyArgument(...) +/// matching y +AST_POLYMORPHIC_MATCHER_P(HasAnyArgument, Matcher<clang::Expr>, InnerMatcher) { + COMPILE_ASSERT((llvm::is_base_of<clang::CallExpr, NodeType>::value || + llvm::is_base_of<clang::CXXConstructExpr, NodeType>::value), + instantiated_with_wrong_types); + for (unsigned I = 0; I < Node.getNumArgs(); ++I) { + if (InnerMatcher.Matches(*Node.getArg(I)->IgnoreParenImpCasts(), + Finder, Builder)) { + return true; + } + } + return false; +} + +/// Matches the n'th parameter of a function declaration. +/// +/// Given +/// class X { void f(int x) {} }; +/// Method(HasParameter(0, HasType(Variable()))) +/// matches f(int x) {} +/// with HasParameter(...) +/// matching int x +AST_MATCHER_P2(clang::FunctionDecl, HasParameter, + unsigned, N, Matcher<clang::ParmVarDecl>, InnerMatcher) { + assert(N >= 0); + return (N < Node.getNumParams() && + InnerMatcher.Matches( + *Node.getParamDecl(N), Finder, Builder)); +} + +/// Matches any parameter of a function declaration. +/// Does not match the 'this' parameter of a method. +/// +/// Given +/// class X { void f(int x, int y, int z) {} }; +/// Method(HasAnyParameter(HasName("y"))) +/// matches f(int x, int y, int z) {} +/// with HasAnyParameter(...) +/// matching int y +AST_MATCHER_P(clang::FunctionDecl, HasAnyParameter, + Matcher<clang::ParmVarDecl>, InnerMatcher) { + for (unsigned I = 0; I < Node.getNumParams(); ++I) { + if (InnerMatcher.Matches(*Node.getParamDecl(I), Finder, Builder)) { + return true; + } + } + return false; +} + +/// Matches the condition expression of an if statement or conditional operator. +/// +/// Example matches true (matcher = HasCondition(BoolLiteral(Equals(true)))) +/// if (true) {} +AST_POLYMORPHIC_MATCHER_P(HasCondition, Matcher<clang::Expr>, InnerMatcher) { + COMPILE_ASSERT((llvm::is_base_of<clang::IfStmt, NodeType>::value) || + (llvm::is_base_of<clang::ConditionalOperator, + NodeType>::value), + has_condition_requires_if_statement_or_conditional_operator); + const clang::Expr *const Condition = Node.getCond(); + return (Condition != NULL && + InnerMatcher.Matches(*Condition, Finder, Builder)); +} + +/// Matches a 'for' statement that has a given body. +/// +/// Given +/// for (;;) {} +/// HasBody(CompoundStatement()) +/// matches 'for (;;) {}' +/// with CompoundStatement() +/// matching '{}' +AST_MATCHER_P(clang::ForStmt, HasBody, Matcher<clang::Stmt>, InnerMatcher) { + const clang::Stmt *const Statement = Node.getBody(); + return (Statement != NULL && + InnerMatcher.Matches(*Statement, Finder, Builder)); +} + +/// Matches compound statements where at least one substatement matches a +/// given matcher. +/// +/// Given +/// { {}; 1+2; } +/// HasAnySubstatement(CompoundStatement()) +/// matches '{ {}; 1+2; }' +/// with CompoundStatement() +/// matching '{}' +AST_MATCHER_P(clang::CompoundStmt, HasAnySubstatement, + Matcher<clang::Stmt>, InnerMatcher) { + for (clang::CompoundStmt::const_body_iterator It = Node.body_begin(); + It != Node.body_end(); + ++It) { + if (InnerMatcher.Matches(**It, Finder, Builder)) return true; + } + return false; +} + +/// Checks that a compound statement contains a specific number of child +/// statements. +/// +/// Example: Given +/// { for (;;) {} } +/// CompoundStatement(StatementCountIs(0))) +/// matches '{}' +/// but does not match the outer compound statement. +AST_MATCHER_P(clang::CompoundStmt, StatementCountIs, unsigned, N) { + return Node.size() == N; +} + +/// Matches literals that are equal to the given value. +/// +/// Example matches true (matcher = BoolLiteral(Equals(true))) +/// true +template <typename ValueT> +PolymorphicMatcherWithParam1<ValueEqualsMatcher, ValueT> Equals( + const ValueT &Value) { + return PolymorphicMatcherWithParam1<ValueEqualsMatcher, ValueT>(Value); +} + +/// Matches the operator Name of operator expressions (binary or unary). +/// +/// Example matches a || b (matcher = BinaryOperator(HasOperatorName("||"))) +/// !(a || b) +AST_POLYMORPHIC_MATCHER_P(HasOperatorName, std::string, Name) { + COMPILE_ASSERT( + (llvm::is_base_of<clang::BinaryOperator, NodeType>::value) || + (llvm::is_base_of<clang::UnaryOperator, NodeType>::value), + has_condition_requires_if_statement_or_conditional_operator); + return Name == Node.getOpcodeStr(Node.getOpcode()); +} + +/// Matches the left hand side of binary operator expressions. +/// +/// Example matches a (matcher = BinaryOperator(HasLHS())) +/// a || b +AST_MATCHER_P(clang::BinaryOperator, HasLHS, + Matcher<clang::Expr>, InnerMatcher) { + clang::Expr *LeftHandSide = Node.getLHS(); + return (LeftHandSide != NULL && + InnerMatcher.Matches(*LeftHandSide, Finder, Builder)); +} + +/// Matches the right hand side of binary operator expressions. +/// +/// Example matches b (matcher = BinaryOperator(HasRHS())) +/// a || b +AST_MATCHER_P(clang::BinaryOperator, HasRHS, + Matcher<clang::Expr>, InnerMatcher) { + clang::Expr *RightHandSide = Node.getRHS(); + return (RightHandSide != NULL && + InnerMatcher.Matches(*RightHandSide, Finder, Builder)); +} + +/// Matches if either the left hand side or the right hand side of a binary +/// operator matches. +inline Matcher<clang::BinaryOperator> HasEitherOperand( + const Matcher<clang::Expr> &InnerMatcher) { + return AnyOf(HasLHS(InnerMatcher), HasRHS(InnerMatcher)); +} + +/// Matches if the operand of a unary operator matches. +/// +/// Example matches true (matcher = HasOperand(BoolLiteral(Equals(true)))) +/// !true +AST_MATCHER_P(clang::UnaryOperator, HasUnaryOperand, + Matcher<clang::Expr>, InnerMatcher) { + clang::Expr *Operand = Node.getSubExpr(); + return (Operand != NULL && + InnerMatcher.Matches(*Operand, Finder, Builder)); +} + +/// Matches the true branch expression of a conditional operator. +/// +/// Example matches a +/// condition ? a : b +AST_MATCHER_P(clang::ConditionalOperator, HasTrueExpression, + Matcher<clang::Expr>, InnerMatcher) { + clang::Expr *Expression = Node.getTrueExpr(); + return (Expression != NULL && + InnerMatcher.Matches(*Expression, Finder, Builder)); +} + +/// Matches the false branch expression of a conditional operator. +/// +/// Example matches b +/// condition ? a : b +AST_MATCHER_P(clang::ConditionalOperator, HasFalseExpression, + Matcher<clang::Expr>, Matcher) { + clang::Expr *Expression = Node.getFalseExpr(); + return (Expression != NULL && + Matcher.Matches(*Expression, Finder, Builder)); +} + +/// Matches if a declaration has a body attached. +/// +/// Example matches A, va, fa +/// class A {}; +/// class B; // Doesn't match, as it has no body. +/// int va; +/// extern int vb; // Doesn't match, as it doesn't define the variable. +/// void fa() {} +/// void fb(); // Doesn't match, as it has no body. +inline PolymorphicMatcherWithParam0<IsDefinitionMatcher> IsDefinition() { + return PolymorphicMatcherWithParam0<IsDefinitionMatcher>(); +} + +/// Matches the class declaration that the given method declaration belongs to. +/// TODO(qrczak): Generalize this for other kinds of declarations. +/// FIXME: What other kind of declarations would we need to generalize +/// this to? +/// +/// Example matches A() in the last line +/// (matcher = ConstructorCall(HasDeclaration(Method( +/// OfClass(HasName("A")))))) +/// class A { +/// public: +/// A(); +/// }; +/// A a = A(); +AST_MATCHER_P(clang::CXXMethodDecl, OfClass, + Matcher<clang::CXXRecordDecl>, InnerMatcher) { + const clang::CXXRecordDecl *Parent = Node.getParent(); + return (Parent != NULL && + InnerMatcher.Matches(*Parent, Finder, Builder)); +} + +/// Matches member expressions that are called with '->' as opposed to '.'. +/// Member calls on the implicit this pointer match as called with '->'. +/// +/// Given +/// class Y { +/// void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; } +/// int a; +/// static int b; +/// }; +/// MemberExpression(IsArrow()) +/// matches this->x, x, y.x, a, this->b +inline Matcher<clang::MemberExpr> IsArrow() { + return MakeMatcher(new IsArrowMatcher()); +} + +} // namespace match + +/// Runs over an AST and finds matches. +/// FIXME: Define exactly what "one match" is. +/// +/// Not intended to be subclassed. +class MatchFinder { + public: + struct MatchResult { + BoundNodes Nodes; + + ///@{ + /// Utilities for interpreting the matched AST structures. + clang::ASTContext *Context; + clang::SourceManager *SourceManager; + ///@} + }; + + /// Called when the Match registered for it was successfully found in the AST. + class MatchCallback { + public: + virtual ~MatchCallback(); + virtual void Run(const MatchResult &Result) = 0; + }; + + /// Called when parsing is finished. Intended for testing only. + class ParsingDoneTestCallback { + public: + virtual ~ParsingDoneTestCallback(); + virtual void Run() = 0; + }; + + MatchFinder(); + ~MatchFinder(); + + /// Adds a NodeMatcher to match when running over the AST. + /// Calls action with the BoundNodes on every match. + /// Adding more than one InnerMatcher allows finding different matches in a + /// single pass over the AST. + void AddMatcher(const Matcher<clang::Decl> &NodeMatch, + MatchCallback *Action); + /// Adds a NodeMatcher to match when running over the AST. + /// Calls action with the BoundNodes on every match. + /// Adding more than one InnerMatcher allows finding different matches in a + /// single pass over the AST. + void AddMatcher(const Matcher<clang::QualType> &NodeMatch, + MatchCallback *Action); + /// Adds a NodeMatcher to match when running over the AST. + /// Calls action with the BoundNodes on every match. + /// Adding more than one InnerMatcher allows finding different matches in a + /// single pass over the AST. + void AddMatcher(const Matcher<clang::Stmt> &NodeMatch, + MatchCallback *Action); + + /// Finds all matches in the given code and runs the corresponding triggers. + /// Returns true if the code parsed correctly. + bool FindAll(const std::string &Code); + + /// Creates a clang FrontendAction factory that finds all matches. + FrontendActionFactory *NewFrontendActionFactory(); + + /// The provided closure is called after parsing is done, before the AST is + /// traversed. Useful for benchmarking. + /// Each call to FindAll(...) will call the closure once. + void RegisterTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone); + + private: + clang::FrontendAction *NewVisitorAction(); + + /// The MatchCallback*'s will be called every time the UntypedBaseMatcher + /// matches on the AST. + std::vector< std::pair<const UntypedBaseMatcher*, MatchCallback*> > Triggers; + + /// Called when parsing is done. + ParsingDoneTestCallback *ParsingDone; + + friend class MatchFinderFrontendActionFactory; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_AST_MATCHERS_H diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h index a32147c3eb..63c8b6eb22 100644 --- a/include/clang/Tooling/Tooling.h +++ b/include/clang/Tooling/Tooling.h @@ -43,11 +43,11 @@ bool RunSyntaxOnlyToolOnCode( /// \param Argv The command line arguments, including the path the binary /// was started with (Argv[0]). bool RunToolWithFlags( - clang::FrontendAction* ToolAction, int Argc, char *Argv[]); + clang::FrontendAction *ToolAction, int Argc, char *Argv[]); /// \brief Converts a vector<string> into a vector<char*> suitable to pass /// to main-style functions taking (int Argc, char *Argv[]). -std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command); +std::vector<char*> CommandLineToArgv(const std::vector<std::string> *Command); /// \brief Specifies the working directory and command of a compilation. struct CompileCommand { diff --git a/include/clang/Tooling/VariadicFunction.h b/include/clang/Tooling/VariadicFunction.h new file mode 100644 index 0000000000..6c19d90615 --- /dev/null +++ b/include/clang/Tooling/VariadicFunction.h @@ -0,0 +1,1398 @@ +//===--- VariadicFunctions.h - Variadic Functions ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements compile-time type-safe variadic functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_VARIADIC_FUNCTION_H +#define LLVM_CLANG_TOOLING_VARIADIC_FUNCTION_H + +#include <stddef.h> // Defines NULL. + +namespace clang { +namespace tooling { +namespace internal { + +/// The VariadicFunction class template makes it easy to define +/// type-safe variadic functions where all arguments have the same +/// type. +/// +/// Suppose we need a variadic function like this: +/// +/// Result Foo(const Arg &a0, const Arg &a1, ..., const Arg &an); +/// +/// Instead of many overloads of Foo(), we only need to define a helper +/// function that takes an array of arguments: +/// +/// Result FooImpl(const Arg *const args[], int count) { +/// // 'count' is the number of values in the array; args[i] is a pointer +/// // to the i-th argument passed to Foo(). Therefore, write *args[i] +/// // to access the i-th argument. +/// ... +/// } +/// +/// and then define Foo() like this: +/// +/// const VariadicFunction<Result, Arg, FooImpl> Foo; +/// +/// VariadicFunction takes care of defining the overloads of Foo(). +/// +/// Actually, Foo is a function object (i.e. functor) instead of a plain +/// function. This object is stateless and its constructor/destructor +/// does nothing, so it's safe to call Foo(...) at any time. +/// +/// Sometimes we need a variadic function to have some fixed leading +/// arguments whose types may be different from that of the optional +/// arguments. For example: +/// +/// bool FullMatch(const StringRef &s, const RE ®ex, +/// const Arg &a0, ..., const Arg &an); +/// +/// VariadicFunctionN is for such cases, where N is the number of fixed +/// arguments. It is like VariadicFunction, except that it takes N more +/// template arguments for the types of the fixed arguments: +/// +/// bool FullMatchImpl(const StringRef &s, const RE ®ex, +/// const Arg *const args[], int count) { ... } +/// const VariadicFunction2<bool, const StringRef&, +/// const RE&, Arg, FullMatchImpl> +/// FullMatch; +/// +/// Currently VariadicFunction and friends support up-to 3 +/// fixed leading arguments and up-to 32 optional arguments. +template <typename Result, typename Arg, + Result (*Func)(const Arg *const [], int count)> +class VariadicFunction { + public: + VariadicFunction() {} + + Result operator()() const { + return Func(NULL, 0); + } + + Result operator()(const Arg &a0) const { + const Arg *const args[] = { &a0 }; + return Func(args, 1); + } + + Result operator()(const Arg &a0, const Arg &a1) const { + const Arg *const args[] = { &a0, &a1 }; + return Func(args, 2); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2) const { + const Arg *const args[] = { &a0, &a1, &a2 }; + return Func(args, 3); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3 }; + return Func(args, 4); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4 }; + return Func(args, 5); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5 }; + return Func(args, 6); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6 }; + return Func(args, 7); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7 }; + return Func(args, 8); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8 }; + return Func(args, 9); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9 }; + return Func(args, 10); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10 }; + return Func(args, 11); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11 }; + return Func(args, 12); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12 }; + return Func(args, 13); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13 }; + return Func(args, 14); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14 }; + return Func(args, 15); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15 }; + return Func(args, 16); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16 }; + return Func(args, 17); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17 }; + return Func(args, 18); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18 }; + return Func(args, 19); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19 }; + return Func(args, 20); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19, + const Arg &a20) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, + &a20 }; + return Func(args, 21); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19, + const Arg &a20, const Arg &a21) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21 }; + return Func(args, 22); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19, + const Arg &a20, const Arg &a21, const Arg &a22) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22 }; + return Func(args, 23); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19, + const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23 }; + return Func(args, 24); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19, + const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23, + const Arg &a24) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24 }; + return Func(args, 25); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19, + const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23, + const Arg &a24, const Arg &a25) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25 }; + return Func(args, 26); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19, + const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23, + const Arg &a24, const Arg &a25, const Arg &a26) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26 }; + return Func(args, 27); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19, + const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23, + const Arg &a24, const Arg &a25, const Arg &a26, const Arg &a27) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27 }; + return Func(args, 28); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19, + const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23, + const Arg &a24, const Arg &a25, const Arg &a26, const Arg &a27, + const Arg &a28) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28 }; + return Func(args, 29); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19, + const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23, + const Arg &a24, const Arg &a25, const Arg &a26, const Arg &a27, + const Arg &a28, const Arg &a29) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29 }; + return Func(args, 30); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19, + const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23, + const Arg &a24, const Arg &a25, const Arg &a26, const Arg &a27, + const Arg &a28, const Arg &a29, const Arg &a30) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30 }; + return Func(args, 31); + } + + Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3, + const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7, + const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11, + const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15, + const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19, + const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23, + const Arg &a24, const Arg &a25, const Arg &a26, const Arg &a27, + const Arg &a28, const Arg &a29, const Arg &a30, const Arg &a31) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30, &a31 }; + return Func(args, 32); + } +}; + +template <typename Result, typename Param0, typename Arg, + Result (*Func)(Param0, const Arg *const [], int count)> +class VariadicFunction1 { + public: + VariadicFunction1() {} + + Result operator()(Param0 p0) const { + return Func(p0, NULL, 0); + } + + Result operator()(Param0 p0, const Arg &a0) const { + const Arg *const args[] = { &a0 }; + return Func(p0, args, 1); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1) const { + const Arg *const args[] = { &a0, &a1 }; + return Func(p0, args, 2); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, + const Arg &a2) const { + const Arg *const args[] = { &a0, &a1, &a2 }; + return Func(p0, args, 3); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3 }; + return Func(p0, args, 4); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4 }; + return Func(p0, args, 5); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5 }; + return Func(p0, args, 6); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6 }; + return Func(p0, args, 7); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7 }; + return Func(p0, args, 8); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8 }; + return Func(p0, args, 9); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9 }; + return Func(p0, args, 10); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10 }; + return Func(p0, args, 11); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11 }; + return Func(p0, args, 12); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12 }; + return Func(p0, args, 13); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13 }; + return Func(p0, args, 14); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14 }; + return Func(p0, args, 15); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15 }; + return Func(p0, args, 16); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16 }; + return Func(p0, args, 17); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17 }; + return Func(p0, args, 18); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18 }; + return Func(p0, args, 19); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18, + const Arg &a19) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19 }; + return Func(p0, args, 20); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18, + const Arg &a19, const Arg &a20) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, + &a20 }; + return Func(p0, args, 21); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18, + const Arg &a19, const Arg &a20, const Arg &a21) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21 }; + return Func(p0, args, 22); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18, + const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22 }; + return Func(p0, args, 23); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18, + const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22, + const Arg &a23) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23 }; + return Func(p0, args, 24); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18, + const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22, + const Arg &a23, const Arg &a24) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24 }; + return Func(p0, args, 25); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18, + const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22, + const Arg &a23, const Arg &a24, const Arg &a25) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25 }; + return Func(p0, args, 26); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18, + const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22, + const Arg &a23, const Arg &a24, const Arg &a25, const Arg &a26) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26 }; + return Func(p0, args, 27); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18, + const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22, + const Arg &a23, const Arg &a24, const Arg &a25, const Arg &a26, + const Arg &a27) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27 }; + return Func(p0, args, 28); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18, + const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22, + const Arg &a23, const Arg &a24, const Arg &a25, const Arg &a26, + const Arg &a27, const Arg &a28) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28 }; + return Func(p0, args, 29); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18, + const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22, + const Arg &a23, const Arg &a24, const Arg &a25, const Arg &a26, + const Arg &a27, const Arg &a28, const Arg &a29) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29 }; + return Func(p0, args, 30); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18, + const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22, + const Arg &a23, const Arg &a24, const Arg &a25, const Arg &a26, + const Arg &a27, const Arg &a28, const Arg &a29, const Arg &a30) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30 }; + return Func(p0, args, 31); + } + + Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2, + const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6, + const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10, + const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14, + const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18, + const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22, + const Arg &a23, const Arg &a24, const Arg &a25, const Arg &a26, + const Arg &a27, const Arg &a28, const Arg &a29, const Arg &a30, + const Arg &a31) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30, &a31 }; + return Func(p0, args, 32); + } +}; + +template <typename Result, typename Param0, typename Param1, typename Arg, + Result (*Func)(Param0, Param1, const Arg *const [], int count)> +class VariadicFunction2 { + public: + VariadicFunction2() {} + + Result operator()(Param0 p0, Param1 p1) const { + return Func(p0, p1, NULL, 0); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0) const { + const Arg *const args[] = { &a0 }; + return Func(p0, p1, args, 1); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1) const { + const Arg *const args[] = { &a0, &a1 }; + return Func(p0, p1, args, 2); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2) const { + const Arg *const args[] = { &a0, &a1, &a2 }; + return Func(p0, p1, args, 3); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3 }; + return Func(p0, p1, args, 4); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4 }; + return Func(p0, p1, args, 5); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5 }; + return Func(p0, p1, args, 6); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6 }; + return Func(p0, p1, args, 7); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7 }; + return Func(p0, p1, args, 8); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8 }; + return Func(p0, p1, args, 9); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9 }; + return Func(p0, p1, args, 10); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10 }; + return Func(p0, p1, args, 11); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11 }; + return Func(p0, p1, args, 12); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12 }; + return Func(p0, p1, args, 13); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13 }; + return Func(p0, p1, args, 14); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14 }; + return Func(p0, p1, args, 15); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15 }; + return Func(p0, p1, args, 16); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16 }; + return Func(p0, p1, args, 17); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17 }; + return Func(p0, p1, args, 18); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18 }; + return Func(p0, p1, args, 19); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18, const Arg &a19) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19 }; + return Func(p0, p1, args, 20); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18, const Arg &a19, const Arg &a20) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, + &a20 }; + return Func(p0, p1, args, 21); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21 }; + return Func(p0, p1, args, 22); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21, + const Arg &a22) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22 }; + return Func(p0, p1, args, 23); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21, + const Arg &a22, const Arg &a23) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23 }; + return Func(p0, p1, args, 24); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21, + const Arg &a22, const Arg &a23, const Arg &a24) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24 }; + return Func(p0, p1, args, 25); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21, + const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25 }; + return Func(p0, p1, args, 26); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21, + const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25, + const Arg &a26) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26 }; + return Func(p0, p1, args, 27); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21, + const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25, + const Arg &a26, const Arg &a27) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27 }; + return Func(p0, p1, args, 28); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21, + const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25, + const Arg &a26, const Arg &a27, const Arg &a28) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28 }; + return Func(p0, p1, args, 29); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21, + const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25, + const Arg &a26, const Arg &a27, const Arg &a28, const Arg &a29) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29 }; + return Func(p0, p1, args, 30); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21, + const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25, + const Arg &a26, const Arg &a27, const Arg &a28, const Arg &a29, + const Arg &a30) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30 }; + return Func(p0, p1, args, 31); + } + + Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1, + const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5, + const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9, + const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13, + const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17, + const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21, + const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25, + const Arg &a26, const Arg &a27, const Arg &a28, const Arg &a29, + const Arg &a30, const Arg &a31) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30, &a31 }; + return Func(p0, p1, args, 32); + } +}; + +template <typename Result, typename Param0, typename Param1, typename Param2, + typename Arg, + Result (*Func)(Param0, Param1, Param2, const Arg *const [], + int count)> +class VariadicFunction3 { + public: + VariadicFunction3() {} + + Result operator()(Param0 p0, Param1 p1, Param2 p2) const { + return Func(p0, p1, p2, NULL, 0); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0) const { + const Arg *const args[] = { &a0 }; + return Func(p0, p1, p2, args, 1); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1) const { + const Arg *const args[] = { &a0, &a1 }; + return Func(p0, p1, p2, args, 2); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2) const { + const Arg *const args[] = { &a0, &a1, &a2 }; + return Func(p0, p1, p2, args, 3); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3 }; + return Func(p0, p1, p2, args, 4); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4 }; + return Func(p0, p1, p2, args, 5); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5 }; + return Func(p0, p1, p2, args, 6); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6 }; + return Func(p0, p1, p2, args, 7); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7 }; + return Func(p0, p1, p2, args, 8); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8 }; + return Func(p0, p1, p2, args, 9); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9 }; + return Func(p0, p1, p2, args, 10); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10 }; + return Func(p0, p1, p2, args, 11); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11 }; + return Func(p0, p1, p2, args, 12); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12 }; + return Func(p0, p1, p2, args, 13); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13 }; + return Func(p0, p1, p2, args, 14); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14 }; + return Func(p0, p1, p2, args, 15); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15 }; + return Func(p0, p1, p2, args, 16); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16 }; + return Func(p0, p1, p2, args, 17); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17 }; + return Func(p0, p1, p2, args, 18); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18 }; + return Func(p0, p1, p2, args, 19); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18, const Arg &a19) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19 }; + return Func(p0, p1, p2, args, 20); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, + &a20 }; + return Func(p0, p1, p2, args, 21); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20, + const Arg &a21) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21 }; + return Func(p0, p1, p2, args, 22); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20, + const Arg &a21, const Arg &a22) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22 }; + return Func(p0, p1, p2, args, 23); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20, + const Arg &a21, const Arg &a22, const Arg &a23) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23 }; + return Func(p0, p1, p2, args, 24); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20, + const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24 }; + return Func(p0, p1, p2, args, 25); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20, + const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24, + const Arg &a25) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25 }; + return Func(p0, p1, p2, args, 26); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20, + const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24, + const Arg &a25, const Arg &a26) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26 }; + return Func(p0, p1, p2, args, 27); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20, + const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24, + const Arg &a25, const Arg &a26, const Arg &a27) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27 }; + return Func(p0, p1, p2, args, 28); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20, + const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24, + const Arg &a25, const Arg &a26, const Arg &a27, const Arg &a28) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28 }; + return Func(p0, p1, p2, args, 29); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20, + const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24, + const Arg &a25, const Arg &a26, const Arg &a27, const Arg &a28, + const Arg &a29) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29 }; + return Func(p0, p1, p2, args, 30); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20, + const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24, + const Arg &a25, const Arg &a26, const Arg &a27, const Arg &a28, + const Arg &a29, const Arg &a30) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30 }; + return Func(p0, p1, p2, args, 31); + } + + Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0, + const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4, + const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8, + const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12, + const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16, + const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20, + const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24, + const Arg &a25, const Arg &a26, const Arg &a27, const Arg &a28, + const Arg &a29, const Arg &a30, const Arg &a31) const { + const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, + &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20, + &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30, &a31 }; + return Func(p0, p1, p2, args, 32); + } +}; + +} // end namespace internal +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_VARIADIC_FUNCTION_H diff --git a/lib/Tooling/ASTMatchers.cpp b/lib/Tooling/ASTMatchers.cpp new file mode 100644 index 0000000000..f03580ea34 --- /dev/null +++ b/lib/Tooling/ASTMatchers.cpp @@ -0,0 +1,564 @@ +//===--- ASTMatchers.cpp - Structural query framework ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a framework of AST matchers that can be used to express +// structural queries on C++ code. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Tooling/ASTMatchers.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/DenseMap.h" +#include <assert.h> +#include <stddef.h> +#include <set> +#include <utility> + +namespace clang { +namespace tooling { + +// Returns the value that 'a_map' maps 'key' to, or NULL if 'key' is +// not in 'a_map'. +template <typename Map> +static const typename Map::mapped_type *Find( + const Map &AMap, const typename Map::key_type &Key) { + typename Map::const_iterator It = AMap.find(Key); + return It == AMap.end() ? NULL : &It->second; +} + +// We use memoization to avoid running the same matcher on the same +// AST node twice. This pair is the key for looking up match +// result. It consists of an ID of the MatcherInterface (for +// identifying the matcher) and a pointer to the AST node. +typedef std::pair<uint64_t, const void*> UntypedMatchInput; + +// Used to store the result of a match and possibly bound nodes. +struct MemoizedMatchResult { + bool ResultOfMatch; + BoundNodes Nodes; +}; + +// A RecursiveASTVisitor that traverses all children or all descendants of +// a node. +class MatchChildASTVisitor + : public clang::RecursiveASTVisitor<MatchChildASTVisitor> { + public: + typedef clang::RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase; + + // Creates an AST visitor that matches 'matcher' on all children or + // descendants of a traversed node. max_depth is the maximum depth + // to traverse: use 1 for matching the children and INT_MAX for + // matching the descendants. + MatchChildASTVisitor(const UntypedBaseMatcher *BaseMatcher, + ASTMatchFinder *Finder, + BoundNodesBuilder *Builder, + int MaxDepth, + ASTMatchFinder::TraversalMethod Traversal) + : BaseMatcher(BaseMatcher), + Finder(Finder), + Builder(Builder), + CurrentDepth(-1), + MaxDepth(MaxDepth), + Traversal(Traversal), + Matches(false) {} + + // Returns true if a match is found in the subtree rooted at the + // given AST node. This is done via a set of mutually recursive + // functions. Here's how the recursion is done (the *wildcard can + // actually be Decl, Stmt, or Type): + // + // - Traverse(node) calls BaseTraverse(node) when it needs + // to visit the descendants of node. + // - BaseTraverse(node) then calls (via VisitorBase::Traverse*(node)) + // Traverse*(c) for each child c of 'node'. + // - Traverse*(c) in turn calls Traverse(c), completing the + // recursion. + template <typename T> + bool FindMatch(const T &Node) { + Reset(); + Traverse(Node); + return Matches; + } + + // The following are overriding methods from the base visitor class. + // They are public only to allow CRTP to work. They are *not *part + // of the public API of this class. + bool TraverseDecl(clang::Decl *DeclNode) { + return (DeclNode == NULL) || Traverse(*DeclNode); + } + bool TraverseStmt(clang::Stmt *StmtNode) { + const clang::Stmt *StmtToTraverse = StmtNode; + if (Traversal == + ASTMatchFinder::kIgnoreImplicitCastsAndParentheses) { + const clang::Expr *ExprNode = dyn_cast_or_null<clang::Expr>(StmtNode); + if (ExprNode != NULL) { + StmtToTraverse = ExprNode->IgnoreParenImpCasts(); + } + } + return (StmtToTraverse == NULL) || Traverse(*StmtToTraverse); + } + bool TraverseType(clang::QualType TypeNode) { + return Traverse(TypeNode); + } + + bool shouldVisitTemplateInstantiations() const { return true; } + + private: + // Resets the state of this object. + void Reset() { + Matches = false; + CurrentDepth = -1; + } + + // Forwards the call to the corresponding Traverse*() method in the + // base visitor class. + bool BaseTraverse(const clang::Decl &DeclNode) { + return VisitorBase::TraverseDecl(const_cast<clang::Decl*>(&DeclNode)); + } + bool BaseTraverse(const clang::Stmt &StmtNode) { + return VisitorBase::TraverseStmt(const_cast<clang::Stmt*>(&StmtNode)); + } + bool BaseTraverse(clang::QualType TypeNode) { + return VisitorBase::TraverseType(TypeNode); + } + + // Traverses the subtree rooted at 'node'; returns true if the + // traversal should continue after this function returns; also sets + // matched_ to true if a match is found during the traversal. + template <typename T> + bool Traverse(const T &Node) { + COMPILE_ASSERT(IsBaseType<T>::value, + traverse_can_only_be_instantiated_with_base_type); + ++CurrentDepth; + bool ShouldContinue; + if (CurrentDepth == 0) { + // We don't want to match the root node, so just recurse. + ShouldContinue = BaseTraverse(Node); + } else if (BaseMatcher->Matches(Node, Finder, Builder)) { + Matches = true; + ShouldContinue = false; // Abort as soon as a match is found. + } else if (CurrentDepth < MaxDepth) { + // The current node doesn't match, and we haven't reached the + // maximum depth yet, so recurse. + ShouldContinue = BaseTraverse(Node); + } else { + // The current node doesn't match, and we have reached the + // maximum depth, so don't recurse (but continue the traversal + // such that other nodes at the current level can be visited). + ShouldContinue = true; + } + --CurrentDepth; + return ShouldContinue; + } + + const UntypedBaseMatcher *const BaseMatcher; + ASTMatchFinder *const Finder; + BoundNodesBuilder *const Builder; + int CurrentDepth; + const int MaxDepth; + const ASTMatchFinder::TraversalMethod Traversal; + bool Matches; +}; + +// Controls the outermost traversal of the AST and allows to match multiple +// matchers. +class MatchASTVisitor : public clang::RecursiveASTVisitor<MatchASTVisitor>, + public ASTMatchFinder { + public: + MatchASTVisitor(std::vector< std::pair<const UntypedBaseMatcher*, + MatchFinder::MatchCallback*> > *Triggers, + clang::SourceManager *VisitorSourceManager, + clang::LangOptions *LanguageOptions) + : Triggers(Triggers), + VisitorSourceManager(VisitorSourceManager), + LanguageOptions(LanguageOptions), + ActiveASTContext(NULL) { + assert(VisitorSourceManager != NULL); + assert(LanguageOptions != NULL); + // FIXME: add rewriter_(*source_manager, *language_options) + } + + void set_active_ast_context(clang::ASTContext *NewActiveASTContext) { + ActiveASTContext = NewActiveASTContext; + } + + // The following Visit*() and Traverse*() functions "override" + // methods in RecursiveASTVisitor. + + bool VisitTypedefDecl(clang::TypedefDecl *DeclNode) { + // When we see 'typedef A B', we add name 'B' to the set of names + // A's canonical type maps to. This is necessary for implementing + // IsDerivedFrom(x) properly, where x can be the name of the base + // class or any of its aliases. + // + // In general, the is-alias-of (as defined by typedefs) relation + // is tree-shaped, as you can typedef a type more than once. For + // example, + // + // typedef A B; + // typedef A C; + // typedef C D; + // typedef C E; + // + // gives you + // + // A + // |- B + // `- C + // |- D + // `- E + // + // It is wrong to assume that the relation is a chain. A correct + // implementation of IsDerivedFrom() needs to recognize that B and + // E are aliases, even though neither is a typedef of the other. + // Therefore, we cannot simply walk through one typedef chain to + // find out whether the type name matches. + const clang::Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr(); + const clang::Type *CanonicalType = // root of the typedef tree + ActiveASTContext->getCanonicalType(TypeNode); + TypeToUnqualifiedAliases[CanonicalType].insert( + DeclNode->getName().str()); + return true; + } + + bool TraverseDecl(clang::Decl *DeclNode); + bool TraverseStmt(clang::Stmt *StmtNode); + bool TraverseType(clang::QualType TypeNode); + bool TraverseTypeLoc(clang::TypeLoc TypeNode); + + // Matches children or descendants of 'Node' with 'BaseMatcher'. + template <typename T> + bool MemoizedMatchesRecursively( + const T &Node, const UntypedBaseMatcher &BaseMatcher, + BoundNodesBuilder *Builder, int MaxDepth, + TraversalMethod Traversal) { + COMPILE_ASSERT((llvm::is_same<T, clang::Decl>::value) || + (llvm::is_same<T, clang::Stmt>::value), + type_does_not_support_memoization); + const UntypedMatchInput input(BaseMatcher.GetID(), &Node); + std::pair <MemoizationMap::iterator, bool> + InsertResult = ResultCache.insert( + std::make_pair(input, MemoizedMatchResult())); + if (InsertResult.second) { + BoundNodesBuilder DescendantBoundNodesBuilder; + InsertResult.first->second.ResultOfMatch = + MatchesRecursively(Node, BaseMatcher, &DescendantBoundNodesBuilder, + MaxDepth, Traversal); + InsertResult.first->second.Nodes = + DescendantBoundNodesBuilder.Build(); + } + InsertResult.first->second.Nodes.CopyTo(Builder); + return InsertResult.first->second.ResultOfMatch; + } + + // Matches children or descendants of 'Node' with 'BaseMatcher'. + template <typename T> + bool MatchesRecursively( + const T &Node, const UntypedBaseMatcher &BaseMatcher, + BoundNodesBuilder *Builder, int MaxDepth, + TraversalMethod Traversal) { + MatchChildASTVisitor Visitor( + &BaseMatcher, this, Builder, MaxDepth, Traversal); + return Visitor.FindMatch(Node); + } + + virtual bool ClassIsDerivedFrom(const clang::CXXRecordDecl *Declaration, + const std::string &BaseName) const; + + // Implements ASTMatchFinder::MatchesChildOf. + virtual bool MatchesChildOf(const clang::Decl &DeclNode, + const UntypedBaseMatcher &BaseMatcher, + BoundNodesBuilder *Builder, + TraversalMethod Traversal) { + return MatchesRecursively( + DeclNode, BaseMatcher, Builder, 1, Traversal); + } + virtual bool MatchesChildOf(const clang::Stmt &StmtNode, + const UntypedBaseMatcher &BaseMatcher, + BoundNodesBuilder *Builder, + TraversalMethod Traversal) { + return MatchesRecursively( + StmtNode, BaseMatcher, Builder, 1, Traversal); + } + + // Implements ASTMatchFinder::MatchesDescendantOf. + virtual bool MatchesDescendantOf(const clang::Decl &DeclNode, + const UntypedBaseMatcher &BaseMatcher, + BoundNodesBuilder *Builder) { + return MemoizedMatchesRecursively( + DeclNode, BaseMatcher, Builder, INT_MAX, kAsIs); + } + virtual bool MatchesDescendantOf(const clang::Stmt &StmtNode, + const UntypedBaseMatcher &BaseMatcher, + BoundNodesBuilder *Builder) { + return MemoizedMatchesRecursively( + StmtNode, BaseMatcher, Builder, INT_MAX, kAsIs); + } + + bool shouldVisitTemplateInstantiations() const { return true; } + + private: + // Returns true if 'TypeNode' is also known by the name 'Name'. In other + // words, there is a type (including typedef) with the name 'Name' + // that is equal to 'TypeNode'. + bool TypeHasAlias( + const clang::Type *TypeNode, const std::string &Name) const { + const clang::Type *const CanonicalType = + ActiveASTContext->getCanonicalType(TypeNode); + const std::set<std::string> *UnqualifiedAlias = + Find(TypeToUnqualifiedAliases, CanonicalType); + return UnqualifiedAlias != NULL && UnqualifiedAlias->count(Name) > 0; + } + + // Matches all registered matchers on the given node and calls the + // result callback for every node that matches. + template <typename T> + void Match(const T &node) { + for (std::vector< std::pair<const UntypedBaseMatcher*, + MatchFinder::MatchCallback*> >::const_iterator + It = Triggers->begin(), End = Triggers->end(); + It != End; ++It) { + BoundNodesBuilder Builder; + if (It->first->Matches(node, this, &Builder)) { + MatchFinder::MatchResult Result; + Result.Nodes = Builder.Build(); + Result.Context = ActiveASTContext; + Result.SourceManager = VisitorSourceManager; + It->second->Run(Result); + } + } + } + + std::vector< std::pair<const UntypedBaseMatcher*, + MatchFinder::MatchCallback*> > *const Triggers; + clang::SourceManager *const VisitorSourceManager; + clang::LangOptions *const LanguageOptions; + clang::ASTContext *ActiveASTContext; + + // Maps a canonical type to the names of its typedefs. + llvm::DenseMap<const clang::Type*, std::set<std::string> > + TypeToUnqualifiedAliases; + + // Maps (matcher, node) -> the match result for memoization. + typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap; + MemoizationMap ResultCache; +}; + +// Returns true if the given class is directly or indirectly derived +// from a base type with the given name. A class is considered to be +// also derived from itself. +bool MatchASTVisitor::ClassIsDerivedFrom( + const clang::CXXRecordDecl *Declaration, + const std::string &BaseName) const { + if (std::string(Declaration->getName()) == BaseName) { + return true; + } + if (!Declaration->hasDefinition()) { + return false; + } + typedef clang::CXXRecordDecl::base_class_const_iterator BaseIterator; + for (BaseIterator It = Declaration->bases_begin(), + End = Declaration->bases_end(); It != End; ++It) { + const clang::Type *TypeNode = It->getType().getTypePtr(); + + if (TypeHasAlias(TypeNode, BaseName)) + return true; + + // clang::Type::getAs<...>() drills through typedefs. + if (TypeNode->getAs<clang::DependentNameType>() != NULL || + TypeNode->getAs<clang::TemplateTypeParmType>() != NULL) { + // Dependent names and template TypeNode parameters will be matched when + // the template is instantiated. + continue; + } + clang::CXXRecordDecl *ClassDecl = NULL; + clang::TemplateSpecializationType const *TemplateType = + TypeNode->getAs<clang::TemplateSpecializationType>(); + if (TemplateType != NULL) { + if (TemplateType->getTemplateName().isDependent()) { + // Dependent template specializations will be matched when the + // template is instantiated. + continue; + } + // For template specialization types which are specializing a template + // declaration which is an explicit or partial specialization of another + // template declaration, getAsCXXRecordDecl() returns the corresponding + // ClassTemplateSpecializationDecl. + // + // For template specialization types which are specializing a template + // declaration which is neither an explicit nor partial specialization of + // another template declaration, getAsCXXRecordDecl() returns NULL and + // we get the CXXRecordDecl of the templated declaration. + clang::CXXRecordDecl *SpecializationDecl = + TemplateType->getAsCXXRecordDecl(); + if (SpecializationDecl != NULL) { + ClassDecl = SpecializationDecl; + } else { + ClassDecl = llvm::dyn_cast<clang::CXXRecordDecl>( + TemplateType->getTemplateName() + .getAsTemplateDecl()->getTemplatedDecl()); + } + } else { + ClassDecl = TypeNode->getAsCXXRecordDecl(); + } + assert(ClassDecl != NULL); + assert(ClassDecl != Declaration); + if (ClassIsDerivedFrom(ClassDecl, BaseName)) { + return true; + } + } + return false; +} + +bool MatchASTVisitor::TraverseDecl(clang::Decl *DeclNode) { + if (DeclNode == NULL) { + return true; + } + Match(*DeclNode); + return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode); +} + +bool MatchASTVisitor::TraverseStmt(clang::Stmt *StmtNode) { + if (StmtNode == NULL) { + return true; + } + Match(*StmtNode); + return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode); +} + +bool MatchASTVisitor::TraverseType(clang::QualType TypeNode) { + Match(TypeNode); + return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode); +} + +bool MatchASTVisitor::TraverseTypeLoc(clang::TypeLoc TypeLoc) { + return clang::RecursiveASTVisitor<MatchASTVisitor>:: + TraverseType(TypeLoc.getType()); +} + +class MatchASTConsumer : public clang::ASTConsumer { + public: + MatchASTConsumer(std::vector< std::pair<const UntypedBaseMatcher*, + MatchFinder::MatchCallback*> > *Triggers, + MatchFinder::ParsingDoneTestCallback *ParsingDone, + clang::SourceManager *ConsumerSourceManager, + clang::LangOptions *LanaguageOptions) + : Visitor(Triggers, ConsumerSourceManager, LanaguageOptions), + ParsingDone(ParsingDone) {} + + private: + virtual void HandleTranslationUnit( + clang::ASTContext &Context) { // NOLINT: external API uses refs + if (ParsingDone != NULL) { + ParsingDone->Run(); + } + Visitor.set_active_ast_context(&Context); + Visitor.TraverseDecl(Context.getTranslationUnitDecl()); + Visitor.set_active_ast_context(NULL); + } + + MatchASTVisitor Visitor; + MatchFinder::ParsingDoneTestCallback *ParsingDone; +}; + +class MatchASTAction : public clang::ASTFrontendAction { + public: + explicit MatchASTAction( + std::vector< std::pair<const UntypedBaseMatcher*, + MatchFinder::MatchCallback*> > *Triggers, + MatchFinder::ParsingDoneTestCallback *ParsingDone) + : Triggers(Triggers), + ParsingDone(ParsingDone) {} + + private: + clang::ASTConsumer *CreateASTConsumer( + clang::CompilerInstance &Compiler, + llvm::StringRef) { + return new MatchASTConsumer(Triggers, + ParsingDone, + &Compiler.getSourceManager(), + &Compiler.getLangOpts()); + } + + std::vector< std::pair<const UntypedBaseMatcher*, + MatchFinder::MatchCallback*> > *const Triggers; + MatchFinder::ParsingDoneTestCallback *ParsingDone; +}; + +MatchFinder::MatchCallback::~MatchCallback() {} +MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {} + +MatchFinder::MatchFinder() : ParsingDone(NULL) {} + +MatchFinder::~MatchFinder() { + for (std::vector< std::pair<const UntypedBaseMatcher*, + MatchFinder::MatchCallback*> >::const_iterator + It = Triggers.begin(), End = Triggers.end(); + It != End; ++It) { + delete It->first; + delete It->second; + } +} + +void MatchFinder::AddMatcher(const Matcher<clang::Decl> &NodeMatch, + MatchCallback *Action) { + Triggers.push_back(std::make_pair( + new TypedBaseMatcher<clang::Decl>(NodeMatch), Action)); +} + +void MatchFinder::AddMatcher(const Matcher<clang::QualType> &NodeMatch, + MatchCallback *Action) { + Triggers.push_back(std::make_pair( + new TypedBaseMatcher<clang::QualType>(NodeMatch), Action)); +} + +void MatchFinder::AddMatcher(const Matcher<clang::Stmt> &NodeMatch, + MatchCallback *Action) { + Triggers.push_back(std::make_pair( + new TypedBaseMatcher<clang::Stmt>(NodeMatch), Action)); +} + +bool MatchFinder::FindAll(const std::string &Code) { + return RunSyntaxOnlyToolOnCode( + new MatchASTAction(&Triggers, ParsingDone), Code); +} + +clang::FrontendAction *MatchFinder::NewVisitorAction() { + return new MatchASTAction(&Triggers, ParsingDone); +} + +class MatchFinderFrontendActionFactory : public FrontendActionFactory { + public: + explicit MatchFinderFrontendActionFactory(MatchFinder *Finder) + : Finder(Finder) {} + + virtual clang::FrontendAction *New() { + return Finder->NewVisitorAction(); + } + + private: + MatchFinder *const Finder; +}; + +FrontendActionFactory *MatchFinder::NewFrontendActionFactory() { + return new MatchFinderFrontendActionFactory(this); +} + +void MatchFinder::RegisterTestCallbackAfterParsing( + MatchFinder::ParsingDoneTestCallback *NewParsingDone) { + ParsingDone = NewParsingDone; +} + +} // end namespace tooling +} // end namespace clang diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt index f52cf6c891..0a0020a555 100644 --- a/lib/Tooling/CMakeLists.txt +++ b/lib/Tooling/CMakeLists.txt @@ -1,6 +1,7 @@ SET(LLVM_USED_LIBS clangBasic clangFrontend clangAST) add_clang_library(clangTooling + ASTMatchers.cpp JsonCompileCommandLineDatabase.cpp Tooling.cpp ) diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp index 9cc92f1ae6..97a9463852 100644 --- a/lib/Tooling/Tooling.cpp +++ b/lib/Tooling/Tooling.cpp @@ -1,4 +1,4 @@ -//===--- Tooling.cpp - Running clang standalone tools --------------------===// +//===--- Tooling.cpp - Running clang standalone tools ---------------------===// // // The LLVM Compiler Infrastructure // @@ -44,7 +44,7 @@ namespace { // - it must contain at least a program path, // - argv[0], ..., and argv[argc - 1] mustn't be NULL, and // - argv[argc] must be NULL. -void ValidateArgv(int argc, char* argv[]) { +void ValidateArgv(int argc, char *argv[]) { if (argc < 1) { fprintf(stderr, "ERROR: argc is %d. It must be >= 1.\n", argc); abort(); @@ -69,7 +69,7 @@ void ValidateArgv(int argc, char* argv[]) { // code that sets up a compiler to run tools on it, and we should refactor // it to be based on the same framework. -static clang::Diagnostic* NewTextDiagnostics() { +static clang::Diagnostic *NewTextDiagnostics() { llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs( new clang::DiagnosticIDs()); clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter( @@ -81,15 +81,15 @@ static clang::Diagnostic* NewTextDiagnostics() { static int StaticSymbol; /// \brief Builds a clang driver initialized for running clang tools. -static clang::driver::Driver* NewDriver(clang::Diagnostic* Diagnostics, - const char* BinaryName) { +static clang::driver::Driver *NewDriver(clang::Diagnostic *Diagnostics, + const char *BinaryName) { // This just needs to be some symbol in the binary. - void* const SymbolAddr = &StaticSymbol; + void *const SymbolAddr = &StaticSymbol; const llvm::sys::Path ExePath = llvm::sys::Path::GetMainExecutable(BinaryName, SymbolAddr); const std::string DefaultOutputName = "a.out"; - clang::driver::Driver* CompilerDriver = new clang::driver::Driver( + clang::driver::Driver *CompilerDriver = new clang::driver::Driver( ExePath.str(), llvm::sys::getHostTriple(), DefaultOutputName, false, false, *Diagnostics); CompilerDriver->setTitle("clang_based_tool"); @@ -98,8 +98,8 @@ static clang::driver::Driver* NewDriver(clang::Diagnostic* Diagnostics, /// \brief Retrieves the clang CC1 specific flags out of the compilation's jobs. /// Returns NULL on error. -static const clang::driver::ArgStringList* GetCC1Arguments( - clang::Diagnostic* Diagnostics, clang::driver::Compilation* Compilation) { +static const clang::driver::ArgStringList *GetCC1Arguments( + clang::Diagnostic *Diagnostics, clang::driver::Compilation *Compilation) { // We expect to get back exactly one Command job, if we didn't something // failed. Extract that job from the Compilation. const clang::driver::JobList &Jobs = Compilation->getJobs(); @@ -124,10 +124,10 @@ static const clang::driver::ArgStringList* GetCC1Arguments( } /// \brief Returns a clang build invocation initialized from the CC1 flags. -static clang::CompilerInvocation* NewInvocation( - clang::Diagnostic* Diagnostics, - const clang::driver::ArgStringList& CC1Args) { - clang::CompilerInvocation* Invocation = new clang::CompilerInvocation; +static clang::CompilerInvocation *NewInvocation( + clang::Diagnostic *Diagnostics, + const clang::driver::ArgStringList &CC1Args) { + clang::CompilerInvocation *Invocation = new clang::CompilerInvocation; clang::CompilerInvocation::CreateFromArgs( *Invocation, CC1Args.data(), CC1Args.data() + CC1Args.size(), *Diagnostics); @@ -137,11 +137,11 @@ static clang::CompilerInvocation* NewInvocation( /// \brief Runs the specified clang tool action and returns whether it executed /// successfully. -static bool RunInvocation(const char* BinaryName, - clang::driver::Compilation* Compilation, - clang::CompilerInvocation* Invocation, - const clang::driver::ArgStringList& CC1Args, - clang::FrontendAction* ToolAction) { +static bool RunInvocation(const char *BinaryName, + clang::driver::Compilation *Compilation, + clang::CompilerInvocation *Invocation, + const clang::driver::ArgStringList &CC1Args, + clang::FrontendAction *ToolAction) { llvm::OwningPtr<clang::FrontendAction> ScopedToolAction(ToolAction); // Show the invocation, with -v. if (Invocation->getHeaderSearchOpts().Verbose) { @@ -164,7 +164,7 @@ static bool RunInvocation(const char* BinaryName, if (Compiler.getHeaderSearchOpts().UseBuiltinIncludes && Compiler.getHeaderSearchOpts().ResourceDir.empty()) { // This just needs to be some symbol in the binary. - void* const SymbolAddr = &StaticSymbol; + void *const SymbolAddr = &StaticSymbol; Compiler.getHeaderSearchOpts().ResourceDir = clang::CompilerInvocation::GetResourcesPath(BinaryName, SymbolAddr); } @@ -175,7 +175,7 @@ static bool RunInvocation(const char* BinaryName, /// \brief Converts a string vector representing a Command line into a C /// string vector representing the Argv (including the trailing NULL). -std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command) { +std::vector<char*> CommandLineToArgv(const std::vector<std::string> *Command) { std::vector<char*> Result(Command->size() + 1); for (std::vector<char*>::size_type I = 0; I < Command->size(); ++I) { Result[I] = const_cast<char*>((*Command)[I].c_str()); @@ -185,14 +185,14 @@ std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command) { } bool RunToolWithFlags( - clang::FrontendAction* ToolAction, int Args, char* Argv[]) { + clang::FrontendAction *ToolAction, int Args, char *Argv[]) { ValidateArgv(Args, Argv); const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics()); const llvm::OwningPtr<clang::driver::Driver> Driver( NewDriver(Diagnostics.get(), Argv[0])); const llvm::OwningPtr<clang::driver::Compilation> Compilation( Driver->BuildCompilation(llvm::ArrayRef<const char*>(Argv, Args))); - const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments( + const clang::driver::ArgStringList *const CC1Args = GetCC1Arguments( Diagnostics.get(), Compilation.get()); if (CC1Args == NULL) { return false; @@ -208,11 +208,11 @@ bool RunToolWithFlags( /// \param FileContents A mapping from file name to source code. For each /// entry a virtual file mapping will be created when running the tool. bool RunToolWithFlagsOnCode( - const std::vector<std::string>& CommandLine, - const std::map<std::string, std::string>& FileContents, - clang::FrontendAction* ToolAction) { + const std::vector<std::string> &CommandLine, + const std::map<std::string, std::string> &FileContents, + clang::FrontendAction *ToolAction) { const std::vector<char*> Argv = CommandLineToArgv(&CommandLine); - const char* const BinaryName = Argv[0]; + const char *const BinaryName = Argv[0]; const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics()); const llvm::OwningPtr<clang::driver::Driver> Driver( @@ -224,7 +224,7 @@ bool RunToolWithFlagsOnCode( const llvm::OwningPtr<clang::driver::Compilation> Compilation( Driver->BuildCompilation(llvm::ArrayRef<const char*>(&Argv[0], Argv.size() - 1))); - const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments( + const clang::driver::ArgStringList *const CC1Args = GetCC1Arguments( Diagnostics.get(), Compilation.get()); if (CC1Args == NULL) { return false; @@ -236,7 +236,7 @@ bool RunToolWithFlagsOnCode( It = FileContents.begin(), End = FileContents.end(); It != End; ++It) { // Inject the code as the given file name into the preprocessor options. - const llvm::MemoryBuffer* Input = + const llvm::MemoryBuffer *Input = llvm::MemoryBuffer::getMemBuffer(It->second.c_str()); Invocation->getPreprocessorOpts().addRemappedFile(It->first.c_str(), Input); } @@ -247,8 +247,8 @@ bool RunToolWithFlagsOnCode( bool RunSyntaxOnlyToolOnCode( clang::FrontendAction *ToolAction, llvm::StringRef Code) { - const char* const FileName = "input.cc"; - const char* const CommandLine[] = { + const char *const FileName = "input.cc"; + const char *const CommandLine[] = { "clang-tool", "-fsyntax-only", FileName }; std::map<std::string, std::string> FileContents; diff --git a/test/Tooling/remove-cstr-calls.cpp b/test/Tooling/remove-cstr-calls.cpp new file mode 100644 index 0000000000..a43960aec5 --- /dev/null +++ b/test/Tooling/remove-cstr-calls.cpp @@ -0,0 +1,20 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: echo '[{"directory":".","command":"clang++ '$(llvm-config --cppflags all)' -c %s","file":"%s"}]' > %t/compile_commands.json +// RUN: remove-cstr-calls %t %s | FileCheck %s + +#include <string> + +namespace llvm { struct StringRef { StringRef(const char *p); }; } + +void f1(const std::string &s) { + f1(s.c_str()); // CHECK:remove-cstr-calls.cpp:11:6:11:14:s +} +void f2(const llvm::StringRef r) { + std::string s; + f2(s.c_str()); // CHECK:remove-cstr-calls.cpp:15:6:15:14:s +} +void f3(const llvm::StringRef &r) { + std::string s; + f3(s.c_str()); // CHECK:remove-cstr-calls.cpp:19:6:19:14:s +} diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index cc2d5f4f83..1fc11ab66e 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -69,3 +69,8 @@ add_clang_unittest(JsonCompileCommandLineDatabase Tooling/JsonCompileCommandLineDatabaseTest.cpp USED_LIBS gtest gtest_main clangTooling ) + +add_clang_unittest(ASTMatchersTest + Tooling/ASTMatchersTest.cpp + USED_LIBS gtest gtest_main clangTooling + ) diff --git a/unittests/Tooling/ASTMatchersTest.cpp b/unittests/Tooling/ASTMatchersTest.cpp new file mode 100644 index 0000000000..93a30ef5d9 --- /dev/null +++ b/unittests/Tooling/ASTMatchersTest.cpp @@ -0,0 +1,1602 @@ +//===- unittest/Tooling/ASTMatchersTest.cpp - AST matcher unit tests ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/ASTMatchers.h" +#include "gtest/gtest.h" + +namespace clang { +namespace tooling { + +using match::AnyOf; +using match::AllOf; +using match::ArgumentCountIs; +using match::BinaryOperator; +using match::BoolLiteral; +using match::StringLiteral; +using match::IntegerLiteral; +using match::CharacterLiteral; +using match::Call; +using match::Callee; +using match::Class; +using match::CompoundStatement; +using match::ConstructorCall; +using match::DeclarationMatcher; +using match::DefaultArgument; +using match::ConditionalOperator; +using match::DeclarationReference; +using match::Expression; +using match::Equals; +using match::For; +using match::Has; +using match::HasAnyArgument; +using match::HasAnyParameter; +using match::HasAnySubstatement; +using match::HasArgument; +using match::HasBody; +using match::HasCondition; +using match::HasDeclaration; +using match::HasDescendant; +using match::HasEitherOperand; +using match::HasFalseExpression; +using match::HasInitializer; +using match::HasLHS; +using match::HasName; +using match::HasUnaryOperand; +using match::HasOperatorName; +using match::HasOverloadedOperatorName; +using match::HasParameter; +using match::HasRHS; +using match::HasTrueExpression; +using match::HasType; +using match::Id; +using match::If; +using match::IsArrow; +using match::IsDefinition; +using match::IsDerivedFrom; +using match::MemberExpression; +using match::Method; +using match::Not; +using match::OfClass; +using match::On; +using match::OverloadedOperatorCall; +using match::PointsTo; +using match::References; +using match::StatementCountIs; +using match::StatementMatcher; +using match::ThisPointerType; +using match::To; +using match::TypeMatcher; +using match::UnaryOperator; +using match::Variable; + +class BoundNodesCallback { + public: + virtual ~BoundNodesCallback() {} + virtual bool Run(const BoundNodes *BoundNodes) = 0; +}; + +// If 'FindResultVerifier' is not NULL, sets *Verified to the result of +// running 'FindResultVerifier' with the bound nodes as argument. +// If 'FindResultVerifier' is NULL, sets *Verified to true when Run is called. +class VerifyMatch : public MatchFinder::MatchCallback { + public: + VerifyMatch(BoundNodesCallback *FindResultVerifier, bool *Verified) + : Verified(Verified), FindResultReviewer(FindResultVerifier) {} + + virtual void Run(const MatchFinder::MatchResult &Result) { + if (FindResultReviewer != NULL) { + *Verified = FindResultReviewer->Run(&Result.Nodes); + } else { + *Verified = true; + } + } + + private: + bool *const Verified; + BoundNodesCallback *const FindResultReviewer; +}; + +template <typename T> +testing::AssertionResult MatchesConditionally( + const std::string &Code, const T &AMatcher, bool ExpectMatch) { + bool Found = false; + MatchFinder Finder; + Finder.AddMatcher(AMatcher, new VerifyMatch(NULL, &Found)); + if (!Finder.FindAll(Code)) { + return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; + } + if (!Found && ExpectMatch) { + return testing::AssertionFailure() + << "Could not find match in \"" << Code << "\""; + } else if (Found && !ExpectMatch) { + return testing::AssertionFailure() + << "Found unexpected match in \"" << Code << "\""; + } + return testing::AssertionSuccess(); +} + +template <typename T> +testing::AssertionResult Matches(const std::string &Code, const T &AMatcher) { + return MatchesConditionally(Code, AMatcher, true); +} + +template <typename T> +testing::AssertionResult NotMatches( + const std::string &Code, const T &AMatcher) { + return MatchesConditionally(Code, AMatcher, false); +} + +template <typename T> +testing::AssertionResult MatchAndVerifyResultConditionally( + const std::string &Code, const T &AMatcher, + BoundNodesCallback *FindResultVerifier, bool ExpectResult) { + llvm::OwningPtr<BoundNodesCallback> ScopedVerifier(FindResultVerifier); + bool VerifiedResult = false; + MatchFinder Finder; + Finder.AddMatcher( + AMatcher, new VerifyMatch(FindResultVerifier, &VerifiedResult)); + if (!Finder.FindAll(Code)) { + return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; + } + if (!VerifiedResult && ExpectResult) { + return testing::AssertionFailure() + << "Could not verify result in \"" << Code << "\""; + } else if (VerifiedResult && !ExpectResult) { + return testing::AssertionFailure() + << "Verified unexpected result in \"" << Code << "\""; + } + return testing::AssertionSuccess(); +} + +// FIXME: Find better names for these functions (or document what they +// do more precisely). +template <typename T> +testing::AssertionResult MatchAndVerifyResultTrue( + const std::string &Code, const T &AMatcher, + BoundNodesCallback *FindResultVerifier) { + return MatchAndVerifyResultConditionally( + Code, AMatcher, FindResultVerifier, true); +} + +template <typename T> +testing::AssertionResult MatchAndVerifyResultFalse( + const std::string &Code, const T &AMatcher, + BoundNodesCallback *FindResultVerifier) { + return MatchAndVerifyResultConditionally( + Code, AMatcher, FindResultVerifier, false); +} + +TEST(HasNameDeathTest, DiesOnEmptyName) { + ASSERT_DEBUG_DEATH({ + DeclarationMatcher HasEmptyName = Class(HasName("")); + EXPECT_TRUE(NotMatches("class X {};", HasEmptyName)); + }, ""); +} + +TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) { + ASSERT_DEBUG_DEATH({ + DeclarationMatcher IsDerivedFromEmpty = Class(IsDerivedFrom("")); + EXPECT_TRUE(NotMatches("class X {};", IsDerivedFromEmpty)); + }, ""); +} + +TEST(DeclarationMatcher, MatchClass) { + DeclarationMatcher ClassMatcher(Class()); + // Even for an empty string there are classes in the AST. + EXPECT_TRUE(Matches("", ClassMatcher)); + + DeclarationMatcher ClassX = Class(Class(HasName("X"))); + EXPECT_TRUE(Matches("class X;", ClassX)); + EXPECT_TRUE(Matches("class X {};", ClassX)); + EXPECT_TRUE(Matches("template<class T> class X {};", ClassX)); + EXPECT_TRUE(NotMatches("", ClassX)); +} + +TEST(DeclarationMatcher, ClassIsDerived) { + DeclarationMatcher IsDerivedFromX = Class(IsDerivedFrom("X")); + + EXPECT_TRUE(Matches("class X {}; class Y : public X {};", IsDerivedFromX)); + EXPECT_TRUE(Matches("class X {}; class Y : public X {};", IsDerivedFromX)); + EXPECT_TRUE(Matches("class X {};", IsDerivedFromX)); + EXPECT_TRUE(Matches("class X;", IsDerivedFromX)); + EXPECT_TRUE(NotMatches("class Y;", IsDerivedFromX)); + EXPECT_TRUE(NotMatches("", IsDerivedFromX)); + + DeclarationMatcher ZIsDerivedFromX = + Class(HasName("Z"), IsDerivedFrom("X")); + EXPECT_TRUE( + Matches("class X {}; class Y : public X {}; class Z : public Y {};", + ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("class X {};" + "template<class T> class Y : public X {};" + "class Z : public Y<int> {};", ZIsDerivedFromX)); + EXPECT_TRUE(Matches("class X {}; template<class T> class Z : public X {};", + ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("template<class T> class X {}; " + "template<class T> class Z : public X<T> {};", + ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("template<class T, class U=T> class X {}; " + "template<class T> class Z : public X<T> {};", + ZIsDerivedFromX)); + EXPECT_TRUE( + NotMatches("template<class X> class A { class Z : public X {}; };", + ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("template<class X> class A { public: class Z : public X {}; }; " + "class X{}; void y() { A<X>::Z z; }", ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("template <class T> class X {}; " + "template<class Y> class A { class Z : public X<Y> {}; };", + ZIsDerivedFromX)); + EXPECT_TRUE( + NotMatches("template<template<class T> class X> class A { " + " class Z : public X<int> {}; };", ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("template<template<class T> class X> class A { " + " public: class Z : public X<int> {}; }; " + "template<class T> class X {}; void y() { A<X>::Z z; }", + ZIsDerivedFromX)); + EXPECT_TRUE( + NotMatches("template<class X> class A { class Z : public X::D {}; };", + ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("template<class X> class A { public: " + " class Z : public X::D {}; }; " + "class Y { public: class X {}; typedef X D; }; " + "void y() { A<Y>::Z z; }", ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("class X {}; typedef X Y; class Z : public Y {};", + ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("template<class T> class Y { typedef typename T::U X; " + " class Z : public X {}; };", ZIsDerivedFromX)); + EXPECT_TRUE(Matches("class X {}; class Z : public ::X {};", + ZIsDerivedFromX)); + EXPECT_TRUE( + NotMatches("template<class T> class X {}; " + "template<class T> class A { class Z : public X<T>::D {}; };", + ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("template<class T> class X { public: typedef X<T> D; }; " + "template<class T> class A { public: " + " class Z : public X<T>::D {}; }; void y() { A<int>::Z z; }", + ZIsDerivedFromX)); + EXPECT_TRUE( + NotMatches("template<class X> class A { class Z : public X::D::E {}; };", + ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("class X {}; typedef X V; typedef V W; class Z : public W {};", + ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("class X {}; class Y : public X {}; " + "typedef Y V; typedef V W; class Z : public W {};", + ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("template<class T, class U> class X {}; " + "template<class T> class A { class Z : public X<T, int> {}; };", + ZIsDerivedFromX)); + EXPECT_TRUE( + NotMatches("template<class X> class D { typedef X A; typedef A B; " + " typedef B C; class Z : public C {}; };", + ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("class X {}; typedef X A; typedef A B; " + "class Z : public B {};", ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("class X {}; typedef X A; typedef A B; typedef B C; " + "class Z : public C {};", ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("class U {}; typedef U X; typedef X V; " + "class Z : public V {};", ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("class Base {}; typedef Base X; " + "class Z : public Base {};", ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("class Base {}; typedef Base Base2; typedef Base2 X; " + "class Z : public Base {};", ZIsDerivedFromX)); + EXPECT_TRUE( + NotMatches("class Base {}; class Base2 {}; typedef Base2 X; " + "class Z : public Base {};", ZIsDerivedFromX)); + EXPECT_TRUE( + Matches("class A {}; typedef A X; typedef A Y; " + "class Z : public Y {};", ZIsDerivedFromX)); + EXPECT_TRUE( + NotMatches("template <typename T> class Z;" + "template <> class Z<void> {};" + "template <typename T> class Z : public Z<void> {};", + IsDerivedFromX)); + EXPECT_TRUE( + Matches("template <typename T> class X;" + "template <> class X<void> {};" + "template <typename T> class X : public X<void> {};", + IsDerivedFromX)); + EXPECT_TRUE(Matches( + "class X {};" + "template <typename T> class Z;" + "template <> class Z<void> {};" + "template <typename T> class Z : public Z<void>, public X {};", + ZIsDerivedFromX)); + + // FIXME: Once we have better matchers for template type matching, + // get rid of the Variable(...) matching and match the right template + // declarations directly. + const char *RecursiveTemplateOneParameter = + "class Base1 {}; class Base2 {};" + "template <typename T> class Z;" + "template <> class Z<void> : public Base1 {};" + "template <> class Z<int> : public Base2 {};" + "template <> class Z<float> : public Z<void> {};" + "template <> class Z<double> : public Z<int> {};" + "template <typename T> class Z : public Z<float>, public Z<double> {};" + "void f() { Z<float> z_float; Z<double> z_double; Z<char> z_char; }"; + EXPECT_TRUE(Matches( + RecursiveTemplateOneParameter, + Variable(HasName("z_float"), + HasInitializer(HasType(Class(IsDerivedFrom("Base1"))))))); + EXPECT_TRUE(NotMatches( + RecursiveTemplateOneParameter, + Variable( + HasName("z_float"), + HasInitializer(HasType(Class(IsDerivedFrom("Base2"))))))); + EXPECT_TRUE(Matches( + RecursiveTemplateOneParameter, + Variable( + HasName("z_char"), + HasInitializer(HasType(Class(IsDerivedFrom("Base1"), + IsDerivedFrom("Base2"))))))); + + const char *RecursiveTemplateTwoParameters = + "class Base1 {}; class Base2 {};" + "template <typename T1, typename T2> class Z;" + "template <typename T> class Z<void, T> : public Base1 {};" + "template <typename T> class Z<int, T> : public Base2 {};" + "template <typename T> class Z<float, T> : public Z<void, T> {};" + "template <typename T> class Z<double, T> : public Z<int, T> {};" + "template <typename T1, typename T2> class Z : " + " public Z<float, T2>, public Z<double, T2> {};" + "void f() { Z<float, void> z_float; Z<double, void> z_double; " + " Z<char, void> z_char; }"; + EXPECT_TRUE(Matches( + RecursiveTemplateTwoParameters, + Variable( + HasName("z_float"), + HasInitializer(HasType(Class(IsDerivedFrom("Base1"))))))); + EXPECT_TRUE(NotMatches( + RecursiveTemplateTwoParameters, + Variable( + HasName("z_float"), + HasInitializer(HasType(Class(IsDerivedFrom("Base2"))))))); + EXPECT_TRUE(Matches( + RecursiveTemplateTwoParameters, + Variable( + HasName("z_char"), + HasInitializer(HasType(Class(IsDerivedFrom("Base1"), + IsDerivedFrom("Base2"))))))); +} + +TEST(DeclarationMatcher, MatchAnyOf) { + DeclarationMatcher YOrZDerivedFromX = + Class(AnyOf(HasName("Y"), AllOf(IsDerivedFrom("X"), HasName("Z")))); + + EXPECT_TRUE( + Matches("class X {}; class Z : public X {};", YOrZDerivedFromX)); + EXPECT_TRUE(Matches("class Y {};", YOrZDerivedFromX)); + EXPECT_TRUE( + NotMatches("class X {}; class W : public X {};", YOrZDerivedFromX)); + EXPECT_TRUE(NotMatches("class Z {};", YOrZDerivedFromX)); + + DeclarationMatcher XOrYOrZOrU = + Class(AnyOf(HasName("X"), HasName("Y"), HasName("Z"), HasName("U"))); + + EXPECT_TRUE(Matches("class X {};", XOrYOrZOrU)); + EXPECT_TRUE(Matches("class Y {};", XOrYOrZOrU)); + EXPECT_TRUE(Matches("class Z {};", XOrYOrZOrU)); + EXPECT_TRUE(Matches("class U {};", XOrYOrZOrU)); + EXPECT_TRUE(NotMatches("class A {};", XOrYOrZOrU)); +} + +TEST(DeclarationMatcher, MatchHas) { + DeclarationMatcher HasClassX = Class(Has(Class(HasName("X")))); + + EXPECT_TRUE(Matches("class Y { class X {}; };", HasClassX)); + EXPECT_TRUE(Matches("class X {};", HasClassX)); + + DeclarationMatcher YHasClassX = + Class(HasName("Y"), Has(Class(HasName("X")))); + EXPECT_TRUE(Matches("class Y { class X {}; };", YHasClassX)); + EXPECT_TRUE(NotMatches("class X {};", YHasClassX)); + EXPECT_TRUE( + NotMatches("class Y { class Z { class X {}; }; };", YHasClassX)); +} + +TEST(DeclarationMatcher, MatchHasRecursiveAllOf) { + DeclarationMatcher Recursive = + Class( + Has(Class( + Has(Class( + HasName("X"))), + Has(Class( + HasName("Y"))), + HasName("Z"))), + Has(Class( + Has(Class( + HasName("A"))), + Has(Class( + HasName("B"))), + HasName("C"))), + HasName("F")); + + EXPECT_TRUE(Matches( + "class F {" + " class Z {" + " class X {};" + " class Y {};" + " };" + " class C {" + " class A {};" + " class B {};" + " };" + "};", Recursive)); + + EXPECT_TRUE(Matches( + "class F {" + " class Z {" + " class A {};" + " class X {};" + " class Y {};" + " };" + " class C {" + " class X {};" + " class A {};" + " class B {};" + " };" + "};", Recursive)); + + EXPECT_TRUE(Matches( + "class O1 {" + " class O2 {" + " class F {" + " class Z {" + " class A {};" + " class X {};" + " class Y {};" + " };" + " class C {" + " class X {};" + " class A {};" + " class B {};" + " };" + " };" + " };" + "};", Recursive)); +} + +TEST(DeclarationMatcher, MatchHasRecursiveAnyOf) { + DeclarationMatcher Recursive = + Class( + AnyOf( + Has(Class( + AnyOf( + Has(Class( + HasName("X"))), + Has(Class( + HasName("Y"))), + HasName("Z")))), + Has(Class( + AnyOf( + HasName("C"), + Has(Class( + HasName("A"))), + Has(Class( + HasName("B")))))), + HasName("F"))); + + EXPECT_TRUE(Matches("class F {};", Recursive)); + EXPECT_TRUE(Matches("class Z {};", Recursive)); + EXPECT_TRUE(Matches("class C {};", Recursive)); + EXPECT_TRUE(Matches("class M { class N { class X {}; }; };", Recursive)); + EXPECT_TRUE(Matches("class M { class N { class B {}; }; };", Recursive)); + EXPECT_TRUE( + Matches("class O1 { class O2 {" + " class M { class N { class B {}; }; }; " + "}; };", Recursive)); +} + +TEST(DeclarationMatcher, MatchNot) { + DeclarationMatcher NotClassX = + Class( + IsDerivedFrom("Y"), + Not(HasName("Y")), + Not(HasName("X"))); + EXPECT_TRUE(NotMatches("", NotClassX)); + EXPECT_TRUE(NotMatches("class Y {};", NotClassX)); + EXPECT_TRUE(Matches("class Y {}; class Z : public Y {};", NotClassX)); + EXPECT_TRUE(NotMatches("class Y {}; class X : public Y {};", NotClassX)); + EXPECT_TRUE( + NotMatches("class Y {}; class Z {}; class X : public Y {};", + NotClassX)); + + DeclarationMatcher ClassXHasNotClassY = + Class( + HasName("X"), + Has(Class(HasName("Z"))), + Not( + Has(Class(HasName("Y"))))); + EXPECT_TRUE(Matches("class X { class Z {}; };", ClassXHasNotClassY)); + EXPECT_TRUE(NotMatches("class X { class Y {}; class Z {}; };", + ClassXHasNotClassY)); +} + +TEST(DeclarationMatcher, HasDescendant) { + DeclarationMatcher ZDescendantClassX = + Class( + HasDescendant(Class(HasName("X"))), + HasName("Z")); + EXPECT_TRUE(Matches("class Z { class X {}; };", ZDescendantClassX)); + EXPECT_TRUE( + Matches("class Z { class Y { class X {}; }; };", ZDescendantClassX)); + EXPECT_TRUE( + Matches("class Z { class A { class Y { class X {}; }; }; };", + ZDescendantClassX)); + EXPECT_TRUE( + Matches("class Z { class A { class B { class Y { class X {}; }; }; }; };", + ZDescendantClassX)); + EXPECT_TRUE(NotMatches("class Z {};", ZDescendantClassX)); + + DeclarationMatcher ZDescendantClassXHasClassY = + Class( + HasDescendant(Class(Has(Class(HasName("Y"))), + HasName("X"))), + HasName("Z")); + EXPECT_TRUE(Matches("class Z { class X { class Y {}; }; };", + ZDescendantClassXHasClassY)); + EXPECT_TRUE( + Matches("class Z { class A { class B { class X { class Y {}; }; }; }; };", + ZDescendantClassXHasClassY)); + EXPECT_TRUE(NotMatches( + "class Z {" + " class A {" + " class B {" + " class X {" + " class C {" + " class Y {};" + " };" + " };" + " }; " + " };" + "};", ZDescendantClassXHasClassY)); + + DeclarationMatcher ZDescendantClassXDescendantClassY = + Class( + HasDescendant(Class(HasDescendant(Class(HasName("Y"))), + HasName("X"))), + HasName("Z")); + EXPECT_TRUE( + Matches("class Z { class A { class X { class B { class Y {}; }; }; }; };", + ZDescendantClassXDescendantClassY)); + EXPECT_TRUE(Matches( + "class Z {" + " class A {" + " class X {" + " class B {" + " class Y {};" + " };" + " class Y {};" + " };" + " };" + "};", ZDescendantClassXDescendantClassY)); +} + +TEST(StatementMatcher, Has) { + StatementMatcher HasVariableI = + Expression( + HasType(PointsTo(Class(HasName("X")))), + Has(DeclarationReference(To(Variable(HasName("i")))))); + + EXPECT_TRUE(Matches( + "class X; X *x(int); void c() { int i; x(i); }", HasVariableI)); + EXPECT_TRUE(NotMatches( + "class X; X *x(int); void c() { int i; x(42); }", HasVariableI)); +} + +TEST(StatementMatcher, HasDescendant) { + StatementMatcher HasDescendantVariableI = + Expression( + HasType(PointsTo(Class(HasName("X")))), + HasDescendant(DeclarationReference(To(Variable(HasName("i")))))); + + EXPECT_TRUE(Matches( + "class X; X *x(bool); bool b(int); void c() { int i; x(b(i)); }", + HasDescendantVariableI)); + EXPECT_TRUE(NotMatches( + "class X; X *x(bool); bool b(int); void c() { int i; x(b(42)); }", + HasDescendantVariableI)); +} + +TEST(TypeMatcher, MatchesClassType) { + TypeMatcher TypeA = HasDeclaration(Class(HasName("A"))); + + EXPECT_TRUE(Matches("class A { public: A *a; };", TypeA)); + EXPECT_TRUE(NotMatches("class A {};", TypeA)); + + TypeMatcher TypeDerivedFromA = HasDeclaration(Class(IsDerivedFrom("A"))); + + EXPECT_TRUE(Matches("class A {}; class B : public A { public: B *b; };", + TypeDerivedFromA)); + EXPECT_TRUE(NotMatches("class A {};", TypeA)); + + TypeMatcher TypeAHasClassB = HasDeclaration( + Class(HasName("A"), Has(Class(HasName("B"))))); + + EXPECT_TRUE( + Matches("class A { public: A *a; class B {}; };", TypeAHasClassB)); +} + +// Returns whether 'bound_nodes' contain a Decl for bound to 'id', which +// can be dynamically casted to T. +template <typename T> +class VerifyIdIsBoundToDecl : public BoundNodesCallback { + public: + explicit VerifyIdIsBoundToDecl(const std::string &Id) : Id(Id) {} + virtual bool Run(const BoundNodes *Nodes) { + const T *Node = Nodes->GetDeclAs<T>(Id); + return Node != NULL; + } + + private: + const std::string Id; +}; +template <typename T> +class VerifyIdIsBoundToStmt : public BoundNodesCallback { + public: + explicit VerifyIdIsBoundToStmt(const std::string &Id) : Id(Id) {} + virtual bool Run(const BoundNodes *Nodes) { + const T *Node = Nodes->GetStmtAs<T>(Id); + return Node != NULL; + } + private: + const std::string Id; +}; + +TEST(Matcher, BindMatchedNodes) { + DeclarationMatcher ClassX = Has(Id("x", Class(HasName("X")))); + + EXPECT_TRUE(MatchAndVerifyResultTrue("class X {};", + ClassX, new VerifyIdIsBoundToDecl<clang::CXXRecordDecl>("x"))); + + EXPECT_TRUE(MatchAndVerifyResultFalse("class X {};", + ClassX, new VerifyIdIsBoundToDecl<clang::CXXRecordDecl>("other-id"))); + + TypeMatcher TypeAHasClassB = HasDeclaration( + Class(HasName("A"), Has(Id("b", Class(HasName("B")))))); + + EXPECT_TRUE(MatchAndVerifyResultTrue("class A { public: A *a; class B {}; };", + TypeAHasClassB, + new VerifyIdIsBoundToDecl<clang::Decl>("b"))); + + StatementMatcher MethodX = Id("x", Call(Callee(Method(HasName("x"))))); + + EXPECT_TRUE(MatchAndVerifyResultTrue("class A { void x() { x(); } };", + MethodX, + new VerifyIdIsBoundToStmt<clang::CXXMemberCallExpr>("x"))); +} + +TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) { + TypeMatcher ClassX = HasDeclaration(Class(HasName("X"))); + EXPECT_TRUE( + Matches("class X {}; void y(X &x) { x; }", Expression(HasType(ClassX)))); + EXPECT_TRUE( + NotMatches("class X {}; void y(X *x) { x; }", + Expression(HasType(ClassX)))); + EXPECT_TRUE( + Matches("class X {}; void y(X *x) { x; }", + Expression(HasType(PointsTo(ClassX))))); +} + +TEST(HasType, TakesQualTypeMatcherAndMatchesValueDecl) { + TypeMatcher ClassX = HasDeclaration(Class(HasName("X"))); + EXPECT_TRUE( + Matches("class X {}; void y() { X x; }", Variable(HasType(ClassX)))); + EXPECT_TRUE( + NotMatches("class X {}; void y() { X *x; }", Variable(HasType(ClassX)))); + EXPECT_TRUE( + Matches("class X {}; void y() { X *x; }", + Variable(HasType(PointsTo(ClassX))))); +} + +TEST(HasType, TakesDeclMatcherAndMatchesExpr) { + DeclarationMatcher ClassX = Class(HasName("X")); + EXPECT_TRUE( + Matches("class X {}; void y(X &x) { x; }", Expression(HasType(ClassX)))); + EXPECT_TRUE( + NotMatches("class X {}; void y(X *x) { x; }", + Expression(HasType(ClassX)))); +} + +TEST(HasType, TakesDeclMatcherAndMatchesValueDecl) { + DeclarationMatcher ClassX = Class(HasName("X")); + EXPECT_TRUE( + Matches("class X {}; void y() { X x; }", Variable(HasType(ClassX)))); + EXPECT_TRUE( + NotMatches("class X {}; void y() { X *x; }", Variable(HasType(ClassX)))); +} + +TEST(Matcher, Call) { + // FIXME: Do we want to overload Call() to directly take + // Matcher<clang::Decl>, too? + StatementMatcher MethodX = Call(HasDeclaration(Method(HasName("x")))); + + EXPECT_TRUE(Matches("class Y { void x() { x(); } };", MethodX)); + EXPECT_TRUE(NotMatches("class Y { void x() {} };", MethodX)); + + StatementMatcher MethodOnY = Call(On(HasType(Class(HasName("Y"))))); + + EXPECT_TRUE( + Matches("class Y { public: void x(); }; void z() { Y y; y.x(); }", + MethodOnY)); + EXPECT_TRUE( + Matches("class Y { public: void x(); }; void z(Y &y) { y.x(); }", + MethodOnY)); + EXPECT_TRUE( + NotMatches("class Y { public: void x(); }; void z(Y *&y) { y->x(); }", + MethodOnY)); + EXPECT_TRUE( + NotMatches("class Y { public: void x(); }; void z(Y y[]) { y->x(); }", + MethodOnY)); + EXPECT_TRUE( + NotMatches("class Y { public: void x(); }; void z() { Y *y; y->x(); }", + MethodOnY)); + + StatementMatcher MethodOnYPointer = + Call(On(HasType(PointsTo(Class(HasName("Y")))))); + + EXPECT_TRUE( + Matches("class Y { public: void x(); }; void z() { Y *y; y->x(); }", + MethodOnYPointer)); + EXPECT_TRUE( + Matches("class Y { public: void x(); }; void z(Y *&y) { y->x(); }", + MethodOnYPointer)); + EXPECT_TRUE( + Matches("class Y { public: void x(); }; void z(Y y[]) { y->x(); }", + MethodOnYPointer)); + EXPECT_TRUE( + NotMatches("class Y { public: void x(); }; void z() { Y y; y.x(); }", + MethodOnYPointer)); + EXPECT_TRUE( + NotMatches("class Y { public: void x(); }; void z(Y &y) { y.x(); }", + MethodOnYPointer)); +} + +TEST(Matcher, OverloadedOperatorCall) { + StatementMatcher OpCall = OverloadedOperatorCall(); + // Unary operator + EXPECT_TRUE(Matches("class Y { }; " + "bool operator!(Y x) { return false; }; " + "Y y; bool c = !y;", OpCall)); + // No match -- special operators like "new", "delete" + // FIXME: figure out why these does not match? + EXPECT_TRUE(NotMatches("class Y { }; " + "void *operator new(unsigned long size) { return 0; } " + "Y *y = new Y;", OpCall)); + EXPECT_TRUE(NotMatches("class Y { }; " + "void operator delete(void *p) { } " + "void a() {Y *y = new Y; delete y;}", OpCall)); + // Binary operator + EXPECT_TRUE(Matches("class Y { }; " + "bool operator&&(Y x, Y y) { return true; }; " + "Y a; Y b; bool c = a && b;", + OpCall)); + // No match -- normal operator, not an overloaded one. + EXPECT_TRUE(NotMatches("bool x = true, y = true; bool t = x && y;", OpCall)); + EXPECT_TRUE(NotMatches("int t = 5 << 2;", OpCall)); +} + +TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) { + StatementMatcher OpCallAndAnd = + OverloadedOperatorCall(HasOverloadedOperatorName("&&")); + EXPECT_TRUE(Matches("class Y { }; " + "bool operator&&(Y x, Y y) { return true; }; " + "Y a; Y b; bool c = a && b;", OpCallAndAnd)); + StatementMatcher OpCallLessLess = + OverloadedOperatorCall(HasOverloadedOperatorName("<<")); + EXPECT_TRUE(NotMatches("class Y { }; " + "bool operator&&(Y x, Y y) { return true; }; " + "Y a; Y b; bool c = a && b;", + OpCallLessLess)); +} + +TEST(Matcher, ThisPointerType) { + StatementMatcher MethodOnY = Call(ThisPointerType(Class(HasName("Y")))); + + EXPECT_TRUE( + Matches("class Y { public: void x(); }; void z() { Y y; y.x(); }", + MethodOnY)); + EXPECT_TRUE( + Matches("class Y { public: void x(); }; void z(Y &y) { y.x(); }", + MethodOnY)); + EXPECT_TRUE( + Matches("class Y { public: void x(); }; void z(Y *&y) { y->x(); }", + MethodOnY)); + EXPECT_TRUE( + Matches("class Y { public: void x(); }; void z(Y y[]) { y->x(); }", + MethodOnY)); + EXPECT_TRUE( + Matches("class Y { public: void x(); }; void z() { Y *y; y->x(); }", + MethodOnY)); + + EXPECT_TRUE(Matches( + "class Y {" + " public: virtual void x();" + "};" + "class X : public Y {" + " public: virtual void x();" + "};" + "void z() { X *x; x->Y::x(); }", MethodOnY)); +} + +TEST(Matcher, VariableUsage) { + StatementMatcher Reference = + DeclarationReference(To( + Variable(HasInitializer( + Call(ThisPointerType(Class(HasName("Y")))))))); + + EXPECT_TRUE(Matches( + "class Y {" + " public:" + " bool x() const;" + "};" + "void z(const Y &y) {" + " bool b = y.x();" + " if (b) {}" + "}", Reference)); + + EXPECT_TRUE(NotMatches( + "class Y {" + " public:" + " bool x() const;" + "};" + "void z(const Y &y) {" + " bool b = y.x();" + "}", Reference)); +} + +TEST(Matcher, CalledVariable) { + StatementMatcher CallOnVariableY = Expression( + Call(On(DeclarationReference(To(Variable(HasName("y"))))))); + + EXPECT_TRUE(Matches( + "class Y { public: void x() { Y y; y.x(); } };", CallOnVariableY)); + EXPECT_TRUE(Matches( + "class Y { public: void x() const { Y y; y.x(); } };", CallOnVariableY)); + EXPECT_TRUE(Matches( + "class Y { public: void x(); };" + "class X : public Y { void z() { X y; y.x(); } };", CallOnVariableY)); + EXPECT_TRUE(Matches( + "class Y { public: void x(); };" + "class X : public Y { void z() { X *y; y->x(); } };", CallOnVariableY)); + EXPECT_TRUE(NotMatches( + "class Y { public: void x(); };" + "class X : public Y { void z() { unsigned long y; ((X*)y)->x(); } };", + CallOnVariableY)); +} + +TEST(MemberExpression, DoesNotMatchClasses) { + EXPECT_TRUE(NotMatches("class Y { void x() {} };", MemberExpression())); +} + +TEST(MemberExpression, MatchesMemberFunctionCall) { + EXPECT_TRUE(Matches("class Y { void x() { x(); } };", MemberExpression())); +} + +TEST(MemberExpression, MatchesVariable) { + EXPECT_TRUE( + Matches("class Y { void x() { this->y; } int y; };", MemberExpression())); + EXPECT_TRUE( + Matches("class Y { void x() { y; } int y; };", MemberExpression())); + EXPECT_TRUE( + Matches("class Y { void x() { Y y; y.y; } int y; };", + MemberExpression())); +} + +TEST(MemberExpression, MatchesStaticVariable) { + EXPECT_TRUE(Matches("class Y { void x() { this->y; } static int y; };", + MemberExpression())); + EXPECT_TRUE(NotMatches("class Y { void x() { y; } static int y; };", + MemberExpression())); + EXPECT_TRUE(NotMatches("class Y { void x() { Y::y; } static int y; };", + MemberExpression())); +} + +TEST(IsArrow, MatchesMemberVariablesViaArrow) { + EXPECT_TRUE(Matches("class Y { void x() { this->y; } int y; };", + MemberExpression(IsArrow()))); + EXPECT_TRUE(Matches("class Y { void x() { y; } int y; };", + MemberExpression(IsArrow()))); + EXPECT_TRUE(NotMatches("class Y { void x() { (*this).y; } int y; };", + MemberExpression(IsArrow()))); +} + +TEST(IsArrow, MatchesStaticMemberVariablesViaArrow) { + EXPECT_TRUE(Matches("class Y { void x() { this->y; } static int y; };", + MemberExpression(IsArrow()))); + EXPECT_TRUE(NotMatches("class Y { void x() { y; } static int y; };", + MemberExpression(IsArrow()))); + EXPECT_TRUE(NotMatches("class Y { void x() { (*this).y; } static int y; };", + MemberExpression(IsArrow()))); +} + +TEST(IsArrow, MatchesMemberCallsViaArrow) { + EXPECT_TRUE(Matches("class Y { void x() { this->x(); } };", + MemberExpression(IsArrow()))); + EXPECT_TRUE(Matches("class Y { void x() { x(); } };", + MemberExpression(IsArrow()))); + EXPECT_TRUE(NotMatches("class Y { void x() { Y y; y.x(); } };", + MemberExpression(IsArrow()))); +} + +TEST(Callee, MatchesDeclarations) { + StatementMatcher CallMethodX = Call(Callee(Method(HasName("x")))); + + EXPECT_TRUE(Matches("class Y { void x() { x(); } };", CallMethodX)); + EXPECT_TRUE(NotMatches("class Y { void x() {} };", CallMethodX)); +} + +TEST(Callee, MatchesMemberExpressions) { + EXPECT_TRUE(Matches("class Y { void x() { this->x(); } };", + Call(Callee(MemberExpression())))); + EXPECT_TRUE( + NotMatches("class Y { void x() { this->x(); } };", Call(Callee(Call())))); +} + +TEST(Matcher, Argument) { + StatementMatcher CallArgumentY = Expression(Call( + HasArgument(0, DeclarationReference(To(Variable(HasName("y"))))))); + + EXPECT_TRUE(Matches("void x(int) { int y; x(y); }", CallArgumentY)); + EXPECT_TRUE( + Matches("class X { void x(int) { int y; x(y); } };", CallArgumentY)); + EXPECT_TRUE(NotMatches("void x(int) { int z; x(z); }", CallArgumentY)); + + StatementMatcher WrongIndex = Expression(Call( + HasArgument(42, DeclarationReference(To(Variable(HasName("y"))))))); + EXPECT_TRUE(NotMatches("void x(int) { int y; x(y); }", WrongIndex)); +} + +TEST(Matcher, AnyArgument) { + StatementMatcher CallArgumentY = Expression(Call( + HasAnyArgument(DeclarationReference(To(Variable(HasName("y"))))))); + EXPECT_TRUE(Matches("void x(int, int) { int y; x(1, y); }", CallArgumentY)); + EXPECT_TRUE(Matches("void x(int, int) { int y; x(y, 42); }", CallArgumentY)); + EXPECT_TRUE(NotMatches("void x(int, int) { x(1, 2); }", CallArgumentY)); +} + +TEST(Matcher, ArgumentCount) { + StatementMatcher Call1Arg = Expression(Call(ArgumentCountIs(1))); + + EXPECT_TRUE(Matches("void x(int) { x(0); }", Call1Arg)); + EXPECT_TRUE(Matches("class X { void x(int) { x(0); } };", Call1Arg)); + EXPECT_TRUE(NotMatches("void x(int, int) { x(0, 0); }", Call1Arg)); +} + +TEST(Matcher, References) { + DeclarationMatcher ReferenceClassX = Variable( + HasType(References(Class(HasName("X"))))); + EXPECT_TRUE(Matches("class X {}; void y(X y) { X &x = y; }", ReferenceClassX)); + EXPECT_TRUE( + Matches("class X {}; void y(X y) { const X &x = y; }", ReferenceClassX)); + EXPECT_TRUE( + NotMatches("class X {}; void y(X y) { X x = y; }", ReferenceClassX)); + EXPECT_TRUE( + NotMatches("class X {}; void y(X *y) { X *&x = y; }", ReferenceClassX)); +} + +TEST(HasParameter, CallsInnerMatcher) { + EXPECT_TRUE(Matches("class X { void x(int) {} };", + Method(HasParameter(0, Variable())))); + EXPECT_TRUE(NotMatches("class X { void x(int) {} };", + Method(HasParameter(0, HasName("x"))))); +} + +TEST(HasParameter, DoesNotMatchIfIndexOutOfBounds) { + EXPECT_TRUE(NotMatches("class X { void x(int) {} };", + Method(HasParameter(42, Variable())))); +} + +TEST(HasType, MatchesParameterVariableTypesStrictly) { + EXPECT_TRUE(Matches("class X { void x(X x) {} };", + Method(HasParameter(0, HasType(Class(HasName("X"))))))); + EXPECT_TRUE(NotMatches("class X { void x(const X &x) {} };", + Method(HasParameter(0, HasType(Class(HasName("X"))))))); + EXPECT_TRUE(Matches("class X { void x(const X *x) {} };", + Method(HasParameter(0, HasType(PointsTo(Class(HasName("X")))))))); + EXPECT_TRUE(Matches("class X { void x(const X &x) {} };", + Method(HasParameter(0, HasType(References(Class(HasName("X")))))))); +} + +TEST(HasAnyParameter, MatchesIndependentlyOfPosition) { + EXPECT_TRUE(Matches("class Y {}; class X { void x(X x, Y y) {} };", + Method(HasAnyParameter(HasType(Class(HasName("X"))))))); + EXPECT_TRUE(Matches("class Y {}; class X { void x(Y y, X x) {} };", + Method(HasAnyParameter(HasType(Class(HasName("X"))))))); +} + +TEST(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) { + EXPECT_TRUE(NotMatches("class Y {}; class X { void x(int) {} };", + Method(HasAnyParameter(HasType(Class(HasName("X"))))))); +} + +TEST(HasAnyParameter, DoesNotMatchThisPointer) { + EXPECT_TRUE(NotMatches("class Y {}; class X { void x() {} };", + Method(HasAnyParameter(HasType(PointsTo(Class(HasName("X")))))))); +} + +TEST(HasName, MatchesParameterVariableDeclartions) { + EXPECT_TRUE(Matches("class Y {}; class X { void x(int x) {} };", + Method(HasAnyParameter(HasName("x"))))); + EXPECT_TRUE(NotMatches("class Y {}; class X { void x(int) {} };", + Method(HasAnyParameter(HasName("x"))))); +} + +TEST(Matcher, ConstructorCall) { + StatementMatcher Constructor = Expression(ConstructorCall()); + + EXPECT_TRUE( + Matches("class X { public: X(); }; void x() { X x; }", Constructor)); + EXPECT_TRUE( + Matches("class X { public: X(); }; void x() { X x = X(); }", + Constructor)); + EXPECT_TRUE( + Matches("class X { public: X(int); }; void x() { X x = 0; }", + Constructor)); + EXPECT_TRUE(Matches("class X {}; void x(int) { X x; }", Constructor)); +} + +TEST(Matcher, ConstructorArgument) { + StatementMatcher Constructor = Expression(ConstructorCall( + HasArgument(0, DeclarationReference(To(Variable(HasName("y"))))))); + + EXPECT_TRUE( + Matches("class X { public: X(int); }; void x() { int y; X x(y); }", + Constructor)); + EXPECT_TRUE( + Matches("class X { public: X(int); }; void x() { int y; X x = X(y); }", + Constructor)); + EXPECT_TRUE( + Matches("class X { public: X(int); }; void x() { int y; X x = y; }", + Constructor)); + EXPECT_TRUE( + NotMatches("class X { public: X(int); }; void x() { int z; X x(z); }", + Constructor)); + + StatementMatcher WrongIndex = Expression(ConstructorCall( + HasArgument(42, DeclarationReference(To(Variable(HasName("y"))))))); + EXPECT_TRUE( + NotMatches("class X { public: X(int); }; void x() { int y; X x(y); }", + WrongIndex)); +} + +TEST(Matcher, ConstructorArgumentCount) { + StatementMatcher Constructor1Arg = + Expression(ConstructorCall(ArgumentCountIs(1))); + + EXPECT_TRUE( + Matches("class X { public: X(int); }; void x() { X x(0); }", + Constructor1Arg)); + EXPECT_TRUE( + Matches("class X { public: X(int); }; void x() { X x = X(0); }", + Constructor1Arg)); + EXPECT_TRUE( + Matches("class X { public: X(int); }; void x() { X x = 0; }", + Constructor1Arg)); + EXPECT_TRUE( + NotMatches("class X { public: X(int, int); }; void x() { X x(0, 0); }", + Constructor1Arg)); +} + +TEST(Matcher, DefaultArgument) { + StatementMatcher Arg = DefaultArgument(); + + EXPECT_TRUE(Matches("void x(int, int = 0) { int y; x(y); }", Arg)); + EXPECT_TRUE( + Matches("class X { void x(int, int = 0) { int y; x(y); } };", Arg)); + EXPECT_TRUE(NotMatches("void x(int, int = 0) { int y; x(y, 0); }", Arg)); +} + +TEST(Matcher, StringLiterals) { + StatementMatcher Literal = Expression(StringLiteral()); + EXPECT_TRUE(Matches("const char *s = \"string\";", Literal)); + // wide string + EXPECT_TRUE(Matches("const wchar_t *s = L\"string\";", Literal)); + // with escaped characters + EXPECT_TRUE(Matches("const char *s = \"\x05five\";", Literal)); + // no matching -- though the data type is the same, there is no string literal + EXPECT_TRUE(NotMatches("const char s[1] = {'a'};", Literal)); +} + +TEST(Matcher, CharacterLiterals) { + StatementMatcher CharLiteral = Expression(CharacterLiteral()); + EXPECT_TRUE(Matches("const char c = 'c';", CharLiteral)); + // wide character + EXPECT_TRUE(Matches("const char c = L'c';", CharLiteral)); + // wide character, Hex encoded, NOT MATCHED! + EXPECT_TRUE(NotMatches("const wchar_t c = 0x2126;", CharLiteral)); + EXPECT_TRUE(NotMatches("const char c = 0x1;", CharLiteral)); +} + +TEST(Matcher, IntegerLiterals) { + StatementMatcher HasIntLiteral = Expression(IntegerLiteral()); + EXPECT_TRUE(Matches("int i = 10;", HasIntLiteral)); + EXPECT_TRUE(Matches("int i = 0x1AB;", HasIntLiteral)); + EXPECT_TRUE(Matches("int i = 10L;", HasIntLiteral)); + EXPECT_TRUE(Matches("int i = 10U;", HasIntLiteral)); + + // Non-matching cases (character literals, float and double) + EXPECT_TRUE(NotMatches("int i = L'a';", + HasIntLiteral)); // this is actually a character + // literal cast to int + EXPECT_TRUE(NotMatches("int i = 'a';", HasIntLiteral)); + EXPECT_TRUE(NotMatches("int i = 1e10;", HasIntLiteral)); + EXPECT_TRUE(NotMatches("int i = 10.0;", HasIntLiteral)); +} + +TEST(Matcher, Conditions) { + StatementMatcher Condition = If(HasCondition(BoolLiteral(Equals(true)))); + + EXPECT_TRUE(Matches("void x() { if (true) {} }", Condition)); + EXPECT_TRUE(NotMatches("void x() { if (false) {} }", Condition)); + EXPECT_TRUE(NotMatches("void x() { bool a = true; if (a) {} }", Condition)); + EXPECT_TRUE(NotMatches("void x() { if (true || false) {} }", Condition)); + EXPECT_TRUE(NotMatches("void x() { if (1) {} }", Condition)); +} + +TEST(MatchBinaryOperator, HasOperatorName) { + StatementMatcher OperatorOr = BinaryOperator(HasOperatorName("||")); + + EXPECT_TRUE(Matches("void x() { true || false; }", OperatorOr)); + EXPECT_TRUE(NotMatches("void x() { true && false; }", OperatorOr)); +} + +TEST(MatchBinaryOperator, HasLHSAndHasRHS) { + StatementMatcher OperatorTrueFalse = + BinaryOperator(HasLHS(BoolLiteral(Equals(true))), + HasRHS(BoolLiteral(Equals(false)))); + + EXPECT_TRUE(Matches("void x() { true || false; }", OperatorTrueFalse)); + EXPECT_TRUE(Matches("void x() { true && false; }", OperatorTrueFalse)); + EXPECT_TRUE(NotMatches("void x() { false || true; }", OperatorTrueFalse)); +} + +TEST(MatchBinaryOperator, HasEitherOperand) { + StatementMatcher HasOperand = + BinaryOperator(HasEitherOperand(BoolLiteral(Equals(false)))); + + EXPECT_TRUE(Matches("void x() { true || false; }", HasOperand)); + EXPECT_TRUE(Matches("void x() { false && true; }", HasOperand)); + EXPECT_TRUE(NotMatches("void x() { true || true; }", HasOperand)); +} + +TEST(Matcher, BinaryOperatorTypes) { + // Integration test that verifies the AST provides all binary operators in + // a way we expect. + // FIXME: Operator ',' + EXPECT_TRUE( + Matches("void x() { 3, 4; }", BinaryOperator(HasOperatorName(",")))); + EXPECT_TRUE( + Matches("bool b; bool c = (b = true);", + BinaryOperator(HasOperatorName("=")))); + EXPECT_TRUE( + Matches("bool b = 1 != 2;", BinaryOperator(HasOperatorName("!=")))); + EXPECT_TRUE( + Matches("bool b = 1 == 2;", BinaryOperator(HasOperatorName("==")))); + EXPECT_TRUE(Matches("bool b = 1 < 2;", BinaryOperator(HasOperatorName("<")))); + EXPECT_TRUE( + Matches("bool b = 1 <= 2;", BinaryOperator(HasOperatorName("<=")))); + EXPECT_TRUE( + Matches("int i = 1 << 2;", BinaryOperator(HasOperatorName("<<")))); + EXPECT_TRUE( + Matches("int i = 1; int j = (i <<= 2);", + BinaryOperator(HasOperatorName("<<=")))); + EXPECT_TRUE(Matches("bool b = 1 > 2;", BinaryOperator(HasOperatorName(">")))); + EXPECT_TRUE( + Matches("bool b = 1 >= 2;", BinaryOperator(HasOperatorName(">=")))); + EXPECT_TRUE( + Matches("int i = 1 >> 2;", BinaryOperator(HasOperatorName(">>")))); + EXPECT_TRUE( + Matches("int i = 1; int j = (i >>= 2);", + BinaryOperator(HasOperatorName(">>=")))); + EXPECT_TRUE( + Matches("int i = 42 ^ 23;", BinaryOperator(HasOperatorName("^")))); + EXPECT_TRUE( + Matches("int i = 42; int j = (i ^= 42);", + BinaryOperator(HasOperatorName("^=")))); + EXPECT_TRUE( + Matches("int i = 42 % 23;", BinaryOperator(HasOperatorName("%")))); + EXPECT_TRUE( + Matches("int i = 42; int j = (i %= 42);", + BinaryOperator(HasOperatorName("%=")))); + EXPECT_TRUE( + Matches("bool b = 42 &23;", BinaryOperator(HasOperatorName("&")))); + EXPECT_TRUE( + Matches("bool b = true && false;", + BinaryOperator(HasOperatorName("&&")))); + EXPECT_TRUE( + Matches("bool b = true; bool c = (b &= false);", + BinaryOperator(HasOperatorName("&=")))); + EXPECT_TRUE( + Matches("bool b = 42 | 23;", BinaryOperator(HasOperatorName("|")))); + EXPECT_TRUE( + Matches("bool b = true || false;", + BinaryOperator(HasOperatorName("||")))); + EXPECT_TRUE( + Matches("bool b = true; bool c = (b |= false);", + BinaryOperator(HasOperatorName("|=")))); + EXPECT_TRUE( + Matches("int i = 42 *23;", BinaryOperator(HasOperatorName("*")))); + EXPECT_TRUE( + Matches("int i = 42; int j = (i *= 23);", + BinaryOperator(HasOperatorName("*=")))); + EXPECT_TRUE( + Matches("int i = 42 / 23;", BinaryOperator(HasOperatorName("/")))); + EXPECT_TRUE( + Matches("int i = 42; int j = (i /= 23);", + BinaryOperator(HasOperatorName("/=")))); + EXPECT_TRUE( + Matches("int i = 42 + 23;", BinaryOperator(HasOperatorName("+")))); + EXPECT_TRUE( + Matches("int i = 42; int j = (i += 23);", + BinaryOperator(HasOperatorName("+=")))); + EXPECT_TRUE( + Matches("int i = 42 - 23;", BinaryOperator(HasOperatorName("-")))); + EXPECT_TRUE( + Matches("int i = 42; int j = (i -= 23);", + BinaryOperator(HasOperatorName("-=")))); + EXPECT_TRUE( + Matches("struct A { void x() { void (A::*a)(); (this->*a)(); } };", + BinaryOperator(HasOperatorName("->*")))); + EXPECT_TRUE( + Matches("struct A { void x() { void (A::*a)(); ((*this).*a)(); } };", + BinaryOperator(HasOperatorName(".*")))); + + // Member expressions as operators are not supported in matches. + EXPECT_TRUE( + NotMatches("struct A { void x(A *a) { a->x(this); } };", + BinaryOperator(HasOperatorName("->")))); + + // Initializer assignments are not represented as operator equals. + EXPECT_TRUE( + NotMatches("bool b = true;", BinaryOperator(HasOperatorName("=")))); + + // Array indexing is not represented as operator. + EXPECT_TRUE(NotMatches("int a[42]; void x() { a[23]; }", UnaryOperator())); + + // Overloaded operators do not match at all. + EXPECT_TRUE(NotMatches( + "struct A { bool operator&&(const A &a) const { return false; } };" + "void x() { A a, b; a && b; }", + BinaryOperator())); +} + +TEST(MatchUnaryOperator, HasOperatorName) { + StatementMatcher OperatorNot = UnaryOperator(HasOperatorName("!")); + + EXPECT_TRUE(Matches("void x() { !true; } ", OperatorNot)); + EXPECT_TRUE(NotMatches("void x() { true; } ", OperatorNot)); +} + +TEST(MatchUnaryOperator, HasUnaryOperand) { + StatementMatcher OperatorOnFalse = + UnaryOperator(HasUnaryOperand(BoolLiteral(Equals(false)))); + + EXPECT_TRUE(Matches("void x() { !false; }", OperatorOnFalse)); + EXPECT_TRUE(NotMatches("void x() { !true; }", OperatorOnFalse)); +} + +TEST(Matcher, UnaryOperatorTypes) { + // Integration test that verifies the AST provides all unary operators in + // a way we expect. + EXPECT_TRUE(Matches("bool b = !true;", UnaryOperator(HasOperatorName("!")))); + EXPECT_TRUE( + Matches("bool b; bool *p = &b;", UnaryOperator(HasOperatorName("&")))); + EXPECT_TRUE(Matches("int i = ~ 1;", UnaryOperator(HasOperatorName("~")))); + EXPECT_TRUE( + Matches("bool *p; bool b = *p;", UnaryOperator(HasOperatorName("*")))); + EXPECT_TRUE( + Matches("int i; int j = +i;", UnaryOperator(HasOperatorName("+")))); + EXPECT_TRUE( + Matches("int i; int j = -i;", UnaryOperator(HasOperatorName("-")))); + EXPECT_TRUE( + Matches("int i; int j = ++i;", UnaryOperator(HasOperatorName("++")))); + EXPECT_TRUE( + Matches("int i; int j = i++;", UnaryOperator(HasOperatorName("++")))); + EXPECT_TRUE( + Matches("int i; int j = --i;", UnaryOperator(HasOperatorName("--")))); + EXPECT_TRUE( + Matches("int i; int j = i--;", UnaryOperator(HasOperatorName("--")))); + + // We don't match conversion operators. + EXPECT_TRUE(NotMatches("int i; double d = (double)i;", UnaryOperator())); + + // Function calls are not represented as operator. + EXPECT_TRUE(NotMatches("void f(); void x() { f(); }", UnaryOperator())); + + // Overloaded operators do not match at all. + // FIXME: We probably want to add that. + EXPECT_TRUE(NotMatches( + "struct A { bool operator!() const { return false; } };" + "void x() { A a; !a; }", UnaryOperator(HasOperatorName("!")))); +} + +TEST(Matcher, ConditionalOperator) { + StatementMatcher Conditional = ConditionalOperator( + HasCondition(BoolLiteral(Equals(true))), + HasTrueExpression(BoolLiteral(Equals(false)))); + + EXPECT_TRUE(Matches("void x() { true ? false : true; }", Conditional)); + EXPECT_TRUE(NotMatches("void x() { false ? false : true; }", Conditional)); + EXPECT_TRUE(NotMatches("void x() { true ? true : false; }", Conditional)); + + StatementMatcher ConditionalFalse = ConditionalOperator( + HasFalseExpression(BoolLiteral(Equals(false)))); + + EXPECT_TRUE(Matches("void x() { true ? true : false; }", ConditionalFalse)); + EXPECT_TRUE( + NotMatches("void x() { true ? false : true; }", ConditionalFalse)); +} + +TEST(Matcher, HasNameSupportsNamespaces) { + EXPECT_TRUE(Matches("namespace a { namespace b { class C; } }", + Class(HasName("a::b::C")))); + EXPECT_TRUE(Matches("namespace a { namespace b { class C; } }", + Class(HasName("::a::b::C")))); + EXPECT_TRUE(Matches("namespace a { namespace b { class C; } }", + Class(HasName("b::C")))); + EXPECT_TRUE(Matches("namespace a { namespace b { class C; } }", + Class(HasName("C")))); + EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }", + Class(HasName("c::b::C")))); + EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }", + Class(HasName("a::c::C")))); + EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }", + Class(HasName("a::b::A")))); + EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }", + Class(HasName("::C")))); + EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }", + Class(HasName("::b::C")))); + EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }", + Class(HasName("z::a::b::C")))); + EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }", + Class(HasName("a+b::C")))); + EXPECT_TRUE(NotMatches("namespace a { namespace b { class AC; } }", + Class(HasName("C")))); +} + +TEST(Matcher, HasNameSupportsOuterClasses) { + EXPECT_TRUE( + Matches("class A { class B { class C; }; };", Class(HasName("A::B::C")))); + EXPECT_TRUE( + Matches("class A { class B { class C; }; };", + Class(HasName("::A::B::C")))); + EXPECT_TRUE( + Matches("class A { class B { class C; }; };", Class(HasName("B::C")))); + EXPECT_TRUE( + Matches("class A { class B { class C; }; };", Class(HasName("C")))); + EXPECT_TRUE( + NotMatches("class A { class B { class C; }; };", + Class(HasName("c::B::C")))); + EXPECT_TRUE( + NotMatches("class A { class B { class C; }; };", + Class(HasName("A::c::C")))); + EXPECT_TRUE( + NotMatches("class A { class B { class C; }; };", + Class(HasName("A::B::A")))); + EXPECT_TRUE( + NotMatches("class A { class B { class C; }; };", Class(HasName("::C")))); + EXPECT_TRUE( + NotMatches("class A { class B { class C; }; };", + Class(HasName("::B::C")))); + EXPECT_TRUE(NotMatches("class A { class B { class C; }; };", + Class(HasName("z::A::B::C")))); + EXPECT_TRUE( + NotMatches("class A { class B { class C; }; };", + Class(HasName("A+B::C")))); +} + +TEST(Matcher, IsDefinition) { + DeclarationMatcher DefinitionOfClassA = + Class(HasName("A"), IsDefinition()); + EXPECT_TRUE(Matches("class A {};", DefinitionOfClassA)); + EXPECT_TRUE(NotMatches("class A;", DefinitionOfClassA)); + + DeclarationMatcher DefinitionOfVariableA = + Variable(HasName("a"), IsDefinition()); + EXPECT_TRUE(Matches("int a;", DefinitionOfVariableA)); + EXPECT_TRUE(NotMatches("extern int a;", DefinitionOfVariableA)); + + DeclarationMatcher DefinitionOfMethodA = + Method(HasName("a"), IsDefinition()); + EXPECT_TRUE(Matches("class A { void a() {} };", DefinitionOfMethodA)); + EXPECT_TRUE(NotMatches("class A { void a(); };", DefinitionOfMethodA)); +} + +TEST(Matcher, OfClass) { + StatementMatcher Constructor = ConstructorCall(HasDeclaration(Method( + OfClass(HasName("X"))))); + + EXPECT_TRUE( + Matches("class X { public: X(); }; void x(int) { X x; }", Constructor)); + EXPECT_TRUE( + Matches("class X { public: X(); }; void x(int) { X x = X(); }", + Constructor)); + EXPECT_TRUE( + NotMatches("class Y { public: Y(); }; void x(int) { Y y; }", + Constructor)); +} + +TEST(Matcher, VisitsTemplateInstantiations) { + EXPECT_TRUE(Matches( + "class A { public: void x(); };" + "template <typename T> class B { public: void y() { T t; t.x(); } };" + "void f() { B<A> b; b.y(); }", Call(Callee(Method(HasName("x")))))); + + EXPECT_TRUE(Matches( + "class A { public: void x(); };" + "class C {" + " public:" + " template <typename T> class B { public: void y() { T t; t.x(); } };" + "};" + "void f() {" + " C::B<A> b; b.y();" + "}", Class(HasName("C"), + HasDescendant(Call(Callee(Method(HasName("x")))))))); +} + +// For testing AST_MATCHER_P(). +AST_MATCHER_P(clang::Decl, Just, Matcher<clang::Decl>, AMatcher) { + // Make sure all special variables are used: node, match_finder, + // bound_nodes_builder, and the parameter named 'AMatcher'. + return AMatcher.Matches(Node, Finder, Builder); +} + +TEST(AstMatcherPMacro, Works) { + DeclarationMatcher HasClassB = Just(Has(Id("b", Class(HasName("B"))))); + + EXPECT_TRUE(MatchAndVerifyResultTrue("class A { class B {}; };", + HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b"))); + + EXPECT_TRUE(MatchAndVerifyResultFalse("class A { class B {}; };", + HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("a"))); + + EXPECT_TRUE(MatchAndVerifyResultFalse("class A { class C {}; };", + HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b"))); +} + +AST_POLYMORPHIC_MATCHER_P( + PolymorphicHas, Matcher<clang::Decl>, AMatcher) { + COMPILE_ASSERT((llvm::is_same<NodeType, clang::Decl>::value) || + (llvm::is_same<NodeType, clang::Stmt>::value), + assert_node_type_is_accessible); + TypedBaseMatcher<clang::Decl> ChildMatcher(AMatcher); + return Finder->MatchesChildOf( + Node, ChildMatcher, Builder, + ASTMatchFinder::kIgnoreImplicitCastsAndParentheses); +} + +TEST(AstPolymorphicMatcherPMacro, Works) { + DeclarationMatcher HasClassB = PolymorphicHas(Id("b", Class(HasName("B")))); + + EXPECT_TRUE(MatchAndVerifyResultTrue("class A { class B {}; };", + HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b"))); + + EXPECT_TRUE(MatchAndVerifyResultFalse("class A { class B {}; };", + HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("a"))); + + EXPECT_TRUE(MatchAndVerifyResultFalse("class A { class C {}; };", + HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b"))); + + StatementMatcher StatementHasClassB = + PolymorphicHas(Class(HasName("B"))); + + EXPECT_TRUE(Matches("void x() { class B {}; }", StatementHasClassB)); +} + +TEST(For, FindsForLoops) { + EXPECT_TRUE(Matches("void f() { for(;;); }", For())); + EXPECT_TRUE(Matches("void f() { if(true) for(;;); }", For())); +} + +TEST(For, ReportsNoFalsePositives) { + EXPECT_TRUE(NotMatches("void f() { ; }", For())); + EXPECT_TRUE(NotMatches("void f() { if(true); }", For())); +} + +TEST(CompoundStatement, HandlesSimpleCases) { + EXPECT_TRUE(NotMatches("void f();", CompoundStatement())); + EXPECT_TRUE(Matches("void f() {}", CompoundStatement())); + EXPECT_TRUE(Matches("void f() {{}}", CompoundStatement())); +} + +TEST(CompoundStatement, DoesNotMatchEmptyStruct) { + // It's not a compound statement just because there's "{}" in the source + // text. This is an AST search, not grep. + EXPECT_TRUE(NotMatches("namespace n { struct S {}; }", + CompoundStatement())); + EXPECT_TRUE(Matches("namespace n { struct S { void f() {{}} }; }", + CompoundStatement())); +} + +TEST(HasBody, FindsBodyOfForLoop) { + StatementMatcher HasCompoundStatementBody = + For(HasBody(CompoundStatement())); + EXPECT_TRUE(Matches("void f() { for(;;) {} }", + HasCompoundStatementBody)); + EXPECT_TRUE(NotMatches("void f() { for(;;); }", + HasCompoundStatementBody)); +} + +TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) { + // The simplest case: every compound statement is in a function + // definition, and the function body itself must be a compound + // statement. + EXPECT_TRUE(Matches("void f() { for (;;); }", + CompoundStatement(HasAnySubstatement(For())))); +} + +TEST(HasAnySubstatement, IsNotRecursive) { + // It's really "has any immediate substatement". + EXPECT_TRUE(NotMatches("void f() { if (true) for (;;); }", + CompoundStatement(HasAnySubstatement(For())))); +} + +TEST(HasAnySubstatement, MatchesInNestedCompoundStatements) { + EXPECT_TRUE(Matches("void f() { if (true) { for (;;); } }", + CompoundStatement(HasAnySubstatement(For())))); +} + +TEST(HasAnySubstatement, FindsSubstatementBetweenOthers) { + EXPECT_TRUE(Matches("void f() { 1; 2; 3; for (;;); 4; 5; 6; }", + CompoundStatement(HasAnySubstatement(For())))); +} + +TEST(StatementCountIs, FindsNoStatementsInAnEmptyCompoundStatement) { + EXPECT_TRUE(Matches("void f() { }", + CompoundStatement(StatementCountIs(0)))); + EXPECT_TRUE(NotMatches("void f() {}", + CompoundStatement(StatementCountIs(1)))); +} + +TEST(StatementCountIs, AppearsToMatchOnlyOneCount) { + EXPECT_TRUE(Matches("void f() { 1; }", + CompoundStatement(StatementCountIs(1)))); + EXPECT_TRUE(NotMatches("void f() { 1; }", + CompoundStatement(StatementCountIs(0)))); + EXPECT_TRUE(NotMatches("void f() { 1; }", + CompoundStatement(StatementCountIs(2)))); +} + +TEST(StatementCountIs, WorksWithMultipleStatements) { + EXPECT_TRUE(Matches("void f() { 1; 2; 3; }", + CompoundStatement(StatementCountIs(3)))); +} + +TEST(StatementCountIs, WorksWithNestedCompoundStatements) { + EXPECT_TRUE(Matches("void f() { { 1; } { 1; 2; 3; 4; } }", + CompoundStatement(StatementCountIs(1)))); + EXPECT_TRUE(Matches("void f() { { 1; } { 1; 2; 3; 4; } }", + CompoundStatement(StatementCountIs(2)))); + EXPECT_TRUE(NotMatches("void f() { { 1; } { 1; 2; 3; 4; } }", + CompoundStatement(StatementCountIs(3)))); + EXPECT_TRUE(Matches("void f() { { 1; } { 1; 2; 3; 4; } }", + CompoundStatement(StatementCountIs(4)))); +} + +} // end namespace tooling +} // end namespace clang |