blob: 9e7bf6362f75484ec52e0dd9eadef0c63336cf33 [file] [log] [blame]
Jonas Tothf22f3482018-01-17 10:27:41 +00001//===--- AvoidGotoCheck.cpp - clang-tidy-----------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Jonas Tothf22f3482018-01-17 10:27:41 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "AvoidGotoCheck.h"
10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12
13using namespace clang::ast_matchers;
14
15namespace clang {
16namespace tidy {
17namespace cppcoreguidelines {
18
Benjamin Kramerf8c99292018-02-18 19:02:35 +000019namespace {
Jonas Tothf22f3482018-01-17 10:27:41 +000020AST_MATCHER(GotoStmt, isForwardJumping) {
Stephen Kelly43465bf2018-08-09 22:42:26 +000021 return Node.getBeginLoc() < Node.getLabel()->getBeginLoc();
Jonas Tothf22f3482018-01-17 10:27:41 +000022}
Benjamin Kramerf8c99292018-02-18 19:02:35 +000023} // namespace
Jonas Tothf22f3482018-01-17 10:27:41 +000024
25void AvoidGotoCheck::registerMatchers(MatchFinder *Finder) {
26 if (!getLangOpts().CPlusPlus)
27 return;
28
29 // TODO: This check does not recognize `IndirectGotoStmt` which is a
30 // GNU extension. These must be matched separately and an AST matcher
31 // is currently missing for them.
32
33 // Check if the 'goto' is used for control flow other than jumping
34 // out of a nested loop.
35 auto Loop = stmt(anyOf(forStmt(), cxxForRangeStmt(), whileStmt(), doStmt()));
36 auto NestedLoop =
37 stmt(anyOf(forStmt(hasAncestor(Loop)), cxxForRangeStmt(hasAncestor(Loop)),
38 whileStmt(hasAncestor(Loop)), doStmt(hasAncestor(Loop))));
39
40 Finder->addMatcher(gotoStmt(anyOf(unless(hasAncestor(NestedLoop)),
41 unless(isForwardJumping())))
42 .bind("goto"),
43 this);
44}
45
46void AvoidGotoCheck::check(const MatchFinder::MatchResult &Result) {
47 const auto *Goto = Result.Nodes.getNodeAs<GotoStmt>("goto");
48
49 diag(Goto->getGotoLoc(), "avoid using 'goto' for flow control")
50 << Goto->getSourceRange();
Stephen Kelly43465bf2018-08-09 22:42:26 +000051 diag(Goto->getLabel()->getBeginLoc(), "label defined here",
Jonas Tothf22f3482018-01-17 10:27:41 +000052 DiagnosticIDs::Note);
53}
54} // namespace cppcoreguidelines
55} // namespace tidy
56} // namespace clang