clang-tools 20.0.0git
ExceptionAnalyzer.h
Go to the documentation of this file.
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.
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.
39 public:
40 using Throwables = llvm::SmallSet<const Type *, 2>;
43
44 /// By default the exception situation is unknown and must be
45 /// clarified step-wise.
46 ExceptionInfo() : Behaviour(State::NotThrowing), ContainsUnknown(false) {}
48 : Behaviour(S), ContainsUnknown(S == State::Unknown) {}
49
50 ExceptionInfo(const 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.
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
NodeType Type
Bundle the gathered information about an entity like a function regarding it's exception behaviour.
bool 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 clear()
Clear the state to 'NonThrowing' to make the corresponding entity neutral.
const Throwables & getExceptionTypes() const
References the set of known exception types that can escape from the corresponding entity.
void registerException(const Type *ExceptionType)
Register a single exception type as recognized potential exception to be thrown.
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...
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.
bool containsUnknownElements() const
Signal if the there is any 'Unknown' element within the scope of the related entity.
ExceptionInfo & operator=(ExceptionInfo &&)=default
This class analysis if a FunctionDecl can in principle throw an exception, either directly or indirec...
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.
ExceptionInfo analyze(const FunctionDecl *Func)