clang-tools 23.0.0git
EmptyCatchCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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 "EmptyCatchCheck.h"
10#include "../utils/Matchers.h"
12#include "clang/AST/ASTContext.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "clang/Lex/Lexer.h"
15
16using namespace clang::ast_matchers;
17using ::clang::ast_matchers::internal::Matcher;
18
19namespace clang::tidy::bugprone {
20
21namespace {
22AST_MATCHER(CXXCatchStmt, isInMacro) {
23 return Node.getBeginLoc().isMacroID() || Node.getEndLoc().isMacroID() ||
24 Node.getCatchLoc().isMacroID();
25}
26
27AST_MATCHER_P(CXXCatchStmt, hasHandler, Matcher<Stmt>, InnerMatcher) {
28 const Stmt *Handler = Node.getHandlerBlock();
29 if (!Handler)
30 return false;
31 return InnerMatcher.matches(*Handler, Finder, Builder);
32}
33
34AST_MATCHER_P(CXXCatchStmt, hasCaughtType, Matcher<QualType>, InnerMatcher) {
35 return InnerMatcher.matches(Node.getCaughtType(), Finder, Builder);
36}
37
38AST_MATCHER_P(CompoundStmt, hasAnyTextFromList, std::vector<StringRef>, List) {
39 if (List.empty())
40 return false;
41
42 ASTContext &Context = Finder->getASTContext();
43 const SourceManager &SM = Context.getSourceManager();
44 StringRef Text = Lexer::getSourceText(
45 CharSourceRange::getTokenRange(Node.getSourceRange()), SM,
46 Context.getLangOpts());
47 return llvm::any_of(List, [&](const StringRef &Str) {
48 return Text.contains_insensitive(Str);
49 });
50}
51
52} // namespace
53
55 : ClangTidyCheck(Name, Context),
56 IgnoreCatchWithKeywords(utils::options::parseStringList(
57 Options.get("IgnoreCatchWithKeywords", "@TODO;@FIXME"))),
58 AllowEmptyCatchForExceptions(utils::options::parseStringList(
59 Options.get("AllowEmptyCatchForExceptions", ""))) {}
60
62 Options.store(Opts, "IgnoreCatchWithKeywords",
63 utils::options::serializeStringList(IgnoreCatchWithKeywords));
64 Options.store(
65 Opts, "AllowEmptyCatchForExceptions",
66 utils::options::serializeStringList(AllowEmptyCatchForExceptions));
67}
68
70 const LangOptions &LangOpts) const {
71 return LangOpts.CPlusPlus;
72}
73
74std::optional<TraversalKind> EmptyCatchCheck::getCheckTraversalKind() const {
75 return TK_IgnoreUnlessSpelledInSource;
76}
77
78void EmptyCatchCheck::registerMatchers(MatchFinder *Finder) {
79 auto AllowedNamedExceptionDecl = namedDecl(
80 matchers::matchesAnyListedRegexName(AllowEmptyCatchForExceptions));
81 auto AllowedNamedExceptionTypes =
82 qualType(anyOf(hasDeclaration(AllowedNamedExceptionDecl),
83 references(AllowedNamedExceptionDecl),
84 pointsTo(AllowedNamedExceptionDecl)));
85 auto IgnoredExceptionType =
86 qualType(anyOf(AllowedNamedExceptionTypes,
87 hasCanonicalType(AllowedNamedExceptionTypes)));
88
89 Finder->addMatcher(
90 cxxCatchStmt(unless(isInMacro()),
91 unless(hasCaughtType(IgnoredExceptionType)),
92 hasHandler(compoundStmt(
93 statementCountIs(0),
94 unless(hasAnyTextFromList(IgnoreCatchWithKeywords)))))
95 .bind("catch"),
96 this);
97}
98
99void EmptyCatchCheck::check(const MatchFinder::MatchResult &Result) {
100 const auto *MatchedCatchStmt = Result.Nodes.getNodeAs<CXXCatchStmt>("catch");
101
102 diag(
103 MatchedCatchStmt->getCatchLoc(),
104 "empty catch statements hide issues; to handle exceptions appropriately, "
105 "consider re-throwing, handling, or avoiding catch altogether");
106}
107
108} // namespace clang::tidy::bugprone
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
EmptyCatchCheck(StringRef Name, ClangTidyContext *Context)
std::optional< TraversalKind > getCheckTraversalKind() const override
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID)
AST_MATCHER(BinaryOperator, isRelationalOperator)
inline ::clang::ast_matchers::internal::Matcher< NamedDecl > matchesAnyListedRegexName(llvm::ArrayRef< StringRef > NameList)
std::string serializeStringList(ArrayRef< StringRef > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
llvm::StringMap< ClangTidyValue > OptionMap