clang 20.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`.
69 ///
70 /// The callback `Initialize` runs on the storage location if newly created.
71 /// Returns nullptr if unable to find or create a value.
72 ///
73 /// Requirements:
74 ///
75 /// - `CE` should return a location (GLValue or a record type).
76 ///
77 /// DEPRECATED: switch users to the below overload which takes Callee and Type
78 /// directly.
81 Environment &Env, llvm::function_ref<void(StorageLocation &)> Initialize);
82
83 /// Creates or returns a previously created `StorageLocation` associated with
84 /// a const method call `obj.getFoo()` where `RecordLoc` is the
85 /// `RecordStorageLocation` of `obj`, `Callee` is the decl for `getFoo`.
86 ///
87 /// The callback `Initialize` runs on the storage location if newly created.
88 ///
89 /// Requirements:
90 ///
91 /// - `Callee` should return a location (return type is a reference type or a
92 /// record type).
94 const RecordStorageLocation &RecordLoc, const FunctionDecl *Callee,
95 Environment &Env, llvm::function_ref<void(StorageLocation &)> Initialize);
96
98 ConstMethodReturnValues.erase(&RecordLoc);
99 }
100
103 ConstMethodReturnStorageLocations.erase(&RecordLoc);
104 }
105
107 return Base::operator==(Other);
108 }
109
111
112private:
113 // Maps a record storage location and const method to the value to return
114 // from that const method.
115 using ConstMethodReturnValuesType =
116 llvm::SmallDenseMap<const RecordStorageLocation *,
117 llvm::SmallDenseMap<const FunctionDecl *, Value *>>;
118 ConstMethodReturnValuesType ConstMethodReturnValues;
119
120 // Maps a record storage location and const method to the record storage
121 // location to return from that const method.
122 using ConstMethodReturnStorageLocationsType = llvm::SmallDenseMap<
123 const RecordStorageLocation *,
124 llvm::SmallDenseMap<const FunctionDecl *, StorageLocation *>>;
125 ConstMethodReturnStorageLocationsType ConstMethodReturnStorageLocations;
126};
127
128namespace internal {
129
130template <typename T>
131llvm::SmallDenseMap<const RecordStorageLocation *,
132 llvm::SmallDenseMap<const FunctionDecl *, T *>>
134 const llvm::SmallDenseMap<const RecordStorageLocation *,
135 llvm::SmallDenseMap<const FunctionDecl *, T *>>
136 &Map1,
137 const llvm::SmallDenseMap<const RecordStorageLocation *,
138 llvm::SmallDenseMap<const FunctionDecl *, T *>>
139 &Map2,
140 LatticeEffect &Effect) {
141 llvm::SmallDenseMap<const RecordStorageLocation *,
142 llvm::SmallDenseMap<const FunctionDecl *, T *>>
143 Result;
144 for (auto &[Loc, DeclToT] : Map1) {
145 auto It = Map2.find(Loc);
146 if (It == Map2.end()) {
148 continue;
149 }
150 const auto &OtherDeclToT = It->second;
151 auto &JoinedDeclToT = Result[Loc];
152 for (auto [Func, Var] : DeclToT) {
153 T *OtherVar = OtherDeclToT.lookup(Func);
154 if (OtherVar == nullptr || OtherVar != Var) {
156 continue;
157 }
158 JoinedDeclToT.insert({Func, Var});
159 }
160 }
161 return Result;
162}
163
164} // namespace internal
165
166template <typename Base>
169
170 LatticeEffect Effect = Base::join(Other);
171
172 // For simplicity, we only retain values that are identical, but not ones that
173 // are non-identical but equivalent. This is likely to be sufficient in
174 // practice, and it reduces implementation complexity considerably.
175
176 ConstMethodReturnValues =
177 clang::dataflow::internal::joinConstMethodMap<dataflow::Value>(
178 ConstMethodReturnValues, Other.ConstMethodReturnValues, Effect);
179
180 ConstMethodReturnStorageLocations =
181 clang::dataflow::internal::joinConstMethodMap<dataflow::StorageLocation>(
182 ConstMethodReturnStorageLocations,
183 Other.ConstMethodReturnStorageLocations, Effect);
184
185 return Effect;
186}
187
188template <typename Base>
190 const RecordStorageLocation &RecordLoc, const CallExpr *CE,
191 Environment &Env) {
192 QualType Type = CE->getType();
193 assert(!Type.isNull());
194 assert(!Type->isReferenceType());
195 assert(!Type->isRecordType());
196
197 auto &ObjMap = ConstMethodReturnValues[&RecordLoc];
198 const FunctionDecl *DirectCallee = CE->getDirectCallee();
199 if (DirectCallee == nullptr)
200 return nullptr;
201 auto it = ObjMap.find(DirectCallee);
202 if (it != ObjMap.end())
203 return it->second;
204
205 Value *Val = Env.createValue(Type);
206 if (Val != nullptr)
207 ObjMap.insert({DirectCallee, Val});
208 return Val;
209}
210
211template <typename Base>
214 const RecordStorageLocation &RecordLoc, const CallExpr *CE,
215 Environment &Env, llvm::function_ref<void(StorageLocation &)> Initialize) {
216 assert(!CE->getType().isNull());
217 assert(CE->isGLValue() || CE->getType()->isRecordType());
218 auto &ObjMap = ConstMethodReturnStorageLocations[&RecordLoc];
219 const FunctionDecl *DirectCallee = CE->getDirectCallee();
220 if (DirectCallee == nullptr)
221 return nullptr;
222 auto it = ObjMap.find(DirectCallee);
223 if (it != ObjMap.end())
224 return it->second;
225
228 Initialize(Loc);
229
230 ObjMap.insert({DirectCallee, &Loc});
231 return &Loc;
232}
233
234template <typename Base>
237 const RecordStorageLocation &RecordLoc, const FunctionDecl *Callee,
238 Environment &Env, llvm::function_ref<void(StorageLocation &)> Initialize) {
239 assert(Callee != nullptr);
240 QualType Type = Callee->getReturnType();
241 assert(!Type.isNull());
242 assert(Type->isReferenceType() || Type->isRecordType());
243 auto &ObjMap = ConstMethodReturnStorageLocations[&RecordLoc];
244 auto it = ObjMap.find(Callee);
245 if (it != ObjMap.end())
246 return *it->second;
247
248 StorageLocation &Loc = Env.createStorageLocation(Type.getNonReferenceType());
249 Initialize(Loc);
250
251 ObjMap.insert({Callee, &Loc});
252 return Loc;
253}
254
255} // namespace dataflow
256} // namespace clang
257
258#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CACHED_CONST_ACCESSORS_LATTICE_H
const Environment & Env
Definition: HTMLLogger.cpp:147
llvm::MachO::RecordLoc RecordLoc
Definition: MachO.h:41
SourceLocation Loc
Definition: SemaObjC.cpp:759
C Language Family Type Representation.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2874
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition: Expr.h:3047
bool isGLValue() const
Definition: Expr.h:280
QualType getType() const
Definition: Expr.h:142
Represents a function declaration or definition.
Definition: Decl.h:1935
A (possibly-)qualified type.
Definition: Type.h:929
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:996
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
Definition: Type.h:8134
The base class of the type hierarchy.
Definition: Type.h:1828
bool isReferenceType() const
Definition: Type.h:8204
bool isRecordType() const
Definition: Type.h:8286
A mixin for a lattice that additionally maintains a cache of stable method call return values to mode...
LatticeJoinEffect join(const CachedConstAccessorsLattice &Other)
void clearConstMethodReturnStorageLocations(const RecordStorageLocation &RecordLoc)
bool operator==(const CachedConstAccessorsLattice &Other) const
StorageLocation * getOrCreateConstMethodReturnStorageLocation(const RecordStorageLocation &RecordLoc, const CallExpr *CE, Environment &Env, llvm::function_ref< void(StorageLocation &)> Initialize)
Creates or returns a previously created StorageLocation associated with a const method call obj....
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)
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.
const FunctionProtoType * T
@ Other
Other implicit parameter.