1 //===-- TypeSynthetic.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 #ifndef LLDB_DATAFORMATTERS_TYPESYNTHETIC_H 10 #define LLDB_DATAFORMATTERS_TYPESYNTHETIC_H 11 12 #include <cstdint> 13 14 #include <functional> 15 #include <initializer_list> 16 #include <memory> 17 #include <string> 18 #include <vector> 19 20 #include "lldb/lldb-enumerations.h" 21 #include "lldb/lldb-public.h" 22 23 #include "lldb/Core/ValueObject.h" 24 #include "lldb/Utility/StructuredData.h" 25 26 namespace lldb_private { 27 class SyntheticChildrenFrontEnd { 28 protected: 29 ValueObject &m_backend; 30 31 void SetValid(bool valid) { m_valid = valid; } 32 33 bool IsValid() { return m_valid; } 34 35 public: 36 SyntheticChildrenFrontEnd(ValueObject &backend) 37 : m_backend(backend), m_valid(true) {} 38 39 virtual ~SyntheticChildrenFrontEnd() = default; 40 41 virtual size_t CalculateNumChildren() = 0; 42 43 virtual size_t CalculateNumChildren(uint32_t max) { 44 auto count = CalculateNumChildren(); 45 return count <= max ? count : max; 46 } 47 48 virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx) = 0; 49 50 virtual size_t GetIndexOfChildWithName(ConstString name) = 0; 51 52 // this function is assumed to always succeed and it if fails, the front-end 53 // should know to deal with it in the correct way (most probably, by refusing 54 // to return any children) the return value of Update() should actually be 55 // interpreted as "ValueObjectSyntheticFilter cache is good/bad" if =true, 56 // ValueObjectSyntheticFilter is allowed to use the children it fetched 57 // previously and cached if =false, ValueObjectSyntheticFilter must throw 58 // away its cache, and query again for children 59 virtual bool Update() = 0; 60 61 // if this function returns false, then CalculateNumChildren() MUST return 0 62 // since UI frontends might validly decide not to inquire for children given 63 // a false return value from this call if it returns true, then 64 // CalculateNumChildren() can return any number >= 0 (0 being valid) it 65 // should if at all possible be more efficient than CalculateNumChildren() 66 virtual bool MightHaveChildren() = 0; 67 68 // if this function returns a non-null ValueObject, then the returned 69 // ValueObject will stand for this ValueObject whenever a "value" request is 70 // made to this ValueObject 71 virtual lldb::ValueObjectSP GetSyntheticValue() { return nullptr; } 72 73 // if this function returns a non-empty ConstString, then clients are 74 // expected to use the return as the name of the type of this ValueObject for 75 // display purposes 76 virtual ConstString GetSyntheticTypeName() { return ConstString(); } 77 78 typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer; 79 typedef std::unique_ptr<SyntheticChildrenFrontEnd> AutoPointer; 80 81 protected: 82 lldb::ValueObjectSP 83 CreateValueObjectFromExpression(llvm::StringRef name, 84 llvm::StringRef expression, 85 const ExecutionContext &exe_ctx); 86 87 lldb::ValueObjectSP 88 CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address, 89 const ExecutionContext &exe_ctx, 90 CompilerType type); 91 92 lldb::ValueObjectSP CreateValueObjectFromData(llvm::StringRef name, 93 const DataExtractor &data, 94 const ExecutionContext &exe_ctx, 95 CompilerType type); 96 97 private: 98 bool m_valid; 99 SyntheticChildrenFrontEnd(const SyntheticChildrenFrontEnd &) = delete; 100 const SyntheticChildrenFrontEnd & 101 operator=(const SyntheticChildrenFrontEnd &) = delete; 102 }; 103 104 class SyntheticValueProviderFrontEnd : public SyntheticChildrenFrontEnd { 105 public: 106 SyntheticValueProviderFrontEnd(ValueObject &backend) 107 : SyntheticChildrenFrontEnd(backend) {} 108 109 ~SyntheticValueProviderFrontEnd() override = default; 110 111 size_t CalculateNumChildren() override { return 0; } 112 113 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { return nullptr; } 114 115 size_t GetIndexOfChildWithName(ConstString name) override { 116 return UINT32_MAX; 117 } 118 119 bool Update() override { return false; } 120 121 bool MightHaveChildren() override { return false; } 122 123 lldb::ValueObjectSP GetSyntheticValue() override = 0; 124 125 private: 126 SyntheticValueProviderFrontEnd(const SyntheticValueProviderFrontEnd &) = 127 delete; 128 const SyntheticValueProviderFrontEnd & 129 operator=(const SyntheticValueProviderFrontEnd &) = delete; 130 }; 131 132 class SyntheticChildren { 133 public: 134 class Flags { 135 public: 136 Flags() = default; 137 138 Flags(const Flags &other) : m_flags(other.m_flags) {} 139 140 Flags(uint32_t value) : m_flags(value) {} 141 142 Flags &operator=(const Flags &rhs) { 143 if (&rhs != this) 144 m_flags = rhs.m_flags; 145 146 return *this; 147 } 148 149 Flags &operator=(const uint32_t &rhs) { 150 m_flags = rhs; 151 return *this; 152 } 153 154 Flags &Clear() { 155 m_flags = 0; 156 return *this; 157 } 158 159 bool GetCascades() const { 160 return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade; 161 } 162 163 Flags &SetCascades(bool value = true) { 164 if (value) 165 m_flags |= lldb::eTypeOptionCascade; 166 else 167 m_flags &= ~lldb::eTypeOptionCascade; 168 return *this; 169 } 170 171 bool GetSkipPointers() const { 172 return (m_flags & lldb::eTypeOptionSkipPointers) == 173 lldb::eTypeOptionSkipPointers; 174 } 175 176 Flags &SetSkipPointers(bool value = true) { 177 if (value) 178 m_flags |= lldb::eTypeOptionSkipPointers; 179 else 180 m_flags &= ~lldb::eTypeOptionSkipPointers; 181 return *this; 182 } 183 184 bool GetSkipReferences() const { 185 return (m_flags & lldb::eTypeOptionSkipReferences) == 186 lldb::eTypeOptionSkipReferences; 187 } 188 189 Flags &SetSkipReferences(bool value = true) { 190 if (value) 191 m_flags |= lldb::eTypeOptionSkipReferences; 192 else 193 m_flags &= ~lldb::eTypeOptionSkipReferences; 194 return *this; 195 } 196 197 bool GetNonCacheable() const { 198 return (m_flags & lldb::eTypeOptionNonCacheable) == 199 lldb::eTypeOptionNonCacheable; 200 } 201 202 Flags &SetNonCacheable(bool value = true) { 203 if (value) 204 m_flags |= lldb::eTypeOptionNonCacheable; 205 else 206 m_flags &= ~lldb::eTypeOptionNonCacheable; 207 return *this; 208 } 209 210 bool GetFrontEndWantsDereference() const { 211 return (m_flags & lldb::eTypeOptionFrontEndWantsDereference) == 212 lldb::eTypeOptionFrontEndWantsDereference; 213 } 214 215 Flags &SetFrontEndWantsDereference(bool value = true) { 216 if (value) 217 m_flags |= lldb::eTypeOptionFrontEndWantsDereference; 218 else 219 m_flags &= ~lldb::eTypeOptionFrontEndWantsDereference; 220 return *this; 221 } 222 223 uint32_t GetValue() { return m_flags; } 224 225 void SetValue(uint32_t value) { m_flags = value; } 226 227 private: 228 uint32_t m_flags = lldb::eTypeOptionCascade; 229 }; 230 231 SyntheticChildren(const Flags &flags); 232 233 virtual ~SyntheticChildren(); 234 235 bool Cascades() const { return m_flags.GetCascades(); } 236 237 bool SkipsPointers() const { return m_flags.GetSkipPointers(); } 238 239 bool SkipsReferences() const { return m_flags.GetSkipReferences(); } 240 241 bool NonCacheable() const { return m_flags.GetNonCacheable(); } 242 243 bool WantsDereference() const { return m_flags.GetFrontEndWantsDereference();} 244 245 void SetCascades(bool value) { m_flags.SetCascades(value); } 246 247 void SetSkipsPointers(bool value) { m_flags.SetSkipPointers(value); } 248 249 void SetSkipsReferences(bool value) { m_flags.SetSkipReferences(value); } 250 251 void SetNonCacheable(bool value) { m_flags.SetNonCacheable(value); } 252 253 uint32_t GetOptions() { return m_flags.GetValue(); } 254 255 void SetOptions(uint32_t value) { m_flags.SetValue(value); } 256 257 virtual bool IsScripted() = 0; 258 259 virtual std::string GetDescription() = 0; 260 261 virtual SyntheticChildrenFrontEnd::AutoPointer 262 GetFrontEnd(ValueObject &backend) = 0; 263 264 typedef std::shared_ptr<SyntheticChildren> SharedPointer; 265 266 uint32_t &GetRevision() { return m_my_revision; } 267 268 protected: 269 uint32_t m_my_revision = 0; 270 Flags m_flags; 271 272 private: 273 SyntheticChildren(const SyntheticChildren &) = delete; 274 const SyntheticChildren &operator=(const SyntheticChildren &) = delete; 275 }; 276 277 class TypeFilterImpl : public SyntheticChildren { 278 std::vector<std::string> m_expression_paths; 279 280 public: 281 TypeFilterImpl(const SyntheticChildren::Flags &flags) 282 : SyntheticChildren(flags) {} 283 284 TypeFilterImpl(const SyntheticChildren::Flags &flags, 285 const std::initializer_list<const char *> items) 286 : SyntheticChildren(flags) { 287 for (auto path : items) 288 AddExpressionPath(path); 289 } 290 291 void AddExpressionPath(const char *path) { 292 AddExpressionPath(std::string(path)); 293 } 294 295 void Clear() { m_expression_paths.clear(); } 296 297 size_t GetCount() const { return m_expression_paths.size(); } 298 299 const char *GetExpressionPathAtIndex(size_t i) const { 300 return m_expression_paths[i].c_str(); 301 } 302 303 bool SetExpressionPathAtIndex(size_t i, const char *path) { 304 return SetExpressionPathAtIndex(i, std::string(path)); 305 } 306 307 void AddExpressionPath(const std::string &path); 308 309 bool SetExpressionPathAtIndex(size_t i, const std::string &path); 310 311 bool IsScripted() override { return false; } 312 313 std::string GetDescription() override; 314 315 class FrontEnd : public SyntheticChildrenFrontEnd { 316 public: 317 FrontEnd(TypeFilterImpl *flt, ValueObject &backend) 318 : SyntheticChildrenFrontEnd(backend), filter(flt) {} 319 320 ~FrontEnd() override = default; 321 322 size_t CalculateNumChildren() override { return filter->GetCount(); } 323 324 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { 325 if (idx >= filter->GetCount()) 326 return lldb::ValueObjectSP(); 327 return m_backend.GetSyntheticExpressionPathChild( 328 filter->GetExpressionPathAtIndex(idx), true); 329 } 330 331 bool Update() override { return false; } 332 333 bool MightHaveChildren() override { return filter->GetCount() > 0; } 334 335 size_t GetIndexOfChildWithName(ConstString name) override; 336 337 typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer; 338 339 private: 340 TypeFilterImpl *filter; 341 342 FrontEnd(const FrontEnd &) = delete; 343 const FrontEnd &operator=(const FrontEnd &) = delete; 344 }; 345 346 SyntheticChildrenFrontEnd::AutoPointer 347 GetFrontEnd(ValueObject &backend) override { 348 return SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(this, backend)); 349 } 350 351 typedef std::shared_ptr<TypeFilterImpl> SharedPointer; 352 353 private: 354 TypeFilterImpl(const TypeFilterImpl &) = delete; 355 const TypeFilterImpl &operator=(const TypeFilterImpl &) = delete; 356 }; 357 358 class CXXSyntheticChildren : public SyntheticChildren { 359 public: 360 typedef std::function<SyntheticChildrenFrontEnd *(CXXSyntheticChildren *, 361 lldb::ValueObjectSP)> 362 CreateFrontEndCallback; 363 CXXSyntheticChildren(const SyntheticChildren::Flags &flags, 364 const char *description, CreateFrontEndCallback callback); 365 366 virtual ~CXXSyntheticChildren(); 367 368 bool IsScripted() override { return false; } 369 370 std::string GetDescription() override; 371 372 SyntheticChildrenFrontEnd::AutoPointer 373 GetFrontEnd(ValueObject &backend) override { 374 return SyntheticChildrenFrontEnd::AutoPointer( 375 m_create_callback(this, backend.GetSP())); 376 } 377 378 protected: 379 CreateFrontEndCallback m_create_callback; 380 std::string m_description; 381 382 private: 383 CXXSyntheticChildren(const CXXSyntheticChildren &) = delete; 384 const CXXSyntheticChildren &operator=(const CXXSyntheticChildren &) = delete; 385 }; 386 387 class ScriptedSyntheticChildren : public SyntheticChildren { 388 std::string m_python_class; 389 std::string m_python_code; 390 391 public: 392 ScriptedSyntheticChildren(const SyntheticChildren::Flags &flags, 393 const char *pclass, const char *pcode = nullptr) 394 : SyntheticChildren(flags) { 395 if (pclass) 396 m_python_class = pclass; 397 if (pcode) 398 m_python_code = pcode; 399 } 400 401 const char *GetPythonClassName() { return m_python_class.c_str(); } 402 403 const char *GetPythonCode() { return m_python_code.c_str(); } 404 405 void SetPythonClassName(const char *fname) { 406 m_python_class.assign(fname); 407 m_python_code.clear(); 408 } 409 410 void SetPythonCode(const char *script) { m_python_code.assign(script); } 411 412 std::string GetDescription() override; 413 414 bool IsScripted() override { return true; } 415 416 class FrontEnd : public SyntheticChildrenFrontEnd { 417 public: 418 FrontEnd(std::string pclass, ValueObject &backend); 419 420 ~FrontEnd() override; 421 422 bool IsValid(); 423 424 size_t CalculateNumChildren() override; 425 426 size_t CalculateNumChildren(uint32_t max) override; 427 428 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 429 430 bool Update() override; 431 432 bool MightHaveChildren() override; 433 434 size_t GetIndexOfChildWithName(ConstString name) override; 435 436 lldb::ValueObjectSP GetSyntheticValue() override; 437 438 ConstString GetSyntheticTypeName() override; 439 440 typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer; 441 442 private: 443 std::string m_python_class; 444 StructuredData::ObjectSP m_wrapper_sp; 445 ScriptInterpreter *m_interpreter; 446 447 FrontEnd(const FrontEnd &) = delete; 448 const FrontEnd &operator=(const FrontEnd &) = delete; 449 }; 450 451 SyntheticChildrenFrontEnd::AutoPointer 452 GetFrontEnd(ValueObject &backend) override { 453 auto synth_ptr = SyntheticChildrenFrontEnd::AutoPointer( 454 new FrontEnd(m_python_class, backend)); 455 if (synth_ptr && ((FrontEnd *)synth_ptr.get())->IsValid()) 456 return synth_ptr; 457 return nullptr; 458 } 459 460 private: 461 ScriptedSyntheticChildren(const ScriptedSyntheticChildren &) = delete; 462 const ScriptedSyntheticChildren & 463 operator=(const ScriptedSyntheticChildren &) = delete; 464 }; 465 } // namespace lldb_private 466 467 #endif // LLDB_DATAFORMATTERS_TYPESYNTHETIC_H 468