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 llvm::SmallDenseMap<const RecordStorageLocation *,
125 llvm::SmallDenseMap<const FunctionDecl *, T *>>
126 Result;
127 for (auto &[Loc, DeclToT] : Map1) {
128 auto It = Map2.find(Loc);
129 if (It == Map2.end()) {
131 continue;
132 }
133 const auto &OtherDeclToT = It->second;
134 auto &JoinedDeclToT = Result[Loc];
135 for (auto [Func, Var] : DeclToT) {
136 T *OtherVar = OtherDeclToT.lookup(Func);
137 if (OtherVar == nullptr || OtherVar != Var) {
139 continue;
140 }
141 JoinedDeclToT.insert({Func, Var});
142 }
143 }
144 return Result;
145}
146
147} // namespace internal
148
149template <typename Base>
152
153 LatticeEffect Effect = Base::join(Other);
154
155 // For simplicity, we only retain values that are identical, but not ones that
156 // are non-identical but equivalent. This is likely to be sufficient in
157 // practice, and it reduces implementation complexity considerably.
158
159 ConstMethodReturnValues =
160 clang::dataflow::internal::joinConstMethodMap<dataflow::Value>(
161 ConstMethodReturnValues, Other.ConstMethodReturnValues, Effect);
162
163 ConstMethodReturnStorageLocations =
164 clang::dataflow::internal::joinConstMethodMap<dataflow::StorageLocation>(
165 ConstMethodReturnStorageLocations,
166 Other.ConstMethodReturnStorageLocations, Effect);
167
168 return Effect;
169}
170
171template <typename Base>
173 const RecordStorageLocation &RecordLoc, const CallExpr *CE,
174 Environment &Env) {
175 QualType Type = CE->getType();
176 assert(!Type.isNull());
177 assert(!Type->isReferenceType());
178 assert(!Type->isRecordType());
179
180 auto &ObjMap = ConstMethodReturnValues[&RecordLoc];
181 const FunctionDecl *DirectCallee = CE->getDirectCallee();
182 if (DirectCallee == nullptr)
183 return nullptr;
184 auto it = ObjMap.find(DirectCallee);
185 if (it != ObjMap.end())
186 return it->second;
187
188 Value *Val = Env.createValue(Type);
189 if (Val != nullptr)
190 ObjMap.insert({DirectCallee, Val});
191 return Val;
192}
193
194template <typename Base>
197 const RecordStorageLocation &RecordLoc, const FunctionDecl *Callee,
198 Environment &Env, llvm::function_ref<void(StorageLocation &)> Initialize) {
199 assert(Callee != nullptr);
200 QualType Type = Callee->getReturnType();
201 assert(!Type.isNull());
202 assert(Type->isReferenceType() || Type->isRecordType());
203 auto &ObjMap = ConstMethodReturnStorageLocations[&RecordLoc];
204 auto it = ObjMap.find(Callee);
205 if (it != ObjMap.end())
206 return *it->second;
207
208 StorageLocation &Loc = Env.createStorageLocation(Type.getNonReferenceType());
209 Initialize(Loc);
210
211 ObjMap.insert({Callee, &Loc});
212 return Loc;
213}
214
215} // namespace dataflow
216} // namespace clang
217
218#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:754
C Language Family Type Representation.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2879
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition: Expr.h:3062
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:8604
bool isRecordType() const
Definition: TypeBase.h:8707
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)
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)
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.