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