|
|
|||
File indexing completed on 2026-05-10 08:36:22
0001 //===--- ExceptionAnalyzer.h - clang-tidy -----------------------*- C++ -*-===// 0002 // 0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 0004 // See https://llvm.org/LICENSE.txt for license information. 0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0006 // 0007 //===----------------------------------------------------------------------===// 0008 0009 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_EXCEPTION_ANALYZER_H 0010 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_EXCEPTION_ANALYZER_H 0011 0012 #include "clang/AST/ASTContext.h" 0013 #include "clang/ASTMatchers/ASTMatchFinder.h" 0014 #include "llvm/ADT/SmallSet.h" 0015 #include "llvm/ADT/StringSet.h" 0016 0017 namespace clang::tidy::utils { 0018 0019 /// This class analysis if a `FunctionDecl` can in principle throw an 0020 /// exception, either directly or indirectly. It can be configured to ignore 0021 /// custom exception types. 0022 class ExceptionAnalyzer { 0023 public: 0024 enum class State { 0025 Throwing, ///< The function can definitely throw given an AST. 0026 NotThrowing, ///< This function can not throw, given an AST. 0027 Unknown, ///< This can happen for extern functions without available 0028 ///< definition. 0029 }; 0030 0031 /// Bundle the gathered information about an entity like a function regarding 0032 /// it's exception behaviour. The 'NonThrowing'-state can be considered as the 0033 /// neutral element in terms of information propagation. 0034 /// In the case of 'Throwing' state it is possible that 'getExceptionTypes' 0035 /// does not include *ALL* possible types as there is the possibility that 0036 /// an 'Unknown' function is called that might throw a previously unknown 0037 /// exception at runtime. 0038 class ExceptionInfo { 0039 public: 0040 using Throwables = llvm::SmallSet<const Type *, 2>; 0041 static ExceptionInfo createUnknown() { return {State::Unknown}; } 0042 static ExceptionInfo createNonThrowing() { return {State::Throwing}; } 0043 0044 /// By default the exception situation is unknown and must be 0045 /// clarified step-wise. 0046 ExceptionInfo() : Behaviour(State::NotThrowing), ContainsUnknown(false) {} 0047 ExceptionInfo(State S) 0048 : Behaviour(S), ContainsUnknown(S == State::Unknown) {} 0049 0050 ExceptionInfo(const ExceptionInfo &) = default; 0051 ExceptionInfo &operator=(const ExceptionInfo &) = default; 0052 ExceptionInfo(ExceptionInfo &&) = default; 0053 ExceptionInfo &operator=(ExceptionInfo &&) = default; 0054 0055 State getBehaviour() const { return Behaviour; } 0056 0057 /// Register a single exception type as recognized potential exception to be 0058 /// thrown. 0059 void registerException(const Type *ExceptionType); 0060 0061 /// Registers a `SmallVector` of exception types as recognized potential 0062 /// exceptions to be thrown. 0063 void registerExceptions(const Throwables &Exceptions); 0064 0065 /// Updates the local state according to the other state. That means if 0066 /// for example a function contains multiple statements the 'ExceptionInfo' 0067 /// for the final function is the merged result of each statement. 0068 /// If one of these statements throws the whole function throws and if one 0069 /// part is unknown and the rest is non-throwing the result will be 0070 /// unknown. 0071 ExceptionInfo &merge(const ExceptionInfo &Other); 0072 0073 /// This method is useful in case 'catch' clauses are analyzed as it is 0074 /// possible to catch multiple exception types by one 'catch' if they 0075 /// are a subclass of the 'catch'ed exception type. 0076 /// Returns 'true' if some exceptions were filtered, otherwise 'false'. 0077 bool filterByCatch(const Type *HandlerTy, const ASTContext &Context); 0078 0079 /// Filter the set of thrown exception type against a set of ignored 0080 /// types that shall not be considered in the exception analysis. 0081 /// This includes explicit `std::bad_alloc` ignoring as separate option. 0082 ExceptionInfo & 0083 filterIgnoredExceptions(const llvm::StringSet<> &IgnoredTypes, 0084 bool IgnoreBadAlloc); 0085 0086 /// Clear the state to 'NonThrowing' to make the corresponding entity 0087 /// neutral. 0088 void clear(); 0089 0090 /// References the set of known exception types that can escape from the 0091 /// corresponding entity. 0092 const Throwables &getExceptionTypes() const { return ThrownExceptions; } 0093 0094 /// Signal if the there is any 'Unknown' element within the scope of 0095 /// the related entity. This might be relevant if the entity is 'Throwing' 0096 /// and to ensure that no other exception then 'getExceptionTypes' can 0097 /// occur. If there is an 'Unknown' element this can not be guaranteed. 0098 bool containsUnknownElements() const { return ContainsUnknown; } 0099 0100 private: 0101 /// Recalculate the 'Behaviour' for example after filtering. 0102 void reevaluateBehaviour(); 0103 0104 /// Keep track if the entity related to this 'ExceptionInfo' can in 0105 /// principle throw, if it's unknown or if it won't throw. 0106 State Behaviour; 0107 0108 /// Keep track if the entity contains any unknown elements to keep track 0109 /// of the certainty of decisions and/or correct 'Behaviour' transition 0110 /// after filtering. 0111 bool ContainsUnknown; 0112 0113 /// 'ThrownException' is empty if the 'Behaviour' is either 'NotThrowing' or 0114 /// 'Unknown'. 0115 Throwables ThrownExceptions; 0116 }; 0117 0118 ExceptionAnalyzer() = default; 0119 0120 void ignoreBadAlloc(bool ShallIgnore) { IgnoreBadAlloc = ShallIgnore; } 0121 void ignoreExceptions(llvm::StringSet<> ExceptionNames) { 0122 IgnoredExceptions = std::move(ExceptionNames); 0123 } 0124 0125 ExceptionInfo analyze(const FunctionDecl *Func); 0126 ExceptionInfo analyze(const Stmt *Stmt); 0127 0128 private: 0129 ExceptionInfo 0130 throwsException(const FunctionDecl *Func, 0131 const ExceptionInfo::Throwables &Caught, 0132 llvm::SmallSet<const FunctionDecl *, 32> &CallStack); 0133 ExceptionInfo 0134 throwsException(const Stmt *St, const ExceptionInfo::Throwables &Caught, 0135 llvm::SmallSet<const FunctionDecl *, 32> &CallStack); 0136 0137 ExceptionInfo analyzeImpl(const FunctionDecl *Func); 0138 ExceptionInfo analyzeImpl(const Stmt *Stmt); 0139 0140 template <typename T> ExceptionInfo analyzeDispatch(const T *Node); 0141 0142 bool IgnoreBadAlloc = true; 0143 llvm::StringSet<> IgnoredExceptions; 0144 llvm::DenseMap<const FunctionDecl *, ExceptionInfo> FunctionCache{32U}; 0145 }; 0146 0147 } // namespace clang::tidy::utils 0148 0149 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_EXCEPTION_ANALYZER_H
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|