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