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