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