void AvoidGotoCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; // TODO: This check does not recognize `IndirectGotoStmt` which is a // GNU extension. These must be matched separately and an AST matcher // is currently missing for them. // Check if the 'goto' is used for control flow other than jumping // out of a nested loop. auto Loop = stmt(anyOf(forStmt(), cxxForRangeStmt(), whileStmt(), doStmt())); auto NestedLoop = stmt(anyOf(forStmt(hasAncestor(Loop)), cxxForRangeStmt(hasAncestor(Loop)), whileStmt(hasAncestor(Loop)), doStmt(hasAncestor(Loop)))); Finder->addMatcher(gotoStmt(anyOf(unless(hasAncestor(NestedLoop)), unless(isForwardJumping()))) .bind("goto"), this); }
#include "ASTUtility.h" //match do statement StatementMatcher gotoStmtMatcher = gotoStmt().bind("gotoStmt"); class GotoStmtPrinter : public MatchFinder::MatchCallback { public: virtual void run(const MatchFinder::MatchResult &Result) { //get the node clang::ASTContext *Context = Result.Context; const clang::GotoStmt *gtStmt = Result.Nodes.getNodeAs<clang::GotoStmt>("gotoStmt"); if(!gtStmt || ASTUtility::IsStmtInSTDFile(gtStmt, Context)) return; ASTUtility::Print(gtStmt, Context, "Rule028"); } }; //"My tool options" is the name. static llvm::cl::OptionCategory MyToolCategory("My tool options"); int main(int argc, const char **argv) { //CommonOptionsParser constructor will parse arguments and create a //CompilationDatabase. In case of error it will terminate the program. CommonOptionsParser OptionsParser(argc, argv, MyToolCategory); //once we have a CompilationDatabase, we can create a ClangTool and run our //FrontendAction over some code. ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList());