1 //===-- TypeSynthetic.h -------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef lldb_TypeSynthetic_h_ 11 #define lldb_TypeSynthetic_h_ 12 13 // C Includes 14 #include <stdint.h> 15 16 // C++ Includes 17 #include <string> 18 #include <vector> 19 20 // Other libraries and framework includes 21 22 // Project includes 23 #include "lldb/lldb-public.h" 24 #include "lldb/lldb-enumerations.h" 25 26 #include "lldb/Core/ValueObject.h" 27 #include "lldb/Interpreter/ScriptInterpreterPython.h" 28 #include "lldb/Symbol/Type.h" 29 30 namespace lldb_private { 31 class SyntheticChildrenFrontEnd 32 { 33 protected: 34 ValueObject &m_backend; 35 36 void SetValid(bool valid)37 SetValid (bool valid) 38 { 39 m_valid = valid; 40 } 41 42 bool IsValid()43 IsValid () 44 { 45 return m_valid; 46 } 47 48 public: 49 SyntheticChildrenFrontEnd(ValueObject & backend)50 SyntheticChildrenFrontEnd (ValueObject &backend) : 51 m_backend(backend), 52 m_valid(true) 53 {} 54 55 virtual ~SyntheticChildrenFrontEnd()56 ~SyntheticChildrenFrontEnd () 57 { 58 } 59 60 virtual size_t 61 CalculateNumChildren () = 0; 62 63 virtual lldb::ValueObjectSP 64 GetChildAtIndex (size_t idx) = 0; 65 66 virtual size_t 67 GetIndexOfChildWithName (const ConstString &name) = 0; 68 69 // this function is assumed to always succeed and it if fails, the front-end should know to deal 70 // with it in the correct way (most probably, by refusing to return any children) 71 // the return value of Update() should actually be interpreted as "ValueObjectSyntheticFilter cache is good/bad" 72 // if =true, ValueObjectSyntheticFilter is allowed to use the children it fetched previously and cached 73 // if =false, ValueObjectSyntheticFilter must throw away its cache, and query again for children 74 virtual bool 75 Update () = 0; 76 77 // if this function returns false, then CalculateNumChildren() MUST return 0 since UI frontends 78 // might validly decide not to inquire for children given a false return value from this call 79 // if it returns true, then CalculateNumChildren() can return any number >= 0 (0 being valid) 80 // it should if at all possible be more efficient than CalculateNumChildren() 81 virtual bool 82 MightHaveChildren () = 0; 83 84 typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer; 85 typedef std::unique_ptr<SyntheticChildrenFrontEnd> AutoPointer; 86 87 private: 88 bool m_valid; 89 DISALLOW_COPY_AND_ASSIGN(SyntheticChildrenFrontEnd); 90 }; 91 92 class SyntheticChildren 93 { 94 public: 95 96 class Flags 97 { 98 public: 99 Flags()100 Flags () : 101 m_flags (lldb::eTypeOptionCascade) 102 {} 103 Flags(const Flags & other)104 Flags (const Flags& other) : 105 m_flags (other.m_flags) 106 {} 107 Flags(uint32_t value)108 Flags (uint32_t value) : 109 m_flags (value) 110 {} 111 112 Flags& 113 operator = (const Flags& rhs) 114 { 115 if (&rhs != this) 116 m_flags = rhs.m_flags; 117 118 return *this; 119 } 120 121 Flags& 122 operator = (const uint32_t& rhs) 123 { 124 m_flags = rhs; 125 return *this; 126 } 127 128 Flags& Clear()129 Clear() 130 { 131 m_flags = 0; 132 return *this; 133 } 134 135 bool GetCascades()136 GetCascades () const 137 { 138 return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade; 139 } 140 141 Flags& 142 SetCascades (bool value = true) 143 { 144 if (value) 145 m_flags |= lldb::eTypeOptionCascade; 146 else 147 m_flags &= ~lldb::eTypeOptionCascade; 148 return *this; 149 } 150 151 bool GetSkipPointers()152 GetSkipPointers () const 153 { 154 return (m_flags & lldb::eTypeOptionSkipPointers) == lldb::eTypeOptionSkipPointers; 155 } 156 157 Flags& 158 SetSkipPointers (bool value = true) 159 { 160 if (value) 161 m_flags |= lldb::eTypeOptionSkipPointers; 162 else 163 m_flags &= ~lldb::eTypeOptionSkipPointers; 164 return *this; 165 } 166 167 bool GetSkipReferences()168 GetSkipReferences () const 169 { 170 return (m_flags & lldb::eTypeOptionSkipReferences) == lldb::eTypeOptionSkipReferences; 171 } 172 173 Flags& 174 SetSkipReferences (bool value = true) 175 { 176 if (value) 177 m_flags |= lldb::eTypeOptionSkipReferences; 178 else 179 m_flags &= ~lldb::eTypeOptionSkipReferences; 180 return *this; 181 } 182 183 uint32_t GetValue()184 GetValue () 185 { 186 return m_flags; 187 } 188 189 void SetValue(uint32_t value)190 SetValue (uint32_t value) 191 { 192 m_flags = value; 193 } 194 195 private: 196 uint32_t m_flags; 197 }; 198 SyntheticChildren(const Flags & flags)199 SyntheticChildren (const Flags& flags) : 200 m_flags(flags) 201 { 202 } 203 204 virtual ~SyntheticChildren()205 ~SyntheticChildren () 206 { 207 } 208 209 bool Cascades()210 Cascades () const 211 { 212 return m_flags.GetCascades(); 213 } 214 bool SkipsPointers()215 SkipsPointers () const 216 { 217 return m_flags.GetSkipPointers(); 218 } 219 bool SkipsReferences()220 SkipsReferences () const 221 { 222 return m_flags.GetSkipReferences(); 223 } 224 225 void SetCascades(bool value)226 SetCascades (bool value) 227 { 228 m_flags.SetCascades(value); 229 } 230 231 void SetSkipsPointers(bool value)232 SetSkipsPointers (bool value) 233 { 234 m_flags.SetSkipPointers(value); 235 } 236 237 void SetSkipsReferences(bool value)238 SetSkipsReferences (bool value) 239 { 240 m_flags.SetSkipReferences(value); 241 } 242 243 uint32_t GetOptions()244 GetOptions () 245 { 246 return m_flags.GetValue(); 247 } 248 249 void SetOptions(uint32_t value)250 SetOptions (uint32_t value) 251 { 252 m_flags.SetValue(value); 253 } 254 255 virtual bool 256 IsScripted () = 0; 257 258 virtual std::string 259 GetDescription () = 0; 260 261 virtual SyntheticChildrenFrontEnd::AutoPointer 262 GetFrontEnd (ValueObject &backend) = 0; 263 264 typedef std::shared_ptr<SyntheticChildren> SharedPointer; 265 typedef bool(*SyntheticChildrenCallback)(void*, ConstString, const SyntheticChildren::SharedPointer&); 266 267 uint32_t& GetRevision()268 GetRevision () 269 { 270 return m_my_revision; 271 } 272 273 protected: 274 uint32_t m_my_revision; 275 Flags m_flags; 276 277 private: 278 DISALLOW_COPY_AND_ASSIGN(SyntheticChildren); 279 }; 280 281 class TypeFilterImpl : public SyntheticChildren 282 { 283 std::vector<std::string> m_expression_paths; 284 public: TypeFilterImpl(const SyntheticChildren::Flags & flags)285 TypeFilterImpl(const SyntheticChildren::Flags& flags) : 286 SyntheticChildren(flags), 287 m_expression_paths() 288 { 289 } 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 m_expression_paths() 295 { 296 for (auto path : items) 297 AddExpressionPath (path); 298 } 299 300 void AddExpressionPath(const char * path)301 AddExpressionPath (const char* path) 302 { 303 AddExpressionPath(std::string(path)); 304 } 305 306 void Clear()307 Clear() 308 { 309 m_expression_paths.clear(); 310 } 311 312 size_t GetCount()313 GetCount() const 314 { 315 return m_expression_paths.size(); 316 } 317 318 const char* GetExpressionPathAtIndex(size_t i)319 GetExpressionPathAtIndex(size_t i) const 320 { 321 return m_expression_paths[i].c_str(); 322 } 323 324 bool SetExpressionPathAtIndex(size_t i,const char * path)325 SetExpressionPathAtIndex (size_t i, const char* path) 326 { 327 return SetExpressionPathAtIndex(i, std::string(path)); 328 } 329 330 void AddExpressionPath(const std::string & path)331 AddExpressionPath (const std::string& path) 332 { 333 bool need_add_dot = true; 334 if (path[0] == '.' || 335 (path[0] == '-' && path[1] == '>') || 336 path[0] == '[') 337 need_add_dot = false; 338 // add a '.' symbol to help forgetful users 339 if(!need_add_dot) 340 m_expression_paths.push_back(path); 341 else 342 m_expression_paths.push_back(std::string(".") + path); 343 } 344 345 bool SetExpressionPathAtIndex(size_t i,const std::string & path)346 SetExpressionPathAtIndex (size_t i, const std::string& path) 347 { 348 if (i >= GetCount()) 349 return false; 350 bool need_add_dot = true; 351 if (path[0] == '.' || 352 (path[0] == '-' && path[1] == '>') || 353 path[0] == '[') 354 need_add_dot = false; 355 // add a '.' symbol to help forgetful users 356 if(!need_add_dot) 357 m_expression_paths[i] = path; 358 else 359 m_expression_paths[i] = std::string(".") + path; 360 return true; 361 } 362 363 bool IsScripted()364 IsScripted () 365 { 366 return false; 367 } 368 369 std::string 370 GetDescription (); 371 372 class FrontEnd : public SyntheticChildrenFrontEnd 373 { 374 private: 375 TypeFilterImpl* filter; 376 public: 377 FrontEnd(TypeFilterImpl * flt,ValueObject & backend)378 FrontEnd(TypeFilterImpl* flt, 379 ValueObject &backend) : 380 SyntheticChildrenFrontEnd(backend), 381 filter(flt) 382 {} 383 384 virtual ~FrontEnd()385 ~FrontEnd () 386 { 387 } 388 389 virtual size_t CalculateNumChildren()390 CalculateNumChildren () 391 { 392 return filter->GetCount(); 393 } 394 395 virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx)396 GetChildAtIndex (size_t idx) 397 { 398 if (idx >= filter->GetCount()) 399 return lldb::ValueObjectSP(); 400 return m_backend.GetSyntheticExpressionPathChild(filter->GetExpressionPathAtIndex(idx), true); 401 } 402 403 virtual bool Update()404 Update() { return false; } 405 406 virtual bool MightHaveChildren()407 MightHaveChildren () 408 { 409 return filter->GetCount() > 0; 410 } 411 412 virtual size_t GetIndexOfChildWithName(const ConstString & name)413 GetIndexOfChildWithName (const ConstString &name) 414 { 415 const char* name_cstr = name.GetCString(); 416 for (size_t i = 0; i < filter->GetCount(); i++) 417 { 418 const char* expr_cstr = filter->GetExpressionPathAtIndex(i); 419 if (expr_cstr) 420 { 421 if (*expr_cstr == '.') 422 expr_cstr++; 423 else if (*expr_cstr == '-' && *(expr_cstr+1) == '>') 424 expr_cstr += 2; 425 } 426 if (!::strcmp(name_cstr, expr_cstr)) 427 return i; 428 } 429 return UINT32_MAX; 430 } 431 432 typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer; 433 434 private: 435 DISALLOW_COPY_AND_ASSIGN(FrontEnd); 436 }; 437 438 virtual SyntheticChildrenFrontEnd::AutoPointer GetFrontEnd(ValueObject & backend)439 GetFrontEnd(ValueObject &backend) 440 { 441 return SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(this, backend)); 442 } 443 444 private: 445 DISALLOW_COPY_AND_ASSIGN(TypeFilterImpl); 446 }; 447 448 class CXXSyntheticChildren : public SyntheticChildren 449 { 450 public: 451 typedef SyntheticChildrenFrontEnd* (*CreateFrontEndCallback) (CXXSyntheticChildren*, lldb::ValueObjectSP); 452 protected: 453 CreateFrontEndCallback m_create_callback; 454 std::string m_description; 455 public: CXXSyntheticChildren(const SyntheticChildren::Flags & flags,const char * description,CreateFrontEndCallback callback)456 CXXSyntheticChildren (const SyntheticChildren::Flags& flags, 457 const char* description, 458 CreateFrontEndCallback callback) : 459 SyntheticChildren(flags), 460 m_create_callback(callback), 461 m_description(description ? description : "") 462 { 463 } 464 465 bool IsScripted()466 IsScripted () 467 { 468 return false; 469 } 470 471 std::string 472 GetDescription (); 473 474 virtual SyntheticChildrenFrontEnd::AutoPointer GetFrontEnd(ValueObject & backend)475 GetFrontEnd (ValueObject &backend) 476 { 477 return SyntheticChildrenFrontEnd::AutoPointer(m_create_callback(this, backend.GetSP())); 478 } 479 480 private: 481 DISALLOW_COPY_AND_ASSIGN(CXXSyntheticChildren); 482 }; 483 484 #ifndef LLDB_DISABLE_PYTHON 485 486 class ScriptedSyntheticChildren : public SyntheticChildren 487 { 488 std::string m_python_class; 489 std::string m_python_code; 490 public: 491 492 ScriptedSyntheticChildren (const SyntheticChildren::Flags& flags, 493 const char* pclass, 494 const char* pcode = NULL) : SyntheticChildren(flags)495 SyntheticChildren(flags), 496 m_python_class(), 497 m_python_code() 498 { 499 if (pclass) 500 m_python_class = pclass; 501 if (pcode) 502 m_python_code = pcode; 503 } 504 505 const char* GetPythonClassName()506 GetPythonClassName () 507 { 508 return m_python_class.c_str(); 509 } 510 511 const char* GetPythonCode()512 GetPythonCode () 513 { 514 return m_python_code.c_str(); 515 } 516 517 void SetPythonClassName(const char * fname)518 SetPythonClassName (const char* fname) 519 { 520 m_python_class.assign(fname); 521 m_python_code.clear(); 522 } 523 524 void SetPythonCode(const char * script)525 SetPythonCode (const char* script) 526 { 527 m_python_code.assign(script); 528 } 529 530 std::string 531 GetDescription (); 532 533 bool IsScripted()534 IsScripted () 535 { 536 return true; 537 } 538 539 class FrontEnd : public SyntheticChildrenFrontEnd 540 { 541 private: 542 std::string m_python_class; 543 lldb::ScriptInterpreterObjectSP m_wrapper_sp; 544 ScriptInterpreter *m_interpreter; 545 public: 546 547 FrontEnd (std::string pclass, 548 ValueObject &backend); 549 550 bool IsValid()551 IsValid () 552 { 553 return m_wrapper_sp.get() != nullptr && m_wrapper_sp->operator bool() && m_interpreter != nullptr; 554 } 555 556 virtual 557 ~FrontEnd (); 558 559 virtual size_t CalculateNumChildren()560 CalculateNumChildren () 561 { 562 if (!m_wrapper_sp || m_interpreter == NULL) 563 return 0; 564 return m_interpreter->CalculateNumChildren(m_wrapper_sp); 565 } 566 567 virtual lldb::ValueObjectSP 568 GetChildAtIndex (size_t idx); 569 570 virtual bool Update()571 Update () 572 { 573 if (!m_wrapper_sp || m_interpreter == NULL) 574 return false; 575 576 return m_interpreter->UpdateSynthProviderInstance(m_wrapper_sp); 577 } 578 579 virtual bool MightHaveChildren()580 MightHaveChildren () 581 { 582 if (!m_wrapper_sp || m_interpreter == NULL) 583 return false; 584 585 return m_interpreter->MightHaveChildrenSynthProviderInstance(m_wrapper_sp); 586 } 587 588 virtual size_t GetIndexOfChildWithName(const ConstString & name)589 GetIndexOfChildWithName (const ConstString &name) 590 { 591 if (!m_wrapper_sp || m_interpreter == NULL) 592 return UINT32_MAX; 593 return m_interpreter->GetIndexOfChildWithName(m_wrapper_sp, name.GetCString()); 594 } 595 596 typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer; 597 598 private: 599 DISALLOW_COPY_AND_ASSIGN(FrontEnd); 600 }; 601 602 virtual SyntheticChildrenFrontEnd::AutoPointer GetFrontEnd(ValueObject & backend)603 GetFrontEnd(ValueObject &backend) 604 { 605 auto synth_ptr = SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(m_python_class, backend)); 606 if (synth_ptr && ((FrontEnd*)synth_ptr.get())->IsValid()) 607 return synth_ptr; 608 return NULL; 609 } 610 611 private: 612 DISALLOW_COPY_AND_ASSIGN(ScriptedSyntheticChildren); 613 }; 614 #endif 615 } // namespace lldb_private 616 617 #endif // lldb_TypeSynthetic_h_ 618