clang 22.0.0git
CachedConstAccessorsLattice.h
Go to the documentation of this file.
1//===-- CachedConstAccessorsLattice.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 the lattice mixin that additionally maintains a cache of
10// stable method call return values to model const accessor member functions.
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CACHED_CONST_ACCESSORS_LATTICE_H
14#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CACHED_CONST_ACCESSORS_LATTICE_H
15
16#include "clang/AST/Decl.h"
17#include "clang/AST/Expr.h"
18#include "clang/AST/Type.h"
23#include "llvm/ADT/DenseMap.h"
24#include "llvm/ADT/STLFunctionalExtras.h"
25
26namespace clang {
27namespace dataflow {
28
29/// A mixin for a lattice that additionally maintains a cache of stable method
30/// call return values to model const accessors methods. When a non-const method
31/// is called, the cache should be cleared causing the next call to a const
32/// method to be considered a different value. NOTE: The user is responsible for
33/// clearing the cache.
34///
35/// For example:
36///
37/// class Bar {
38/// public:
39/// const std::optional<Foo>& getFoo() const;
40/// void clear();
41/// };
42//
43/// void func(Bar& s) {
44/// if (s.getFoo().has_value()) {
45/// use(s.getFoo().value()); // safe (checked earlier getFoo())
46/// s.clear();
47/// use(s.getFoo().value()); // unsafe (invalidate cache for s)
48/// }
49/// }
50template <typename Base> class CachedConstAccessorsLattice : public Base {
51public:
52 using Base::Base; // inherit all constructors
53
54 /// Creates or returns a previously created `Value` associated with a const
55 /// method call `obj.getFoo()` where `RecordLoc` is the
56 /// `RecordStorageLocation` of `obj`.
57 /// Returns nullptr if unable to find or create a value.
58 ///
59 /// Requirements:
60 ///
61 /// - `CE` should return a value (not a reference or record type)
62 Value *
64 const CallExpr *CE, Environment &Env);
65
66 /// Creates or returns a previously created `StorageLocation` associated with
67 /// a const method call `obj.getFoo()` where `RecordLoc` is the
68 /// `RecordStorageLocation` of `obj`, `Callee` is the decl for `getFoo`.
69 ///
70 /// The callback `Initialize` runs on the storage location if newly created.
71 ///
72 /// Requirements:
73 ///
74 /// - `Callee` should return a location (return type is a reference type or a
75 /// record type).
77 const RecordStorageLocation &RecordLoc, const FunctionDecl *Callee,
78 Environment &Env, llvm::function_ref<void(StorageLocation &)> Initialize);
79
81 ConstMethodReturnValues.erase(&RecordLoc);
82 }
83
86 ConstMethodReturnStorageLocations.erase(&RecordLoc);
87 }
88
90 return Base::operator==(Other);
91 }
92
94
95private:
96 // Maps a record storage location and const method to the value to return
97 // from that const method.
98 using ConstMethodReturnValuesType =
99 llvm::SmallDenseMap<const RecordStorageLocation *,
100 llvm::SmallDenseMap<const FunctionDecl *, Value *>>;
101 ConstMethodReturnValuesType ConstMethodReturnValues;
102
103 // Maps a record storage location and const method to the record storage
104 // location to return from that const method.
105 using ConstMethodReturnStorageLocationsType = llvm::SmallDenseMap<
106 const RecordStorageLocation *,
107 llvm::SmallDenseMap<const FunctionDecl *, StorageLocation *>>;
108 ConstMethodReturnStorageLocationsType ConstMethodReturnStorageLocations;
109};
110
111namespace internal {
112
113template <typename T>
114llvm::SmallDenseMap<const RecordStorageLocation *,
115 llvm::SmallDenseMap<const FunctionDecl *, T *>>
117 const llvm::SmallDenseMap<const RecordStorageLocation *,
118 llvm::SmallDenseMap<const FunctionDecl *, T *>>
119 &Map1,
120 const llvm::SmallDenseMap<const RecordStorageLocation *,
121 llvm::SmallDenseMap<const FunctionDecl *, T *>>
122 &Map2,
123 LatticeEffect &Effect) {
124 // Intersect the two maps, and note if change was made.
125 llvm::SmallDenseMap<const RecordStorageLocation *,
126 llvm::SmallDenseMap<const FunctionDecl *, T *>>
127 Result;
128 for (auto &[Loc, DeclToT] : Map1) {
129 auto It = Map2.find(Loc);
130 if (It == Map2.end()) {
131 Effect = LatticeEffect::Changed;
132 continue;
133 }
134 const auto &OtherDeclToT = It->second;
135 auto &JoinedDeclToT = Result[Loc];
136 for (auto [Func, Var] : DeclToT) {
137 T *OtherVar = OtherDeclToT.lookup(Func);
138 if (OtherVar == nullptr || OtherVar != Var) {
139 Effect = LatticeEffect::Changed;
140 continue;
141 }
142 JoinedDeclToT.insert({Func, Var});
143 }
144 }
145 return Result;
146}
147
148} // namespace internal
149
150template <typename Base>
153
154 LatticeEffect Effect = Base::join(Other);
155
156 // For simplicity, we only retain values that are identical, but not ones that
157 // are non-identical but equivalent. This is likely to be sufficient in
158 // practice, and it reduces implementation complexity considerably.
159
160 ConstMethodReturnValues =
162 ConstMethodReturnValues, Other.ConstMethodReturnValues, Effect);
163
164 ConstMethodReturnStorageLocations =
166 ConstMethodReturnStorageLocations,
167 Other.ConstMethodReturnStorageLocations, Effect);
168
169 return Effect;
170}
171
172template <typename Base>
174 const RecordStorageLocation &RecordLoc, const CallExpr *CE,
175 Environment &Env) {
176 QualType Type = CE->getType();
177 assert(!Type.isNull());
178 assert(!Type->isReferenceType());
179 assert(!Type->isRecordType());
180
181 auto &ObjMap = ConstMethodReturnValues[&RecordLoc];
182 const FunctionDecl *DirectCallee = CE->getDirectCallee();
183 if (DirectCallee == nullptr)
184 return nullptr;
185 auto it = ObjMap.find(DirectCallee);
186 if (it != ObjMap.end())
187 return it->second;
188
189 Value *Val = Env.createValue(Type);
190 if (Val != nullptr)
191 ObjMap.insert({DirectCallee, Val});
192 return Val;
193}
194
195template <typename Base>
198 const RecordStorageLocation &RecordLoc, const FunctionDecl *Callee,
199 Environment &Env, llvm::function_ref<void(StorageLocation &)> Initialize) {
200 assert(Callee != nullptr);
201 QualType Type = Callee->getReturnType();
202 assert(!Type.isNull());
203 assert(Type->isReferenceType() || Type->isRecordType());
204 auto &ObjMap = ConstMethodReturnStorageLocations[&RecordLoc];
205 auto it = ObjMap.find(Callee);
206 if (it != ObjMap.end())
207 return *it->second;
208
209 StorageLocation &Loc = Env.createStorageLocation(Type.getNonReferenceType());
210 Initialize(Loc);
211
212 ObjMap.insert({Callee, &Loc});
213 return Loc;
214}
215
216} // namespace dataflow
217} // namespace clang
218
219#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CACHED_CONST_ACCESSORS_LATTICE_H
llvm::MachO::RecordLoc RecordLoc
Definition MachO.h:41
C Language Family Type Representation.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2877
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3060
QualType getType() const
Definition Expr.h:144
Represents a function declaration or definition.
Definition Decl.h:1999
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:8546
bool isRecordType() const
Definition TypeBase.h:8649
A mixin for a lattice that additionally maintains a cache of stable method call return values to mode...
LatticeEffect join(const CachedConstAccessorsLattice &Other)
void clearConstMethodReturnStorageLocations(const RecordStorageLocation &RecordLoc)
StorageLocation & getOrCreateConstMethodReturnStorageLocation(const RecordStorageLocation &RecordLoc, const FunctionDecl *Callee, Environment &Env, llvm::function_ref< void(StorageLocation &)> Initialize)
Creates or returns a previously created StorageLocation associated with a const method call obj....
bool operator==(const CachedConstAccessorsLattice &Other) const
void clearConstMethodReturnValues(const RecordStorageLocation &RecordLoc)
Value * getOrCreateConstMethodReturnValue(const RecordStorageLocation &RecordLoc, const CallExpr *CE, Environment &Env)
Creates or returns a previously created Value associated with a const method call obj....
Holds the state of the program (store and heap) at a given program point.
StorageLocation & createStorageLocation(QualType Type)
Creates a storage location appropriate for Type.
Value * createValue(QualType Type)
Creates a value appropriate for Type, if Type is supported, otherwise returns null.
A storage location for a record (struct, class, or union).
Base class for elements of the local variable store and of the heap.
Base class for all values computed by abstract interpretation.
Definition Value.h:33
llvm::SmallDenseMap< const RecordStorageLocation *, llvm::SmallDenseMap< const FunctionDecl *, T * > > joinConstMethodMap(const llvm::SmallDenseMap< const RecordStorageLocation *, llvm::SmallDenseMap< const FunctionDecl *, T * > > &Map1, const llvm::SmallDenseMap< const RecordStorageLocation *, llvm::SmallDenseMap< const FunctionDecl *, T * > > &Map2, LatticeEffect &Effect)
Dataflow Directional Tag Classes.
Definition AdornedCFG.h:29
LatticeEffect
Effect indicating whether a lattice operation resulted in a new value.
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
Definition TypeBase.h:905
const FunctionProtoType * T
@ Other
Other implicit parameter.
Definition Decl.h:1745