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_TypeSynthetic_h_ 10 #define lldb_TypeSynthetic_h_ 11 12 #include <stdint.h> 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 DISALLOW_COPY_AND_ASSIGN(SyntheticChildrenFrontEnd); 100 }; 101 102 class SyntheticValueProviderFrontEnd : public SyntheticChildrenFrontEnd { 103 public: 104 SyntheticValueProviderFrontEnd(ValueObject &backend) 105 : SyntheticChildrenFrontEnd(backend) {} 106 107 ~SyntheticValueProviderFrontEnd() override = default; 108 109 size_t CalculateNumChildren() override { return 0; } 110 111 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { return nullptr; } 112 113 size_t GetIndexOfChildWithName(ConstString name) override { 114 return UINT32_MAX; 115 } 116 117 bool Update() override { return false; } 118 119 bool MightHaveChildren() override { return false; } 120 121 lldb::ValueObjectSP GetSyntheticValue() override = 0; 122 123 private: 124 DISALLOW_COPY_AND_ASSIGN(SyntheticValueProviderFrontEnd); 125 }; 126 127 class SyntheticChildren { 128 public: 129 class Flags { 130 public: 131 Flags() : m_flags(lldb::eTypeOptionCascade) {} 132 133 Flags(const Flags &other) : m_flags(other.m_flags) {} 134 135 Flags(uint32_t value) : m_flags(value) {} 136 137 Flags &operator=(const Flags &rhs) { 138 if (&rhs != this) 139 m_flags = rhs.m_flags; 140 141 return *this; 142 } 143 144 Flags &operator=(const uint32_t &rhs) { 145 m_flags = rhs; 146 return *this; 147 } 148 149 Flags &Clear() { 150 m_flags = 0; 151 return *this; 152 } 153 154 bool GetCascades() const { 155 return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade; 156 } 157 158 Flags &SetCascades(bool value = true) { 159 if (value) 160 m_flags |= lldb::eTypeOptionCascade; 161 else 162 m_flags &= ~lldb::eTypeOptionCascade; 163 return *this; 164 } 165 166 bool GetSkipPointers() const { 167 return (m_flags & lldb::eTypeOptionSkipPointers) == 168 lldb::eTypeOptionSkipPointers; 169 } 170 171 Flags &SetSkipPointers(bool value = true) { 172 if (value) 173 m_flags |= lldb::eTypeOptionSkipPointers; 174 else 175 m_flags &= ~lldb::eTypeOptionSkipPointers; 176 return *this; 177 } 178 179 bool GetSkipReferences() const { 180 return (m_flags & lldb::eTypeOptionSkipReferences) == 181 lldb::eTypeOptionSkipReferences; 182 } 183 184 Flags &SetSkipReferences(bool value = true) { 185 if (value) 186 m_flags |= lldb::eTypeOptionSkipReferences; 187 else 188 m_flags &= ~lldb::eTypeOptionSkipReferences; 189 return *this; 190 } 191 192 bool GetNonCacheable() const { 193 return (m_flags & lldb::eTypeOptionNonCacheable) == 194 lldb::eTypeOptionNonCacheable; 195 } 196 197 Flags &SetNonCacheable(bool value = true) { 198 if (value) 199 m_flags |= lldb::eTypeOptionNonCacheable; 200 else 201 m_flags &= ~lldb::eTypeOptionNonCacheable; 202 return *this; 203 } 204 205 bool GetFrontEndWantsDereference() const { 206 return (m_flags & lldb::eTypeOptionFrontEndWantsDereference) == 207 lldb::eTypeOptionFrontEndWantsDereference; 208 } 209 210 Flags &SetFrontEndWantsDereference(bool value = true) { 211 if (value) 212 m_flags |= lldb::eTypeOptionFrontEndWantsDereference; 213 else 214 m_flags &= ~lldb::eTypeOptionFrontEndWantsDereference; 215 return *this; 216 } 217 218 uint32_t GetValue() { return m_flags; } 219 220 void SetValue(uint32_t value) { m_flags = value; } 221 222 private: 223 uint32_t m_flags; 224 }; 225 226 SyntheticChildren(const Flags &flags) : m_flags(flags) {} 227 228 virtual ~SyntheticChildren() = default; 229 230 bool Cascades() const { return m_flags.GetCascades(); } 231 232 bool SkipsPointers() const { return m_flags.GetSkipPointers(); } 233 234 bool SkipsReferences() const { return m_flags.GetSkipReferences(); } 235 236 bool NonCacheable() const { return m_flags.GetNonCacheable(); } 237 238 bool WantsDereference() const { return m_flags.GetFrontEndWantsDereference();} 239 240 void SetCascades(bool value) { m_flags.SetCascades(value); } 241 242 void SetSkipsPointers(bool value) { m_flags.SetSkipPointers(value); } 243 244 void SetSkipsReferences(bool value) { m_flags.SetSkipReferences(value); } 245 246 void SetNonCacheable(bool value) { m_flags.SetNonCacheable(value); } 247 248 uint32_t GetOptions() { return m_flags.GetValue(); } 249 250 void SetOptions(uint32_t value) { m_flags.SetValue(value); } 251 252 virtual bool IsScripted() = 0; 253 254 virtual std::string GetDescription() = 0; 255 256 virtual SyntheticChildrenFrontEnd::AutoPointer 257 GetFrontEnd(ValueObject &backend) = 0; 258 259 typedef std::shared_ptr<SyntheticChildren> SharedPointer; 260 261 uint32_t &GetRevision() { return m_my_revision; } 262 263 protected: 264 uint32_t m_my_revision; 265 Flags m_flags; 266 267 private: 268 DISALLOW_COPY_AND_ASSIGN(SyntheticChildren); 269 }; 270 271 class TypeFilterImpl : public SyntheticChildren { 272 std::vector<std::string> m_expression_paths; 273 274 public: 275 TypeFilterImpl(const SyntheticChildren::Flags &flags) 276 : SyntheticChildren(flags), m_expression_paths() {} 277 278 TypeFilterImpl(const SyntheticChildren::Flags &flags, 279 const std::initializer_list<const char *> items) 280 : SyntheticChildren(flags), m_expression_paths() { 281 for (auto path : items) 282 AddExpressionPath(path); 283 } 284 285 void AddExpressionPath(const char *path) { 286 AddExpressionPath(std::string(path)); 287 } 288 289 void Clear() { m_expression_paths.clear(); } 290 291 size_t GetCount() const { return m_expression_paths.size(); } 292 293 const char *GetExpressionPathAtIndex(size_t i) const { 294 return m_expression_paths[i].c_str(); 295 } 296 297 bool SetExpressionPathAtIndex(size_t i, const char *path) { 298 return SetExpressionPathAtIndex(i, std::string(path)); 299 } 300 301 void AddExpressionPath(const std::string &path); 302 303 bool SetExpressionPathAtIndex(size_t i, const std::string &path); 304 305 bool IsScripted() override { return false; } 306 307 std::string GetDescription() override; 308 309 class FrontEnd : public SyntheticChildrenFrontEnd { 310 public: 311 FrontEnd(TypeFilterImpl *flt, ValueObject &backend) 312 : SyntheticChildrenFrontEnd(backend), filter(flt) {} 313 314 ~FrontEnd() override = default; 315 316 size_t CalculateNumChildren() override { return filter->GetCount(); } 317 318 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { 319 if (idx >= filter->GetCount()) 320 return lldb::ValueObjectSP(); 321 return m_backend.GetSyntheticExpressionPathChild( 322 filter->GetExpressionPathAtIndex(idx), true); 323 } 324 325 bool Update() override { return false; } 326 327 bool MightHaveChildren() override { return filter->GetCount() > 0; } 328 329 size_t GetIndexOfChildWithName(ConstString name) override; 330 331 typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer; 332 333 private: 334 TypeFilterImpl *filter; 335 336 DISALLOW_COPY_AND_ASSIGN(FrontEnd); 337 }; 338 339 SyntheticChildrenFrontEnd::AutoPointer 340 GetFrontEnd(ValueObject &backend) override { 341 return SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(this, backend)); 342 } 343 344 typedef std::shared_ptr<TypeFilterImpl> SharedPointer; 345 346 private: 347 DISALLOW_COPY_AND_ASSIGN(TypeFilterImpl); 348 }; 349 350 class CXXSyntheticChildren : public SyntheticChildren { 351 public: 352 typedef std::function<SyntheticChildrenFrontEnd *(CXXSyntheticChildren *, 353 lldb::ValueObjectSP)> 354 CreateFrontEndCallback; 355 CXXSyntheticChildren(const SyntheticChildren::Flags &flags, 356 const char *description, CreateFrontEndCallback callback) 357 : SyntheticChildren(flags), m_create_callback(callback), 358 m_description(description ? description : "") {} 359 360 bool IsScripted() override { return false; } 361 362 std::string GetDescription() override; 363 364 SyntheticChildrenFrontEnd::AutoPointer 365 GetFrontEnd(ValueObject &backend) override { 366 return SyntheticChildrenFrontEnd::AutoPointer( 367 m_create_callback(this, backend.GetSP())); 368 } 369 370 protected: 371 CreateFrontEndCallback m_create_callback; 372 std::string m_description; 373 374 private: 375 DISALLOW_COPY_AND_ASSIGN(CXXSyntheticChildren); 376 }; 377 378 class ScriptedSyntheticChildren : public SyntheticChildren { 379 std::string m_python_class; 380 std::string m_python_code; 381 382 public: 383 ScriptedSyntheticChildren(const SyntheticChildren::Flags &flags, 384 const char *pclass, const char *pcode = nullptr) 385 : SyntheticChildren(flags), m_python_class(), m_python_code() { 386 if (pclass) 387 m_python_class = pclass; 388 if (pcode) 389 m_python_code = pcode; 390 } 391 392 const char *GetPythonClassName() { return m_python_class.c_str(); } 393 394 const char *GetPythonCode() { return m_python_code.c_str(); } 395 396 void SetPythonClassName(const char *fname) { 397 m_python_class.assign(fname); 398 m_python_code.clear(); 399 } 400 401 void SetPythonCode(const char *script) { m_python_code.assign(script); } 402 403 std::string GetDescription() override; 404 405 bool IsScripted() override { return true; } 406 407 class FrontEnd : public SyntheticChildrenFrontEnd { 408 public: 409 FrontEnd(std::string pclass, ValueObject &backend); 410 411 ~FrontEnd() override; 412 413 bool IsValid(); 414 415 size_t CalculateNumChildren() override; 416 417 size_t CalculateNumChildren(uint32_t max) override; 418 419 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 420 421 bool Update() override; 422 423 bool MightHaveChildren() override; 424 425 size_t GetIndexOfChildWithName(ConstString name) override; 426 427 lldb::ValueObjectSP GetSyntheticValue() override; 428 429 ConstString GetSyntheticTypeName() override; 430 431 typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer; 432 433 private: 434 std::string m_python_class; 435 StructuredData::ObjectSP m_wrapper_sp; 436 ScriptInterpreter *m_interpreter; 437 438 DISALLOW_COPY_AND_ASSIGN(FrontEnd); 439 }; 440 441 SyntheticChildrenFrontEnd::AutoPointer 442 GetFrontEnd(ValueObject &backend) override { 443 auto synth_ptr = SyntheticChildrenFrontEnd::AutoPointer( 444 new FrontEnd(m_python_class, backend)); 445 if (synth_ptr && ((FrontEnd *)synth_ptr.get())->IsValid()) 446 return synth_ptr; 447 return nullptr; 448 } 449 450 private: 451 DISALLOW_COPY_AND_ASSIGN(ScriptedSyntheticChildren); 452 }; 453 } // namespace lldb_private 454 455 #endif // lldb_TypeSynthetic_h_ 456