Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -3052,7 +3052,8 @@ AST_POLYMORPHIC_MATCHER_P(hasBody, AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt, WhileStmt, - CXXForRangeStmt), + CXXForRangeStmt, + FunctionDecl), internal::Matcher, InnerMatcher) { const Stmt *const Statement = Node.getBody(); return (Statement != nullptr && Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -29,7 +29,16 @@ public DeclVisitor, public StmtVisitor { ASTImporter &Importer; - + + template + void ImportMultipleItems(IIter Ibegin, IIter Iend, OIter Obegin) { + ASTImporter &ImporterRef = Importer; + std::transform(Ibegin, Iend, Obegin, + [&ImporterRef](ItemT I) -> ItemT { + return ImporterRef.Import(I); + }); + } + public: explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) { } @@ -86,6 +95,10 @@ void ImportDeclarationNameLoc(const DeclarationNameInfo &From, DeclarationNameInfo& To); void ImportDeclContext(DeclContext *FromDC, bool ForceImport = false); + + typedef DesignatedInitExpr::Designator Designator; + Designator ImportDesignator(const Designator &D); + /// \brief What we should import from the definition. enum ImportDefinitionKind { @@ -174,6 +187,7 @@ DeclGroupRef ImportDeclGroup(DeclGroupRef DG); Stmt *VisitStmt(Stmt *S); + Stmt *VisitGCCAsmStmt(GCCAsmStmt *S); Stmt *VisitDeclStmt(DeclStmt *S); Stmt *VisitNullStmt(NullStmt *S); Stmt *VisitCompoundStmt(CompoundStmt *S); @@ -191,7 +205,6 @@ Stmt *VisitContinueStmt(ContinueStmt *S); Stmt *VisitBreakStmt(BreakStmt *S); Stmt *VisitReturnStmt(ReturnStmt *S); - // FIXME: GCCAsmStmt // FIXME: MSAsmStmt // FIXME: SEHExceptStmt // FIXME: SEHFinallyStmt @@ -212,13 +225,29 @@ // Importing expressions Expr *VisitExpr(Expr *E); + Expr *VisitVAArgExpr(VAArgExpr *E); + Expr *VisitGNUNullExpr(GNUNullExpr *E); + Expr *VisitPredefinedExpr(PredefinedExpr *E); Expr *VisitDeclRefExpr(DeclRefExpr *E); + Expr *VisitInitListExpr(InitListExpr *ILE); + Expr *VisitDesignatedInitExpr(DesignatedInitExpr *E); + Expr *VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); + Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); Expr *VisitIntegerLiteral(IntegerLiteral *E); + Expr *VisitFloatingLiteral(FloatingLiteral *E); Expr *VisitCharacterLiteral(CharacterLiteral *E); + Expr *VisitStringLiteral(StringLiteral *E); + Expr *VisitCompoundLiteralExpr(CompoundLiteralExpr *E); + Expr *VisitAtomicExpr(AtomicExpr *E); + Expr *VisitAddrLabelExpr(AddrLabelExpr *E); Expr *VisitParenExpr(ParenExpr *E); + Expr *VisitParenListExpr(ParenListExpr *E); + Expr *VisitStmtExpr(StmtExpr *E); Expr *VisitUnaryOperator(UnaryOperator *E); Expr *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); Expr *VisitBinaryOperator(BinaryOperator *E); + Expr *VisitConditionalOperator(ConditionalOperator *E); + Expr *VisitBinaryConditionalOperator(BinaryConditionalOperator *E); Expr *VisitCompoundAssignOperator(CompoundAssignOperator *E); Expr *VisitImplicitCastExpr(ImplicitCastExpr *E); Expr *VisitCStyleCastExpr(CStyleCastExpr *E); @@ -229,6 +258,28 @@ } using namespace clang; +//------------------------------------------------------------------------------ +// Utilities +//------------------------------------------------------------------------------ + +namespace { + +template +static bool containsNullPtr(IIter Ibegin, IIter Iend) { + return std::find(Ibegin, Iend, nullptr) == Iend; +} + +template +static bool checkPossibleNull(IIter Ibegin, IIter Iend, OIter Obegin) { + for (; Ibegin != Iend; Ibegin++, Obegin++) + if (*Obegin == nullptr && Ibegin != nullptr) + return false; + return true; +} + +} // end anonymous namespace + + //---------------------------------------------------------------------------- // Structural Equivalence //---------------------------------------------------------------------------- @@ -4591,7 +4642,84 @@ << S->getStmtClassName(); return nullptr; } - + + +Stmt *ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) { + SmallVector Names; + for (unsigned i = 0, e = S->getNumOutputs(); i != e; i++) { + IdentifierInfo *ToII = Importer.Import(S->getOutputIdentifier(i)); + if (!ToII) + return nullptr; + Names.push_back(ToII); + } + for (unsigned i = 0, e = S->getNumInputs(); i != e; i++) { + IdentifierInfo *ToII = Importer.Import(S->getInputIdentifier(i)); + if (!ToII) + return nullptr; + Names.push_back(ToII); + } + + SmallVector Clobbers; + for (unsigned i = 0, e = S->getNumClobbers(); i != e; i++) { + StringLiteral *Clobber = cast_or_null( + Importer.Import(S->getClobberStringLiteral(i))); + if (!Clobber) + return nullptr; + Clobbers.push_back(Clobber); + } + + SmallVector Constraints; + for (unsigned i = 0, e = S->getNumOutputs(); i != e; i++) { + StringLiteral *Output = cast_or_null( + Importer.Import(S->getOutputConstraintLiteral(i))); + if (!Output) + return nullptr; + Constraints.push_back(Output); + } + + for (unsigned i = 0, e = S->getNumInputs(); i != e; i++) { + StringLiteral *Input = cast_or_null( + Importer.Import(S->getInputConstraintLiteral(i))); + if (!Input) + return nullptr; + Constraints.push_back(Input); + } + + SmallVector Exprs; + for (int i = 0, e = S->getNumOutputs(); i != e; i++) { + if (Expr *Out = Importer.Import(S->getOutputExpr(i))) + Exprs.push_back(Out); + else + return nullptr; + } + for (int i = 0, e = S->getNumInputs(); i != e; i++) { + if (Expr *Input = Importer.Import(S->getInputExpr(i))) + Exprs.push_back(Input); + else + return nullptr; + } + + StringLiteral *AsmStr = cast_or_null( + Importer.Import(S->getAsmString())); + if (!AsmStr) + return nullptr; + + return new (Importer.getToContext()) GCCAsmStmt( + Importer.getToContext(), + Importer.Import(S->getAsmLoc()), + S->isSimple(), + S->isVolatile(), + S->getNumOutputs(), + S->getNumInputs(), + Names.data(), + Constraints.data(), + Exprs.data(), + AsmStr, + S->getNumClobbers(), + Clobbers.data(), + Importer.Import(S->getRParenLoc())); +} + Stmt *ASTNodeImporter::VisitDeclStmt(DeclStmt *S) { DeclGroupRef ToDG = ImportDeclGroup(S->getDeclGroup()); for (Decl *ToD : ToDG) { @@ -5034,6 +5162,48 @@ return nullptr; } +Expr *ASTNodeImporter::VisitVAArgExpr(VAArgExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + Expr *SubExpr = Importer.Import(E->getSubExpr()); + if (!SubExpr && E->getSubExpr()) + return nullptr; + + TypeSourceInfo *TInfo = Importer.Import(E->getWrittenTypeInfo()); + if (!TInfo) + return nullptr; + + return new (Importer.getToContext()) VAArgExpr( + Importer.Import(E->getBuiltinLoc()), SubExpr, TInfo, + Importer.Import(E->getRParenLoc()), T, E->isMicrosoftABI()); +} + + +Expr *ASTNodeImporter::VisitGNUNullExpr(GNUNullExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + return new (Importer.getToContext()) GNUNullExpr( + T, Importer.Import(E->getExprLoc())); +} + +Expr *ASTNodeImporter::VisitPredefinedExpr(PredefinedExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + StringLiteral *SL = cast_or_null( + Importer.Import(E->getFunctionName())); + if (!SL && E->getFunctionName()) + return nullptr; + + return new (Importer.getToContext()) PredefinedExpr( + Importer.Import(E->getExprLoc()), T, E->getIdentType(), SL); +} + Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { ValueDecl *ToD = cast_or_null(Importer.Import(E->getDecl())); if (!ToD) @@ -5064,6 +5234,118 @@ return DRE; } + +Expr *ASTNodeImporter::VisitInitListExpr(InitListExpr *ILE) { + QualType T = Importer.Import(ILE->getType()); + if (T.isNull()) + return nullptr; + + llvm::SmallVector Exprs(ILE->getNumInits()); + ImportMultipleItems( + ILE->getInits(), ILE->getInits() + ILE->getNumInits(), Exprs.begin()); + if (!checkPossibleNull(ILE->begin(), ILE->end(), Exprs.begin())) + return nullptr; + + ASTContext &ToCtx = Importer.getToContext(); + InitListExpr *To = new (ToCtx) InitListExpr( + ToCtx, Importer.Import(ILE->getLBraceLoc()), + Exprs, Importer.Import(ILE->getLBraceLoc())); + To->setType(T); + + if (ILE->hasArrayFiller()) { + Expr *Filter = Importer.Import(ILE->getArrayFiller()); + if (!Filter) + return nullptr; + To->setArrayFiller(Filter); + } + + if (FieldDecl *FromFD = ILE->getInitializedFieldInUnion()) { + FieldDecl *ToFD = cast_or_null(Importer.Import(FromFD)); + if (!ToFD) + return nullptr; + To->setInitializedFieldInUnion(ToFD); + } + + if (InitListExpr *SyntForm = ILE->getSyntacticForm()) { + InitListExpr *ToSyntForm = cast_or_null( + Importer.Import(SyntForm)); + if (!ToSyntForm) + return nullptr; + To->setSyntacticForm(ToSyntForm); + } + + To->sawArrayRangeDesignator(ILE->hadArrayRangeDesignator()); + To->setValueDependent(ILE->isValueDependent()); + To->setInstantiationDependent(ILE->isInstantiationDependent()); + + return To; +} + +ASTNodeImporter::Designator +ASTNodeImporter::ImportDesignator(const Designator &D) { + if (D.isFieldDesignator()) { + IdentifierInfo *ToFieldName = Importer.Import(D.getFieldName()); + // Caller checks for import error + return Designator(ToFieldName, Importer.Import(D.getDotLoc()), + Importer.Import(D.getFieldLoc())); + } + if (D.isArrayDesignator()) + return Designator(D.getFirstExprIndex(), + Importer.Import(D.getLBracketLoc()), + Importer.Import(D.getRBracketLoc())); + + assert(D.isArrayRangeDesignator()); + return Designator(D.getFirstExprIndex(), + Importer.Import(D.getLBracketLoc()), + Importer.Import(D.getEllipsisLoc()), + Importer.Import(D.getRBracketLoc())); +} + + +Expr *ASTNodeImporter::VisitDesignatedInitExpr(DesignatedInitExpr *DIE) { + Expr *Init = cast_or_null(Importer.Import(DIE->getInit())); + if (!Init) + return nullptr; + + SmallVector IndexExprs(DIE->getNumSubExprs() - 1); + // List elements from the second, the first is Init itself + for (unsigned I = 1, E = DIE->getNumSubExprs(); I < E; I++) { + if (Expr *Arg = cast_or_null(Importer.Import(DIE->getSubExpr(I)))) + IndexExprs.push_back(Arg); + else + return nullptr; + } + + SmallVector Designators(DIE->size()); + std::transform(DIE->designators_begin(), DIE->designators_end(), + Designators.begin(), + [this](const Designator &D) -> Designator { + return ImportDesignator(D); + }); + + for (auto I = DIE->designators_begin(), E = DIE->designators_end(); I != E; + ++I) + if (I->isFieldDesignator() && !I->getFieldName()) + return nullptr; + + return DesignatedInitExpr::Create( + Importer.getToContext(), Designators.data(), Designators.size(), + IndexExprs, Importer.Import(DIE->getEqualOrColonLoc()), + DIE->usesGNUSyntax(), Init); +} + +Expr *ASTNodeImporter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { + ASTContext &ToCtx = Importer.getToContext(); + return new(ToCtx) CXXNullPtrLiteralExpr(ToCtx.NullPtrTy, + Importer.Import(E->getLocation())); +} + +Expr *ASTNodeImporter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { + ASTContext &ToCtx = Importer.getToContext(); + return new (ToCtx) CXXBoolLiteralExpr(E->getValue(), ToCtx.BoolTy, + Importer.Import(E->getLocation())); +} + Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) { QualType T = Importer.Import(E->getType()); if (T.isNull()) @@ -5074,6 +5356,16 @@ Importer.Import(E->getLocation())); } +Expr *ASTNodeImporter::VisitFloatingLiteral(FloatingLiteral *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + return FloatingLiteral::Create(Importer.getToContext(), + E->getValue(), E->isExact(), T, + Importer.Import(E->getLocation())); +} + Expr *ASTNodeImporter::VisitCharacterLiteral(CharacterLiteral *E) { QualType T = Importer.Import(E->getType()); if (T.isNull()) @@ -5084,6 +5376,69 @@ Importer.Import(E->getLocation())); } +Expr *ASTNodeImporter::VisitStringLiteral(StringLiteral *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + SmallVector Locations(E->getNumConcatenated()); + ImportMultipleItems(E->tokloc_begin(), E->tokloc_end(), + Locations.begin()); + + return StringLiteral::Create(Importer.getToContext(), E->getBytes(), + E->getKind(), E->isPascal(), T, + Locations.data(), Locations.size()); +} + +Expr *ASTNodeImporter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + TypeSourceInfo *TInfo = Importer.Import(E->getTypeSourceInfo()); + if (!TInfo) + return nullptr; + + Expr *Init = Importer.Import(E->getInitializer()); + if (!Init) + return nullptr; + + return new (Importer.getToContext()) CompoundLiteralExpr( + Importer.Import(E->getLParenLoc()), TInfo, T, E->getValueKind(), + Init, E->isFileScope()); +} + +Expr *ASTNodeImporter::VisitAtomicExpr(AtomicExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + SmallVector Exprs(E->getNumSubExprs()); + ImportMultipleItems( + E->getSubExprs(), E->getSubExprs() + E->getNumSubExprs(), + Exprs.begin()); + if (!containsNullPtr(Exprs.begin(), Exprs.end())) + return nullptr; + + return new (Importer.getToContext()) AtomicExpr( + Importer.Import(E->getBuiltinLoc()), Exprs, T, E->getOp(), + Importer.Import(E->getRParenLoc())); +} + +Expr *ASTNodeImporter::VisitAddrLabelExpr(AddrLabelExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + LabelDecl *ToLabel = cast_or_null(Importer.Import(E->getLabel())); + if (!ToLabel) + return nullptr; + + return new (Importer.getToContext()) AddrLabelExpr( + Importer.Import(E->getAmpAmpLoc()), Importer.Import(E->getLabelLoc()), + ToLabel, T); +} + Expr *ASTNodeImporter::VisitParenExpr(ParenExpr *E) { Expr *SubExpr = Importer.Import(E->getSubExpr()); if (!SubExpr) @@ -5095,6 +5450,32 @@ SubExpr); } +Expr *ASTNodeImporter::VisitParenListExpr(ParenListExpr *E) { + SmallVector Exprs(E->getNumExprs()); + ImportMultipleItems(E->getExprs(), E->getExprs() + E->getNumExprs(), + Exprs.begin()); + if (!containsNullPtr(Exprs.begin(), Exprs.end())) + return nullptr; + + return new (Importer.getToContext()) ParenListExpr( + Importer.getToContext(), Importer.Import(E->getLParenLoc()), + Exprs, Importer.Import(E->getLParenLoc())); +} + +Expr *ASTNodeImporter::VisitStmtExpr(StmtExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + CompoundStmt *ToSubStmt = cast_or_null( + Importer.Import(E->getSubStmt())); + if (!ToSubStmt && E->getSubStmt()) + return nullptr; + + return new (Importer.getToContext()) StmtExpr(ToSubStmt, T, + Importer.Import(E->getLParenLoc()), Importer.Import(E->getRParenLoc())); +} + Expr *ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) { QualType T = Importer.Import(E->getType()); if (T.isNull()) @@ -5155,6 +5536,62 @@ E->isFPContractable()); } +Expr *ASTNodeImporter::VisitConditionalOperator(ConditionalOperator *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + Expr *ToLHS = Importer.Import(E->getLHS()); + if (!ToLHS) + return nullptr; + + Expr *ToRHS = Importer.Import(E->getRHS()); + if (!ToRHS) + return nullptr; + + Expr *ToCond = Importer.Import(E->getCond()); + if (!ToCond) + return nullptr; + + return new (Importer.getToContext()) ConditionalOperator( + ToCond, Importer.Import(E->getQuestionLoc()), + ToLHS, Importer.Import(E->getColonLoc()), + ToRHS, T, E->getValueKind(), E->getObjectKind()); +} + +Expr *ASTNodeImporter::VisitBinaryConditionalOperator( + BinaryConditionalOperator *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + Expr *Common = Importer.Import(E->getCommon()); + if (!Common) + return nullptr; + + Expr *Cond = Importer.Import(E->getCond()); + if (!Cond) + return nullptr; + + OpaqueValueExpr *OpaqueValue = cast_or_null( + Importer.Import(E->getOpaqueValue())); + if (!OpaqueValue) + return nullptr; + + Expr *TrueExpr = Importer.Import(E->getTrueExpr()); + if (!TrueExpr) + return nullptr; + + Expr *FalseExpr = Importer.Import(E->getFalseExpr()); + if (!FalseExpr) + return nullptr; + + return new (Importer.getToContext()) BinaryConditionalOperator( + Common, OpaqueValue, Cond, TrueExpr, FalseExpr, + Importer.Import(E->getQuestionLoc()), Importer.Import(E->getColonLoc()), + T, E->getValueKind(), E->getObjectKind()); +} + Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) { QualType T = Importer.Import(E->getType()); if (T.isNull()) Index: unittests/AST/ASTImporterTest.cpp =================================================================== --- /dev/null +++ unittests/AST/ASTImporterTest.cpp @@ -0,0 +1,106 @@ +//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Tests for the correct import of AST nodes from one AST context to another. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTImporter.h" +#include "MatchVerifier.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" + +namespace clang { +namespace ast_matchers { + +using clang::tooling::newFrontendActionFactory; +using clang::tooling::runToolOnCodeWithArgs; +using clang::tooling::FrontendActionFactory; + +typedef std::vector StringVector; + +void getLangArgs(Language Lang, StringVector &Args) { + switch (Lang) { + case Lang_C: + Args.push_back("-std=c99"); + break; + case Lang_C89: + Args.push_back("-std=c89"); + break; + case Lang_CXX: + Args.push_back("-std=c++98"); + break; + case Lang_CXX11: + Args.push_back("-std=c++11"); + break; + case Lang_OpenCL: + case Lang_OBJCXX: + break; + } +} + +template +testing::AssertionResult +testImport(const std::string &FromCode, Language FromLang, + const std::string &ToCode, Language ToLang, + MatchVerifier &Verifier, + const MatcherType &AMatcher) { + StringVector FromArgs, ToArgs; + getLangArgs(FromLang, FromArgs); + getLangArgs(ToLang, ToArgs); + + std::unique_ptr + FromAST = tooling::buildASTFromCodeWithArgs(FromCode, FromArgs), + ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs); + + ASTContext &FromCtx = FromAST->getASTContext(), + &ToCtx = ToAST->getASTContext(); + + ASTImporter Importer(FromCtx, FromAST->getFileManager(), + ToCtx, ToAST->getFileManager(), false); + + IdentifierInfo *ImportedII = &FromCtx.Idents.get("declToImport"); + assert(ImportedII && "Declaration with 'declToImport' name" + "should be specified in test!"); + DeclarationName ImportDeclName(ImportedII); + SmallVector FoundDecls; + FromCtx.getTranslationUnitDecl()->localUncachedLookup( + ImportDeclName, FoundDecls); + + assert(FoundDecls.size() == 1 && + "Tests for multiple declarations are not supported yet!"); + + auto Imported = Importer.Import(*FoundDecls.begin()); + + // This should dump source locations and assert if some source locations + // were not imported + llvm::raw_null_ostream ToNothing; + ToCtx.getTranslationUnitDecl()->print(ToNothing); + + return Verifier.match(Imported, AMatcher); +} + +TEST(ImportExpr, ImportStringLiteral) { + MatchVerifier Verifier; + EXPECT_TRUE(testImport("void declToImport() { \"foo\"; }", + Lang_CXX, "", Lang_CXX, Verifier, + functionDecl( + hasBody( + compoundStmt( + has( + stringLiteral( + hasType( + asString("const char [4]"))))))))); +} + +} // end namespace ast_matchers +} // end namespace clang Index: unittests/AST/CMakeLists.txt =================================================================== --- unittests/AST/CMakeLists.txt +++ unittests/AST/CMakeLists.txt @@ -4,6 +4,7 @@ add_clang_unittest(ASTTests ASTContextParentMapTest.cpp + ASTImporterTest.cpp ASTTypeTraitsTest.cpp ASTVectorTest.cpp CommentLexer.cpp Index: unittests/AST/MatchVerifier.h =================================================================== --- unittests/AST/MatchVerifier.h +++ unittests/AST/MatchVerifier.h @@ -62,6 +62,9 @@ std::vector& Args, Language L); + template + testing::AssertionResult match(const Decl *D, const MatcherType &AMatcher); + protected: void run(const MatchFinder::MatchResult &Result) override; virtual void verify(const MatchFinder::MatchResult &Result, @@ -127,6 +130,22 @@ return testing::AssertionSuccess(); } +/// \brief Runs a matcher over some AST, and returns the result of the +/// verifier for the matched node. +template template +testing::AssertionResult MatchVerifier::match( + const Decl *D, const MatcherType &AMatcher) { + MatchFinder Finder; + Finder.addMatcher(AMatcher.bind(""), this); + + setFailure("Could not find match"); + Finder.match(*D, D->getASTContext()); + + if (!Verified) + return testing::AssertionFailure() << VerifyResult; + return testing::AssertionSuccess(); +} + template void MatchVerifier::run(const MatchFinder::MatchResult &Result) { const NodeType *Node = Result.Nodes.getNodeAs("");