namespace clang {
-using PolicyAdjusterType =
- Optional<llvm::function_ref<void(PrintingPolicy &Policy)>>;
-
-static void PrintStmt(raw_ostream &Out, const ASTContext *Context,
- const Stmt *S, PolicyAdjusterType PolicyAdjuster) {
- assert(S != nullptr && "Expected non-null Stmt");
- PrintingPolicy Policy = Context->getPrintingPolicy();
- if (PolicyAdjuster)
- (*PolicyAdjuster)(Policy);
- S->printPretty(Out, /*Helper*/ nullptr, Policy);
-}
+using PrintingPolicyAdjuster = llvm::function_ref<void(PrintingPolicy &Policy)>;
+
+template <typename NodeType>
+using NodePrinter =
+ std::function<void(llvm::raw_ostream &Out, const ASTContext *Context,
+ const NodeType *Node,
+ PrintingPolicyAdjuster PolicyAdjuster)>;
+template <typename NodeType>
+using NodeFilter = std::function<bool(const NodeType *Node)>;
+
+template <typename NodeType>
class PrintMatch : public ast_matchers::MatchFinder::MatchCallback {
+ using PrinterT = NodePrinter<NodeType>;
+ using FilterT = NodeFilter<NodeType>;
+
SmallString<1024> Printed;
- unsigned NumFoundStmts;
- PolicyAdjusterType PolicyAdjuster;
+ unsigned NumFoundNodes;
+ PrinterT Printer;
+ FilterT Filter;
+ PrintingPolicyAdjuster PolicyAdjuster;
public:
- PrintMatch(PolicyAdjusterType PolicyAdjuster)
- : NumFoundStmts(0), PolicyAdjuster(PolicyAdjuster) {}
+ PrintMatch(PrinterT Printer, PrintingPolicyAdjuster PolicyAdjuster,
+ FilterT Filter)
+ : NumFoundNodes(0), Printer(std::move(Printer)),
+ Filter(std::move(Filter)), PolicyAdjuster(PolicyAdjuster) {}
void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
- const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
- if (!S)
+ const NodeType *N = Result.Nodes.getNodeAs<NodeType>("id");
+ if (!N || !Filter(N))
return;
- NumFoundStmts++;
- if (NumFoundStmts > 1)
+ NumFoundNodes++;
+ if (NumFoundNodes > 1)
return;
llvm::raw_svector_ostream Out(Printed);
- PrintStmt(Out, Result.Context, S, PolicyAdjuster);
+ Printer(Out, Result.Context, N, PolicyAdjuster);
}
StringRef getPrinted() const { return Printed; }
- unsigned getNumFoundStmts() const { return NumFoundStmts; }
+ unsigned getNumFoundNodes() const { return NumFoundNodes; }
};
-template <typename T>
-::testing::AssertionResult
-PrintedStmtMatches(StringRef Code, const std::vector<std::string> &Args,
- const T &NodeMatch, StringRef ExpectedPrinted,
- PolicyAdjusterType PolicyAdjuster = None) {
+template <typename NodeType> bool NoNodeFilter(const NodeType *) {
+ return true;
+}
- PrintMatch Printer(PolicyAdjuster);
+template <typename NodeType, typename Matcher>
+::testing::AssertionResult
+PrintedNodeMatches(StringRef Code, const std::vector<std::string> &Args,
+ const Matcher &NodeMatch, StringRef ExpectedPrinted,
+ StringRef FileName, NodePrinter<NodeType> Printer,
+ PrintingPolicyAdjuster PolicyAdjuster = nullptr,
+ bool AllowError = false,
+ // Would like to use a lambda for the default value, but that
+ // trips gcc 7 up.
+ NodeFilter<NodeType> Filter = &NoNodeFilter<NodeType>) {
+
+ PrintMatch<NodeType> Callback(Printer, PolicyAdjuster, Filter);
ast_matchers::MatchFinder Finder;
- Finder.addMatcher(NodeMatch, &Printer);
+ Finder.addMatcher(NodeMatch, &Callback);
std::unique_ptr<tooling::FrontendActionFactory> Factory(
tooling::newFrontendActionFactory(&Finder));
- if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args))
+ bool ToolResult;
+ if (FileName.empty()) {
+ ToolResult = tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args);
+ } else {
+ ToolResult =
+ tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName);
+ }
+ if (!ToolResult && !AllowError)
return testing::AssertionFailure()
<< "Parsing error in \"" << Code.str() << "\"";
- if (Printer.getNumFoundStmts() == 0)
- return testing::AssertionFailure() << "Matcher didn't find any statements";
+ if (Callback.getNumFoundNodes() == 0)
+ return testing::AssertionFailure() << "Matcher didn't find any nodes";
- if (Printer.getNumFoundStmts() > 1)
+ if (Callback.getNumFoundNodes() > 1)
return testing::AssertionFailure()
- << "Matcher should match only one statement (found "
- << Printer.getNumFoundStmts() << ")";
+ << "Matcher should match only one node (found "
+ << Callback.getNumFoundNodes() << ")";
- if (Printer.getPrinted() != ExpectedPrinted)
+ if (Callback.getPrinted() != ExpectedPrinted)
return ::testing::AssertionFailure()
<< "Expected \"" << ExpectedPrinted.str() << "\", got \""
- << Printer.getPrinted().str() << "\"";
+ << Callback.getPrinted().str() << "\"";
return ::testing::AssertionSuccess();
}
//
//===----------------------------------------------------------------------===//
+#include "ASTPrint.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
namespace {
-using PrintingPolicyModifier = void (*)(PrintingPolicy &policy);
-
void PrintDecl(raw_ostream &Out, const ASTContext *Context, const Decl *D,
- PrintingPolicyModifier PolicyModifier) {
+ PrintingPolicyAdjuster PolicyModifier) {
PrintingPolicy Policy = Context->getPrintingPolicy();
Policy.TerseOutput = true;
Policy.Indentation = 0;
D->print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ false);
}
-class PrintMatch : public MatchFinder::MatchCallback {
- SmallString<1024> Printed;
- unsigned NumFoundDecls;
- PrintingPolicyModifier PolicyModifier;
-
-public:
- PrintMatch(PrintingPolicyModifier PolicyModifier)
- : NumFoundDecls(0), PolicyModifier(PolicyModifier) {}
-
- void run(const MatchFinder::MatchResult &Result) override {
- const Decl *D = Result.Nodes.getNodeAs<Decl>("id");
- if (!D || D->isImplicit())
- return;
- NumFoundDecls++;
- if (NumFoundDecls > 1)
- return;
-
- llvm::raw_svector_ostream Out(Printed);
- PrintDecl(Out, Result.Context, D, PolicyModifier);
- }
-
- StringRef getPrinted() const {
- return Printed;
- }
-
- unsigned getNumFoundDecls() const {
- return NumFoundDecls;
- }
-};
-
::testing::AssertionResult
PrintedDeclMatches(StringRef Code, const std::vector<std::string> &Args,
const DeclarationMatcher &NodeMatch,
StringRef ExpectedPrinted, StringRef FileName,
- PrintingPolicyModifier PolicyModifier = nullptr,
+ PrintingPolicyAdjuster PolicyModifier = nullptr,
bool AllowError = false) {
- PrintMatch Printer(PolicyModifier);
- MatchFinder Finder;
- Finder.addMatcher(NodeMatch, &Printer);
- std::unique_ptr<FrontendActionFactory> Factory(
- newFrontendActionFactory(&Finder));
-
- if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName) &&
- !AllowError)
- return testing::AssertionFailure()
- << "Parsing error in \"" << Code.str() << "\"";
-
- if (Printer.getNumFoundDecls() == 0)
- return testing::AssertionFailure()
- << "Matcher didn't find any declarations";
-
- if (Printer.getNumFoundDecls() > 1)
- return testing::AssertionFailure()
- << "Matcher should match only one declaration "
- "(found " << Printer.getNumFoundDecls() << ")";
-
- if (Printer.getPrinted() != ExpectedPrinted)
- return ::testing::AssertionFailure()
- << "Expected \"" << ExpectedPrinted.str() << "\", "
- "got \"" << Printer.getPrinted().str() << "\"";
-
- return ::testing::AssertionSuccess();
+ return PrintedNodeMatches<Decl>(
+ Code, Args, NodeMatch, ExpectedPrinted, FileName, PrintDecl,
+ PolicyModifier, AllowError,
+ // Filter out implicit decls
+ [](const Decl *D) { return !D->isImplicit(); });
}
::testing::AssertionResult
PrintedDeclCXX98Matches(StringRef Code, StringRef DeclName,
StringRef ExpectedPrinted,
- PrintingPolicyModifier PolicyModifier = nullptr) {
+ PrintingPolicyAdjuster PolicyModifier = nullptr) {
std::vector<std::string> Args(1, "-std=c++98");
return PrintedDeclMatches(Code, Args, namedDecl(hasName(DeclName)).bind("id"),
ExpectedPrinted, "input.cc", PolicyModifier);
::testing::AssertionResult
PrintedDeclCXX98Matches(StringRef Code, const DeclarationMatcher &NodeMatch,
StringRef ExpectedPrinted,
- PrintingPolicyModifier PolicyModifier = nullptr) {
+ PrintingPolicyAdjuster PolicyModifier = nullptr) {
std::vector<std::string> Args(1, "-std=c++98");
return PrintedDeclMatches(Code,
Args,
::testing::AssertionResult
PrintedDeclCXX17Matches(StringRef Code, const DeclarationMatcher &NodeMatch,
StringRef ExpectedPrinted,
- PrintingPolicyModifier PolicyModifier = nullptr) {
+ PrintingPolicyAdjuster PolicyModifier = nullptr) {
std::vector<std::string> Args{"-std=c++17", "-fno-delayed-template-parsing"};
return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, "input.cc",
PolicyModifier);
::testing::AssertionResult
PrintedDeclC11Matches(StringRef Code, const DeclarationMatcher &NodeMatch,
StringRef ExpectedPrinted,
- PrintingPolicyModifier PolicyModifier = nullptr) {
+ PrintingPolicyAdjuster PolicyModifier = nullptr) {
std::vector<std::string> Args(1, "-std=c11");
return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, "input.c",
PolicyModifier);
//
//===----------------------------------------------------------------------===//
+#include "ASTPrint.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/PrettyPrinter.h"
const DeclarationMatcher &NodeMatch, StringRef ExpectedPrinted,
StringRef FileName,
std::function<void(llvm::raw_ostream &, const NamedDecl *)> Print) {
- PrintMatch Printer(std::move(Print));
- MatchFinder Finder;
- Finder.addMatcher(NodeMatch, &Printer);
- std::unique_ptr<FrontendActionFactory> Factory =
- newFrontendActionFactory(&Finder);
-
- if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
- return testing::AssertionFailure()
- << "Parsing error in \"" << Code.str() << "\"";
-
- if (Printer.getNumFoundDecls() == 0)
- return testing::AssertionFailure()
- << "Matcher didn't find any named declarations";
-
- if (Printer.getNumFoundDecls() > 1)
- return testing::AssertionFailure()
- << "Matcher should match only one named declaration "
- "(found " << Printer.getNumFoundDecls() << ")";
-
- if (Printer.getPrinted() != ExpectedPrinted)
- return ::testing::AssertionFailure()
- << "Expected \"" << ExpectedPrinted.str() << "\", "
- "got \"" << Printer.getPrinted().str() << "\"";
-
- return ::testing::AssertionSuccess();
+ return PrintedNodeMatches<NamedDecl>(
+ Code, Args, NodeMatch, ExpectedPrinted, FileName,
+ [Print](llvm::raw_ostream &Out, const ASTContext *Context,
+ const NamedDecl *ND,
+ PrintingPolicyAdjuster PolicyAdjuster) { Print(Out, ND); });
}
::testing::AssertionResult
has(compoundStmt(has(stmt().bind("id")))));
}
+static void PrintStmt(raw_ostream &Out, const ASTContext *Context,
+ const Stmt *S, PrintingPolicyAdjuster PolicyAdjuster) {
+ assert(S != nullptr && "Expected non-null Stmt");
+ PrintingPolicy Policy = Context->getPrintingPolicy();
+ if (PolicyAdjuster)
+ PolicyAdjuster(Policy);
+ S->printPretty(Out, /*Helper*/ nullptr, Policy);
+}
+
+template <typename Matcher>
+::testing::AssertionResult
+PrintedStmtMatches(StringRef Code, const std::vector<std::string> &Args,
+ const Matcher &NodeMatch, StringRef ExpectedPrinted,
+ PrintingPolicyAdjuster PolicyAdjuster = nullptr) {
+ return PrintedNodeMatches<Stmt>(Code, Args, NodeMatch, ExpectedPrinted, "",
+ PrintStmt, PolicyAdjuster);
+}
+
template <typename T>
::testing::AssertionResult
PrintedStmtCXXMatches(StdVer Standard, StringRef Code, const T &NodeMatch,
StringRef ExpectedPrinted,
- PolicyAdjusterType PolicyAdjuster = None) {
+ PrintingPolicyAdjuster PolicyAdjuster = nullptr) {
const char *StdOpt;
switch (Standard) {
case StdVer::CXX98: StdOpt = "-std=c++98"; break;
::testing::AssertionResult
PrintedStmtMSMatches(StringRef Code, const T &NodeMatch,
StringRef ExpectedPrinted,
- PolicyAdjusterType PolicyAdjuster = None) {
+ PrintingPolicyAdjuster PolicyAdjuster = nullptr) {
std::vector<std::string> Args = {
"-std=c++98",
"-target", "i686-pc-win32",
::testing::AssertionResult
PrintedStmtObjCMatches(StringRef Code, const T &NodeMatch,
StringRef ExpectedPrinted,
- PolicyAdjusterType PolicyAdjuster = None) {
+ PrintingPolicyAdjuster PolicyAdjuster = nullptr) {
std::vector<std::string> Args = {
"-ObjC",
"-fobjc-runtime=macosx-10.12.0",
};
)";
// No implicit 'this'.
- ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
- CPPSource, memberExpr(anything()).bind("id"), "field",
- PolicyAdjusterType(
- [](PrintingPolicy &PP) { PP.SuppressImplicitBase = true; })));
+ ASSERT_TRUE(PrintedStmtCXXMatches(
+ StdVer::CXX11, CPPSource, memberExpr(anything()).bind("id"), "field",
+
+ [](PrintingPolicy &PP) { PP.SuppressImplicitBase = true; }));
// Print implicit 'this'.
ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
CPPSource, memberExpr(anything()).bind("id"), "this->field"));
@end
)";
// No implicit 'self'.
- ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"),
- "return ivar;\n",
- PolicyAdjusterType([](PrintingPolicy &PP) {
- PP.SuppressImplicitBase = true;
- })));
+ ASSERT_TRUE(PrintedStmtObjCMatches(
+ ObjCSource, returnStmt().bind("id"), "return ivar;\n",
+
+ [](PrintingPolicy &PP) { PP.SuppressImplicitBase = true; }));
// Print implicit 'self'.
ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"),
"return self->ivar;\n"));
// body not printed when TerseOutput is on.
ASSERT_TRUE(PrintedStmtCXXMatches(
StdVer::CXX11, CPPSource, lambdaExpr(anything()).bind("id"), "[] {}",
- PolicyAdjusterType([](PrintingPolicy &PP) { PP.TerseOutput = true; })));
+
+ [](PrintingPolicy &PP) { PP.TerseOutput = true; }));
}