diff options
author | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 13:58:24 +0300 |
---|---|---|
committer | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 14:11:53 +0300 |
commit | 11a895b7e15d1c5a1f52706396b82e3f9db953cb (patch) | |
tree | fabc6d883b0f946151f61ae7865cee9f529a1fdd /contrib/libs/clang16/include/clang/Analysis/FlowSensitive | |
parent | 9685917341315774aad5733b1793b1e533a88bbb (diff) | |
download | ydb-11a895b7e15d1c5a1f52706396b82e3f9db953cb.tar.gz |
Export clang-format16 via ydblib project
6e6be3a95868fde888d801b7590af4044049563f
Diffstat (limited to 'contrib/libs/clang16/include/clang/Analysis/FlowSensitive')
19 files changed, 2896 insertions, 0 deletions
diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/CFGMatchSwitch.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/CFGMatchSwitch.h new file mode 100644 index 0000000000..fb652c1d2e --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/CFGMatchSwitch.h @@ -0,0 +1,109 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===---- CFGMatchSwitch.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the `CFGMatchSwitch` abstraction for building a "switch" +// statement for control flow graph elements. Each case of the switch is +// defined by an ASTMatcher which is applied on the AST node contained in the +// input `CFGElement`. +// +// Currently, the `CFGMatchSwitch` only handles `CFGElement`s of +// `Kind::Statement` and `Kind::Initializer`. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_ +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_ + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Stmt.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/MatchSwitch.h" +#include <functional> +#include <utility> + +namespace clang { +namespace dataflow { + +template <typename State, typename Result = void> +using CFGMatchSwitch = + std::function<Result(const CFGElement &, ASTContext &, State &)>; + +/// Collects cases of a "match switch": a collection of matchers paired with +/// callbacks, which together define a switch that can be applied to an AST node +/// contained in a CFG element. +template <typename State, typename Result = void> class CFGMatchSwitchBuilder { +public: + /// Registers an action `A` for `CFGStmt`s that will be triggered by the match + /// of the pattern `M` against the `Stmt` contained in the input `CFGStmt`. + /// + /// Requirements: + /// + /// `NodeT` should be derived from `Stmt`. + template <typename NodeT> + CFGMatchSwitchBuilder && + CaseOfCFGStmt(MatchSwitchMatcher<Stmt> M, + MatchSwitchAction<NodeT, State, Result> A) && { + std::move(StmtBuilder).template CaseOf<NodeT>(M, A); + return std::move(*this); + } + + /// Registers an action `A` for `CFGInitializer`s that will be triggered by + /// the match of the pattern `M` against the `CXXCtorInitializer` contained in + /// the input `CFGInitializer`. + /// + /// Requirements: + /// + /// `NodeT` should be derived from `CXXCtorInitializer`. + template <typename NodeT> + CFGMatchSwitchBuilder && + CaseOfCFGInit(MatchSwitchMatcher<CXXCtorInitializer> M, + MatchSwitchAction<NodeT, State, Result> A) && { + std::move(InitBuilder).template CaseOf<NodeT>(M, A); + return std::move(*this); + } + + CFGMatchSwitch<State, Result> Build() && { + return [StmtMS = std::move(StmtBuilder).Build(), + InitMS = std::move(InitBuilder).Build()](const CFGElement &Element, + ASTContext &Context, + State &S) -> Result { + switch (Element.getKind()) { + case CFGElement::Initializer: + return InitMS(*Element.castAs<CFGInitializer>().getInitializer(), + Context, S); + case CFGElement::Statement: + case CFGElement::Constructor: + case CFGElement::CXXRecordTypedCall: + return StmtMS(*Element.castAs<CFGStmt>().getStmt(), Context, S); + default: + // FIXME: Handle other kinds of CFGElement. + return Result(); + } + }; + } + +private: + ASTMatchSwitchBuilder<Stmt, State, Result> StmtBuilder; + ASTMatchSwitchBuilder<CXXCtorInitializer, State, Result> InitBuilder; +}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CFGMATCHSWITCH_H_ + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/ControlFlowContext.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/ControlFlowContext.h new file mode 100644 index 0000000000..0e544131a5 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/ControlFlowContext.h @@ -0,0 +1,78 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- ControlFlowContext.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a ControlFlowContext class that is used by dataflow +// analyses that run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Stmt.h" +#include "clang/Analysis/CFG.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Error.h" +#include <memory> +#include <utility> + +namespace clang { +namespace dataflow { + +/// Holds CFG and other derived context that is needed to perform dataflow +/// analysis. +class ControlFlowContext { +public: + /// Builds a ControlFlowContext from an AST node. `D` is the function in which + /// `S` resides and must not be null. + static llvm::Expected<ControlFlowContext> build(const Decl *D, Stmt &S, + ASTContext &C); + + /// Returns the `Decl` containing the statement used to construct the CFG, if + /// available. + const Decl *getDecl() const { return ContainingDecl; } + + /// Returns the CFG that is stored in this context. + const CFG &getCFG() const { return *Cfg; } + + /// Returns a mapping from statements to basic blocks that contain them. + const llvm::DenseMap<const Stmt *, const CFGBlock *> &getStmtToBlock() const { + return StmtToBlock; + } + +private: + // FIXME: Once the deprecated `build` method is removed, mark `D` as "must not + // be null" and add an assertion. + ControlFlowContext(const Decl *D, std::unique_ptr<CFG> Cfg, + llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock) + : ContainingDecl(D), Cfg(std::move(Cfg)), + StmtToBlock(std::move(StmtToBlock)) {} + + /// The `Decl` containing the statement used to construct the CFG. + const Decl *ContainingDecl; + std::unique_ptr<CFG> Cfg; + llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock; +}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h new file mode 100644 index 0000000000..aca8bf77ec --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -0,0 +1,258 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- DataflowAnalysis.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines base types and functions for building dataflow analyses +// that run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSIS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSIS_H + +#include <iterator> +#include <optional> +#include <type_traits> +#include <utility> +#include <vector> + +#include "clang/AST/ASTContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Analysis/FlowSensitive/DataflowLattice.h" +#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" +#include "llvm/ADT/Any.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Error.h" + +namespace clang { +namespace dataflow { + +/// Base class template for dataflow analyses built on a single lattice type. +/// +/// Requirements: +/// +/// `Derived` must be derived from a specialization of this class template and +/// must provide the following public members: +/// * `LatticeT initialElement()` - returns a lattice element that models the +/// initial state of a basic block; +/// * `void transfer(const CFGElement *, LatticeT &, Environment &)` - applies +/// the analysis transfer function for a given CFG element and lattice +/// element. +/// +/// `Derived` can optionally provide the following members: +/// * `void transferBranch(bool Branch, const Stmt *Stmt, TypeErasedLattice &E, +/// Environment &Env)` - applies the analysis transfer +/// function for a given edge from a CFG block of a conditional statement. +/// +/// `Derived` can optionally override the following members: +/// * `bool merge(QualType, const Value &, const Value &, Value &, +/// Environment &)` - joins distinct values. This could be a strict +/// lattice join or a more general widening operation. +/// +/// `LatticeT` is a bounded join-semilattice that is used by `Derived` and must +/// provide the following public members: +/// * `LatticeJoinEffect join(const LatticeT &)` - joins the object and the +/// argument by computing their least upper bound, modifies the object if +/// necessary, and returns an effect indicating whether any changes were +/// made to it; +/// * `bool operator==(const LatticeT &) const` - returns true if and only if +/// the object is equal to the argument. +/// +/// `LatticeT` can optionally provide the following members: +/// * `LatticeJoinEffect widen(const LatticeT &Previous)` - replaces the +/// lattice element with an approximation that can reach a fixed point more +/// quickly than iterated application of the transfer function alone. The +/// previous value is provided to inform the choice of widened value. The +/// function must also serve as a comparison operation, by indicating whether +/// the widened value is equivalent to the previous value with the returned +/// `LatticeJoinEffect`. +template <typename Derived, typename LatticeT> +class DataflowAnalysis : public TypeErasedDataflowAnalysis { +public: + /// Bounded join-semilattice that is used in the analysis. + using Lattice = LatticeT; + + explicit DataflowAnalysis(ASTContext &Context) : Context(Context) {} + + /// Deprecated. Use the `DataflowAnalysisOptions` constructor instead. + explicit DataflowAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer) + : DataflowAnalysis( + Context, + {ApplyBuiltinTransfer + ? DataflowAnalysisContext::Options{} + : std::optional<DataflowAnalysisContext::Options>()}) {} + + explicit DataflowAnalysis(ASTContext &Context, + DataflowAnalysisOptions Options) + : TypeErasedDataflowAnalysis(Options), Context(Context) {} + + ASTContext &getASTContext() final { return Context; } + + TypeErasedLattice typeErasedInitialElement() final { + return {static_cast<Derived *>(this)->initialElement()}; + } + + LatticeJoinEffect joinTypeErased(TypeErasedLattice &E1, + const TypeErasedLattice &E2) final { + Lattice &L1 = llvm::any_cast<Lattice &>(E1.Value); + const Lattice &L2 = llvm::any_cast<const Lattice &>(E2.Value); + return L1.join(L2); + } + + LatticeJoinEffect widenTypeErased(TypeErasedLattice &Current, + const TypeErasedLattice &Previous) final { + Lattice &C = llvm::any_cast<Lattice &>(Current.Value); + const Lattice &P = llvm::any_cast<const Lattice &>(Previous.Value); + return widenInternal(Rank0{}, C, P); + } + + bool isEqualTypeErased(const TypeErasedLattice &E1, + const TypeErasedLattice &E2) final { + const Lattice &L1 = llvm::any_cast<const Lattice &>(E1.Value); + const Lattice &L2 = llvm::any_cast<const Lattice &>(E2.Value); + return L1 == L2; + } + + void transferTypeErased(const CFGElement *Element, TypeErasedLattice &E, + Environment &Env) final { + Lattice &L = llvm::any_cast<Lattice &>(E.Value); + static_cast<Derived *>(this)->transfer(Element, L, Env); + } + + void transferBranchTypeErased(bool Branch, const Stmt *Stmt, + TypeErasedLattice &E, Environment &Env) final { + transferBranchInternal(Rank0{}, *static_cast<Derived *>(this), Branch, Stmt, + E, Env); + } + +private: + // These `Rank` structs are used for template metaprogramming to choose + // between overloads. + struct Rank1 {}; + struct Rank0 : Rank1 {}; + + // The first-choice implementation: use `widen` when it is available. + template <typename T> + static auto widenInternal(Rank0, T &Current, const T &Prev) + -> decltype(Current.widen(Prev)) { + return Current.widen(Prev); + } + + // The second-choice implementation: `widen` is unavailable. Widening is + // merged with equality checking, so when widening is unimplemented, we + // default to equality checking. + static LatticeJoinEffect widenInternal(Rank1, const Lattice &Current, + const Lattice &Prev) { + return Prev == Current ? LatticeJoinEffect::Unchanged + : LatticeJoinEffect::Changed; + } + + // The first-choice implementation: `transferBranch` is implemented. + template <typename Analysis> + static auto transferBranchInternal(Rank0, Analysis &A, bool Branch, + const Stmt *Stmt, TypeErasedLattice &L, + Environment &Env) + -> std::void_t<decltype(A.transferBranch( + Branch, Stmt, std::declval<LatticeT &>(), Env))> { + A.transferBranch(Branch, Stmt, llvm::any_cast<Lattice &>(L.Value), Env); + } + + // The second-choice implementation: `transferBranch` is unimplemented. No-op. + template <typename Analysis> + static void transferBranchInternal(Rank1, Analysis &A, bool, const Stmt *, + TypeErasedLattice &, Environment &) {} + + ASTContext &Context; +}; + +// Model of the program at a given program point. +template <typename LatticeT> struct DataflowAnalysisState { + // Model of a program property. + LatticeT Lattice; + + // Model of the state of the program (store and heap). + Environment Env; +}; + +/// Performs dataflow analysis and returns a mapping from basic block IDs to +/// dataflow analysis states that model the respective basic blocks. The +/// returned vector, if any, will have the same size as the number of CFG +/// blocks, with indices corresponding to basic block IDs. Returns an error if +/// the dataflow analysis cannot be performed successfully. Otherwise, calls +/// `PostVisitCFG` on each CFG element with the final analysis results at that +/// program point. +template <typename AnalysisT> +llvm::Expected<std::vector< + std::optional<DataflowAnalysisState<typename AnalysisT::Lattice>>>> +runDataflowAnalysis( + const ControlFlowContext &CFCtx, AnalysisT &Analysis, + const Environment &InitEnv, + std::function<void(const CFGElement &, const DataflowAnalysisState< + typename AnalysisT::Lattice> &)> + PostVisitCFG = nullptr) { + std::function<void(const CFGElement &, + const TypeErasedDataflowAnalysisState &)> + PostVisitCFGClosure = nullptr; + if (PostVisitCFG) { + PostVisitCFGClosure = [&PostVisitCFG]( + const CFGElement &Element, + const TypeErasedDataflowAnalysisState &State) { + auto *Lattice = + llvm::any_cast<typename AnalysisT::Lattice>(&State.Lattice.Value); + PostVisitCFG(Element, DataflowAnalysisState<typename AnalysisT::Lattice>{ + *Lattice, State.Env}); + }; + } + + auto TypeErasedBlockStates = runTypeErasedDataflowAnalysis( + CFCtx, Analysis, InitEnv, PostVisitCFGClosure); + if (!TypeErasedBlockStates) + return TypeErasedBlockStates.takeError(); + + std::vector<std::optional<DataflowAnalysisState<typename AnalysisT::Lattice>>> + BlockStates; + BlockStates.reserve(TypeErasedBlockStates->size()); + + llvm::transform( + std::move(*TypeErasedBlockStates), std::back_inserter(BlockStates), + [](auto &OptState) { + return llvm::transformOptional(std::move(OptState), [](auto &&State) { + return DataflowAnalysisState<typename AnalysisT::Lattice>{ + llvm::any_cast<typename AnalysisT::Lattice>( + std::move(State.Lattice.Value)), + std::move(State.Env)}; + }); + }); + return BlockStates; +} + +/// Abstract base class for dataflow "models": reusable analysis components that +/// model a particular aspect of program semantics in the `Environment`. For +/// example, a model may capture a type and its related functions. +class DataflowModel : public Environment::ValueModel { +public: + /// Return value indicates whether the model processed the `Element`. + virtual bool transfer(const CFGElement *Element, Environment &Env) = 0; +}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSIS_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h new file mode 100644 index 0000000000..7c70a92c34 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -0,0 +1,411 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- DataflowAnalysisContext.h -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a DataflowAnalysisContext class that owns objects that +// encompass the state of a program and stores context that is used during +// dataflow analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSISCONTEXT_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSISCONTEXT_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/TypeOrdering.h" +#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" +#include "clang/Analysis/FlowSensitive/Solver.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" +#include "clang/Analysis/FlowSensitive/Value.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/Compiler.h" +#include <cassert> +#include <memory> +#include <optional> +#include <type_traits> +#include <utility> +#include <vector> + +namespace clang { +namespace dataflow { + +/// Skip past nodes that the CFG does not emit. These nodes are invisible to +/// flow-sensitive analysis, and should be ignored as they will effectively not +/// exist. +/// +/// * `ParenExpr` - The CFG takes the operator precedence into account, but +/// otherwise omits the node afterwards. +/// +/// * `ExprWithCleanups` - The CFG will generate the appropriate calls to +/// destructors and then omit the node. +/// +const Expr &ignoreCFGOmittedNodes(const Expr &E); +const Stmt &ignoreCFGOmittedNodes(const Stmt &S); + +/// Returns the set of all fields in the type. +llvm::DenseSet<const FieldDecl *> getObjectFields(QualType Type); + +struct ContextSensitiveOptions { + /// The maximum depth to analyze. A value of zero is equivalent to disabling + /// context-sensitive analysis entirely. + unsigned Depth = 2; +}; + +/// Owns objects that encompass the state of a program and stores context that +/// is used during dataflow analysis. +class DataflowAnalysisContext { +public: + struct Options { + /// Options for analyzing function bodies when present in the translation + /// unit, or empty to disable context-sensitive analysis. Note that this is + /// fundamentally limited: some constructs, such as recursion, are + /// explicitly unsupported. + std::optional<ContextSensitiveOptions> ContextSensitiveOpts; + }; + + /// Constructs a dataflow analysis context. + /// + /// Requirements: + /// + /// `S` must not be null. + DataflowAnalysisContext(std::unique_ptr<Solver> S, + Options Opts = Options{ + /*ContextSensitiveOpts=*/std::nullopt}) + : S(std::move(S)), TrueVal(createAtomicBoolValue()), + FalseVal(createAtomicBoolValue()), Opts(Opts) { + assert(this->S != nullptr); + } + + /// Takes ownership of `Loc` and returns a reference to it. + /// + /// Requirements: + /// + /// `Loc` must not be null. + template <typename T> + std::enable_if_t<std::is_base_of<StorageLocation, T>::value, T &> + takeOwnership(std::unique_ptr<T> Loc) { + assert(Loc != nullptr); + Locs.push_back(std::move(Loc)); + return *cast<T>(Locs.back().get()); + } + + /// Takes ownership of `Val` and returns a reference to it. + /// + /// Requirements: + /// + /// `Val` must not be null. + template <typename T> + std::enable_if_t<std::is_base_of<Value, T>::value, T &> + takeOwnership(std::unique_ptr<T> Val) { + assert(Val != nullptr); + Vals.push_back(std::move(Val)); + return *cast<T>(Vals.back().get()); + } + + /// Returns a new storage location appropriate for `Type`. + /// + /// A null `Type` is interpreted as the pointee type of `std::nullptr_t`. + StorageLocation &createStorageLocation(QualType Type); + + /// Returns a stable storage location for `D`. + StorageLocation &getStableStorageLocation(const VarDecl &D); + + /// Returns a stable storage location for `E`. + StorageLocation &getStableStorageLocation(const Expr &E); + + /// Assigns `Loc` as the storage location of `D`. + /// + /// Requirements: + /// + /// `D` must not be assigned a storage location. + void setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { + assert(DeclToLoc.find(&D) == DeclToLoc.end()); + DeclToLoc[&D] = &Loc; + } + + /// Returns the storage location assigned to `D` or null if `D` has no + /// assigned storage location. + StorageLocation *getStorageLocation(const ValueDecl &D) const { + auto It = DeclToLoc.find(&D); + return It == DeclToLoc.end() ? nullptr : It->second; + } + + /// Assigns `Loc` as the storage location of `E`. + /// + /// Requirements: + /// + /// `E` must not be assigned a storage location. + void setStorageLocation(const Expr &E, StorageLocation &Loc) { + const Expr &CanonE = ignoreCFGOmittedNodes(E); + assert(ExprToLoc.find(&CanonE) == ExprToLoc.end()); + ExprToLoc[&CanonE] = &Loc; + } + + /// Returns the storage location assigned to `E` or null if `E` has no + /// assigned storage location. + StorageLocation *getStorageLocation(const Expr &E) const { + auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E)); + return It == ExprToLoc.end() ? nullptr : It->second; + } + + /// Returns a pointer value that represents a null pointer. Calls with + /// `PointeeType` that are canonically equivalent will return the same result. + /// A null `PointeeType` can be used for the pointee of `std::nullptr_t`. + PointerValue &getOrCreateNullPointerValue(QualType PointeeType); + + /// Returns a symbolic boolean value that models a boolean literal equal to + /// `Value`. + AtomicBoolValue &getBoolLiteralValue(bool Value) const { + return Value ? TrueVal : FalseVal; + } + + /// Creates an atomic boolean value. + AtomicBoolValue &createAtomicBoolValue() { + return takeOwnership(std::make_unique<AtomicBoolValue>()); + } + + /// Creates a Top value for booleans. Each instance is unique and can be + /// assigned a distinct truth value during solving. + /// + /// FIXME: `Top iff Top` is true when both Tops are identical (by pointer + /// equality), but not when they are distinct values. We should improve the + /// implementation so that `Top iff Top` has a consistent meaning, regardless + /// of the identity of `Top`. Moreover, I think the meaning should be + /// `false`. + TopBoolValue &createTopBoolValue() { + return takeOwnership(std::make_unique<TopBoolValue>()); + } + + /// Returns a boolean value that represents the conjunction of `LHS` and + /// `RHS`. Subsequent calls with the same arguments, regardless of their + /// order, will return the same result. If the given boolean values represent + /// the same value, the result will be the value itself. + BoolValue &getOrCreateConjunction(BoolValue &LHS, BoolValue &RHS); + + /// Returns a boolean value that represents the disjunction of `LHS` and + /// `RHS`. Subsequent calls with the same arguments, regardless of their + /// order, will return the same result. If the given boolean values represent + /// the same value, the result will be the value itself. + BoolValue &getOrCreateDisjunction(BoolValue &LHS, BoolValue &RHS); + + /// Returns a boolean value that represents the negation of `Val`. Subsequent + /// calls with the same argument will return the same result. + BoolValue &getOrCreateNegation(BoolValue &Val); + + /// Returns a boolean value that represents `LHS => RHS`. Subsequent calls + /// with the same arguments, will return the same result. If the given boolean + /// values represent the same value, the result will be a value that + /// represents the true boolean literal. + BoolValue &getOrCreateImplication(BoolValue &LHS, BoolValue &RHS); + + /// Returns a boolean value that represents `LHS <=> RHS`. Subsequent calls + /// with the same arguments, regardless of their order, will return the same + /// result. If the given boolean values represent the same value, the result + /// will be a value that represents the true boolean literal. + BoolValue &getOrCreateIff(BoolValue &LHS, BoolValue &RHS); + + /// Creates a fresh flow condition and returns a token that identifies it. The + /// token can be used to perform various operations on the flow condition such + /// as adding constraints to it, forking it, joining it with another flow + /// condition, or checking implications. + AtomicBoolValue &makeFlowConditionToken(); + + /// Adds `Constraint` to the flow condition identified by `Token`. + void addFlowConditionConstraint(AtomicBoolValue &Token, + BoolValue &Constraint); + + /// Creates a new flow condition with the same constraints as the flow + /// condition identified by `Token` and returns its token. + AtomicBoolValue &forkFlowCondition(AtomicBoolValue &Token); + + /// Creates a new flow condition that represents the disjunction of the flow + /// conditions identified by `FirstToken` and `SecondToken`, and returns its + /// token. + AtomicBoolValue &joinFlowConditions(AtomicBoolValue &FirstToken, + AtomicBoolValue &SecondToken); + + // FIXME: This function returns the flow condition expressed directly as its + // constraints: (C1 AND C2 AND ...). This differs from the general approach in + // the framework where a flow condition is represented as a token (an atomic + // boolean) with dependencies and constraints tracked in `FlowConditionDeps` + // and `FlowConditionConstraints`: (FC <=> C1 AND C2 AND ...). + // Consider if we should make the representation of flow condition consistent, + // returning an atomic boolean token with separate constraints instead. + // + /// Builds and returns the logical formula defining the flow condition + /// identified by `Token`. If a value in the formula is present as a key in + /// `Substitutions`, it will be substituted with the value it maps to. + /// As an example, say we have flow condition tokens FC1, FC2, FC3 and + /// FlowConditionConstraints: { FC1: C1, + /// FC2: C2, + /// FC3: (FC1 v FC2) ^ C3 } + /// buildAndSubstituteFlowCondition(FC3, {{C1 -> C1'}}) will return a value + /// corresponding to (C1' v C2) ^ C3. + BoolValue &buildAndSubstituteFlowCondition( + AtomicBoolValue &Token, + llvm::DenseMap<AtomicBoolValue *, BoolValue *> Substitutions); + + /// Returns true if and only if the constraints of the flow condition + /// identified by `Token` imply that `Val` is true. + bool flowConditionImplies(AtomicBoolValue &Token, BoolValue &Val); + + /// Returns true if and only if the constraints of the flow condition + /// identified by `Token` are always true. + bool flowConditionIsTautology(AtomicBoolValue &Token); + + /// Returns true if `Val1` is equivalent to `Val2`. + /// Note: This function doesn't take into account constraints on `Val1` and + /// `Val2` imposed by the flow condition. + bool equivalentBoolValues(BoolValue &Val1, BoolValue &Val2); + + LLVM_DUMP_METHOD void dumpFlowCondition(AtomicBoolValue &Token); + + /// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise, + /// returns null. + const ControlFlowContext *getControlFlowContext(const FunctionDecl *F); + + const Options &getOptions() { return Opts; } + +private: + friend class Environment; + + struct NullableQualTypeDenseMapInfo : private llvm::DenseMapInfo<QualType> { + static QualType getEmptyKey() { + // Allow a NULL `QualType` by using a different value as the empty key. + return QualType::getFromOpaquePtr(reinterpret_cast<Type *>(1)); + } + + using DenseMapInfo::getHashValue; + using DenseMapInfo::getTombstoneKey; + using DenseMapInfo::isEqual; + }; + + // Extends the set of modeled field declarations. + void addModeledFields(const llvm::DenseSet<const FieldDecl *> &Fields); + + /// Returns the fields of `Type`, limited to the set of fields modeled by this + /// context. + llvm::DenseSet<const FieldDecl *> getReferencedFields(QualType Type); + + /// Adds all constraints of the flow condition identified by `Token` and all + /// of its transitive dependencies to `Constraints`. `VisitedTokens` is used + /// to track tokens of flow conditions that were already visited by recursive + /// calls. + void addTransitiveFlowConditionConstraints( + AtomicBoolValue &Token, llvm::DenseSet<BoolValue *> &Constraints, + llvm::DenseSet<AtomicBoolValue *> &VisitedTokens); + + /// Returns the outcome of satisfiability checking on `Constraints`. + /// Possible outcomes are: + /// - `Satisfiable`: A satisfying assignment exists and is returned. + /// - `Unsatisfiable`: A satisfying assignment does not exist. + /// - `TimedOut`: The search for a satisfying assignment was not completed. + Solver::Result querySolver(llvm::DenseSet<BoolValue *> Constraints); + + /// Returns true if the solver is able to prove that there is no satisfying + /// assignment for `Constraints` + bool isUnsatisfiable(llvm::DenseSet<BoolValue *> Constraints) { + return querySolver(std::move(Constraints)).getStatus() == + Solver::Result::Status::Unsatisfiable; + } + + /// Returns a boolean value as a result of substituting `Val` and its sub + /// values based on entries in `SubstitutionsCache`. Intermediate results are + /// stored in `SubstitutionsCache` to avoid reprocessing values that have + /// already been visited. + BoolValue &substituteBoolValue( + BoolValue &Val, + llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache); + + /// Builds and returns the logical formula defining the flow condition + /// identified by `Token`, sub values may be substituted based on entries in + /// `SubstitutionsCache`. Intermediate results are stored in + /// `SubstitutionsCache` to avoid reprocessing values that have already been + /// visited. + BoolValue &buildAndSubstituteFlowConditionWithCache( + AtomicBoolValue &Token, + llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache); + + std::unique_ptr<Solver> S; + + // Storage for the state of a program. + std::vector<std::unique_ptr<StorageLocation>> Locs; + std::vector<std::unique_ptr<Value>> Vals; + + // Maps from program declarations and statements to storage locations that are + // assigned to them. These assignments are global (aggregated across all basic + // blocks) and are used to produce stable storage locations when the same + // basic blocks are evaluated multiple times. The storage locations that are + // in scope for a particular basic block are stored in `Environment`. + llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc; + llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc; + + // Null pointer values, keyed by the canonical pointee type. + // + // FIXME: The pointer values are indexed by the pointee types which are + // required to initialize the `PointeeLoc` field in `PointerValue`. Consider + // creating a type-independent `NullPointerValue` without a `PointeeLoc` + // field. + llvm::DenseMap<QualType, PointerValue *, NullableQualTypeDenseMapInfo> + NullPointerVals; + + AtomicBoolValue &TrueVal; + AtomicBoolValue &FalseVal; + + Options Opts; + + // Indices that are used to avoid recreating the same composite boolean + // values. + llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, ConjunctionValue *> + ConjunctionVals; + llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, DisjunctionValue *> + DisjunctionVals; + llvm::DenseMap<BoolValue *, NegationValue *> NegationVals; + llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, ImplicationValue *> + ImplicationVals; + llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, BiconditionalValue *> + BiconditionalVals; + + // Flow conditions are tracked symbolically: each unique flow condition is + // associated with a fresh symbolic variable (token), bound to the clause that + // defines the flow condition. Conceptually, each binding corresponds to an + // "iff" of the form `FC <=> (C1 ^ C2 ^ ...)` where `FC` is a flow condition + // token (an atomic boolean) and `Ci`s are the set of constraints in the flow + // flow condition clause. The set of constraints (C1 ^ C2 ^ ...) are stored in + // the `FlowConditionConstraints` map, keyed by the token of the flow + // condition. + // + // Flow conditions depend on other flow conditions if they are created using + // `forkFlowCondition` or `joinFlowConditions`. The graph of flow condition + // dependencies is stored in the `FlowConditionDeps` map. + llvm::DenseMap<AtomicBoolValue *, llvm::DenseSet<AtomicBoolValue *>> + FlowConditionDeps; + llvm::DenseMap<AtomicBoolValue *, BoolValue *> FlowConditionConstraints; + + llvm::DenseMap<const FunctionDecl *, ControlFlowContext> FunctionContexts; + + // Fields modeled by environments covered by this context. + llvm::DenseSet<const FieldDecl *> ModeledFields; +}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSISCONTEXT_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h new file mode 100644 index 0000000000..d6299584c8 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -0,0 +1,513 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- DataflowEnvironment.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines an Environment class that is used by dataflow analyses +// that run over Control-Flow Graphs (CFGs) to keep track of the state of the +// program at given program points. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" +#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" +#include "clang/Analysis/FlowSensitive/DataflowLattice.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" +#include "clang/Analysis/FlowSensitive/Value.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/ErrorHandling.h" +#include <memory> +#include <type_traits> +#include <utility> + +namespace clang { +namespace dataflow { + +/// Indicates what kind of indirections should be skipped past when retrieving +/// storage locations or values. +/// +/// FIXME: Consider renaming this or replacing it with a more appropriate model. +/// See the discussion in https://reviews.llvm.org/D116596 for context. +enum class SkipPast { + /// No indirections should be skipped past. + None, + /// An optional reference should be skipped past. + Reference, + /// An optional reference should be skipped past, then an optional pointer + /// should be skipped past. + ReferenceThenPointer, +}; + +/// Indicates the result of a tentative comparison. +enum class ComparisonResult { + Same, + Different, + Unknown, +}; + +/// Holds the state of the program (store and heap) at a given program point. +/// +/// WARNING: Symbolic values that are created by the environment for static +/// local and global variables are not currently invalidated on function calls. +/// This is unsound and should be taken into account when designing dataflow +/// analyses. +class Environment { +public: + /// Supplements `Environment` with non-standard comparison and join + /// operations. + class ValueModel { + public: + virtual ~ValueModel() = default; + + /// Returns: + /// `Same`: `Val1` is equivalent to `Val2`, according to the model. + /// `Different`: `Val1` is distinct from `Val2`, according to the model. + /// `Unknown`: The model can't determine a relationship between `Val1` and + /// `Val2`. + /// + /// Requirements: + /// + /// `Val1` and `Val2` must be distinct. + /// + /// `Val1` and `Val2` must model values of type `Type`. + /// + /// `Val1` and `Val2` must be assigned to the same storage location in + /// `Env1` and `Env2` respectively. + virtual ComparisonResult compare(QualType Type, const Value &Val1, + const Environment &Env1, const Value &Val2, + const Environment &Env2) { + // FIXME: Consider adding QualType to StructValue and removing the Type + // argument here. + return ComparisonResult::Unknown; + } + + /// Modifies `MergedVal` to approximate both `Val1` and `Val2`. This could + /// be a strict lattice join or a more general widening operation. + /// + /// If this function returns true, `MergedVal` will be assigned to a storage + /// location of type `Type` in `MergedEnv`. + /// + /// `Env1` and `Env2` can be used to query child values and path condition + /// implications of `Val1` and `Val2` respectively. + /// + /// Requirements: + /// + /// `Val1` and `Val2` must be distinct. + /// + /// `Val1`, `Val2`, and `MergedVal` must model values of type `Type`. + /// + /// `Val1` and `Val2` must be assigned to the same storage location in + /// `Env1` and `Env2` respectively. + virtual bool merge(QualType Type, const Value &Val1, + const Environment &Env1, const Value &Val2, + const Environment &Env2, Value &MergedVal, + Environment &MergedEnv) { + return true; + } + + /// This function may widen the current value -- replace it with an + /// approximation that can reach a fixed point more quickly than iterated + /// application of the transfer function alone. The previous value is + /// provided to inform the choice of widened value. The function must also + /// serve as a comparison operation, by indicating whether the widened value + /// is equivalent to the previous value. + /// + /// Returns either: + /// + /// `nullptr`, if this value is not of interest to the model, or + /// + /// `&Prev`, if the widened value is equivalent to `Prev`, or + /// + /// A non-null value that approximates `Current`. `Prev` is available to + /// inform the chosen approximation. + /// + /// `PrevEnv` and `CurrentEnv` can be used to query child values and path + /// condition implications of `Prev` and `Current`, respectively. + /// + /// Requirements: + /// + /// `Prev` and `Current` must model values of type `Type`. + /// + /// `Prev` and `Current` must be assigned to the same storage location in + /// `PrevEnv` and `CurrentEnv`, respectively. + virtual Value *widen(QualType Type, Value &Prev, const Environment &PrevEnv, + Value &Current, Environment &CurrentEnv) { + // The default implementation reduces to just comparison, since comparison + // is required by the API, even if no widening is performed. + switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) { + case ComparisonResult::Same: + return &Prev; + case ComparisonResult::Different: + return &Current; + case ComparisonResult::Unknown: + return nullptr; + } + llvm_unreachable("all cases in switch covered"); + } + }; + + /// Creates an environment that uses `DACtx` to store objects that encompass + /// the state of a program. + explicit Environment(DataflowAnalysisContext &DACtx); + + Environment(const Environment &Other); + Environment &operator=(const Environment &Other); + + Environment(Environment &&Other) = default; + Environment &operator=(Environment &&Other) = default; + + /// Creates an environment that uses `DACtx` to store objects that encompass + /// the state of a program. + /// + /// If `DeclCtx` is a function, initializes the environment with symbolic + /// representations of the function parameters. + /// + /// If `DeclCtx` is a non-static member function, initializes the environment + /// with a symbolic representation of the `this` pointee. + Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx); + + const DataflowAnalysisContext::Options &getAnalysisOptions() { + return DACtx->getOptions(); + } + + /// Creates and returns an environment to use for an inline analysis of the + /// callee. Uses the storage location from each argument in the `Call` as the + /// storage location for the corresponding parameter in the callee. + /// + /// Requirements: + /// + /// The callee of `Call` must be a `FunctionDecl`. + /// + /// The body of the callee must not reference globals. + /// + /// The arguments of `Call` must map 1:1 to the callee's parameters. + Environment pushCall(const CallExpr *Call) const; + Environment pushCall(const CXXConstructExpr *Call) const; + + /// Moves gathered information back into `this` from a `CalleeEnv` created via + /// `pushCall`. + void popCall(const Environment &CalleeEnv); + + /// Returns true if and only if the environment is equivalent to `Other`, i.e + /// the two environments: + /// - have the same mappings from declarations to storage locations, + /// - have the same mappings from expressions to storage locations, + /// - have the same or equivalent (according to `Model`) values assigned to + /// the same storage locations. + /// + /// Requirements: + /// + /// `Other` and `this` must use the same `DataflowAnalysisContext`. + bool equivalentTo(const Environment &Other, + Environment::ValueModel &Model) const; + + /// Joins the environment with `Other` by taking the intersection of storage + /// locations and values that are stored in them. Distinct values that are + /// assigned to the same storage locations in the environment and `Other` are + /// merged using `Model`. + /// + /// Requirements: + /// + /// `Other` and `this` must use the same `DataflowAnalysisContext`. + LatticeJoinEffect join(const Environment &Other, + Environment::ValueModel &Model); + + + /// Widens the environment point-wise, using `PrevEnv` as needed to inform the + /// approximation. + /// + /// Requirements: + /// + /// `PrevEnv` must be the immediate previous version of the environment. + /// `PrevEnv` and `this` must use the same `DataflowAnalysisContext`. + LatticeJoinEffect widen(const Environment &PrevEnv, + Environment::ValueModel &Model); + + // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`, + // `getStableStorageLocation`, or something more appropriate. + + /// Creates a storage location appropriate for `Type`. Does not assign a value + /// to the returned storage location in the environment. + /// + /// Requirements: + /// + /// `Type` must not be null. + StorageLocation &createStorageLocation(QualType Type); + + /// Creates a storage location for `D`. Does not assign the returned storage + /// location to `D` in the environment. Does not assign a value to the + /// returned storage location in the environment. + StorageLocation &createStorageLocation(const VarDecl &D); + + /// Creates a storage location for `E`. Does not assign the returned storage + /// location to `E` in the environment. Does not assign a value to the + /// returned storage location in the environment. + StorageLocation &createStorageLocation(const Expr &E); + + /// Assigns `Loc` as the storage location of `D` in the environment. + /// + /// Requirements: + /// + /// `D` must not be assigned a storage location in the environment. + void setStorageLocation(const ValueDecl &D, StorageLocation &Loc); + + /// Returns the storage location assigned to `D` in the environment, applying + /// the `SP` policy for skipping past indirections, or null if `D` isn't + /// assigned a storage location in the environment. + StorageLocation *getStorageLocation(const ValueDecl &D, SkipPast SP) const; + + /// Assigns `Loc` as the storage location of `E` in the environment. + /// + /// Requirements: + /// + /// `E` must not be assigned a storage location in the environment. + void setStorageLocation(const Expr &E, StorageLocation &Loc); + + /// Returns the storage location assigned to `E` in the environment, applying + /// the `SP` policy for skipping past indirections, or null if `E` isn't + /// assigned a storage location in the environment. + StorageLocation *getStorageLocation(const Expr &E, SkipPast SP) const; + + /// Returns the storage location assigned to the `this` pointee in the + /// environment or null if the `this` pointee has no assigned storage location + /// in the environment. + StorageLocation *getThisPointeeStorageLocation() const; + + /// Returns the storage location of the return value or null, if unset. + StorageLocation *getReturnStorageLocation() const; + + /// Returns a pointer value that represents a null pointer. Calls with + /// `PointeeType` that are canonically equivalent will return the same result. + PointerValue &getOrCreateNullPointerValue(QualType PointeeType); + + /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise + /// return null. If `Type` is a pointer or reference type, creates all the + /// necessary storage locations and values for indirections until it finds a + /// non-pointer/non-reference type. + /// + /// Requirements: + /// + /// `Type` must not be null. + Value *createValue(QualType Type); + + /// Assigns `Val` as the value of `Loc` in the environment. + void setValue(const StorageLocation &Loc, Value &Val); + + /// Returns the value assigned to `Loc` in the environment or null if `Loc` + /// isn't assigned a value in the environment. + Value *getValue(const StorageLocation &Loc) const; + + /// Equivalent to `getValue(getStorageLocation(D, SP), SkipPast::None)` if `D` + /// is assigned a storage location in the environment, otherwise returns null. + Value *getValue(const ValueDecl &D, SkipPast SP) const; + + /// Equivalent to `getValue(getStorageLocation(E, SP), SkipPast::None)` if `E` + /// is assigned a storage location in the environment, otherwise returns null. + Value *getValue(const Expr &E, SkipPast SP) const; + + /// Transfers ownership of `Loc` to the analysis context and returns a + /// reference to it. + /// + /// Requirements: + /// + /// `Loc` must not be null. + template <typename T> + std::enable_if_t<std::is_base_of<StorageLocation, T>::value, T &> + takeOwnership(std::unique_ptr<T> Loc) { + return DACtx->takeOwnership(std::move(Loc)); + } + + /// Transfers ownership of `Val` to the analysis context and returns a + /// reference to it. + /// + /// Requirements: + /// + /// `Val` must not be null. + template <typename T> + std::enable_if_t<std::is_base_of<Value, T>::value, T &> + takeOwnership(std::unique_ptr<T> Val) { + return DACtx->takeOwnership(std::move(Val)); + } + + /// Returns a symbolic boolean value that models a boolean literal equal to + /// `Value` + AtomicBoolValue &getBoolLiteralValue(bool Value) const { + return DACtx->getBoolLiteralValue(Value); + } + + /// Returns an atomic boolean value. + BoolValue &makeAtomicBoolValue() const { + return DACtx->createAtomicBoolValue(); + } + + /// Returns a unique instance of boolean Top. + BoolValue &makeTopBoolValue() const { + return DACtx->createTopBoolValue(); + } + + /// Returns a boolean value that represents the conjunction of `LHS` and + /// `RHS`. Subsequent calls with the same arguments, regardless of their + /// order, will return the same result. If the given boolean values represent + /// the same value, the result will be the value itself. + BoolValue &makeAnd(BoolValue &LHS, BoolValue &RHS) const { + return DACtx->getOrCreateConjunction(LHS, RHS); + } + + /// Returns a boolean value that represents the disjunction of `LHS` and + /// `RHS`. Subsequent calls with the same arguments, regardless of their + /// order, will return the same result. If the given boolean values represent + /// the same value, the result will be the value itself. + BoolValue &makeOr(BoolValue &LHS, BoolValue &RHS) const { + return DACtx->getOrCreateDisjunction(LHS, RHS); + } + + /// Returns a boolean value that represents the negation of `Val`. Subsequent + /// calls with the same argument will return the same result. + BoolValue &makeNot(BoolValue &Val) const { + return DACtx->getOrCreateNegation(Val); + } + + /// Returns a boolean value represents `LHS` => `RHS`. Subsequent calls with + /// the same arguments, will return the same result. If the given boolean + /// values represent the same value, the result will be a value that + /// represents the true boolean literal. + BoolValue &makeImplication(BoolValue &LHS, BoolValue &RHS) const { + return DACtx->getOrCreateImplication(LHS, RHS); + } + + /// Returns a boolean value represents `LHS` <=> `RHS`. Subsequent calls with + /// the same arguments, regardless of their order, will return the same + /// result. If the given boolean values represent the same value, the result + /// will be a value that represents the true boolean literal. + BoolValue &makeIff(BoolValue &LHS, BoolValue &RHS) const { + return DACtx->getOrCreateIff(LHS, RHS); + } + + /// Returns the token that identifies the flow condition of the environment. + AtomicBoolValue &getFlowConditionToken() const { return *FlowConditionToken; } + + /// Builds and returns the logical formula defining the flow condition + /// identified by `Token`. If a value in the formula is present as a key in + /// `Substitutions`, it will be substituted with the value it maps to. + BoolValue &buildAndSubstituteFlowCondition( + AtomicBoolValue &Token, + llvm::DenseMap<AtomicBoolValue *, BoolValue *> Substitutions) { + return DACtx->buildAndSubstituteFlowCondition(Token, + std::move(Substitutions)); + } + + /// Adds `Val` to the set of clauses that constitute the flow condition. + void addToFlowCondition(BoolValue &Val); + + /// Returns true if and only if the clauses that constitute the flow condition + /// imply that `Val` is true. + bool flowConditionImplies(BoolValue &Val) const; + + /// Returns the `DeclContext` of the block being analysed, if any. Otherwise, + /// returns null. + const DeclContext *getDeclCtx() const { return CallStack.back(); } + + /// Returns whether this `Environment` can be extended to analyze the given + /// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a + /// given `MaxDepth`. + bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const; + + /// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise, + /// returns null. + const ControlFlowContext *getControlFlowContext(const FunctionDecl *F) { + return DACtx->getControlFlowContext(F); + } + + LLVM_DUMP_METHOD void dump() const; + LLVM_DUMP_METHOD void dump(raw_ostream &OS) const; + +private: + /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise + /// return null. + /// + /// Recursively initializes storage locations and values until it sees a + /// self-referential pointer or reference type. `Visited` is used to track + /// which types appeared in the reference/pointer chain in order to avoid + /// creating a cyclic dependency with self-referential pointers/references. + /// + /// Requirements: + /// + /// `Type` must not be null. + Value *createValueUnlessSelfReferential(QualType Type, + llvm::DenseSet<QualType> &Visited, + int Depth, int &CreatedValuesCount); + + StorageLocation &skip(StorageLocation &Loc, SkipPast SP) const; + const StorageLocation &skip(const StorageLocation &Loc, SkipPast SP) const; + + /// Shared implementation of `pushCall` overloads. Note that unlike + /// `pushCall`, this member is invoked on the environment of the callee, not + /// of the caller. + void pushCallInternal(const FunctionDecl *FuncDecl, + ArrayRef<const Expr *> Args); + + /// Assigns storage locations and values to all variables in `Vars`. + void initVars(llvm::DenseSet<const VarDecl *> Vars); + + // `DACtx` is not null and not owned by this object. + DataflowAnalysisContext *DACtx; + + + // FIXME: move the fields `CallStack`, `ReturnLoc` and `ThisPointeeLoc` into a + // separate call-context object, shared between environments in the same call. + // https://github.com/llvm/llvm-project/issues/59005 + + // `DeclContext` of the block being analysed if provided. + std::vector<const DeclContext *> CallStack; + + // In a properly initialized `Environment`, `ReturnLoc` should only be null if + // its `DeclContext` could not be cast to a `FunctionDecl`. + StorageLocation *ReturnLoc = nullptr; + // The storage location of the `this` pointee. Should only be null if the + // function being analyzed is only a function and not a method. + StorageLocation *ThisPointeeLoc = nullptr; + + // Maps from program declarations and statements to storage locations that are + // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these + // include only storage locations that are in scope for a particular basic + // block. + llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc; + llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc; + + llvm::DenseMap<const StorageLocation *, Value *> LocToVal; + + // Maps locations of struct members to symbolic values of the structs that own + // them and the decls of the struct members. + llvm::DenseMap<const StorageLocation *, + std::pair<StructValue *, const ValueDecl *>> + MemberLocToStruct; + + AtomicBoolValue *FlowConditionToken; +}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowLattice.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowLattice.h new file mode 100644 index 0000000000..ebc30f6f5d --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowLattice.h @@ -0,0 +1,42 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- DataflowLattice.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines base types for building lattices to be used in dataflow +// analyses that run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWLATTICE_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWLATTICE_H + +namespace clang { +namespace dataflow { + +/// Effect indicating whether a lattice join operation resulted in a new value. +// FIXME: Rename to `LatticeEffect` since `widen` uses it as well, and we are +// likely removing it from `join`. +enum class LatticeJoinEffect { + Unchanged, + Changed, +}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWLATTICE_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowWorklist.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowWorklist.h new file mode 100644 index 0000000000..03af4fe02b --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DataflowWorklist.h @@ -0,0 +1,106 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- DataflowWorklist.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// A simple and reusable worklist for flow-sensitive analyses. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWWORKLIST_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWWORKLIST_H + +#include "clang/Analysis/Analyses/PostOrderCFGView.h" +#include "clang/Analysis/CFG.h" +#include "llvm/ADT/PriorityQueue.h" + +namespace clang { +/// A worklist implementation where the enqueued blocks will be dequeued based +/// on the order defined by 'Comp'. +template <typename Comp, unsigned QueueSize> class DataflowWorklistBase { + llvm::BitVector EnqueuedBlocks; + PostOrderCFGView *POV; + llvm::PriorityQueue<const CFGBlock *, + SmallVector<const CFGBlock *, QueueSize>, Comp> + WorkList; + +public: + DataflowWorklistBase(const CFG &Cfg, PostOrderCFGView *POV, Comp C) + : EnqueuedBlocks(Cfg.getNumBlockIDs()), POV(POV), WorkList(C) {} + + const PostOrderCFGView *getCFGView() const { return POV; } + + void enqueueBlock(const CFGBlock *Block) { + if (Block && !EnqueuedBlocks[Block->getBlockID()]) { + EnqueuedBlocks[Block->getBlockID()] = true; + WorkList.push(Block); + } + } + + const CFGBlock *dequeue() { + if (WorkList.empty()) + return nullptr; + const CFGBlock *B = WorkList.top(); + WorkList.pop(); + EnqueuedBlocks[B->getBlockID()] = false; + return B; + } +}; + +struct ReversePostOrderCompare { + PostOrderCFGView::BlockOrderCompare Cmp; + bool operator()(const CFGBlock *lhs, const CFGBlock *rhs) const { + return Cmp(rhs, lhs); + } +}; + +/// A worklist implementation for forward dataflow analysis. The enqueued +/// blocks will be dequeued in reverse post order. The worklist cannot contain +/// the same block multiple times at once. +struct ForwardDataflowWorklist + : DataflowWorklistBase<ReversePostOrderCompare, 20> { + ForwardDataflowWorklist(const CFG &Cfg, PostOrderCFGView *POV) + : DataflowWorklistBase(Cfg, POV, + ReversePostOrderCompare{POV->getComparator()}) {} + + ForwardDataflowWorklist(const CFG &Cfg, AnalysisDeclContext &Ctx) + : ForwardDataflowWorklist(Cfg, Ctx.getAnalysis<PostOrderCFGView>()) {} + + void enqueueSuccessors(const CFGBlock *Block) { + for (auto B : Block->succs()) + enqueueBlock(B); + } +}; + +/// A worklist implementation for backward dataflow analysis. The enqueued +/// block will be dequeued in post order. The worklist cannot contain the same +/// block multiple times at once. +struct BackwardDataflowWorklist + : DataflowWorklistBase<PostOrderCFGView::BlockOrderCompare, 20> { + BackwardDataflowWorklist(const CFG &Cfg, AnalysisDeclContext &Ctx) + : DataflowWorklistBase( + Cfg, Ctx.getAnalysis<PostOrderCFGView>(), + Ctx.getAnalysis<PostOrderCFGView>()->getComparator()) {} + + void enqueuePredecessors(const CFGBlock *Block) { + for (auto B : Block->preds()) + enqueueBlock(B); + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWWORKLIST_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DebugSupport.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DebugSupport.h new file mode 100644 index 0000000000..eccd18ea09 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/DebugSupport.h @@ -0,0 +1,99 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- DebugSupport.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines functions which generate more readable forms of data +// structures used in the dataflow analyses, for debugging purposes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DEBUGSUPPORT_H_ +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DEBUGSUPPORT_H_ + +#include <string> +#include <vector> + +#include "clang/Analysis/FlowSensitive/Solver.h" +#include "clang/Analysis/FlowSensitive/Value.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace dataflow { + +/// Returns a string representation of a value kind. +llvm::StringRef debugString(Value::Kind Kind); + +/// Returns a string representation of a boolean assignment to true or false. +llvm::StringRef debugString(Solver::Result::Assignment Assignment); + +/// Returns a string representation of the result status of a SAT check. +llvm::StringRef debugString(Solver::Result::Status Status); + +/// Returns a string representation for the boolean value `B`. +/// +/// Atomic booleans appearing in the boolean value `B` are assigned to labels +/// either specified in `AtomNames` or created by default rules as B0, B1, ... +/// +/// Requirements: +/// +/// Names assigned to atoms should not be repeated in `AtomNames`. +std::string debugString( + const BoolValue &B, + llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}}); + +/// Returns a string representation for `Constraints` - a collection of boolean +/// formulas. +/// +/// Atomic booleans appearing in the boolean value `Constraints` are assigned to +/// labels either specified in `AtomNames` or created by default rules as B0, +/// B1, ... +/// +/// Requirements: +/// +/// Names assigned to atoms should not be repeated in `AtomNames`. +std::string debugString( + const llvm::DenseSet<BoolValue *> &Constraints, + llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}}); + +/// Returns a string representation for `Constraints` - a collection of boolean +/// formulas and the `Result` of satisfiability checking. +/// +/// Atomic booleans appearing in `Constraints` and `Result` are assigned to +/// labels either specified in `AtomNames` or created by default rules as B0, +/// B1, ... +/// +/// Requirements: +/// +/// Names assigned to atoms should not be repeated in `AtomNames`. +std::string debugString( + ArrayRef<BoolValue *> Constraints, const Solver::Result &Result, + llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}}); +inline std::string debugString( + const llvm::DenseSet<BoolValue *> &Constraints, + const Solver::Result &Result, + llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}}) { + std::vector<BoolValue *> ConstraintsVec(Constraints.begin(), + Constraints.end()); + return debugString(ConstraintsVec, Result, std::move(AtomNames)); +} + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DEBUGSUPPORT_H_ + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/MatchSwitch.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/MatchSwitch.h new file mode 100644 index 0000000000..7a952393a4 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/MatchSwitch.h @@ -0,0 +1,192 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===---- MatchSwitch.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the `MatchSwitch` abstraction for building a "switch" +// statement, where each case of the switch is defined by an AST matcher. The +// cases are considered in order, like pattern matching in functional +// languages. +// +// Currently, the design is catered towards simplifying the implementation of +// `DataflowAnalysis` transfer functions. Based on experience here, this +// library may be generalized and moved to ASTMatchers. +// +//===----------------------------------------------------------------------===// +// +// FIXME: Rename to ASTMatchSwitch.h and update documentation when all usages of +// `MatchSwitch` are updated to `ASTMatchSwitch<Stmt>` + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_ +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_ + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Stmt.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "llvm/ADT/StringRef.h" +#include <functional> +#include <string> +#include <type_traits> +#include <utility> +#include <vector> + +namespace clang { +namespace dataflow { + +/// A common form of state shared between the cases of a transfer function. +template <typename LatticeT> struct TransferState { + TransferState(LatticeT &Lattice, Environment &Env) + : Lattice(Lattice), Env(Env) {} + + /// Current lattice element. + LatticeT &Lattice; + Environment &Env; +}; + +/// A read-only version of TransferState. +template <typename LatticeT> struct TransferStateForDiagnostics { + TransferStateForDiagnostics(const LatticeT &Lattice, const Environment &Env) + : Lattice(Lattice), Env(Env) {} + + /// Current lattice element. + const LatticeT &Lattice; + const Environment &Env; +}; + +template <typename T> +using MatchSwitchMatcher = ast_matchers::internal::Matcher<T>; + +template <typename T, typename State, typename Result = void> +using MatchSwitchAction = std::function<Result( + const T *, const ast_matchers::MatchFinder::MatchResult &, State &)>; + +template <typename BaseT, typename State, typename Result = void> +using ASTMatchSwitch = + std::function<Result(const BaseT &, ASTContext &, State &)>; + +// FIXME: Remove this alias when all usages of `MatchSwitch` are updated to +// `ASTMatchSwitch<Stmt>`. +template <typename State, typename Result = void> +using MatchSwitch = ASTMatchSwitch<Stmt, State, Result>; + +/// Collects cases of a "match switch": a collection of matchers paired with +/// callbacks, which together define a switch that can be applied to a node +/// whose type derives from `BaseT`. This structure can simplify the definition +/// of `transfer` functions that rely on pattern-matching. +/// +/// For example, consider an analysis that handles particular function calls. It +/// can define the `ASTMatchSwitch` once, in the constructor of the analysis, +/// and then reuse it each time that `transfer` is called, with a fresh state +/// value. +/// +/// \code +/// ASTMatchSwitch<Stmt, TransferState<MyLattice> BuildSwitch() { +/// return ASTMatchSwitchBuilder<TransferState<MyLattice>>() +/// .CaseOf(callExpr(callee(functionDecl(hasName("foo")))), TransferFooCall) +/// .CaseOf(callExpr(argumentCountIs(2), +/// callee(functionDecl(hasName("bar")))), +/// TransferBarCall) +/// .Build(); +/// } +/// \endcode +template <typename BaseT, typename State, typename Result = void> +class ASTMatchSwitchBuilder { +public: + /// Registers an action that will be triggered by the match of a pattern + /// against the input statement. + /// + /// Requirements: + /// + /// `NodeT` should be derived from `BaseT`. + template <typename NodeT> + ASTMatchSwitchBuilder &&CaseOf(MatchSwitchMatcher<BaseT> M, + MatchSwitchAction<NodeT, State, Result> A) && { + static_assert(std::is_base_of<BaseT, NodeT>::value, + "NodeT must be derived from BaseT."); + Matchers.push_back(std::move(M)); + Actions.push_back( + [A = std::move(A)](const BaseT *Node, + const ast_matchers::MatchFinder::MatchResult &R, + State &S) { return A(cast<NodeT>(Node), R, S); }); + return std::move(*this); + } + + ASTMatchSwitch<BaseT, State, Result> Build() && { + return [Matcher = BuildMatcher(), Actions = std::move(Actions)]( + const BaseT &Node, ASTContext &Context, State &S) -> Result { + auto Results = ast_matchers::matchDynamic(Matcher, Node, Context); + if (Results.empty()) { + return Result(); + } + // Look through the map for the first binding of the form "TagN..." use + // that to select the action. + for (const auto &Element : Results[0].getMap()) { + llvm::StringRef ID(Element.first); + size_t Index = 0; + if (ID.consume_front("Tag") && !ID.getAsInteger(10, Index) && + Index < Actions.size()) { + return Actions[Index]( + &Node, + ast_matchers::MatchFinder::MatchResult(Results[0], &Context), S); + } + } + return Result(); + }; + } + +private: + ast_matchers::internal::DynTypedMatcher BuildMatcher() { + using ast_matchers::anything; + using ast_matchers::stmt; + using ast_matchers::unless; + using ast_matchers::internal::DynTypedMatcher; + if (Matchers.empty()) + return stmt(unless(anything())); + for (int I = 0, N = Matchers.size(); I < N; ++I) { + std::string Tag = ("Tag" + llvm::Twine(I)).str(); + // Many matchers are not bindable, so ensure that tryBind will work. + Matchers[I].setAllowBind(true); + auto M = *Matchers[I].tryBind(Tag); + // Each anyOf explicitly controls the traversal kind. The anyOf itself is + // set to `TK_AsIs` to ensure no nodes are skipped, thereby deferring to + // the kind of the branches. Then, each branch is either left as is, if + // the kind is already set, or explicitly set to `TK_AsIs`. We choose this + // setting because it is the default interpretation of matchers. + Matchers[I] = + !M.getTraversalKind() ? M.withTraversalKind(TK_AsIs) : std::move(M); + } + // The matcher type on the cases ensures that `Expr` kind is compatible with + // all of the matchers. + return DynTypedMatcher::constructVariadic( + DynTypedMatcher::VO_AnyOf, ASTNodeKind::getFromNodeKind<BaseT>(), + std::move(Matchers)); + } + + std::vector<ast_matchers::internal::DynTypedMatcher> Matchers; + std::vector<MatchSwitchAction<BaseT, State, Result>> Actions; +}; + +// FIXME: Remove this alias when all usages of `MatchSwitchBuilder` are updated +// to `ASTMatchSwitchBuilder<Stmt>`. +template <typename State, typename Result = void> +using MatchSwitchBuilder = ASTMatchSwitchBuilder<Stmt, State, Result>; + +} // namespace dataflow +} // namespace clang +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_ + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Models/ChromiumCheckModel.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Models/ChromiumCheckModel.h new file mode 100644 index 0000000000..1a3646a070 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Models/ChromiumCheckModel.h @@ -0,0 +1,50 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- ChromiumCheckModel.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a dataflow model for Chromium's family of CHECK functions. +// +//===----------------------------------------------------------------------===// +#ifndef CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_CHROMIUMCHECKMODEL_H +#define CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_CHROMIUMCHECKMODEL_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Stmt.h" +#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "llvm/ADT/DenseSet.h" + +namespace clang { +namespace dataflow { + +/// Models the behavior of Chromium's CHECK, DCHECK, etc. macros, so that code +/// after a call to `*CHECK` can rely on the condition being true. +class ChromiumCheckModel : public DataflowModel { +public: + ChromiumCheckModel() = default; + bool transfer(const CFGElement *Element, Environment &Env) override; + +private: + /// Declarations for `::logging::CheckError::.*Check`, lazily initialized. + llvm::SmallDenseSet<const CXXMethodDecl *> CheckDecls; +}; + +} // namespace dataflow +} // namespace clang + +#endif // CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_CHROMIUMCHECKMODEL_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h new file mode 100644 index 0000000000..4b2e3a8a65 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h @@ -0,0 +1,99 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- UncheckedOptionalAccessModel.h --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a dataflow analysis that detects unsafe uses of optional +// values. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_UNCHECKEDOPTIONALACCESSMODEL_H +#define CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_UNCHECKEDOPTIONALACCESSMODEL_H + +#include "clang/AST/ASTContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h" +#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Analysis/FlowSensitive/NoopLattice.h" +#include "clang/Basic/SourceLocation.h" +#include <vector> + +namespace clang { +namespace dataflow { + +// FIXME: Explore using an allowlist-approach, where constructs supported by the +// analysis are always enabled and additional constructs are enabled through the +// `Options`. +struct UncheckedOptionalAccessModelOptions { + /// In generating diagnostics, ignore optionals reachable through overloaded + /// `operator*` or `operator->` (other than those of the optional type + /// itself). The analysis does not equate the results of such calls, so it + /// can't identify when their results are used safely (across calls), + /// resulting in false positives in all such cases. Note: this option does not + /// cover access through `operator[]`. + bool IgnoreSmartPointerDereference = false; +}; + +/// Dataflow analysis that models whether optionals hold values or not. +/// +/// Models the `std::optional`, `absl::optional`, and `base::Optional` types. +class UncheckedOptionalAccessModel + : public DataflowAnalysis<UncheckedOptionalAccessModel, NoopLattice> { +public: + UncheckedOptionalAccessModel(ASTContext &Ctx); + + /// Returns a matcher for the optional classes covered by this model. + static ast_matchers::DeclarationMatcher optionalClassDecl(); + + static NoopLattice initialElement() { return {}; } + + void transfer(const CFGElement *Elt, NoopLattice &L, Environment &Env); + + ComparisonResult compare(QualType Type, const Value &Val1, + const Environment &Env1, const Value &Val2, + const Environment &Env2) override; + + bool merge(QualType Type, const Value &Val1, const Environment &Env1, + const Value &Val2, const Environment &Env2, Value &MergedVal, + Environment &MergedEnv) override; + + Value *widen(QualType Type, Value &Prev, const Environment &PrevEnv, + Value &Current, Environment &CurrentEnv) override; + +private: + CFGMatchSwitch<TransferState<NoopLattice>> TransferMatchSwitch; +}; + +class UncheckedOptionalAccessDiagnoser { +public: + UncheckedOptionalAccessDiagnoser( + UncheckedOptionalAccessModelOptions Options = {}); + + std::vector<SourceLocation> diagnose(ASTContext &Ctx, const CFGElement *Elt, + const Environment &Env); + +private: + CFGMatchSwitch<const Environment, std::vector<SourceLocation>> + DiagnoseMatchSwitch; +}; + +} // namespace dataflow +} // namespace clang + +#endif // CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_UNCHECKEDOPTIONALACCESSMODEL_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/NoopAnalysis.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/NoopAnalysis.h new file mode 100644 index 0000000000..6409a11b04 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/NoopAnalysis.h @@ -0,0 +1,58 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- NoopAnalysis.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a NoopAnalysis class that just uses the builtin transfer. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOPANALYSIS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOPANALYSIS_H + +#include "clang/AST/ASTContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Analysis/FlowSensitive/NoopLattice.h" + +namespace clang { +namespace dataflow { + +class NoopAnalysis : public DataflowAnalysis<NoopAnalysis, NoopLattice> { +public: + /// Deprecated. Use the `DataflowAnalysisOptions` constructor instead. + NoopAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer) + : DataflowAnalysis<NoopAnalysis, NoopLattice>(Context, + ApplyBuiltinTransfer) {} + + /// `ApplyBuiltinTransfer` controls whether to run the built-in transfer + /// functions that model memory during the analysis. Their results are not + /// used by `NoopAnalysis`, but tests that need to inspect the environment + /// should enable them. + NoopAnalysis(ASTContext &Context, DataflowAnalysisOptions Options) + : DataflowAnalysis<NoopAnalysis, NoopLattice>(Context, Options) {} + + static NoopLattice initialElement() { return {}; } + + void transfer(const CFGElement *E, NoopLattice &L, Environment &Env) {} +}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOPANALYSIS_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/NoopLattice.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/NoopLattice.h new file mode 100644 index 0000000000..eab7fe9f72 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/NoopLattice.h @@ -0,0 +1,52 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- NoopLattice.h -------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the lattice with exactly one element. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOP_LATTICE_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOP_LATTICE_H + +#include "clang/Analysis/FlowSensitive/DataflowLattice.h" +#include <ostream> + +namespace clang { +namespace dataflow { + +/// Trivial lattice for dataflow analysis with exactly one element. +/// +/// Useful for analyses that only need the Environment and nothing more. +class NoopLattice { +public: + bool operator==(const NoopLattice &Other) const { return true; } + + LatticeJoinEffect join(const NoopLattice &Other) { + return LatticeJoinEffect::Unchanged; + } +}; + +inline std::ostream &operator<<(std::ostream &OS, const NoopLattice &) { + return OS << "noop"; +} + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOP_LATTICE_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Solver.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Solver.h new file mode 100644 index 0000000000..f6b915581c --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Solver.h @@ -0,0 +1,107 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- Solver.h -------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines an interface for a SAT solver that can be used by +// dataflow analyses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SOLVER_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SOLVER_H + +#include "clang/Analysis/FlowSensitive/Value.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include <optional> + +namespace clang { +namespace dataflow { + +/// An interface for a SAT solver that can be used by dataflow analyses. +class Solver { +public: + struct Result { + enum class Status { + /// Indicates that there exists a satisfying assignment for a boolean + /// formula. + Satisfiable, + + /// Indicates that there is no satisfying assignment for a boolean + /// formula. + Unsatisfiable, + + /// Indicates that the solver gave up trying to find a satisfying + /// assignment for a boolean formula. + TimedOut, + }; + + /// A boolean value is set to true or false in a truth assignment. + enum class Assignment : uint8_t { AssignedFalse = 0, AssignedTrue = 1 }; + + /// Constructs a result indicating that the queried boolean formula is + /// satisfiable. The result will hold a solution found by the solver. + static Result + Satisfiable(llvm::DenseMap<AtomicBoolValue *, Assignment> Solution) { + return Result(Status::Satisfiable, std::move(Solution)); + } + + /// Constructs a result indicating that the queried boolean formula is + /// unsatisfiable. + static Result Unsatisfiable() { return Result(Status::Unsatisfiable, {}); } + + /// Constructs a result indicating that satisfiability checking on the + /// queried boolean formula was not completed. + static Result TimedOut() { return Result(Status::TimedOut, {}); } + + /// Returns the status of satisfiability checking on the queried boolean + /// formula. + Status getStatus() const { return SATCheckStatus; } + + /// Returns a truth assignment to boolean values that satisfies the queried + /// boolean formula if available. Otherwise, an empty optional is returned. + std::optional<llvm::DenseMap<AtomicBoolValue *, Assignment>> + getSolution() const { + return Solution; + } + + private: + Result( + enum Status SATCheckStatus, + std::optional<llvm::DenseMap<AtomicBoolValue *, Assignment>> Solution) + : SATCheckStatus(SATCheckStatus), Solution(std::move(Solution)) {} + + Status SATCheckStatus; + std::optional<llvm::DenseMap<AtomicBoolValue *, Assignment>> Solution; + }; + + virtual ~Solver() = default; + + /// Checks if the conjunction of `Vals` is satisfiable and returns the + /// corresponding result. + /// + /// Requirements: + /// + /// All elements in `Vals` must not be null. + virtual Result solve(llvm::DenseSet<BoolValue *> Vals) = 0; +}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SOLVER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/StorageLocation.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/StorageLocation.h new file mode 100644 index 0000000000..86d075c8bd --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/StorageLocation.h @@ -0,0 +1,111 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- StorageLocation.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines classes that represent elements of the local variable store +// and of the heap during dataflow analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_STORAGELOCATION_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_STORAGELOCATION_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { +namespace dataflow { + +/// Base class for elements of the local variable store and of the heap. +/// +/// Each storage location holds a value. The mapping from storage locations to +/// values is stored in the environment. +class StorageLocation { +public: + enum class Kind { Scalar, Aggregate }; + + StorageLocation(Kind LocKind, QualType Type) : LocKind(LocKind), Type(Type) {} + + // Non-copyable because addresses of storage locations are used as their + // identities throughout framework and user code. The framework is responsible + // for construction and destruction of storage locations. + StorageLocation(const StorageLocation &) = delete; + StorageLocation &operator=(const StorageLocation &) = delete; + + virtual ~StorageLocation() = default; + + Kind getKind() const { return LocKind; } + + QualType getType() const { return Type; } + +private: + Kind LocKind; + QualType Type; +}; + +/// A storage location that is not subdivided further for the purposes of +/// abstract interpretation. For example: `int`, `int*`, `int&`. +class ScalarStorageLocation final : public StorageLocation { +public: + explicit ScalarStorageLocation(QualType Type) + : StorageLocation(Kind::Scalar, Type) {} + + static bool classof(const StorageLocation *Loc) { + return Loc->getKind() == Kind::Scalar; + } +}; + +/// A storage location which is subdivided into smaller storage locations that +/// can be traced independently by abstract interpretation. For example: a +/// struct with public members. The child map is flat, so when used for a struct +/// or class type, all accessible members of base struct and class types are +/// directly accesible as children of this location. +/// FIXME: Currently, the storage location of unions is modelled the same way as +/// that of structs or classes. Eventually, we need to change this modelling so +/// that all of the members of a given union have the same storage location. +class AggregateStorageLocation final : public StorageLocation { +public: + explicit AggregateStorageLocation(QualType Type) + : AggregateStorageLocation( + Type, llvm::DenseMap<const ValueDecl *, StorageLocation *>()) {} + + AggregateStorageLocation( + QualType Type, + llvm::DenseMap<const ValueDecl *, StorageLocation *> Children) + : StorageLocation(Kind::Aggregate, Type), Children(std::move(Children)) {} + + static bool classof(const StorageLocation *Loc) { + return Loc->getKind() == Kind::Aggregate; + } + + /// Returns the child storage location for `D`. + StorageLocation &getChild(const ValueDecl &D) const { + auto It = Children.find(&D); + assert(It != Children.end()); + return *It->second; + } + +private: + llvm::DenseMap<const ValueDecl *, StorageLocation *> Children; +}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_STORAGELOCATION_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Transfer.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Transfer.h new file mode 100644 index 0000000000..5d453fce86 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Transfer.h @@ -0,0 +1,56 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- Transfer.h ----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a transfer function that evaluates a program statement and +// updates an environment accordingly. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_TRANSFER_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_TRANSFER_H + +#include "clang/AST/Stmt.h" +#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" + +namespace clang { +namespace dataflow { + +/// Maps statements to the environments of basic blocks that contain them. +class StmtToEnvMap { +public: + virtual ~StmtToEnvMap() = default; + + /// Returns the environment of the basic block that contains `S` or nullptr if + /// there isn't one. + /// FIXME: Ensure that the result can't be null and return a const reference. + virtual const Environment *getEnvironment(const Stmt &S) const = 0; +}; + +/// Evaluates `S` and updates `Env` accordingly. +/// +/// Requirements: +/// +/// `S` must not be `ParenExpr` or `ExprWithCleanups`. +void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env); + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_TRANSFER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h new file mode 100644 index 0000000000..85569e9095 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h @@ -0,0 +1,177 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- TypeErasedDataflowAnalysis.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines type-erased base types and functions for building dataflow +// analyses that run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_TYPEERASEDDATAFLOWANALYSIS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_TYPEERASEDDATAFLOWANALYSIS_H + +#include <optional> +#include <utility> +#include <vector> + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Stmt.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" +#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Analysis/FlowSensitive/DataflowLattice.h" +#include "llvm/ADT/Any.h" +#include "llvm/Support/Error.h" + +namespace clang { +namespace dataflow { + +struct DataflowAnalysisOptions { + /// Options for the built-in model, or empty to not apply them. + // FIXME: Remove this option once the framework supports composing analyses + // (at which point the built-in transfer functions can be simply a standalone + // analysis). + std::optional<DataflowAnalysisContext::Options> BuiltinOpts = + DataflowAnalysisContext::Options{}; +}; + +/// Type-erased lattice element container. +/// +/// Requirements: +/// +/// The type of the object stored in the container must be a bounded +/// join-semilattice. +struct TypeErasedLattice { + llvm::Any Value; +}; + +/// Type-erased base class for dataflow analyses built on a single lattice type. +class TypeErasedDataflowAnalysis : public Environment::ValueModel { + DataflowAnalysisOptions Options; + +public: + TypeErasedDataflowAnalysis() : Options({}) {} + + TypeErasedDataflowAnalysis(DataflowAnalysisOptions Options) + : Options(Options) {} + + virtual ~TypeErasedDataflowAnalysis() {} + + /// Returns the `ASTContext` that is used by the analysis. + virtual ASTContext &getASTContext() = 0; + + /// Returns a type-erased lattice element that models the initial state of a + /// basic block. + virtual TypeErasedLattice typeErasedInitialElement() = 0; + + /// Joins two type-erased lattice elements by computing their least upper + /// bound. Places the join result in the left element and returns an effect + /// indicating whether any changes were made to it. + virtual LatticeJoinEffect joinTypeErased(TypeErasedLattice &, + const TypeErasedLattice &) = 0; + + /// Chooses a lattice element that approximates the current element at a + /// program point, given the previous element at that point. Places the + /// widened result in the current element (`Current`). Widening is optional -- + /// it is only needed to either accelerate convergence (for lattices with + /// non-trivial height) or guarantee convergence (for lattices with infinite + /// height). + /// + /// Returns an indication of whether any changes were made to `Current` in + /// order to widen. This saves a separate call to `isEqualTypeErased` after + /// the widening. + virtual LatticeJoinEffect + widenTypeErased(TypeErasedLattice &Current, + const TypeErasedLattice &Previous) = 0; + + /// Returns true if and only if the two given type-erased lattice elements are + /// equal. + virtual bool isEqualTypeErased(const TypeErasedLattice &, + const TypeErasedLattice &) = 0; + + /// Applies the analysis transfer function for a given control flow graph + /// element and type-erased lattice element. + virtual void transferTypeErased(const CFGElement *, TypeErasedLattice &, + Environment &) = 0; + + /// Applies the analysis transfer function for a given edge from a CFG block + /// of a conditional statement. + /// @param Stmt The condition which is responsible for the split in the CFG. + /// @param Branch True if the edge goes to the basic block where the + /// condition is true. + virtual void transferBranchTypeErased(bool Branch, const Stmt *, + TypeErasedLattice &, Environment &) = 0; + + /// If the built-in model is enabled, returns the options to be passed to + /// them. Otherwise returns empty. + const std::optional<DataflowAnalysisContext::Options> & + builtinOptions() const { + return Options.BuiltinOpts; + } +}; + +/// Type-erased model of the program at a given program point. +struct TypeErasedDataflowAnalysisState { + /// Type-erased model of a program property. + TypeErasedLattice Lattice; + + /// Model of the state of the program (store and heap). + Environment Env; + + TypeErasedDataflowAnalysisState(TypeErasedLattice Lattice, Environment Env) + : Lattice(std::move(Lattice)), Env(std::move(Env)) {} +}; + +/// Transfers the state of a basic block by evaluating each of its elements in +/// the context of `Analysis` and the states of its predecessors that are +/// available in `BlockStates`. `PostVisitCFG` (if provided) will be applied to +/// each element in the block, after it is evaluated. +/// +/// Requirements: +/// +/// All predecessors of `Block` except those with loop back edges must have +/// already been transferred. States in `BlockStates` that are set to +/// `std::nullopt` represent basic blocks that are not evaluated yet. +TypeErasedDataflowAnalysisState transferBlock( + const ControlFlowContext &CFCtx, + llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>> BlockStates, + const CFGBlock &Block, const Environment &InitEnv, + TypeErasedDataflowAnalysis &Analysis, + std::function<void(const CFGElement &, + const TypeErasedDataflowAnalysisState &)> + PostVisitCFG = nullptr); + +/// Performs dataflow analysis and returns a mapping from basic block IDs to +/// dataflow analysis states that model the respective basic blocks. Indices of +/// the returned vector correspond to basic block IDs. Returns an error if the +/// dataflow analysis cannot be performed successfully. Otherwise, calls +/// `PostVisitCFG` on each CFG element with the final analysis results at that +/// program point. +llvm::Expected<std::vector<std::optional<TypeErasedDataflowAnalysisState>>> +runTypeErasedDataflowAnalysis( + const ControlFlowContext &CFCtx, TypeErasedDataflowAnalysis &Analysis, + const Environment &InitEnv, + std::function<void(const CFGElement &, + const TypeErasedDataflowAnalysisState &)> + PostVisitCFG = nullptr); + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_TYPEERASEDDATAFLOWANALYSIS_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Value.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Value.h new file mode 100644 index 0000000000..c8af7fe16e --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Value.h @@ -0,0 +1,330 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- Value.h -------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines classes for values computed by abstract interpretation +// during dataflow analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_VALUE_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_VALUE_H + +#include "clang/AST/Decl.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <utility> + +namespace clang { +namespace dataflow { + +/// Base class for all values computed by abstract interpretation. +/// +/// Don't use `Value` instances by value. All `Value` instances are allocated +/// and owned by `DataflowAnalysisContext`. +class Value { +public: + enum class Kind { + Integer, + Reference, + Pointer, + Struct, + + // Synthetic boolean values are either atomic values or logical connectives. + TopBool, + AtomicBool, + Conjunction, + Disjunction, + Negation, + Implication, + Biconditional, + }; + + explicit Value(Kind ValKind) : ValKind(ValKind) {} + + // Non-copyable because addresses of values are used as their identities + // throughout framework and user code. The framework is responsible for + // construction and destruction of values. + Value(const Value &) = delete; + Value &operator=(const Value &) = delete; + + virtual ~Value() = default; + + Kind getKind() const { return ValKind; } + + /// Returns the value of the synthetic property with the given `Name` or null + /// if the property isn't assigned a value. + Value *getProperty(llvm::StringRef Name) const { + auto It = Properties.find(Name); + return It == Properties.end() ? nullptr : It->second; + } + + /// Assigns `Val` as the value of the synthetic property with the given + /// `Name`. + void setProperty(llvm::StringRef Name, Value &Val) { + Properties.insert_or_assign(Name, &Val); + } + +private: + Kind ValKind; + llvm::StringMap<Value *> Properties; +}; + +/// An equivalence relation for values. It obeys reflexivity, symmetry and +/// transitivity. It does *not* include comparison of `Properties`. +/// +/// Computes equivalence for these subclasses: +/// * ReferenceValue, PointerValue -- pointee locations are equal. Does not +/// compute deep equality of `Value` at said location. +/// * TopBoolValue -- both are `TopBoolValue`s. +/// +/// Otherwise, falls back to pointer equality. +bool areEquivalentValues(const Value &Val1, const Value &Val2); + +/// Models a boolean. +class BoolValue : public Value { +public: + explicit BoolValue(Kind ValueKind) : Value(ValueKind) {} + + static bool classof(const Value *Val) { + return Val->getKind() == Kind::TopBool || + Val->getKind() == Kind::AtomicBool || + Val->getKind() == Kind::Conjunction || + Val->getKind() == Kind::Disjunction || + Val->getKind() == Kind::Negation || + Val->getKind() == Kind::Implication || + Val->getKind() == Kind::Biconditional; + } +}; + +/// Models the trivially true formula, which is Top in the lattice of boolean +/// formulas. +class TopBoolValue final : public BoolValue { +public: + TopBoolValue() : BoolValue(Kind::TopBool) {} + + static bool classof(const Value *Val) { + return Val->getKind() == Kind::TopBool; + } +}; + +/// Models an atomic boolean. +class AtomicBoolValue : public BoolValue { +public: + explicit AtomicBoolValue() : BoolValue(Kind::AtomicBool) {} + + static bool classof(const Value *Val) { + return Val->getKind() == Kind::AtomicBool; + } +}; + +/// Models a boolean conjunction. +// FIXME: Consider representing binary and unary boolean operations similar +// to how they are represented in the AST. This might become more pressing +// when such operations need to be added for other data types. +class ConjunctionValue : public BoolValue { +public: + explicit ConjunctionValue(BoolValue &LeftSubVal, BoolValue &RightSubVal) + : BoolValue(Kind::Conjunction), LeftSubVal(LeftSubVal), + RightSubVal(RightSubVal) {} + + static bool classof(const Value *Val) { + return Val->getKind() == Kind::Conjunction; + } + + /// Returns the left sub-value of the conjunction. + BoolValue &getLeftSubValue() const { return LeftSubVal; } + + /// Returns the right sub-value of the conjunction. + BoolValue &getRightSubValue() const { return RightSubVal; } + +private: + BoolValue &LeftSubVal; + BoolValue &RightSubVal; +}; + +/// Models a boolean disjunction. +class DisjunctionValue : public BoolValue { +public: + explicit DisjunctionValue(BoolValue &LeftSubVal, BoolValue &RightSubVal) + : BoolValue(Kind::Disjunction), LeftSubVal(LeftSubVal), + RightSubVal(RightSubVal) {} + + static bool classof(const Value *Val) { + return Val->getKind() == Kind::Disjunction; + } + + /// Returns the left sub-value of the disjunction. + BoolValue &getLeftSubValue() const { return LeftSubVal; } + + /// Returns the right sub-value of the disjunction. + BoolValue &getRightSubValue() const { return RightSubVal; } + +private: + BoolValue &LeftSubVal; + BoolValue &RightSubVal; +}; + +/// Models a boolean negation. +class NegationValue : public BoolValue { +public: + explicit NegationValue(BoolValue &SubVal) + : BoolValue(Kind::Negation), SubVal(SubVal) {} + + static bool classof(const Value *Val) { + return Val->getKind() == Kind::Negation; + } + + /// Returns the sub-value of the negation. + BoolValue &getSubVal() const { return SubVal; } + +private: + BoolValue &SubVal; +}; + +/// Models a boolean implication. +/// +/// Equivalent to `!LHS v RHS`. +class ImplicationValue : public BoolValue { +public: + explicit ImplicationValue(BoolValue &LeftSubVal, BoolValue &RightSubVal) + : BoolValue(Kind::Implication), LeftSubVal(LeftSubVal), + RightSubVal(RightSubVal) {} + + static bool classof(const Value *Val) { + return Val->getKind() == Kind::Implication; + } + + /// Returns the left sub-value of the implication. + BoolValue &getLeftSubValue() const { return LeftSubVal; } + + /// Returns the right sub-value of the implication. + BoolValue &getRightSubValue() const { return RightSubVal; } + +private: + BoolValue &LeftSubVal; + BoolValue &RightSubVal; +}; + +/// Models a boolean biconditional. +/// +/// Equivalent to `(LHS ^ RHS) v (!LHS ^ !RHS)`. +class BiconditionalValue : public BoolValue { +public: + explicit BiconditionalValue(BoolValue &LeftSubVal, BoolValue &RightSubVal) + : BoolValue(Kind::Biconditional), LeftSubVal(LeftSubVal), + RightSubVal(RightSubVal) {} + + static bool classof(const Value *Val) { + return Val->getKind() == Kind::Biconditional; + } + + /// Returns the left sub-value of the biconditional. + BoolValue &getLeftSubValue() const { return LeftSubVal; } + + /// Returns the right sub-value of the biconditional. + BoolValue &getRightSubValue() const { return RightSubVal; } + +private: + BoolValue &LeftSubVal; + BoolValue &RightSubVal; +}; + +/// Models an integer. +class IntegerValue : public Value { +public: + explicit IntegerValue() : Value(Kind::Integer) {} + + static bool classof(const Value *Val) { + return Val->getKind() == Kind::Integer; + } +}; + +/// Models a dereferenced pointer. For example, a reference in C++ or an lvalue +/// in C. +class ReferenceValue final : public Value { +public: + explicit ReferenceValue(StorageLocation &ReferentLoc) + : Value(Kind::Reference), ReferentLoc(ReferentLoc) {} + + static bool classof(const Value *Val) { + return Val->getKind() == Kind::Reference; + } + + StorageLocation &getReferentLoc() const { return ReferentLoc; } + +private: + StorageLocation &ReferentLoc; +}; + +/// Models a symbolic pointer. Specifically, any value of type `T*`. +class PointerValue final : public Value { +public: + explicit PointerValue(StorageLocation &PointeeLoc) + : Value(Kind::Pointer), PointeeLoc(PointeeLoc) {} + + static bool classof(const Value *Val) { + return Val->getKind() == Kind::Pointer; + } + + StorageLocation &getPointeeLoc() const { return PointeeLoc; } + +private: + StorageLocation &PointeeLoc; +}; + +/// Models a value of `struct` or `class` type, with a flat map of fields to +/// child storage locations, containing all accessible members of base struct +/// and class types. +class StructValue final : public Value { +public: + StructValue() : StructValue(llvm::DenseMap<const ValueDecl *, Value *>()) {} + + explicit StructValue(llvm::DenseMap<const ValueDecl *, Value *> Children) + : Value(Kind::Struct), Children(std::move(Children)) {} + + static bool classof(const Value *Val) { + return Val->getKind() == Kind::Struct; + } + + /// Returns the child value that is assigned for `D` or null if the child is + /// not initialized. + Value *getChild(const ValueDecl &D) const { + auto It = Children.find(&D); + if (It == Children.end()) + return nullptr; + return It->second; + } + + /// Assigns `Val` as the child value for `D`. + void setChild(const ValueDecl &D, Value &Val) { Children[&D] = &Val; } + +private: + llvm::DenseMap<const ValueDecl *, Value *> Children; +}; + +raw_ostream &operator<<(raw_ostream &OS, const Value &Val); + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_VALUE_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h new file mode 100644 index 0000000000..b491e55bb9 --- /dev/null +++ b/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h @@ -0,0 +1,48 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- WatchedLiteralsSolver.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a SAT solver implementation that can be used by dataflow +// analyses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_WATCHEDLITERALSSOLVER_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_WATCHEDLITERALSSOLVER_H + +#include "clang/Analysis/FlowSensitive/Solver.h" +#include "clang/Analysis/FlowSensitive/Value.h" +#include "llvm/ADT/DenseSet.h" + +namespace clang { +namespace dataflow { + +/// A SAT solver that is an implementation of Algorithm D from Knuth's The Art +/// of Computer Programming Volume 4: Satisfiability, Fascicle 6. It is based on +/// the Davis-Putnam-Logemann-Loveland (DPLL) algorithm, keeps references to a +/// single "watched" literal per clause, and uses a set of "active" variables +/// for unit propagation. +class WatchedLiteralsSolver : public Solver { +public: + Result solve(llvm::DenseSet<BoolValue *> Vals) override; +}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_WATCHEDLITERALSSOLVER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif |