Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 1 | // Part of the Crubit project, under the Apache License v2.0 with LLVM |
| 2 | // Exceptions. See /LICENSE for license information. |
| 3 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 4 | |
| 5 | #ifndef DEVTOOLS_RUST_CC_INTEROP_LIFETIME_ANALYSIS_OBJECT_REPOSITORY_H_ |
| 6 | #define DEVTOOLS_RUST_CC_INTEROP_LIFETIME_ANALYSIS_OBJECT_REPOSITORY_H_ |
| 7 | |
| 8 | #include <functional> |
| 9 | #include <optional> |
| 10 | #include <string> |
| 11 | #include <variant> |
| 12 | |
| 13 | #include "lifetime_analysis/object.h" |
| 14 | #include "lifetime_analysis/object_set.h" |
| 15 | #include "lifetime_analysis/points_to_map.h" |
| 16 | #include "lifetime_annotations/type_lifetimes.h" |
| 17 | #include "clang/AST/Decl.h" |
| 18 | #include "clang/AST/Expr.h" |
| 19 | #include "clang/AST/ExprCXX.h" |
| 20 | #include "llvm/ADT/DenseMap.h" |
Martin Brænne | 4a1231d | 2022-07-01 01:45:44 -0700 | [diff] [blame] | 21 | #include "llvm/Support/Allocator.h" |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 22 | |
| 23 | namespace clang { |
| 24 | namespace tidy { |
| 25 | namespace lifetimes { |
| 26 | |
| 27 | // A record-type expression has 2 modes: |
| 28 | // 1. If it's being assigned to a reference, then the contents of the expression |
| 29 | // are a glvalue. This is because references require an object to point to. |
| 30 | // 2. If it's being assigned to a record object, then the expression itself is |
| 31 | // not creating an object, but initializing it. So the expression's type is |
| 32 | // a pure value, and it acts _on_ the initializing object instead of |
| 33 | // producing an object. |
| 34 | inline bool IsInitExprInitializingARecordObject(const clang::Expr* expr) { |
| 35 | return expr->getType()->isRecordType() && expr->isPRValue(); |
| 36 | } |
| 37 | |
| 38 | // A repository for the objects used in the lifetime analysis of a single |
| 39 | // function. |
Martin Brænne | fb8153d | 2022-06-28 04:05:14 -0700 | [diff] [blame] | 40 | // This class establishes a relationship between AST nodes (e.g. variable |
| 41 | // declarations) and the objects that represent them. It also stores additional |
| 42 | // information about objects that does not change during the analysis. |
| 43 | // The `ObjectRepository` only stores state that does not change during the |
| 44 | // analysis; it is therefore not part of the lattice. |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 45 | class ObjectRepository { |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 46 | private: |
Martin Brænne | e9a4a47 | 2022-07-01 02:26:55 -0700 | [diff] [blame] | 47 | using MapType = llvm::DenseMap<const clang::ValueDecl*, const Object*>; |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 48 | |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 49 | public: |
| 50 | // An `Object` might represent objects that have either a single value (such |
| 51 | // as plain variables) or multiple ones (such as arrays, or structs). |
| 52 | // Assignment behaves differently in the two cases. |
| 53 | enum class ObjectValueType { |
| 54 | kSingleValued, |
| 55 | kMultiValued, |
| 56 | }; |
| 57 | |
| 58 | // Tag struct for InitializedObject: the object being initialized is the |
| 59 | // return value of the function. |
| 60 | struct ReturnValue {}; |
| 61 | |
| 62 | // Maps a given struct-Object to the Object for each of its fields. |
| 63 | // TODO(veluca): this approach does not produce correct results when |
| 64 | // diamond-problem-style multiple inheritance happens. |
| 65 | using FieldObjects = |
Martin Brænne | 1b98ac6 | 2022-07-01 06:24:52 -0700 | [diff] [blame] | 66 | llvm::DenseMap<std::pair<const Object*, const clang::FieldDecl*>, |
| 67 | const Object*>; |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 68 | |
| 69 | // Maps a given struct-Object to the Object for each of its bases. |
| 70 | using BaseObjects = |
Martin Brænne | 1b98ac6 | 2022-07-01 06:24:52 -0700 | [diff] [blame] | 71 | llvm::DenseMap<std::pair<const Object*, const clang::Type*>, |
| 72 | const Object*>; |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 73 | |
Martin Brænne | d7f2009 | 2022-06-28 04:04:33 -0700 | [diff] [blame] | 74 | // Iterator refers to a pair consisting of a variable declaration and the |
| 75 | // object representing that variable. |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 76 | using const_iterator = MapType::const_iterator; |
| 77 | using value_type = MapType::value_type; |
| 78 | |
| 79 | // Initializes the map with objects for all variables that are declared or |
| 80 | // referenced in `func`. |
| 81 | explicit ObjectRepository(const clang::FunctionDecl* func); |
| 82 | |
| 83 | // Move-only. |
| 84 | ObjectRepository(ObjectRepository&&) = default; |
| 85 | ObjectRepository& operator=(ObjectRepository&&) = default; |
| 86 | |
| 87 | // Returns a human-readable representation of the mapping. |
| 88 | std::string DebugString() const; |
| 89 | |
| 90 | const_iterator begin() const { return object_repository_.begin(); } |
| 91 | const_iterator end() const { return object_repository_.end(); } |
| 92 | |
Martin Brænne | 4a1231d | 2022-07-01 01:45:44 -0700 | [diff] [blame] | 93 | // Creates an object with the given lifetime and type. |
| 94 | // The returned object will live as long as this `ObjectRepository`. |
| 95 | const Object* CreateObject(Lifetime lifetime, clang::QualType type); |
| 96 | |
| 97 | // Creates an object representing a declared function. |
| 98 | // The returned object will live as long as this `ObjectRepository`. |
| 99 | const Object* CreateObjectFromFunctionDecl(const clang::FunctionDecl& func); |
| 100 | |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 101 | // Returns the object associated with a variable or function. |
Martin Brænne | 46b5f07 | 2022-07-01 02:29:16 -0700 | [diff] [blame] | 102 | const Object* GetDeclObject(const clang::ValueDecl* decl) const; |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 103 | |
| 104 | // Returns the object associated with a materialize temporary expression. |
Martin Brænne | d7c0d0b | 2022-07-01 05:43:00 -0700 | [diff] [blame] | 105 | const Object* GetTemporaryObject( |
| 106 | const clang::MaterializeTemporaryExpr* expr) const; |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 107 | |
| 108 | // Returns the object representing the value of a function parameter at |
| 109 | // function entry. |
| 110 | // Note: This `Object` does not represent the parameter variable itself; |
| 111 | // use GetDeclObject() to retrieve that. We're using an `Object` here |
| 112 | // because we don't have a dedicated "value" class, but you should not |
| 113 | // use this object's identity in any way; i.e. no other `Object` in the |
| 114 | // points-to map should ever point to the object returned by this |
| 115 | // function. |
Martin Brænne | d7c0d0b | 2022-07-01 05:43:00 -0700 | [diff] [blame] | 116 | const Object* GetOriginalParameterValue( |
| 117 | const clang::ParmVarDecl* var_decl) const; |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 118 | |
| 119 | // Returns the object associated with an argument to a CallExpr. |
Martin Brænne | d7c0d0b | 2022-07-01 05:43:00 -0700 | [diff] [blame] | 120 | const Object* GetCallExprArgumentObject(const clang::CallExpr* expr, |
| 121 | size_t arg_index) const; |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 122 | |
| 123 | // Returns the object associated with the `this` argument to a CallExpr that |
| 124 | // represents a method call. Note that this object represents the `this` |
| 125 | // pointer, not the object that the method is being called on. |
Martin Brænne | d7c0d0b | 2022-07-01 05:43:00 -0700 | [diff] [blame] | 126 | const Object* GetCallExprThisPointer(const clang::CallExpr* expr) const; |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 127 | |
| 128 | // Returns the object associated with an argument to a CXXConstructExpr. |
Martin Brænne | d7c0d0b | 2022-07-01 05:43:00 -0700 | [diff] [blame] | 129 | const Object* GetCXXConstructExprArgumentObject( |
| 130 | const clang::CXXConstructExpr* expr, size_t arg_index) const; |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 131 | |
| 132 | // Returns the object associated with the `this` argument to a |
| 133 | // CXXConstructExpr. Note that this object represents the `this` pointer, not |
| 134 | // the object that the method is being called on (which is represnted by the |
| 135 | // object from GetInitializedObject()). |
Martin Brænne | d7c0d0b | 2022-07-01 05:43:00 -0700 | [diff] [blame] | 136 | const Object* GetCXXConstructExprThisPointer( |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 137 | const clang::CXXConstructExpr* expr) const; |
| 138 | |
| 139 | // Returns the object associated with, and initialized by, a constructor call |
| 140 | // (CXXConstructExpr) or a initializer list (CXXInitListExpr). Note that this |
| 141 | // represents the actual class object being initialized, not the `this` |
| 142 | // pointer to it that is passed to methods of the class, and which is |
| 143 | // represented by the object from GetCXXConstructExprThisPointer(). |
Martin Brænne | d7c0d0b | 2022-07-01 05:43:00 -0700 | [diff] [blame] | 144 | const Object* GetInitializedObject(const clang::Expr* initializer_expr) const; |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 145 | |
| 146 | // Returns what kind of values the given object represents. |
Martin Brænne | 1b98ac6 | 2022-07-01 06:24:52 -0700 | [diff] [blame] | 147 | ObjectValueType GetObjectValueType(const Object* object) const; |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 148 | |
| 149 | // Returns the object that represents `*this`, if in a member function. |
Martin Brænne | d7c0d0b | 2022-07-01 05:43:00 -0700 | [diff] [blame] | 150 | std::optional<const Object*> GetThisObject() const { return this_object_; } |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 151 | |
| 152 | // Returns the `Object` associated with the return value of the function. |
| 153 | // Unlike the `Object`s for variables, the "return value object" is a fiction |
| 154 | // -- there is not, in general, going to be a single object associated with |
| 155 | // the return value, and it will not, in general, be possible to take the |
| 156 | // address of the return value object. It's still a useful fiction, however, |
| 157 | // because it allows us to treat return values the same way as other values. |
Martin Brænne | d7c0d0b | 2022-07-01 05:43:00 -0700 | [diff] [blame] | 158 | const Object* GetReturnObject() const { return return_object_; } |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 159 | |
| 160 | // Returns the object associated with a given field in the struct |
| 161 | // represented by `struct_object`. |
Martin Brænne | af59468 | 2022-07-01 06:12:16 -0700 | [diff] [blame] | 162 | const Object* GetFieldObject(const Object* struct_object, |
Martin Brænne | 1b98ac6 | 2022-07-01 06:24:52 -0700 | [diff] [blame] | 163 | const clang::FieldDecl* field) const; |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 164 | |
| 165 | // Returns the objects associated with a given field in the structs |
| 166 | // represented by `struct_objects`. |
| 167 | ObjectSet GetFieldObject(const ObjectSet& struct_objects, |
| 168 | const clang::FieldDecl* field) const; |
| 169 | |
| 170 | // Returns FieldObjects; useful for producing debugging output. |
| 171 | const FieldObjects& GetFieldObjects() const { return field_object_map_; } |
| 172 | |
| 173 | // Returns the object associated with a given base of the struct |
| 174 | // represented by `struct_object`. |
Martin Brænne | 1b98ac6 | 2022-07-01 06:24:52 -0700 | [diff] [blame] | 175 | const Object* GetBaseClassObject(const Object* struct_object, |
Martin Brænne | e08ac88 | 2022-07-01 02:24:49 -0700 | [diff] [blame] | 176 | const clang::Type* base) const; |
Martin Brænne | af59468 | 2022-07-01 06:12:16 -0700 | [diff] [blame] | 177 | const Object* GetBaseClassObject(const Object* struct_object, |
Martin Brænne | e08ac88 | 2022-07-01 02:24:49 -0700 | [diff] [blame] | 178 | const clang::QualType base) const { |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 179 | return GetBaseClassObject(struct_object, base.getTypePtr()); |
| 180 | } |
| 181 | |
| 182 | // Returns the objects associated with a given base of the structs |
| 183 | // represented by `struct_object`. |
| 184 | ObjectSet GetBaseClassObject(const ObjectSet& struct_objects, |
| 185 | const clang::Type* base) const; |
| 186 | |
| 187 | // Returns BaseObjects; useful for producing debugging output. |
| 188 | const BaseObjects& GetBaseObjects() const { return base_object_map_; } |
| 189 | |
| 190 | // Returns the PointsToMap implied by variable declarations, i.e. assuming |
| 191 | // that no code has been executed yet. |
| 192 | const PointsToMap& InitialPointsToMap() const { |
| 193 | return initial_points_to_map_; |
| 194 | } |
| 195 | |
| 196 | // Creates and returns an object with static lifetime of the given type. |
| 197 | // Also creates any transitive objects if required. |
| 198 | // When called multiple times with the same `type`, this function always |
| 199 | // returns the same object. This is to guarantee that the number of objects |
| 200 | // used in the analysis is bounded and that therefore the lattice is finite |
| 201 | // and the analysis terminates. |
Martin Brænne | d7c0d0b | 2022-07-01 05:43:00 -0700 | [diff] [blame] | 202 | const Object* CreateStaticObject(clang::QualType type); |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 203 | |
| 204 | private: |
Martin Brænne | 493d4d4 | 2022-07-01 05:44:23 -0700 | [diff] [blame] | 205 | void CreateObjects(const Object* root_object, clang::QualType type, |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 206 | LifetimeFactory lifetime_factory, bool transitive); |
| 207 | |
Martin Brænne | d8e3214 | 2022-07-01 01:54:41 -0700 | [diff] [blame] | 208 | const Object* CloneObject(const Object* object); |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 209 | |
Martin Brænne | 46f1a57 | 2022-07-01 02:07:07 -0700 | [diff] [blame] | 210 | std::optional<const Object*> GetFieldObjectInternal( |
Martin Brænne | 1b98ac6 | 2022-07-01 06:24:52 -0700 | [diff] [blame] | 211 | const Object* struct_object, const clang::FieldDecl* field) const; |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 212 | |
Martin Brænne | 4a1231d | 2022-07-01 01:45:44 -0700 | [diff] [blame] | 213 | llvm::SpecificBumpPtrAllocator<Object> object_allocator_; |
| 214 | |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 215 | // Map from each variable declaration to the object which it declares. |
| 216 | MapType object_repository_; |
| 217 | |
| 218 | // Map from each materialized temporary to the object which it declares. |
Martin Brænne | 8f8e4fe | 2022-07-01 01:53:28 -0700 | [diff] [blame] | 219 | llvm::DenseMap<const clang::MaterializeTemporaryExpr*, const Object*> |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 220 | temporary_objects_; |
| 221 | |
| 222 | // Map from each function parameter to an object representing its initial |
| 223 | // value at function entry. |
Martin Brænne | d8e3214 | 2022-07-01 01:54:41 -0700 | [diff] [blame] | 224 | llvm::DenseMap<const clang::ParmVarDecl*, const Object*> |
| 225 | initial_parameter_object_; |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 226 | |
| 227 | // Map from each initializer (constructors or initializer lists) to the object |
| 228 | // which it initializes. |
| 229 | // |
| 230 | // An object in this map may occur in other places too: `object_repository_` |
| 231 | // if it is an lvalue, or `return_object_`. Or it may be a temporary in which |
| 232 | // case it is only found in this map. |
Martin Brænne | ecd58c3 | 2022-07-01 02:25:47 -0700 | [diff] [blame] | 233 | llvm::DenseMap<const clang::Expr*, const Object*> initialized_objects_; |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 234 | |
Martin Brænne | 04fb3a4 | 2022-07-01 01:52:21 -0700 | [diff] [blame] | 235 | std::optional<const Object*> this_object_; |
| 236 | const Object* return_object_; |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 237 | |
Martin Brænne | 1b98ac6 | 2022-07-01 06:24:52 -0700 | [diff] [blame] | 238 | llvm::DenseMap<const Object*, ObjectValueType> object_value_types_; |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 239 | |
| 240 | class VarDeclVisitor; |
| 241 | |
| 242 | PointsToMap initial_points_to_map_; |
| 243 | FieldObjects field_object_map_; |
| 244 | BaseObjects base_object_map_; |
| 245 | |
Martin Brænne | 982a115 | 2022-07-01 01:55:53 -0700 | [diff] [blame] | 246 | llvm::DenseMap<std::pair<const clang::Expr*, size_t>, const Object*> |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 247 | call_expr_args_objects_; |
| 248 | |
Martin Brænne | 982a115 | 2022-07-01 01:55:53 -0700 | [diff] [blame] | 249 | llvm::DenseMap<const clang::Expr*, const Object*> call_expr_this_pointers_; |
Martin Brænne | 5740582 | 2022-07-01 01:36:46 -0700 | [diff] [blame] | 250 | |
Martin Brænne | 3b587cf | 2022-07-01 01:57:01 -0700 | [diff] [blame] | 251 | llvm::DenseMap<clang::QualType, const Object*> static_objects_; |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 252 | }; |
| 253 | |
| 254 | } // namespace lifetimes |
| 255 | } // namespace tidy |
| 256 | } // namespace clang |
| 257 | |
| 258 | #endif // DEVTOOLS_RUST_CC_INTEROP_LIFETIME_ANALYSIS_OBJECT_REPOSITORY_H_ |