Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Analysis/FlowSensitive/Arena.h
Line
Count
Source
1
//===-- Arena.h -------------------------------*- C++ -------------------*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE__ARENA_H
9
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE__ARENA_H
10
11
#include "clang/Analysis/FlowSensitive/Formula.h"
12
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
13
#include "clang/Analysis/FlowSensitive/Value.h"
14
#include "llvm/ADT/StringRef.h"
15
#include <vector>
16
17
namespace clang::dataflow {
18
19
/// The Arena owns the objects that model data within an analysis.
20
/// For example, `Value`, `StorageLocation`, `Atom`, and `Formula`.
21
class Arena {
22
public:
23
658
  Arena() : True(makeAtom()), False(makeAtom()) {}
24
  Arena(const Arena &) = delete;
25
  Arena &operator=(const Arena &) = delete;
26
27
  /// Creates a `T` (some subclass of `StorageLocation`), forwarding `args` to
28
  /// the constructor, and returns a reference to it.
29
  ///
30
  /// The `DataflowAnalysisContext` takes ownership of the created object. The
31
  /// object will be destroyed when the `DataflowAnalysisContext` is destroyed.
32
  template <typename T, typename... Args>
33
  std::enable_if_t<std::is_base_of<StorageLocation, T>::value, T &>
34
5.13k
  create(Args &&...args) {
35
    // Note: If allocation of individual `StorageLocation`s turns out to be
36
    // costly, consider creating specializations of `create<T>` for commonly
37
    // used `StorageLocation` subclasses and make them use a `BumpPtrAllocator`.
38
5.13k
    return *cast<T>(
39
5.13k
        Locs.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
40
5.13k
            .get());
41
5.13k
  }
std::__1::enable_if<std::is_base_of<clang::dataflow::StorageLocation, clang::dataflow::RecordStorageLocation>::value, clang::dataflow::RecordStorageLocation&>::type clang::dataflow::Arena::create<clang::dataflow::RecordStorageLocation, clang::QualType&, llvm::DenseMap<clang::ValueDecl const*, clang::dataflow::StorageLocation*, llvm::DenseMapInfo<clang::ValueDecl const*, void>, llvm::detail::DenseMapPair<clang::ValueDecl const*, clang::dataflow::StorageLocation*> > >(clang::QualType&, llvm::DenseMap<clang::ValueDecl const*, clang::dataflow::StorageLocation*, llvm::DenseMapInfo<clang::ValueDecl const*, void>, llvm::detail::DenseMapPair<clang::ValueDecl const*, clang::dataflow::StorageLocation*> >&&)
Line
Count
Source
34
2.47k
  create(Args &&...args) {
35
    // Note: If allocation of individual `StorageLocation`s turns out to be
36
    // costly, consider creating specializations of `create<T>` for commonly
37
    // used `StorageLocation` subclasses and make them use a `BumpPtrAllocator`.
38
2.47k
    return *cast<T>(
39
2.47k
        Locs.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
40
2.47k
            .get());
41
2.47k
  }
std::__1::enable_if<std::is_base_of<clang::dataflow::StorageLocation, clang::dataflow::ScalarStorageLocation>::value, clang::dataflow::ScalarStorageLocation&>::type clang::dataflow::Arena::create<clang::dataflow::ScalarStorageLocation, clang::QualType&>(clang::QualType&)
Line
Count
Source
34
2.65k
  create(Args &&...args) {
35
    // Note: If allocation of individual `StorageLocation`s turns out to be
36
    // costly, consider creating specializations of `create<T>` for commonly
37
    // used `StorageLocation` subclasses and make them use a `BumpPtrAllocator`.
38
2.65k
    return *cast<T>(
39
2.65k
        Locs.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
40
2.65k
            .get());
41
2.65k
  }
42
43
  /// Creates a `T` (some subclass of `Value`), forwarding `args` to the
44
  /// constructor, and returns a reference to it.
45
  ///
46
  /// The `DataflowAnalysisContext` takes ownership of the created object. The
47
  /// object will be destroyed when the `DataflowAnalysisContext` is destroyed.
48
  template <typename T, typename... Args>
49
  std::enable_if_t<std::is_base_of<Value, T>::value, T &>
50
11.0k
  create(Args &&...args) {
51
    // Note: If allocation of individual `Value`s turns out to be costly,
52
    // consider creating specializations of `create<T>` for commonly used
53
    // `Value` subclasses and make them use a `BumpPtrAllocator`.
54
11.0k
    return *cast<T>(
55
11.0k
        Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
56
11.0k
            .get());
57
11.0k
  }
std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::IntegerValue>::value, clang::dataflow::IntegerValue&>::type clang::dataflow::Arena::create<clang::dataflow::IntegerValue>()
Line
Count
Source
50
1.63k
  create(Args &&...args) {
51
    // Note: If allocation of individual `Value`s turns out to be costly,
52
    // consider creating specializations of `create<T>` for commonly used
53
    // `Value` subclasses and make them use a `BumpPtrAllocator`.
54
1.63k
    return *cast<T>(
55
1.63k
        Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
56
1.63k
            .get());
57
1.63k
  }
std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::AtomicBoolValue>::value, clang::dataflow::AtomicBoolValue&>::type clang::dataflow::Arena::create<clang::dataflow::AtomicBoolValue, clang::dataflow::Formula const&>(clang::dataflow::Formula const&)
Line
Count
Source
50
2.03k
  create(Args &&...args) {
51
    // Note: If allocation of individual `Value`s turns out to be costly,
52
    // consider creating specializations of `create<T>` for commonly used
53
    // `Value` subclasses and make them use a `BumpPtrAllocator`.
54
2.03k
    return *cast<T>(
55
2.03k
        Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
56
2.03k
            .get());
57
2.03k
  }
std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::FormulaBoolValue>::value, clang::dataflow::FormulaBoolValue&>::type clang::dataflow::Arena::create<clang::dataflow::FormulaBoolValue, clang::dataflow::Formula const&>(clang::dataflow::Formula const&)
Line
Count
Source
50
708
  create(Args &&...args) {
51
    // Note: If allocation of individual `Value`s turns out to be costly,
52
    // consider creating specializations of `create<T>` for commonly used
53
    // `Value` subclasses and make them use a `BumpPtrAllocator`.
54
708
    return *cast<T>(
55
708
        Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
56
708
            .get());
57
708
  }
std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::TopBoolValue>::value, clang::dataflow::TopBoolValue&>::type clang::dataflow::Arena::create<clang::dataflow::TopBoolValue, clang::dataflow::Formula const&>(clang::dataflow::Formula const&)
Line
Count
Source
50
49
  create(Args &&...args) {
51
    // Note: If allocation of individual `Value`s turns out to be costly,
52
    // consider creating specializations of `create<T>` for commonly used
53
    // `Value` subclasses and make them use a `BumpPtrAllocator`.
54
49
    return *cast<T>(
55
49
        Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
56
49
            .get());
57
49
  }
std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::PointerValue>::value, clang::dataflow::PointerValue&>::type clang::dataflow::Arena::create<clang::dataflow::PointerValue, clang::dataflow::StorageLocation&>(clang::dataflow::StorageLocation&)
Line
Count
Source
50
2.05k
  create(Args &&...args) {
51
    // Note: If allocation of individual `Value`s turns out to be costly,
52
    // consider creating specializations of `create<T>` for commonly used
53
    // `Value` subclasses and make them use a `BumpPtrAllocator`.
54
2.05k
    return *cast<T>(
55
2.05k
        Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
56
2.05k
            .get());
57
2.05k
  }
std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::RecordValue>::value, clang::dataflow::RecordValue&>::type clang::dataflow::Arena::create<clang::dataflow::RecordValue, clang::dataflow::RecordStorageLocation&>(clang::dataflow::RecordStorageLocation&)
Line
Count
Source
50
4.49k
  create(Args &&...args) {
51
    // Note: If allocation of individual `Value`s turns out to be costly,
52
    // consider creating specializations of `create<T>` for commonly used
53
    // `Value` subclasses and make them use a `BumpPtrAllocator`.
54
4.49k
    return *cast<T>(
55
4.49k
        Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
56
4.49k
            .get());
57
4.49k
  }
std::__1::enable_if<std::is_base_of<clang::dataflow::Value, clang::dataflow::PointerValue>::value, clang::dataflow::PointerValue&>::type clang::dataflow::Arena::create<clang::dataflow::PointerValue, clang::dataflow::RecordStorageLocation&>(clang::dataflow::RecordStorageLocation&)
Line
Count
Source
50
58
  create(Args &&...args) {
51
    // Note: If allocation of individual `Value`s turns out to be costly,
52
    // consider creating specializations of `create<T>` for commonly used
53
    // `Value` subclasses and make them use a `BumpPtrAllocator`.
54
58
    return *cast<T>(
55
58
        Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
56
58
            .get());
57
58
  }
58
59
  /// Creates a BoolValue wrapping a particular formula.
60
  ///
61
  /// Passing in the same formula will result in the same BoolValue.
62
  /// FIXME: Interning BoolValues but not other Values is inconsistent.
63
  ///        Decide whether we want Value interning or not.
64
  BoolValue &makeBoolValue(const Formula &);
65
66
  /// Creates a fresh atom and wraps in in an AtomicBoolValue.
67
  /// FIXME: For now, identical-address AtomicBoolValue <=> identical atom.
68
  ///        Stop relying on pointer identity and remove this guarantee.
69
1.52k
  AtomicBoolValue &makeAtomValue() {
70
1.52k
    return cast<AtomicBoolValue>(makeBoolValue(makeAtomRef(makeAtom())));
71
1.52k
  }
72
73
  /// Creates a fresh Top boolean value.
74
49
  TopBoolValue &makeTopValue() {
75
    // No need for deduplicating: there's no way to create aliasing Tops.
76
49
    return create<TopBoolValue>(makeAtomRef(makeAtom()));
77
49
  }
78
79
  /// Returns a symbolic integer value that models an integer literal equal to
80
  /// `Value`. These literals are the same every time.
81
  /// Integer literals are not typed; the type is determined by the `Expr` that
82
  /// an integer literal is associated with.
83
  IntegerValue &makeIntLiteral(llvm::APInt Value);
84
85
  // Factories for boolean formulas.
86
  // Formulas are interned: passing the same arguments return the same result.
87
  // For commutative operations like And/Or, interning ignores order.
88
  // Simplifications are applied: makeOr(X, X) => X, etc.
89
90
  /// Returns a formula for the conjunction of `LHS` and `RHS`.
91
  const Formula &makeAnd(const Formula &LHS, const Formula &RHS);
92
93
  /// Returns a formula for the disjunction of `LHS` and `RHS`.
94
  const Formula &makeOr(const Formula &LHS, const Formula &RHS);
95
96
  /// Returns a formula for the negation of `Val`.
97
  const Formula &makeNot(const Formula &Val);
98
99
  /// Returns a formula for `LHS => RHS`.
100
  const Formula &makeImplies(const Formula &LHS, const Formula &RHS);
101
102
  /// Returns a formula for `LHS <=> RHS`.
103
  const Formula &makeEquals(const Formula &LHS, const Formula &RHS);
104
105
  /// Returns a formula for the variable A.
106
  const Formula &makeAtomRef(Atom A);
107
108
  /// Returns a formula for a literal true/false.
109
3.74k
  const Formula &makeLiteral(bool Value) {
110
3.74k
    return makeAtomRef(Value ? 
True1.90k
:
False1.84k
);
111
3.74k
  }
112
113
  // Parses a formula from its textual representation.
114
  // This may refer to atoms that were not produced by makeAtom() yet!
115
  llvm::Expected<const Formula &> parseFormula(llvm::StringRef);
116
117
  /// Returns a new atomic boolean variable, distinct from any other.
118
11.7k
  Atom makeAtom() { return static_cast<Atom>(NextAtom++); };
119
120
  /// Creates a fresh flow condition and returns a token that identifies it. The
121
  /// token can be used to perform various operations on the flow condition such
122
  /// as adding constraints to it, forking it, joining it with another flow
123
  /// condition, or checking implications.
124
8.70k
  Atom makeFlowConditionToken() { return makeAtom(); }
125
126
private:
127
  llvm::BumpPtrAllocator Alloc;
128
129
  // Storage for the state of a program.
130
  std::vector<std::unique_ptr<StorageLocation>> Locs;
131
  std::vector<std::unique_ptr<Value>> Vals;
132
133
  // Indices that are used to avoid recreating the same integer literals and
134
  // composite boolean values.
135
  llvm::DenseMap<llvm::APInt, IntegerValue *> IntegerLiterals;
136
  using FormulaPair = std::pair<const Formula *, const Formula *>;
137
  llvm::DenseMap<FormulaPair, const Formula *> Ands;
138
  llvm::DenseMap<FormulaPair, const Formula *> Ors;
139
  llvm::DenseMap<const Formula *, const Formula *> Nots;
140
  llvm::DenseMap<FormulaPair, const Formula *> Implies;
141
  llvm::DenseMap<FormulaPair, const Formula *> Equals;
142
  llvm::DenseMap<Atom, const Formula *> AtomRefs;
143
144
  llvm::DenseMap<const Formula *, BoolValue *> FormulaValues;
145
  unsigned NextAtom = 0;
146
147
  Atom True, False;
148
};
149
150
} // namespace clang::dataflow
151
152
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE__ARENA_H