LLDB  mainline
AppleObjCDeclVendor.cpp
Go to the documentation of this file.
1 //===-- AppleObjCDeclVendor.cpp -------------------------------------------===//
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 #include "AppleObjCDeclVendor.h"
10 
14 #include "lldb/Core/Module.h"
15 #include "lldb/Target/Process.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Utility/Log.h"
18 
19 #include "clang/AST/ASTContext.h"
20 #include "clang/AST/DeclObjC.h"
21 #include "clang/AST/ExternalASTSource.h"
22 
23 using namespace lldb_private;
24 
26  : public clang::ExternalASTSource {
27 public:
29  : m_decl_vendor(decl_vendor) {}
30 
31  bool FindExternalVisibleDeclsByName(const clang::DeclContext *decl_ctx,
32  clang::DeclarationName name) override {
33 
35  LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
36 
37  if (log) {
38  LLDB_LOGF(log,
39  "AppleObjCExternalASTSource::FindExternalVisibleDeclsByName"
40  " on (ASTContext*)%p Looking for %s in (%sDecl*)%p",
41  static_cast<void *>(&decl_ctx->getParentASTContext()),
42  name.getAsString().c_str(), decl_ctx->getDeclKindName(),
43  static_cast<const void *>(decl_ctx));
44  }
45 
46  do {
47  const clang::ObjCInterfaceDecl *interface_decl =
48  llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx);
49 
50  if (!interface_decl)
51  break;
52 
53  clang::ObjCInterfaceDecl *non_const_interface_decl =
54  const_cast<clang::ObjCInterfaceDecl *>(interface_decl);
55 
56  if (!m_decl_vendor.FinishDecl(non_const_interface_decl))
57  break;
58 
59  clang::DeclContext::lookup_result result =
60  non_const_interface_decl->lookup(name);
61 
62  return (result.size() != 0);
63  } while (false);
64 
65  SetNoExternalVisibleDeclsForName(decl_ctx, name);
66  return false;
67  }
68 
69  void CompleteType(clang::TagDecl *tag_decl) override {
70 
72  LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
73 
74  LLDB_LOGF(log,
75  "AppleObjCExternalASTSource::CompleteType on "
76  "(ASTContext*)%p Completing (TagDecl*)%p named %s",
77  static_cast<void *>(&tag_decl->getASTContext()),
78  static_cast<void *>(tag_decl), tag_decl->getName().str().c_str());
79 
80  LLDB_LOG(log, " AOEAS::CT Before:\n{1}", ClangUtil::DumpDecl(tag_decl));
81 
82  LLDB_LOG(log, " AOEAS::CT After:{1}", ClangUtil::DumpDecl(tag_decl));
83 
84  return;
85  }
86 
87  void CompleteType(clang::ObjCInterfaceDecl *interface_decl) override {
88 
90  LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
91 
92  if (log) {
93  LLDB_LOGF(log,
94  "AppleObjCExternalASTSource::CompleteType on "
95  "(ASTContext*)%p Completing (ObjCInterfaceDecl*)%p named %s",
96  static_cast<void *>(&interface_decl->getASTContext()),
97  static_cast<void *>(interface_decl),
98  interface_decl->getName().str().c_str());
99 
100  LLDB_LOGF(log, " AOEAS::CT Before:");
101  LLDB_LOG(log, " [CT] {0}", ClangUtil::DumpDecl(interface_decl));
102  }
103 
104  m_decl_vendor.FinishDecl(interface_decl);
105 
106  if (log) {
107  LLDB_LOGF(log, " [CT] After:");
108  LLDB_LOG(log, " [CT] {0}", ClangUtil::DumpDecl(interface_decl));
109  }
110  return;
111  }
112 
114  const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
115  llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
116  llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
117  &BaseOffsets,
118  llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
119  &VirtualBaseOffsets) override {
120  return false;
121  }
122 
123  void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
124  clang::TranslationUnitDecl *translation_unit_decl =
125  m_decl_vendor.m_ast_ctx.getASTContext().getTranslationUnitDecl();
126  translation_unit_decl->setHasExternalVisibleStorage();
127  translation_unit_decl->setHasExternalLexicalStorage();
128  }
129 
130 private:
132 };
133 
135  : ClangDeclVendor(eAppleObjCDeclVendor), m_runtime(runtime),
136  m_ast_ctx(
137  "AppleObjCDeclVendor AST",
138  runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple()),
139  m_type_realizer_sp(m_runtime.GetEncodingToType()) {
141  llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> external_source_owning_ptr(
143  m_ast_ctx.getASTContext().setExternalSource(external_source_owning_ptr);
144 }
145 
146 clang::ObjCInterfaceDecl *
148  ISAToInterfaceMap::const_iterator iter = m_isa_to_interface.find(isa);
149 
150  if (iter != m_isa_to_interface.end())
151  return iter->second;
152 
153  clang::ASTContext &ast_ctx = m_ast_ctx.getASTContext();
154 
157 
158  if (!descriptor)
159  return nullptr;
160 
161  ConstString name(descriptor->GetClassName());
162 
163  clang::IdentifierInfo &identifier_info =
164  ast_ctx.Idents.get(name.GetStringRef());
165 
166  clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(
167  ast_ctx, ast_ctx.getTranslationUnitDecl(), clang::SourceLocation(),
168  &identifier_info, nullptr, nullptr);
169 
170  ClangASTMetadata meta_data;
171  meta_data.SetISAPtr(isa);
172  m_ast_ctx.SetMetadata(new_iface_decl, meta_data);
173 
174  new_iface_decl->setHasExternalVisibleStorage();
175  new_iface_decl->setHasExternalLexicalStorage();
176 
177  ast_ctx.getTranslationUnitDecl()->addDecl(new_iface_decl);
178 
179  m_isa_to_interface[isa] = new_iface_decl;
180 
181  return new_iface_decl;
182 }
183 
185 public:
186  ObjCRuntimeMethodType(const char *types) : m_is_valid(false) {
187  const char *cursor = types;
188  enum ParserState { Start = 0, InType, InPos } state = Start;
189  const char *type = nullptr;
190  int brace_depth = 0;
191 
192  uint32_t stepsLeft = 256;
193 
194  while (true) {
195  if (--stepsLeft == 0) {
196  m_is_valid = false;
197  return;
198  }
199 
200  switch (state) {
201  case Start: {
202  switch (*cursor) {
203  default:
204  state = InType;
205  type = cursor;
206  break;
207  case '\0':
208  m_is_valid = true;
209  return;
210  case '0':
211  case '1':
212  case '2':
213  case '3':
214  case '4':
215  case '5':
216  case '6':
217  case '7':
218  case '8':
219  case '9':
220  m_is_valid = false;
221  return;
222  }
223  } break;
224  case InType: {
225  switch (*cursor) {
226  default:
227  ++cursor;
228  break;
229  case '0':
230  case '1':
231  case '2':
232  case '3':
233  case '4':
234  case '5':
235  case '6':
236  case '7':
237  case '8':
238  case '9':
239  if (!brace_depth) {
240  state = InPos;
241  if (type) {
242  m_type_vector.push_back(std::string(type, (cursor - type)));
243  } else {
244  m_is_valid = false;
245  return;
246  }
247  type = nullptr;
248  } else {
249  ++cursor;
250  }
251  break;
252  case '[':
253  case '{':
254  case '(':
255  ++brace_depth;
256  ++cursor;
257  break;
258  case ']':
259  case '}':
260  case ')':
261  if (!brace_depth) {
262  m_is_valid = false;
263  return;
264  }
265  --brace_depth;
266  ++cursor;
267  break;
268  case '\0':
269  m_is_valid = false;
270  return;
271  }
272  } break;
273  case InPos: {
274  switch (*cursor) {
275  default:
276  state = InType;
277  type = cursor;
278  break;
279  case '0':
280  case '1':
281  case '2':
282  case '3':
283  case '4':
284  case '5':
285  case '6':
286  case '7':
287  case '8':
288  case '9':
289  ++cursor;
290  break;
291  case '\0':
292  m_is_valid = true;
293  return;
294  }
295  } break;
296  }
297  }
298  }
299 
300  clang::ObjCMethodDecl *
301  BuildMethod(TypeSystemClang &clang_ast_ctxt,
302  clang::ObjCInterfaceDecl *interface_decl, const char *name,
303  bool instance,
304  ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp) {
305  if (!m_is_valid || m_type_vector.size() < 3)
306  return nullptr;
307 
308  clang::ASTContext &ast_ctx(interface_decl->getASTContext());
309 
310  const bool isInstance = instance;
311  const bool isVariadic = false;
312  const bool isPropertyAccessor = false;
313  const bool isSynthesizedAccessorStub = false;
314  const bool isImplicitlyDeclared = true;
315  const bool isDefined = false;
316  const clang::ObjCMethodDecl::ImplementationControl impControl =
317  clang::ObjCMethodDecl::None;
318  const bool HasRelatedResultType = false;
319  const bool for_expression = true;
320 
321  std::vector<clang::IdentifierInfo *> selector_components;
322 
323  const char *name_cursor = name;
324  bool is_zero_argument = true;
325 
326  while (*name_cursor != '\0') {
327  const char *colon_loc = strchr(name_cursor, ':');
328  if (!colon_loc) {
329  selector_components.push_back(
330  &ast_ctx.Idents.get(llvm::StringRef(name_cursor)));
331  break;
332  } else {
333  is_zero_argument = false;
334  selector_components.push_back(&ast_ctx.Idents.get(
335  llvm::StringRef(name_cursor, colon_loc - name_cursor)));
336  name_cursor = colon_loc + 1;
337  }
338  }
339 
340  clang::IdentifierInfo **identifier_infos = selector_components.data();
341  if (!identifier_infos) {
342  return nullptr;
343  }
344 
345  clang::Selector sel = ast_ctx.Selectors.getSelector(
346  is_zero_argument ? 0 : selector_components.size(),
347  identifier_infos);
348 
349  clang::QualType ret_type =
350  ClangUtil::GetQualType(type_realizer_sp->RealizeType(
351  clang_ast_ctxt, m_type_vector[0].c_str(), for_expression));
352 
353  if (ret_type.isNull())
354  return nullptr;
355 
356  clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create(
357  ast_ctx, clang::SourceLocation(), clang::SourceLocation(), sel,
358  ret_type, nullptr, interface_decl, isInstance, isVariadic,
359  isPropertyAccessor, isSynthesizedAccessorStub, isImplicitlyDeclared,
360  isDefined, impControl, HasRelatedResultType);
361 
362  std::vector<clang::ParmVarDecl *> parm_vars;
363 
364  for (size_t ai = 3, ae = m_type_vector.size(); ai != ae; ++ai) {
365  const bool for_expression = true;
366  clang::QualType arg_type =
367  ClangUtil::GetQualType(type_realizer_sp->RealizeType(
368  clang_ast_ctxt, m_type_vector[ai].c_str(), for_expression));
369 
370  if (arg_type.isNull())
371  return nullptr; // well, we just wasted a bunch of time. Wish we could
372  // delete the stuff we'd just made!
373 
374  parm_vars.push_back(clang::ParmVarDecl::Create(
375  ast_ctx, ret, clang::SourceLocation(), clang::SourceLocation(),
376  nullptr, arg_type, nullptr, clang::SC_None, nullptr));
377  }
378 
379  ret->setMethodParams(ast_ctx,
380  llvm::ArrayRef<clang::ParmVarDecl *>(parm_vars),
381  llvm::ArrayRef<clang::SourceLocation>());
382 
383  return ret;
384  }
385 
386  explicit operator bool() { return m_is_valid; }
387 
388  size_t GetNumTypes() { return m_type_vector.size(); }
389 
390  const char *GetTypeAtIndex(size_t idx) { return m_type_vector[idx].c_str(); }
391 
392 private:
393  typedef std::vector<std::string> TypeVector;
394 
395  TypeVector m_type_vector;
397 };
398 
399 bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) {
401  LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
402 
403  ClangASTMetadata *metadata = m_ast_ctx.GetMetadata(interface_decl);
404  ObjCLanguageRuntime::ObjCISA objc_isa = 0;
405  if (metadata)
406  objc_isa = metadata->GetISAPtr();
407 
408  if (!objc_isa)
409  return false;
410 
411  if (!interface_decl->hasExternalVisibleStorage())
412  return true;
413 
414  interface_decl->startDefinition();
415 
416  interface_decl->setHasExternalVisibleStorage(false);
417  interface_decl->setHasExternalLexicalStorage(false);
418 
421 
422  if (!descriptor)
423  return false;
424 
425  auto superclass_func = [interface_decl,
426  this](ObjCLanguageRuntime::ObjCISA isa) {
427  clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa);
428 
429  if (!superclass_decl)
430  return;
431 
432  FinishDecl(superclass_decl);
433  clang::ASTContext &context = m_ast_ctx.getASTContext();
434  interface_decl->setSuperClass(context.getTrivialTypeSourceInfo(
435  context.getObjCInterfaceType(superclass_decl)));
436  };
437 
438  auto instance_method_func =
439  [log, interface_decl, this](const char *name, const char *types) -> bool {
440  if (!name || !types)
441  return false; // skip this one
442 
443  ObjCRuntimeMethodType method_type(types);
444 
445  clang::ObjCMethodDecl *method_decl = method_type.BuildMethod(
446  m_ast_ctx, interface_decl, name, true, m_type_realizer_sp);
447 
448  LLDB_LOGF(log, "[ AOTV::FD] Instance method [%s] [%s]", name, types);
449 
450  if (method_decl)
451  interface_decl->addDecl(method_decl);
452 
453  return false;
454  };
455 
456  auto class_method_func = [log, interface_decl,
457  this](const char *name, const char *types) -> bool {
458  if (!name || !types)
459  return false; // skip this one
460 
461  ObjCRuntimeMethodType method_type(types);
462 
463  clang::ObjCMethodDecl *method_decl = method_type.BuildMethod(
464  m_ast_ctx, interface_decl, name, false, m_type_realizer_sp);
465 
466  LLDB_LOGF(log, "[ AOTV::FD] Class method [%s] [%s]", name, types);
467 
468  if (method_decl)
469  interface_decl->addDecl(method_decl);
470 
471  return false;
472  };
473 
474  auto ivar_func = [log, interface_decl,
475  this](const char *name, const char *type,
476  lldb::addr_t offset_ptr, uint64_t size) -> bool {
477  if (!name || !type)
478  return false;
479 
480  const bool for_expression = false;
481 
482  LLDB_LOGF(log,
483  "[ AOTV::FD] Instance variable [%s] [%s], offset at %" PRIx64,
484  name, type, offset_ptr);
485 
486  CompilerType ivar_type = m_runtime.GetEncodingToType()->RealizeType(
487  m_ast_ctx, type, for_expression);
488 
489  if (ivar_type.IsValid()) {
490  clang::TypeSourceInfo *const type_source_info = nullptr;
491  const bool is_synthesized = false;
492  clang::ObjCIvarDecl *ivar_decl = clang::ObjCIvarDecl::Create(
493  m_ast_ctx.getASTContext(), interface_decl, clang::SourceLocation(),
494  clang::SourceLocation(), &m_ast_ctx.getASTContext().Idents.get(name),
495  ClangUtil::GetQualType(ivar_type),
496  type_source_info, // TypeSourceInfo *
497  clang::ObjCIvarDecl::Public, nullptr, is_synthesized);
498 
499  if (ivar_decl) {
500  interface_decl->addDecl(ivar_decl);
501  }
502  }
503 
504  return false;
505  };
506 
507  LLDB_LOG(log,
508  "[AppleObjCDeclVendor::FinishDecl] Finishing Objective-C "
509  "interface for %s",
510  descriptor->GetClassName().AsCString());
511 
512  if (!descriptor->Describe(superclass_func, instance_method_func,
513  class_method_func, ivar_func))
514  return false;
515 
516  if (log) {
517  LLDB_LOGF(
518  log,
519  "[AppleObjCDeclVendor::FinishDecl] Finished Objective-C interface");
520 
521  LLDB_LOG(log, " [AOTV::FD] {0}", ClangUtil::DumpDecl(interface_decl));
522  }
523 
524  return true;
525 }
526 
528  uint32_t max_matches,
529  std::vector<CompilerDecl> &decls) {
530 
532  LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
533 
534  LLDB_LOGF(log, "AppleObjCDeclVendor::FindDecls ('%s', %s, %u, )",
535  (const char *)name.AsCString(), append ? "true" : "false",
536  max_matches);
537 
538  if (!append)
539  decls.clear();
540 
541  uint32_t ret = 0;
542 
543  do {
544  // See if the type is already in our ASTContext.
545 
546  clang::ASTContext &ast_ctx = m_ast_ctx.getASTContext();
547 
548  clang::IdentifierInfo &identifier_info =
549  ast_ctx.Idents.get(name.GetStringRef());
550  clang::DeclarationName decl_name =
551  ast_ctx.DeclarationNames.getIdentifier(&identifier_info);
552 
553  clang::DeclContext::lookup_result lookup_result =
554  ast_ctx.getTranslationUnitDecl()->lookup(decl_name);
555 
556  if (!lookup_result.empty()) {
557  if (clang::ObjCInterfaceDecl *result_iface_decl =
558  llvm::dyn_cast<clang::ObjCInterfaceDecl>(lookup_result[0])) {
559  if (log) {
560  clang::QualType result_iface_type =
561  ast_ctx.getObjCInterfaceType(result_iface_decl);
562 
563  uint64_t isa_value = LLDB_INVALID_ADDRESS;
564  ClangASTMetadata *metadata = m_ast_ctx.GetMetadata(result_iface_decl);
565  if (metadata)
566  isa_value = metadata->GetISAPtr();
567 
568  LLDB_LOG(log,
569  "AOCTV::FT Found %s (isa 0x%" PRIx64 ") in the ASTContext",
570  result_iface_type.getAsString(), isa_value);
571  }
572 
573  decls.push_back(m_ast_ctx.GetCompilerDecl(result_iface_decl));
574  ret++;
575  break;
576  } else {
577  LLDB_LOGF(log, "AOCTV::FT There's something in the ASTContext, but "
578  "it's not something we know about");
579  break;
580  }
581  } else if (log) {
582  LLDB_LOGF(log, "AOCTV::FT Couldn't find %s in the ASTContext",
583  name.AsCString());
584  }
585 
586  // It's not. If it exists, we have to put it into our ASTContext.
587 
589 
590  if (!isa) {
591  LLDB_LOGF(log, "AOCTV::FT Couldn't find the isa");
592 
593  break;
594  }
595 
596  clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa);
597 
598  if (!iface_decl) {
599  LLDB_LOGF(log,
600  "AOCTV::FT Couldn't get the Objective-C interface for "
601  "isa 0x%" PRIx64,
602  (uint64_t)isa);
603 
604  break;
605  }
606 
607  if (log) {
608  clang::QualType new_iface_type = ast_ctx.getObjCInterfaceType(iface_decl);
609 
610  LLDB_LOG(log, "AOCTV::FT Created {1} (isa 0x{2:x})",
611  new_iface_type.getAsString(), (uint64_t)isa);
612  }
613 
614  decls.push_back(m_ast_ctx.GetCompilerDecl(iface_decl));
615  ret++;
616  break;
617  } while (false);
618 
619  return ret;
620 }
A class that represents a running process on the host machine.
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
Definition: ConstString.h:223
clang::ObjCInterfaceDecl * GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa)
virtual ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa)
ObjCRuntimeMethodType(const char *types)
virtual EncodingToTypeSP GetEncodingToType()
void CompleteType(clang::ObjCInterfaceDecl *interface_decl) override
A TypeSystem implementation based on Clang.
clang::ObjCMethodDecl * BuildMethod(TypeSystemClang &clang_ast_ctxt, clang::ObjCInterfaceDecl *interface_decl, const char *name, bool instance, ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp)
void SetISAPtr(uint64_t isa_ptr)
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
virtual ObjCISA GetISA(ConstString name)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:242
void SetMetadata(const clang::Decl *object, ClangASTMetadata &meta_data)
bool layoutRecordType(const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, llvm::DenseMap< const clang::FieldDecl *, uint64_t > &FieldOffsets, llvm::DenseMap< const clang::CXXRecordDecl *, clang::CharUnits > &BaseOffsets, llvm::DenseMap< const clang::CXXRecordDecl *, clang::CharUnits > &VirtualBaseOffsets) override
clang::ASTContext & getASTContext()
Returns the clang::ASTContext instance managed by this TypeSystemClang.
void CompleteType(clang::TagDecl *tag_decl) override
CompilerDecl GetCompilerDecl(clang::Decl *decl)
Creates a CompilerDecl from the given Decl with the current TypeSystemClang instance as its typesyste...
bool FinishDecl(clang::ObjCInterfaceDecl *decl)
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
AppleObjCExternalASTSource * m_external_source
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:58
void StartTranslationUnit(clang::ASTConsumer *Consumer) override
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
Definition: ConstString.h:232
ObjCLanguageRuntime::EncodingToTypeSP m_type_realizer_sp
bool FindExternalVisibleDeclsByName(const clang::DeclContext *decl_ctx, clang::DeclarationName name) override
uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches, std::vector< CompilerDecl > &decls) override
Look up the set of Decls that the DeclVendor currently knows about matching a given name...
#define LLDB_LOGF(log,...)
Definition: Log.h:249
std::vector< std::string > TypeVector
AppleObjCDeclVendor(ObjCLanguageRuntime &runtime)
uint64_t addr_t
Definition: lldb-types.h:83
static std::string DumpDecl(const clang::Decl *d)
Returns a textual representation of the given Decl&#39;s AST.
Definition: ClangUtil.cpp:68
A uniqued constant string class.
Definition: ConstString.h:40
Represents a generic type in a programming language.
Definition: CompilerType.h:33
AppleObjCExternalASTSource(AppleObjCDeclVendor &decl_vendor)
#define LIBLLDB_LOG_EXPRESSIONS
Definition: Logging.h:22
static clang::QualType GetQualType(const CompilerType &ct)
Definition: ClangUtil.cpp:36
const char * GetTypeAtIndex(size_t idx)
std::shared_ptr< EncodingToType > EncodingToTypeSP
ClangASTMetadata * GetMetadata(const clang::Decl *object)