aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/clang16/include/clang/Analysis/FlowSensitive/Value.h
blob: c8af7fe16eeb7957494c9efb1ada05fc2eacc36e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
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