aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h')
-rw-r--r--contrib/llvm-project/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h181
1 files changed, 181 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h b/contrib/llvm-project/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
new file mode 100644
index 000000000000..8fcc6a44027a
--- /dev/null
+++ b/contrib/llvm-project/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
@@ -0,0 +1,181 @@
+//===-- 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"
+#include "llvm/Support/Debug.h"
+#include <cassert>
+
+#define DEBUG_TYPE "dataflow"
+
+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,
+ Record,
+ };
+
+ StorageLocation(Kind LocKind, QualType Type) : LocKind(LocKind), Type(Type) {
+ assert(Type.isNull() || !Type->isReferenceType());
+ }
+
+ // 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 for a record (struct, class, or union).
+///
+/// Contains storage locations for all modeled fields of the record (also
+/// referred to as "children"). The child map is flat, so accessible members of
+/// the base class are directly accessible as children of this location.
+///
+/// Record storage locations may also contain so-called synthetic fields. These
+/// are typically used to model the internal state of a class (e.g. the value
+/// stored in a `std::optional`) without having to depend on that class's
+/// implementation details. All `RecordStorageLocation`s of a given type should
+/// have the same synthetic fields.
+///
+/// The storage location for a field of reference type may be null. This
+/// typically occurs in one of two situations:
+/// - The record has not been fully initialized.
+/// - The maximum depth for modelling a self-referential data structure has been
+/// reached.
+/// Storage locations for fields of all other types must be non-null.
+///
+/// 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 RecordStorageLocation final : public StorageLocation {
+public:
+ using FieldToLoc = llvm::DenseMap<const ValueDecl *, StorageLocation *>;
+ using SyntheticFieldMap = llvm::StringMap<StorageLocation *>;
+
+ RecordStorageLocation(QualType Type, FieldToLoc TheChildren,
+ SyntheticFieldMap TheSyntheticFields)
+ : StorageLocation(Kind::Record, Type), Children(std::move(TheChildren)),
+ SyntheticFields(std::move(TheSyntheticFields)) {
+ assert(!Type.isNull());
+ assert(Type->isRecordType());
+ assert([this] {
+ for (auto [Field, Loc] : Children) {
+ if (!Field->getType()->isReferenceType() && Loc == nullptr)
+ return false;
+ }
+ return true;
+ }());
+ }
+
+ static bool classof(const StorageLocation *Loc) {
+ return Loc->getKind() == Kind::Record;
+ }
+
+ /// Returns the child storage location for `D`.
+ ///
+ /// May return null if `D` has reference type; guaranteed to return non-null
+ /// in all other cases.
+ ///
+ /// Note that it is an error to call this with a field that does not exist.
+ /// The function does not return null in this case.
+ StorageLocation *getChild(const ValueDecl &D) const {
+ auto It = Children.find(&D);
+ LLVM_DEBUG({
+ if (It == Children.end()) {
+ llvm::dbgs() << "Couldn't find child " << D.getNameAsString()
+ << " on StorageLocation " << this << " of type "
+ << getType() << "\n";
+ llvm::dbgs() << "Existing children:\n";
+ for ([[maybe_unused]] auto [Field, Loc] : Children) {
+ llvm::dbgs() << Field->getNameAsString() << "\n";
+ }
+ }
+ });
+ assert(It != Children.end());
+ return It->second;
+ }
+
+ /// Returns the storage location for the synthetic field `Name`.
+ /// The synthetic field must exist.
+ StorageLocation &getSyntheticField(llvm::StringRef Name) const {
+ StorageLocation *Loc = SyntheticFields.lookup(Name);
+ assert(Loc != nullptr);
+ return *Loc;
+ }
+
+ llvm::iterator_range<SyntheticFieldMap::const_iterator>
+ synthetic_fields() const {
+ return {SyntheticFields.begin(), SyntheticFields.end()};
+ }
+
+ /// Changes the child storage location for a field `D` of reference type.
+ /// All other fields cannot change their storage location and always retain
+ /// the storage location passed to the `RecordStorageLocation` constructor.
+ ///
+ /// Requirements:
+ ///
+ /// `D` must have reference type.
+ void setChild(const ValueDecl &D, StorageLocation *Loc) {
+ assert(D.getType()->isReferenceType());
+ Children[&D] = Loc;
+ }
+
+ llvm::iterator_range<FieldToLoc::const_iterator> children() const {
+ return {Children.begin(), Children.end()};
+ }
+
+private:
+ FieldToLoc Children;
+ SyntheticFieldMap SyntheticFields;
+};
+
+} // namespace dataflow
+} // namespace clang
+
+#undef DEBUG_TYPE
+
+#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_STORAGELOCATION_H