1 //===--- AvoidGotoCheck.cpp - clang-tidy-----------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "AvoidGotoCheck.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 14 using namespace clang::ast_matchers; 15 16 namespace clang { 17 namespace tidy { 18 namespace cppcoreguidelines { 19 20 namespace { 21 AST_MATCHER(GotoStmt, isForwardJumping) { 22 return Node.getLocStart() < Node.getLabel()->getLocStart(); 23 } 24 } // namespace 25 26 void AvoidGotoCheck::registerMatchers(MatchFinder *Finder) { 27 if (!getLangOpts().CPlusPlus) 28 return; 29 30 // TODO: This check does not recognize `IndirectGotoStmt` which is a 31 // GNU extension. These must be matched separately and an AST matcher 32 // is currently missing for them. 33 34 // Check if the 'goto' is used for control flow other than jumping 35 // out of a nested loop. 36 auto Loop = stmt(anyOf(forStmt(), cxxForRangeStmt(), whileStmt(), doStmt())); 37 auto NestedLoop = 38 stmt(anyOf(forStmt(hasAncestor(Loop)), cxxForRangeStmt(hasAncestor(Loop)), 39 whileStmt(hasAncestor(Loop)), doStmt(hasAncestor(Loop)))); 40 41 Finder->addMatcher(gotoStmt(anyOf(unless(hasAncestor(NestedLoop)), 42 unless(isForwardJumping()))) 43 .bind("goto"), 44 this); 45 } 46 47 void AvoidGotoCheck::check(const MatchFinder::MatchResult &Result) { 48 const auto *Goto = Result.Nodes.getNodeAs<GotoStmt>("goto"); 49 50 diag(Goto->getGotoLoc(), "avoid using 'goto' for flow control") 51 << Goto->getSourceRange(); 52 diag(Goto->getLabel()->getLocStart(), "label defined here", 53 DiagnosticIDs::Note); 54 } 55 } // namespace cppcoreguidelines 56 } // namespace tidy 57 } // namespace clang 58