clang 22.0.0git
StorageLocation.h
Go to the documentation of this file.
1//===-- StorageLocation.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//
9// This file defines classes that represent elements of the local variable store
10// and of the heap during dataflow analysis.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_STORAGELOCATION_H
15#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_STORAGELOCATION_H
16
17#include "clang/AST/Decl.h"
18#include "clang/AST/Type.h"
19#include "llvm/ADT/DenseMap.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/Support/Debug.h"
22#include <cassert>
23
24#define DEBUG_TYPE "dataflow"
25
26namespace clang {
27namespace dataflow {
28
29/// Base class for elements of the local variable store and of the heap.
30///
31/// Each storage location holds a value. The mapping from storage locations to
32/// values is stored in the environment.
34public:
35 enum class Kind {
36 Scalar,
37 Record,
38 };
39
40 StorageLocation(Kind LocKind, QualType Type) : LocKind(LocKind), Type(Type) {
41 assert(Type.isNull() || !Type->isReferenceType());
42 }
43
44 // Non-copyable because addresses of storage locations are used as their
45 // identities throughout framework and user code. The framework is responsible
46 // for construction and destruction of storage locations.
49
50 virtual ~StorageLocation() = default;
51
52 Kind getKind() const { return LocKind; }
53
54 QualType getType() const { return Type; }
55
56private:
57 Kind LocKind;
59};
60
61/// A storage location that is not subdivided further for the purposes of
62/// abstract interpretation. For example: `int`, `int*`, `int&`.
64public:
67
68 static bool classof(const StorageLocation *Loc) {
69 return Loc->getKind() == Kind::Scalar;
70 }
71};
72
73/// A storage location for a record (struct, class, or union).
74///
75/// Contains storage locations for all modeled fields of the record (also
76/// referred to as "children"). The child map is flat, so accessible members of
77/// the base class are directly accessible as children of this location.
78///
79/// Record storage locations may also contain so-called synthetic fields. These
80/// are typically used to model the internal state of a class (e.g. the value
81/// stored in a `std::optional`) without having to depend on that class's
82/// implementation details. All `RecordStorageLocation`s of a given type should
83/// have the same synthetic fields.
84///
85/// The storage location for a field of reference type may be null. This
86/// typically occurs in one of two situations:
87/// - The record has not been fully initialized.
88/// - The maximum depth for modelling a self-referential data structure has been
89/// reached.
90/// Storage locations for fields of all other types must be non-null.
91///
92/// FIXME: Currently, the storage location of unions is modelled the same way as
93/// that of structs or classes. Eventually, we need to change this modelling so
94/// that all of the members of a given union have the same storage location.
96public:
97 using FieldToLoc = llvm::DenseMap<const ValueDecl *, StorageLocation *>;
98 using SyntheticFieldMap = llvm::StringMap<StorageLocation *>;
99
101 SyntheticFieldMap TheSyntheticFields)
102 : StorageLocation(Kind::Record, Type), Children(std::move(TheChildren)),
103 SyntheticFields(std::move(TheSyntheticFields)) {
104 assert(!Type.isNull());
105 assert(Type->isRecordType());
106 assert([this] {
107 for (auto [Field, Loc] : Children) {
108 if (!Field->getType()->isReferenceType() && Loc == nullptr)
109 return false;
110 }
111 return true;
112 }());
113 }
114
115 static bool classof(const StorageLocation *Loc) {
116 return Loc->getKind() == Kind::Record;
117 }
118
119 /// Returns the child storage location for `D`.
120 ///
121 /// May return null if `D` has reference type; guaranteed to return non-null
122 /// in all other cases.
123 ///
124 /// Note that it is an error to call this with a field that does not exist.
125 /// The function does not return null in this case.
127 auto It = Children.find(&D);
128 LLVM_DEBUG({
129 if (It == Children.end()) {
130 llvm::dbgs() << "Couldn't find child " << D.getNameAsString()
131 << " on StorageLocation " << this << " of type "
132 << getType() << "\n";
133 llvm::dbgs() << "Existing children:\n";
134 for ([[maybe_unused]] auto [Field, Loc] : Children) {
135 llvm::dbgs() << Field->getNameAsString() << "\n";
136 }
137 }
138 });
139 assert(It != Children.end());
140 return It->second;
141 }
142
143 /// Returns the storage location for the synthetic field `Name`.
144 /// The synthetic field must exist.
145 StorageLocation &getSyntheticField(llvm::StringRef Name) const {
146 StorageLocation *Loc = SyntheticFields.lookup(Name);
147 assert(Loc != nullptr);
148 return *Loc;
149 }
150
151 llvm::iterator_range<SyntheticFieldMap::const_iterator>
153 return {SyntheticFields.begin(), SyntheticFields.end()};
154 }
155
156 /// Add a synthetic field, if none by that name is already present.
157 void addSyntheticField(llvm::StringRef Name, StorageLocation &Loc) {
158 SyntheticFields.insert({Name, &Loc});
159 }
160
161 /// Changes the child storage location for a field `D` of reference type.
162 /// All other fields cannot change their storage location and always retain
163 /// the storage location passed to the `RecordStorageLocation` constructor.
164 ///
165 /// Requirements:
166 ///
167 /// `D` must have reference type.
169 assert(D.getType()->isReferenceType());
170 Children[&D] = Loc;
171 }
172
173 /// Add a child storage location for a field `D`, if not already present.
175 Children.insert({&D, Loc});
176 }
177
178 llvm::iterator_range<FieldToLoc::const_iterator> children() const {
179 return {Children.begin(), Children.end()};
180 }
181
182private:
183 FieldToLoc Children;
184 SyntheticFieldMap SyntheticFields;
185};
186
187} // namespace dataflow
188} // namespace clang
189
190#undef DEBUG_TYPE
191
192#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_STORAGELOCATION_H
const Decl * D
llvm::MachO::Record Record
Definition: MachO.h:31
SourceLocation Loc
Definition: SemaObjC.cpp:754
C Language Family Type Representation.
A (possibly-)qualified type.
Definition: TypeBase.h:937
The base class of the type hierarchy.
Definition: TypeBase.h:1833
bool isReferenceType() const
Definition: TypeBase.h:8604
bool isRecordType() const
Definition: TypeBase.h:8707
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:711
A storage location for a record (struct, class, or union).
llvm::iterator_range< SyntheticFieldMap::const_iterator > synthetic_fields() const
StorageLocation * getChild(const ValueDecl &D) const
Returns the child storage location for D.
llvm::DenseMap< const ValueDecl *, StorageLocation * > FieldToLoc
llvm::StringMap< StorageLocation * > SyntheticFieldMap
RecordStorageLocation(QualType Type, FieldToLoc TheChildren, SyntheticFieldMap TheSyntheticFields)
void setChild(const ValueDecl &D, StorageLocation *Loc)
Changes the child storage location for a field D of reference type.
StorageLocation & getSyntheticField(llvm::StringRef Name) const
Returns the storage location for the synthetic field Name.
void addSyntheticField(llvm::StringRef Name, StorageLocation &Loc)
Add a synthetic field, if none by that name is already present.
void addChild(const ValueDecl &D, StorageLocation *Loc)
Add a child storage location for a field D, if not already present.
static bool classof(const StorageLocation *Loc)
llvm::iterator_range< FieldToLoc::const_iterator > children() const
A storage location that is not subdivided further for the purposes of abstract interpretation.
static bool classof(const StorageLocation *Loc)
Base class for elements of the local variable store and of the heap.
virtual ~StorageLocation()=default
StorageLocation(Kind LocKind, QualType Type)
StorageLocation & operator=(const StorageLocation &)=delete
StorageLocation(const StorageLocation &)=delete
The JSON file list parser is used to communicate input to InstallAPI.