1//===--- ExceptionAnalyzer.h - clang-tidy -----------------------*- C++ -*-===//
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#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_EXCEPTION_ANALYZER_H
10#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_EXCEPTION_ANALYZER_H
11
12#include "clang/AST/ASTContext.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "llvm/ADT/SmallSet.h"
15#include "llvm/ADT/StringSet.h"
16
17namespace clang::tidy::utils {
18
19/// This class analysis if a `FunctionDecl` can in principle throw an
20/// exception, either directly or indirectly. It can be configured to ignore
21/// custom exception types.
22class ExceptionAnalyzer {
23public:
24 enum class State {
25 Throwing, ///< The function can definitely throw given an AST.
26 NotThrowing, ///< This function can not throw, given an AST.
27 Unknown, ///< This can happen for extern functions without available
28 ///< definition.
29 };
30
31 /// Bundle the gathered information about an entity like a function regarding
32 /// it's exception behaviour. The 'NonThrowing'-state can be considered as the
33 /// neutral element in terms of information propagation.
34 /// In the case of 'Throwing' state it is possible that 'getExceptionTypes'
35 /// does not include *ALL* possible types as there is the possibility that
36 /// an 'Unknown' function is called that might throw a previously unknown
37 /// exception at runtime.
38 class ExceptionInfo {
39 public:
40 using Throwables = llvm::SmallSet<const Type *, 2>;
41 static ExceptionInfo createUnknown() { return {State::Unknown}; }
42 static ExceptionInfo createNonThrowing() { return {State::Throwing}; }
43
44 /// By default the exception situation is unknown and must be
45 /// clarified step-wise.
46 ExceptionInfo() : Behaviour(State::NotThrowing), ContainsUnknown(false) {}
47 ExceptionInfo(State S)
48 : Behaviour(S), ContainsUnknown(S == State::Unknown) {}
49
50 ExceptionInfo(const ExceptionInfo &) = default;
51 ExceptionInfo &operator=(const ExceptionInfo &) = default;
52 ExceptionInfo(ExceptionInfo &&) = default;
53 ExceptionInfo &operator=(ExceptionInfo &&) = default;
54
55 State getBehaviour() const { return Behaviour; }
56
57 /// Register a single exception type as recognized potential exception to be
58 /// thrown.
59 void registerException(const Type *ExceptionType);
60
61 /// Registers a `SmallVector` of exception types as recognized potential
62 /// exceptions to be thrown.
63 void registerExceptions(const Throwables &Exceptions);
64
65 /// Updates the local state according to the other state. That means if
66 /// for example a function contains multiple statements the 'ExceptionInfo'
67 /// for the final function is the merged result of each statement.
68 /// If one of these statements throws the whole function throws and if one
69 /// part is unknown and the rest is non-throwing the result will be
70 /// unknown.
71 ExceptionInfo &merge(const ExceptionInfo &Other);
72
73 /// This method is useful in case 'catch' clauses are analyzed as it is
74 /// possible to catch multiple exception types by one 'catch' if they
75 /// are a subclass of the 'catch'ed exception type.
76 /// Returns 'true' if some exceptions were filtered, otherwise 'false'.
77 bool filterByCatch(const Type *HandlerTy, const ASTContext &Context);
78
79 /// Filter the set of thrown exception type against a set of ignored
80 /// types that shall not be considered in the exception analysis.
81 /// This includes explicit `std::bad_alloc` ignoring as separate option.
82 ExceptionInfo &
83 filterIgnoredExceptions(const llvm::StringSet<> &IgnoredTypes,
84 bool IgnoreBadAlloc);
85
86 /// Clear the state to 'NonThrowing' to make the corresponding entity
87 /// neutral.
88 void clear();
89
90 /// References the set of known exception types that can escape from the
91 /// corresponding entity.
92 const Throwables &getExceptionTypes() const { return ThrownExceptions; }
93
94 /// Signal if the there is any 'Unknown' element within the scope of
95 /// the related entity. This might be relevant if the entity is 'Throwing'
96 /// and to ensure that no other exception then 'getExceptionTypes' can
97 /// occur. If there is an 'Unknown' element this can not be guaranteed.
98 bool containsUnknownElements() const { return ContainsUnknown; }
99
100 private:
101 /// Recalculate the 'Behaviour' for example after filtering.
102 void reevaluateBehaviour();
103
104 /// Keep track if the entity related to this 'ExceptionInfo' can in princple
105 /// throw, if it's unknown or if it won't throw.
106 State Behaviour;
107
108 /// Keep track if the entity contains any unknown elements to keep track
109 /// of the certainty of decisions and/or correct 'Behaviour' transition
110 /// after filtering.
111 bool ContainsUnknown;
112
113 /// 'ThrownException' is empty if the 'Behaviour' is either 'NotThrowing' or
114 /// 'Unknown'.
115 Throwables ThrownExceptions;
116 };
117
118 ExceptionAnalyzer() = default;
119
120 void ignoreBadAlloc(bool ShallIgnore) { IgnoreBadAlloc = ShallIgnore; }
121 void ignoreExceptions(llvm::StringSet<> ExceptionNames) {
122 IgnoredExceptions = std::move(ExceptionNames);
123 }
124
125 ExceptionInfo analyze(const FunctionDecl *Func);
126 ExceptionInfo analyze(const Stmt *Stmt);
127
128private:
129 ExceptionInfo
130 throwsException(const FunctionDecl *Func,
131 const ExceptionInfo::Throwables &Caught,
132 llvm::SmallSet<const FunctionDecl *, 32> &CallStack);
133 ExceptionInfo
134 throwsException(const Stmt *St, const ExceptionInfo::Throwables &Caught,
135 llvm::SmallSet<const FunctionDecl *, 32> &CallStack);
136
137 ExceptionInfo analyzeImpl(const FunctionDecl *Func);
138 ExceptionInfo analyzeImpl(const Stmt *Stmt);
139
140 template <typename T> ExceptionInfo analyzeDispatch(const T *Node);
141
142 bool IgnoreBadAlloc = true;
143 llvm::StringSet<> IgnoredExceptions;
144 llvm::DenseMap<const FunctionDecl *, ExceptionInfo> FunctionCache{32U};
145};
146
147} // namespace clang::tidy::utils
148
149#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_EXCEPTION_ANALYZER_H
150

source code of clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.h