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/Expr.h"
21#include "llvm/ADT/DenseMap.h"
22#include "llvm/ADT/STLFunctionalExtras.h"
23
24namespace clang {
25namespace dataflow {
26
27/// A mixin for a lattice that additionally maintains a cache of stable method
28/// call return values to model const accessors methods. When a non-const method
29/// is called, the cache should be cleared causing the next call to a const
30/// method to be considered a different value. NOTE: The user is responsible for
31/// clearing the cache.
32///
33/// For example:
34///
35/// class Bar {
36/// public:
37/// const std::optional<Foo>& getFoo() const;
38/// void clear();
39/// };
40//
41/// void func(Bar& s) {
42/// if (s.getFoo().has_value()) {
43/// use(s.getFoo().value()); // safe (checked earlier getFoo())
44/// s.clear();
45/// use(s.getFoo().value()); // unsafe (invalidate cache for s)
46/// }
47/// }
48template <typename Base> class CachedConstAccessorsLattice : public Base {
49public:
50 using Base::Base; // inherit all constructors
51
52 /// Creates or returns a previously created `Value` associated with a const
53 /// method call `obj.getFoo()` where `RecordLoc` is the
54 /// `RecordStorageLocation` of `obj`.
55 /// Returns nullptr if unable to find or create a value.
56 ///
57 /// Requirements:
58 ///
59 /// - `CE` should return a value (not a reference or record type)
60 Value *
62 const CallExpr *CE, Environment &Env);
63
64 /// Creates or returns a previously created `StorageLocation` associated with
65 /// a const method call `obj.getFoo()` where `RecordLoc` is the
66 /// `RecordStorageLocation` of `obj`.
67 ///
68 /// The callback `Initialize` runs on the storage location if newly created.
69 /// Returns nullptr if unable to find or create a value.
70 ///
71 /// Requirements:
72 ///
73 /// - `CE` should return a location (GLValue or a record type).
76 Environment &Env, llvm::function_ref<void(StorageLocation &)> Initialize);
77
79 ConstMethodReturnValues.erase(&RecordLoc);
80 }
81
84 ConstMethodReturnStorageLocations.erase(&RecordLoc);
85 }
86
88 return Base::operator==(Other);
89 }
90
92
93private:
94 // Maps a record storage location and const method to the value to return
95 // from that const method.
96 using ConstMethodReturnValuesType =
97 llvm::SmallDenseMap<const RecordStorageLocation *,
98 llvm::SmallDenseMap<const FunctionDecl *, Value *>>;
99 ConstMethodReturnValuesType ConstMethodReturnValues;
100
101 // Maps a record storage location and const method to the record storage
102 // location to return from that const method.
103 using ConstMethodReturnStorageLocationsType = llvm::SmallDenseMap<
104 const RecordStorageLocation *,
105 llvm::SmallDenseMap<const FunctionDecl *, StorageLocation *>>;
106 ConstMethodReturnStorageLocationsType ConstMethodReturnStorageLocations;
107};
108
109namespace internal {
110
111template <typename T>
112llvm::SmallDenseMap<const RecordStorageLocation *,
113 llvm::SmallDenseMap<const FunctionDecl *, T *>>
115 const llvm::SmallDenseMap<const RecordStorageLocation *,
116 llvm::SmallDenseMap<const FunctionDecl *, T *>>
117 &Map1,
118 const llvm::SmallDenseMap<const RecordStorageLocation *,
119 llvm::SmallDenseMap<const FunctionDecl *, T *>>
120 &Map2,
121 LatticeEffect &Effect) {
122 llvm::SmallDenseMap<const RecordStorageLocation *,
123 llvm::SmallDenseMap<const FunctionDecl *, T *>>
124 Result;
125 for (auto &[Loc, DeclToT] : Map1) {
126 auto It = Map2.find(Loc);
127 if (It == Map2.end()) {
129 continue;
130 }
131 const auto &OtherDeclToT = It->second;
132 auto &JoinedDeclToT = Result[Loc];
133 for (auto [Func, Var] : DeclToT) {
134 T *OtherVar = OtherDeclToT.lookup(Func);
135 if (OtherVar == nullptr || OtherVar != Var) {
137 continue;
138 }
139 JoinedDeclToT.insert({Func, Var});
140 }
141 }
142 return Result;
143}
144
145} // namespace internal
146
147template <typename Base>
150
151 LatticeEffect Effect = Base::join(Other);
152
153 // For simplicity, we only retain values that are identical, but not ones that
154 // are non-identical but equivalent. This is likely to be sufficient in
155 // practice, and it reduces implementation complexity considerably.
156
157 ConstMethodReturnValues =
158 clang::dataflow::internal::joinConstMethodMap<dataflow::Value>(
159 ConstMethodReturnValues, Other.ConstMethodReturnValues, Effect);
160
161 ConstMethodReturnStorageLocations =
162 clang::dataflow::internal::joinConstMethodMap<dataflow::StorageLocation>(
163 ConstMethodReturnStorageLocations,
164 Other.ConstMethodReturnStorageLocations, Effect);
165
166 return Effect;
167}
168
169template <typename Base>
171 const RecordStorageLocation &RecordLoc, const CallExpr *CE,
172 Environment &Env) {
173 QualType Type = CE->getType();
174 assert(!Type.isNull());
175 assert(!Type->isReferenceType());
176 assert(!Type->isRecordType());
177
178 auto &ObjMap = ConstMethodReturnValues[&RecordLoc];
179 const FunctionDecl *DirectCallee = CE->getDirectCallee();
180 if (DirectCallee == nullptr)
181 return nullptr;
182 auto it = ObjMap.find(DirectCallee);
183 if (it != ObjMap.end())
184 return it->second;
185
186 Value *Val = Env.createValue(Type);
187 if (Val != nullptr)
188 ObjMap.insert({DirectCallee, Val});
189 return Val;
190}
191
192template <typename Base>
195 const RecordStorageLocation &RecordLoc, const CallExpr *CE,
196 Environment &Env, llvm::function_ref<void(StorageLocation &)> Initialize) {
197 assert(!CE->getType().isNull());
198 assert(CE->isGLValue() || CE->getType()->isRecordType());
199 auto &ObjMap = ConstMethodReturnStorageLocations[&RecordLoc];
200 const FunctionDecl *DirectCallee = CE->getDirectCallee();
201 if (DirectCallee == nullptr)
202 return nullptr;
203 auto it = ObjMap.find(DirectCallee);
204 if (it != ObjMap.end())
205 return it->second;
206
209 Initialize(Loc);
210
211 ObjMap.insert({DirectCallee, &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:759
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.