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