brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · 1a277c8 Raw
162 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_EXCEPTIONANALYZER_H10#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_EXCEPTIONANALYZER_H11 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 an21/// exception, either directly or indirectly. It can be configured to ignore22/// custom exception types.23class ExceptionAnalyzer {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 available29                 ///< definition.30  };31 32  /// We use a MapVector to preserve the order of the functions in the call33  /// 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 regarding37  /// it's exception behaviour. The 'NonThrowing'-state can be considered as the38  /// 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 that41  /// an 'Unknown' function is called that might throw a previously unknown42  /// exception at runtime.43  class ExceptionInfo {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;49      CallStack Stack;50    };51 52    using Throwables = llvm::SmallDenseMap<const Type *, ThrowInfo, 2>;53 54    static ExceptionInfo createUnknown() { return {State::Unknown}; }55    static ExceptionInfo createNonThrowing() { return {State::Throwing}; }56 57    /// By default the exception situation is unknown and must be58    /// clarified step-wise.59    ExceptionInfo() : Behaviour(State::NotThrowing), ContainsUnknown(false) {}60    ExceptionInfo(State S)61        : Behaviour(S), ContainsUnknown(S == State::Unknown) {}62 63    ExceptionInfo(const ExceptionInfo &) = default;64    ExceptionInfo &operator=(const ExceptionInfo &) = default;65    ExceptionInfo(ExceptionInfo &&) = default;66    ExceptionInfo &operator=(ExceptionInfo &&) = default;67 68    State getBehaviour() const { return Behaviour; }69 70    /// Register a single exception type as recognized potential exception to be71    /// thrown.72    void registerException(const Type *ExceptionType,73                           const ThrowInfo &ThrowInfo);74 75    /// Registers a `SmallVector` of exception types as recognized potential76    /// exceptions to be thrown.77    void registerExceptions(const Throwables &Exceptions);78 79    /// Updates the local state according to the other state. That means if80    /// 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 one83    /// part is unknown and the rest is non-throwing the result will be84    /// unknown.85    ExceptionInfo &merge(const ExceptionInfo &Other);86 87    /// This method is useful in case 'catch' clauses are analyzed as it is88    /// possible to catch multiple exception types by one 'catch' if they89    /// 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 ignored94    /// types that shall not be considered in the exception analysis.95    /// This includes explicit `std::bad_alloc` ignoring as separate option.96    ExceptionInfo &97    filterIgnoredExceptions(const llvm::StringSet<> &IgnoredTypes,98                            bool IgnoreBadAlloc);99 100    /// Clear the state to 'NonThrowing' to make the corresponding entity101    /// neutral.102    void clear();103 104    /// References the set of known exceptions that can escape from the105    /// corresponding entity.106    const Throwables &getExceptions() const { return ThrownExceptions; }107 108    /// Signal if the there is any 'Unknown' element within the scope of109    /// the related entity. This might be relevant if the entity is 'Throwing'110    /// and to ensure that no other exception then 'getExceptionTypes' can111    /// 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 in119    /// 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 track123    /// of the certainty of decisions and/or correct 'Behaviour' transition124    /// after filtering.125    bool ContainsUnknown;126 127    /// 'ThrownException' is empty if the 'Behaviour' is either 'NotThrowing' or128    /// '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,148                                CallStack &CallStack);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::utils160 161#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_EXCEPTIONANALYZER_H162