Logo ROOT  
Reference Guide
TClass.cxx
Go to the documentation of this file.
1 // @(#)root/meta:$Id: 7109cb45f1219c2aae6be19906ae5a63e31972ef $
2 // Author: Rene Brun 07/01/95
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TClass
13 TClass instances represent classes, structs and namespaces in the ROOT type system.
14 
15 TClass instances are created starting from different sources of information:
16 1. TStreamerInfo instances saved in a ROOT file which is opened. This is called in jargon an *emulated TClass*.
17 2. From TProtoClass instances saved in a ROOT pcm file created by the dictionary generator and the dictionary itself.
18 3. From a lookup in the AST built by cling.
19 
20 If a TClass instance is built through the mechanisms 1. and 2., it does not contain information about methods of the
21 class/struct/namespace it represents. Conversely, if built through 3. or 1., it does not carry the information which is necessary
22 to ROOT to perform I/O of instances of the class/struct it represents.
23 The mechanisms 1., 2. and 3. are not mutually exclusive: it can happen that during the execution of the program, all
24 the three are triggered, modifying the state of the TClass instance.
25 
26 In order to retrieve a TClass instance from the type system, a query can be executed as follows through the static
27 TClass::GetClass method:
28 
29 ~~~ {.cpp}
30 auto myClassTClass_0 = TClass::GetClass("myClass");
31 auto myClassTClass_1 = TClass::GetClass<myClass>();
32 auto myClassTClass_2 = TClass::GetClass(myClassTypeInfo);
33 ~~~
34 
35 The name of classes is crucial for ROOT. A careful procedure of *name normalization* is carried out for
36 each and every class. A *normalized name* is a valid C++ class name.
37 In order to access the name of a class within the ROOT type system, the method TClass::GetName() can be used.
38 */
39 
40 //*-*x7.5 macros/layout_class
41 
42 #include "TClass.h"
43 
44 #include "strlcpy.h"
45 #include "snprintf.h"
46 #include "TBaseClass.h"
47 #include "TBrowser.h"
48 #include "TBuffer.h"
49 #include "TClassGenerator.h"
50 #include "TClassEdit.h"
51 #include "TClassMenuItem.h"
52 #include "TClassRef.h"
53 #include "TClassTable.h"
54 #include "TDataMember.h"
55 #include "TDataType.h"
56 #include "TDatime.h"
57 #include "TError.h"
58 #include "TExMap.h"
59 #include "TFunctionTemplate.h"
60 #include "THashList.h"
61 #include "TInterpreter.h"
62 #include "TMemberInspector.h"
63 #include "TMethod.h"
64 #include "TMethodArg.h"
65 #include "TMethodCall.h"
66 #include "TObjArray.h"
67 #include "TObjString.h"
68 #include "TProtoClass.h"
69 #include "TROOT.h"
70 #include "TRealData.h"
71 #include "TCheckHashRecursiveRemoveConsistency.h" // Private header
72 #include "TStreamer.h"
73 #include "TStreamerElement.h"
74 #include "TVirtualStreamerInfo.h"
76 #include "TVirtualIsAProxy.h"
77 #include "TVirtualRefProxy.h"
78 #include "TVirtualMutex.h"
79 #include "TVirtualPad.h"
80 #include "THashTable.h"
81 #include "TSchemaRuleSet.h"
82 #include "TGenericClassInfo.h"
83 #include "TIsAProxy.h"
84 #include "TSchemaRule.h"
85 #include "TSystem.h"
86 #include "TThreadSlots.h"
87 #include "ThreadLocalStorage.h"
88 
89 #include <cstdio>
90 #include <cctype>
91 #include <set>
92 #include <iostream>
93 #include <sstream>
94 #include <string>
95 #include <map>
96 #include <typeinfo>
97 #include <cmath>
98 #include <cassert>
99 #include <vector>
100 #include <memory>
101 
102 #include "TSpinLockGuard.h"
103 
104 #ifdef WIN32
105 #include <io.h>
106 #include "Windows4Root.h"
107 #include <Psapi.h>
108 #define RTLD_DEFAULT ((void *)::GetModuleHandle(NULL))
109 #define dlsym(library, function_name) ::GetProcAddress((HMODULE)library, function_name)
110 #else
111 #include <dlfcn.h>
112 #endif
113 
114 #include "TListOfDataMembers.h"
115 #include "TListOfFunctions.h"
117 #include "TListOfEnums.h"
118 #include "TListOfEnumsWithLock.h"
119 #include "TViewPubDataMembers.h"
120 #include "TViewPubFunctions.h"
121 #include "TArray.h"
122 #include "TClonesArray.h"
123 #include "TRef.h"
124 #include "TRefArray.h"
125 
126 using namespace std;
127 
128 // Mutex to protect CINT and META operations
129 // (exported to be used for similar cases in related classes)
130 
132 
133 namespace {
134 
135  static constexpr const char kUndeterminedClassInfoName[] = "<NOT YET DETERMINED FROM fClassInfo>";
136 
137  class TMmallocDescTemp {
138  private:
139  void *fSave;
140  public:
141  TMmallocDescTemp(void *value = 0) :
143  ~TMmallocDescTemp() { ROOT::Internal::gMmallocDesc = fSave; }
144  };
145 
146  // When a new class is created, we need to be able to find
147  // if there are any existing classes that have the same name
148  // after any typedefs are expanded. (This only really affects
149  // template arguments.) To avoid having to search through all classes
150  // in that case, we keep a hash table mapping from the fully
151  // typedef-expanded names to the original class names.
152  // An entry is made in the table only if they are actually different.
153  //
154  // In these objects, the TObjString base holds the typedef-expanded
155  // name (the hash key), and fOrigName holds the original class name
156  // (the value to which the key maps).
157  //
158  class TNameMapNode : public TObjString {
159  public:
160  TString fOrigName;
161 
162  TNameMapNode(const char *typedf, const char *orig) :
163  TObjString (typedf),
164  fOrigName (orig)
165  {
166  }
167  };
168 
169 }
170 
171 std::atomic<Int_t> TClass::fgClassCount;
172 
173 // Implementation of the TDeclNameRegistry
174 
175 ////////////////////////////////////////////////////////////////////////////////
176 /// TDeclNameRegistry class constructor.
177 
178 TClass::TDeclNameRegistry::TDeclNameRegistry(Int_t verbLevel): fVerbLevel(verbLevel)
179 {
180  // MSVC doesn't support fSpinLock=ATOMIC_FLAG_INIT; in the class definition
181  std::atomic_flag_clear( &fSpinLock );
182 }
183 
184 ////////////////////////////////////////////////////////////////////////////////
185 /// Extract this part of the name
186 /// 1. Templates ns::ns2::,,,::THISPART<...
187 /// 2. Namespaces,classes ns::ns2::,,,::THISPART
188 
190 {
191  // Sanity check
192  auto strLen = strlen(name);
193  if (strLen == 0) return;
194  // find <. If none, put end of string
195  const char* endCharPtr = strchr(name, '<');
196  endCharPtr = !endCharPtr ? &name[strLen] : endCharPtr;
197  // find last : before the <. If not found, put begin of string
198  const char* beginCharPtr = endCharPtr;
199  while (beginCharPtr!=name){
200  if (*beginCharPtr==':'){
201  beginCharPtr++;
202  break;
203  }
204  beginCharPtr--;
205  }
206  beginCharPtr = beginCharPtr!=endCharPtr ? beginCharPtr : name;
207  std::string s(beginCharPtr, endCharPtr);
208  if (fVerbLevel>1)
209  printf("TDeclNameRegistry::AddQualifiedName Adding key %s for class/namespace %s\n", s.c_str(), name);
210  ROOT::Internal::TSpinLockGuard slg(fSpinLock);
211  fClassNamesSet.insert(s);
212 }
213 
214 ////////////////////////////////////////////////////////////////////////////////
215 
217 {
218  Bool_t found = false;
219  {
220  ROOT::Internal::TSpinLockGuard slg(fSpinLock);
221  found = fClassNamesSet.find(name) != fClassNamesSet.end();
222  }
223  return found;
224 }
225 
226 ////////////////////////////////////////////////////////////////////////////////
227 
229 {
230  if (fVerbLevel > 1) {
231  printf("TDeclNameRegistry Destructor. List of %lu names:\n",
232  (long unsigned int)fClassNamesSet.size());
233  for (auto const & key: fClassNamesSet) {
234  printf(" - %s\n", key.c_str());
235  }
236  }
237 }
238 
239 ////////////////////////////////////////////////////////////////////////////////
240 
242  const char *name,
243  TDeclNameRegistry &emuRegistry): fState(state),fName(name), fNoInfoOrEmuOrFwdDeclNameRegistry(emuRegistry) {}
244 
245 ////////////////////////////////////////////////////////////////////////////////
246 
248  if (fState == TClass::kNoInfo ||
252  }
253  }
254 
255 // Initialise the global member of TClass
257 
258 //Intent of why/how TClass::New() is called
259 //[Not a static data member because MacOS does not support static thread local data member ... who knows why]
261  TTHREAD_TLS(TClass::ENewType) fgCallingNew = TClass::kRealNew;
262  return fgCallingNew;
263 }
264 
265 struct ObjRepoValue {
266  ObjRepoValue(const TClass *what, Version_t version) : fClass(what),fVersion(version) {}
267  const TClass *fClass;
268  Version_t fVersion;
269 };
270 
272 typedef std::multimap<void*, ObjRepoValue> RepoCont_t;
274 
275 static void RegisterAddressInRepository(const char * /*where*/, void *location, const TClass *what)
276 {
277  // Register the object for special handling in the destructor.
278 
279  Version_t version = what->GetClassVersion();
280 // if (!gObjectVersionRepository.count(location)) {
281 // Info(where, "Registering address %p of class '%s' version %d", location, what->GetName(), version);
282 // } else {
283 // Warning(where, "Registering address %p again of class '%s' version %d", location, what->GetName(), version);
284 // }
285  {
287  gObjectVersionRepository.insert(RepoCont_t::value_type(location, RepoCont_t::mapped_type(what,version)));
288  }
289 #if 0
290  // This code could be used to prevent an address to be registered twice.
291  std::pair<RepoCont_t::iterator, Bool_t> tmp = gObjectVersionRepository.insert(RepoCont_t::value_type>(location, RepoCont_t::mapped_type(what,version)));
292  if (!tmp.second) {
293  Warning(where, "Reregistering an object of class '%s' version %d at address %p", what->GetName(), version, p);
294  gObjectVersionRepository.erase(tmp.first);
295  tmp = gObjectVersionRepository.insert(RepoCont_t::value_type>(location, RepoCont_t::mapped_type(what,version)));
296  if (!tmp.second) {
297  Warning(where, "Failed to reregister an object of class '%s' version %d at address %p", what->GetName(), version, location);
298  }
299  }
300 #endif
301 }
302 
303 static void UnregisterAddressInRepository(const char * /*where*/, void *location, const TClass *what)
304 {
305  // Remove an address from the repository of address/object.
306 
308  RepoCont_t::iterator cur = gObjectVersionRepository.find(location);
309  for (; cur != gObjectVersionRepository.end();) {
310  RepoCont_t::iterator tmp = cur++;
311  if ((tmp->first == location) && (tmp->second.fVersion == what->GetClassVersion())) {
312  // -- We still have an address, version match.
313  // Info(where, "Unregistering address %p of class '%s' version %d", location, what->GetName(), what->GetClassVersion());
314  gObjectVersionRepository.erase(tmp);
315  } else {
316  // -- No address, version match, we've reached the end.
317  break;
318  }
319  }
320 }
321 
322 static void MoveAddressInRepository(const char * /*where*/, void *oldadd, void *newadd, const TClass *what)
323 {
324  // Register in the repository that an object has moved.
325 
326  // Move not only the object itself but also any base classes or sub-objects.
327  size_t objsize = what->Size();
328  long delta = (char*)newadd - (char*)oldadd;
330  RepoCont_t::iterator cur = gObjectVersionRepository.find(oldadd);
331  for (; cur != gObjectVersionRepository.end();) {
332  RepoCont_t::iterator tmp = cur++;
333  if (oldadd <= tmp->first && tmp->first < ( ((char*)oldadd) + objsize) ) {
334  // The location is within the object, let's move it.
335 
336  gObjectVersionRepository.insert(RepoCont_t::value_type(((char*)tmp->first)+delta, RepoCont_t::mapped_type(tmp->second.fClass,tmp->second.fVersion)));
337  gObjectVersionRepository.erase(tmp);
338 
339  } else {
340  // -- No address, version match, we've reached the end.
341  break;
342  }
343  }
344 }
345 
346 //______________________________________________________________________________
347 //______________________________________________________________________________
348 namespace ROOT {
349 #define R__USE_STD_MAP
350  class TMapTypeToTClass {
351 #if defined R__USE_STD_MAP
352  // This wrapper class allow to avoid putting #include <map> in the
353  // TROOT.h header file.
354  public:
355  typedef std::map<std::string,TClass*> IdMap_t;
356  typedef IdMap_t::key_type key_type;
357  typedef IdMap_t::const_iterator const_iterator;
358  typedef IdMap_t::size_type size_type;
359 #ifdef R__WIN32
360  // Window's std::map does NOT defined mapped_type
361  typedef TClass* mapped_type;
362 #else
363  typedef IdMap_t::mapped_type mapped_type;
364 #endif
365 
366  private:
367  IdMap_t fMap;
368 
369  public:
370  void Add(const key_type &key, mapped_type &obj)
371  {
372  // Add the <key,obj> pair to the map.
373  fMap[key] = obj;
374  }
375  mapped_type Find(const key_type &key) const
376  {
377  // Find the type corresponding to the key.
378  IdMap_t::const_iterator iter = fMap.find(key);
379  mapped_type cl = 0;
380  if (iter != fMap.end()) cl = iter->second;
381  return cl;
382  }
383  void Remove(const key_type &key) {
384  // Remove the type corresponding to the key.
385  fMap.erase(key);
386  }
387 #else
388  private:
389  TMap fMap;
390 
391  public:
392 #ifdef R__COMPLETE_MEM_TERMINATION
393  TMapTypeToTClass() {
394  TIter next(&fMap);
395  TObjString *key;
396  while((key = (TObjString*)next())) {
397  delete key;
398  }
399  }
400 #endif
401  void Add(const char *key, TClass *&obj) {
402  TObjString *realkey = new TObjString(key);
403  fMap.Add(realkey, obj);
404  }
405  TClass* Find(const char *key) const {
406  const TPair *a = (const TPair *)fMap.FindObject(key);
407  if (a) return (TClass*) a->Value();
408  return 0;
409  }
410  void Remove(const char *key) {
411  TObjString realkey(key);
412  TObject *actual = fMap.Remove(&realkey);
413  delete actual;
414  }
415 #endif
416  };
417 
418  class TMapDeclIdToTClass {
419  // Wrapper class for the multimap of DeclId_t and TClass.
420  public:
421  typedef multimap<TDictionary::DeclId_t, TClass*> DeclIdMap_t;
422  typedef DeclIdMap_t::key_type key_type;
423  typedef DeclIdMap_t::mapped_type mapped_type;
424  typedef DeclIdMap_t::const_iterator const_iterator;
425  typedef std::pair <const_iterator, const_iterator> equal_range;
426  typedef DeclIdMap_t::size_type size_type;
427 
428  private:
429  DeclIdMap_t fMap;
430 
431  public:
432  void Add(const key_type &key, mapped_type obj)
433  {
434  // Add the <key,obj> pair to the map.
435  std::pair<const key_type, mapped_type> pair = make_pair(key, obj);
436  fMap.insert(pair);
437  }
438  size_type CountElementsWithKey(const key_type &key)
439  {
440  return fMap.count(key);
441  }
442  equal_range Find(const key_type &key) const
443  {
444  // Find the type corresponding to the key.
445  return fMap.equal_range(key);
446  }
447  void Remove(const key_type &key) {
448  // Remove the type corresponding to the key.
449  fMap.erase(key);
450  }
451  };
452 }
453 
455 
456 #ifdef R__COMPLETE_MEM_TERMINATION
457  static IdMap_t gIdMapObject;
458  return &gIdMapObject;
459 #else
460  static IdMap_t *gIdMap = new IdMap_t;
461  return gIdMap;
462 #endif
463 }
464 
466 
467 #ifdef R__COMPLETE_MEM_TERMINATION
468  static DeclIdMap_t gDeclIdMapObject;
469  return &gDeclIdMapObject;
470 #else
471  static DeclIdMap_t *gDeclIdMap = new DeclIdMap_t;
472  return gDeclIdMap;
473 #endif
474 }
475 
476 ////////////////////////////////////////////////////////////////////////////////
477 /// static: Add a class to the list and map of classes.
478 
480 {
481  if (!cl) return;
482 
484  gROOT->GetListOfClasses()->Add(cl);
485  if (cl->GetTypeInfo()) {
486  GetIdMap()->Add(cl->GetTypeInfo()->name(),cl);
487  }
488  if (cl->fClassInfo) {
489  GetDeclIdMap()->Add((void*)(cl->fClassInfo), cl);
490  }
491 }
492 
493 ////////////////////////////////////////////////////////////////////////////////
494 /// static: Add a TClass* to the map of classes.
495 
497 {
498  if (!cl || !id) return;
499  GetDeclIdMap()->Add(id, cl);
500 }
501 
502 ////////////////////////////////////////////////////////////////////////////////
503 /// static: Remove a class from the list and map of classes
504 
506 {
507  if (!oldcl) return;
508 
510  gROOT->GetListOfClasses()->Remove(oldcl);
511  if (oldcl->GetTypeInfo()) {
512  GetIdMap()->Remove(oldcl->GetTypeInfo()->name());
513  }
514  if (oldcl->fClassInfo) {
515  //GetDeclIdMap()->Remove((void*)(oldcl->fClassInfo));
516  }
517 }
518 
519 ////////////////////////////////////////////////////////////////////////////////
520 
522 {
523  if (!id) return;
524  GetDeclIdMap()->Remove(id);
525 }
526 
527 ////////////////////////////////////////////////////////////////////////////////
528 /// Indirect call to the implementation of ShowMember allowing [forward]
529 /// declaration with out a full definition of the TClass class.
530 
531 void ROOT::Class_ShowMembers(TClass *cl, const void *obj, TMemberInspector&insp)
532 {
533  gInterpreter->InspectMembers(insp, obj, cl, kFALSE);
534 }
535 
536 //______________________________________________________________________________
537 //______________________________________________________________________________
538 
539 class TDumpMembers : public TMemberInspector {
540  bool fNoAddr;
541 public:
542  TDumpMembers(bool noAddr): fNoAddr(noAddr) { }
543 
545  void Inspect(TClass *cl, const char *parent, const char *name, const void *addr, Bool_t isTransient);
546 };
547 
548 ////////////////////////////////////////////////////////////////////////////////
549 /// Print value of member mname.
550 ///
551 /// This method is called by the ShowMembers() method for each
552 /// data member when object.Dump() is invoked.
553 ///
554 /// - cl is the pointer to the current class
555 /// - pname is the parent name (in case of composed objects)
556 /// - mname is the data member name
557 /// - add is the data member address
558 
559 void TDumpMembers::Inspect(TClass *cl, const char *pname, const char *mname, const void *add, Bool_t /* isTransient */)
560 {
561  const Int_t kvalue = 30;
562 #ifdef R__B64
563  const Int_t ktitle = 50;
564 #else
565  const Int_t ktitle = 42;
566 #endif
567  const Int_t kline = 1024;
568  Int_t cdate = 0;
569  Int_t ctime = 0;
570  UInt_t *cdatime = 0;
571  char line[kline];
572 
573  TDataType *membertype;
574  EDataType memberDataType = kNoType_t;
575  const char *memberName;
576  const char *memberFullTypeName;
577  const char *memberTitle;
578  Bool_t isapointer;
579  Bool_t isbasic;
580 
581  if (TDataMember *member = cl->GetDataMember(mname)) {
582  if (member->GetDataType()) {
583  memberDataType = (EDataType)member->GetDataType()->GetType();
584  }
585  memberName = member->GetName();
586  memberFullTypeName = member->GetFullTypeName();
587  memberTitle = member->GetTitle();
588  isapointer = member->IsaPointer();
589  isbasic = member->IsBasic();
590  membertype = member->GetDataType();
591  } else if (!cl->IsLoaded()) {
592  // The class is not loaded, hence it is 'emulated' and the main source of
593  // information is the StreamerInfo.
595  if (!info) return;
596  const char *cursor = mname;
597  while ( (*cursor)=='*' ) ++cursor;
598  TString elname( cursor );
599  Ssiz_t pos = elname.Index("[");
600  if ( pos != kNPOS ) {
601  elname.Remove( pos );
602  }
603  TStreamerElement *element = (TStreamerElement*)info->GetElements()->FindObject(elname.Data());
604  if (!element) return;
605  memberFullTypeName = element->GetTypeName();
606 
607  memberDataType = (EDataType)element->GetType();
608 
609  memberName = element->GetName();
610  memberTitle = element->GetTitle();
611  isapointer = element->IsaPointer() || element->GetType() == TVirtualStreamerInfo::kCharStar;
612  membertype = gROOT->GetType(memberFullTypeName);
613 
614  isbasic = membertype !=0;
615  } else {
616  return;
617  }
618 
619 
620  Bool_t isdate = kFALSE;
621  if (strcmp(memberName,"fDatime") == 0 && memberDataType == kUInt_t) {
622  isdate = kTRUE;
623  }
624  Bool_t isbits = kFALSE;
625  if (strcmp(memberName,"fBits") == 0 && memberDataType == kUInt_t) {
626  isbits = kTRUE;
627  }
628  TClass * dataClass = TClass::GetClass(memberFullTypeName);
629  Bool_t isTString = (dataClass == TString::Class());
630  static TClassRef stdClass("std::string");
631  Bool_t isStdString = (dataClass == stdClass);
632 
633  Int_t i;
634  for (i = 0;i < kline; i++) line[i] = ' ';
635  line[kline-1] = 0;
636  snprintf(line,kline,"%s%s ",pname,mname);
637  i = strlen(line); line[i] = ' ';
638 
639  // Encode data value or pointer value
640  char *pointer = (char*)add;
641  char **ppointer = (char**)(pointer);
642 
643  if (isapointer) {
644  char **p3pointer = (char**)(*ppointer);
645  if (!p3pointer)
646  snprintf(&line[kvalue],kline-kvalue,"->0");
647  else if (!isbasic) {
648  if (!fNoAddr) {
649  snprintf(&line[kvalue],kline-kvalue,"->%lx ", (Long_t)p3pointer);
650  }
651  } else if (membertype) {
652  if (!strcmp(membertype->GetTypeName(), "char")) {
653  i = strlen(*ppointer);
654  if (kvalue+i > kline) i=kline-1-kvalue;
655  Bool_t isPrintable = kTRUE;
656  for (Int_t j = 0; j < i; j++) {
657  if (!std::isprint((*ppointer)[j])) {
658  isPrintable = kFALSE;
659  break;
660  }
661  }
662  if (isPrintable) {
663  strncpy(line + kvalue, *ppointer, i);
664  line[kvalue+i] = 0;
665  } else {
666  line[kvalue] = 0;
667  }
668  } else {
669  strncpy(&line[kvalue], membertype->AsString(p3pointer), TMath::Min(kline-1-kvalue,(int)strlen(membertype->AsString(p3pointer))));
670  }
671  } else if (!strcmp(memberFullTypeName, "char*") ||
672  !strcmp(memberFullTypeName, "const char*")) {
673  i = strlen(*ppointer);
674  if (kvalue+i >= kline) i=kline-1-kvalue;
675  Bool_t isPrintable = kTRUE;
676  for (Int_t j = 0; j < i; j++) {
677  if (!std::isprint((*ppointer)[j])) {
678  isPrintable = kFALSE;
679  break;
680  }
681  }
682  if (isPrintable) {
683  strncpy(line + kvalue, *ppointer, std::min( i, kline - kvalue));
684  line[kvalue+i] = 0;
685  } else {
686  line[kvalue] = 0;
687  }
688  } else {
689  if (!fNoAddr) {
690  snprintf(&line[kvalue],kline-kvalue,"->%lx ", (Long_t)p3pointer);
691  }
692  }
693  } else if (membertype) {
694  if (isdate) {
695  cdatime = (UInt_t*)pointer;
696  TDatime::GetDateTime(cdatime[0],cdate,ctime);
697  snprintf(&line[kvalue],kline-kvalue,"%d/%d",cdate,ctime);
698  } else if (isbits) {
699  snprintf(&line[kvalue],kline-kvalue,"0x%08x", *(UInt_t*)pointer);
700  } else {
701  strncpy(&line[kvalue], membertype->AsString(pointer), TMath::Min(kline-1-kvalue,(int)strlen(membertype->AsString(pointer))));
702  }
703  } else {
704  if (isStdString) {
705  std::string *str = (std::string*)pointer;
706  snprintf(&line[kvalue],kline-kvalue,"%s",str->c_str());
707  } else if (isTString) {
708  TString *str = (TString*)pointer;
709  snprintf(&line[kvalue],kline-kvalue,"%s",str->Data());
710  } else {
711  if (!fNoAddr) {
712  snprintf(&line[kvalue],kline-kvalue,"->%lx ", (Long_t)pointer);
713  }
714  }
715  }
716  // Encode data member title
717  if (isdate == kFALSE && strcmp(memberFullTypeName, "char*") && strcmp(memberFullTypeName, "const char*")) {
718  i = strlen(&line[0]); line[i] = ' ';
719  assert(250 > ktitle);
720  strlcpy(&line[ktitle],memberTitle,250-ktitle+1); // strlcpy copy 'size-1' characters.
721  }
722  Printf("%s", line);
723 }
724 
726 
727 //______________________________________________________________________________
728 
729 class TBuildRealData : public TMemberInspector {
730 
731 private:
732  void *fRealDataObject;
733  TClass *fRealDataClass;
734 
735 public:
736  TBuildRealData(void *obj, TClass *cl) {
737  // Main constructor.
738  fRealDataObject = obj;
739  fRealDataClass = cl;
740  }
742  void Inspect(TClass *cl, const char *parent, const char *name, const void *addr, Bool_t isTransient);
743 
744 };
745 
746 ////////////////////////////////////////////////////////////////////////////////
747 /// This method is called from ShowMembers() via BuildRealdata().
748 
749 void TBuildRealData::Inspect(TClass* cl, const char* pname, const char* mname, const void* add, Bool_t isTransient)
750 {
751  TDataMember* dm = cl->GetDataMember(mname);
752  if (!dm) {
753  return;
754  }
755 
756  Bool_t isTransientMember = kFALSE;
757 
758  if (!dm->IsPersistent()) {
759  // For the DataModelEvolution we need access to the transient member.
760  // so we now record them in the list of RealData.
761  isTransientMember = kTRUE;
762  isTransient = kTRUE;
763  }
764 
765  TString rname( pname );
766  // Take into account cases like TPaveStats->TPaveText->TPave->TBox.
767  // Check that member is in a derived class or an object in the class.
768  if (cl != fRealDataClass) {
769  if (!fRealDataClass->InheritsFrom(cl)) {
770  Ssiz_t dot = rname.Index('.');
771  if (dot == kNPOS) {
772  return;
773  }
774  rname[dot] = '\0';
775  if (!fRealDataClass->GetDataMember(rname)) {
776  //could be a data member in a base class like in this example
777  // class Event : public Data {
778  // class Data : public TObject {
779  // EventHeader fEvtHdr;
780  // class EventHeader {
781  // Int_t fEvtNum;
782  // Int_t fRun;
783  // Int_t fDate;
784  // EventVertex fVertex;
785  // class EventVertex {
786  // EventTime fTime;
787  // class EventTime {
788  // Int_t fSec;
789  // Int_t fNanoSec;
790  if (!fRealDataClass->GetBaseDataMember(rname)) {
791  return;
792  }
793  }
794  rname[dot] = '.';
795  }
796  }
797 
798  Long_t offset = Long_t(((Long_t) add) - ((Long_t) fRealDataObject));
799 
800  if (TClassEdit::IsStdArray(dm->GetTypeName())){ // We tackle the std array case
801  TString rdName;
802  TRealData::GetName(rdName,dm);
803  rname += rdName;
804  TRealData* rd = new TRealData(rname.Data(), offset, dm);
805  fRealDataClass->GetListOfRealData()->Add(rd);
806  return;
807  }
808 
809  rname += mname;
810 
811  if (dm->IsaPointer()) {
812  // Data member is a pointer.
813  TRealData* rd = new TRealData(rname, offset, dm);
814  if (isTransientMember) { rd->SetBit(TRealData::kTransient); };
815  fRealDataClass->GetListOfRealData()->Add(rd);
816  } else {
817  // Data Member is a basic data type.
818  TRealData* rd = new TRealData(rname, offset, dm);
819  if (isTransientMember) { rd->SetBit(TRealData::kTransient); };
820  if (!dm->IsBasic()) {
821  rd->SetIsObject(kTRUE);
822 
823  // Make sure that BuildReadData is called for any abstract
824  // bases classes involved in this object, i.e for all the
825  // classes composing this object (base classes, type of
826  // embedded object and same for their data members).
827  //
828  TClass* dmclass = TClass::GetClass(dm->GetTypeName(), kTRUE, isTransient);
829  if (!dmclass) {
830  dmclass = TClass::GetClass(dm->GetTrueTypeName(), kTRUE, isTransient);
831  }
832  if (dmclass) {
833  if ((dmclass != cl) && !dm->IsaPointer()) {
834  if (dmclass->GetCollectionProxy()) {
835  TClass* valcl = dmclass->GetCollectionProxy()->GetValueClass();
836  // We create the real data for the content of the collection to help the case
837  // of split branches in a TTree (where the node for the data member itself
838  // might have been elided). However, in some cases, like transient members
839  // and/or classes, the content might not be create-able. An example is the
840  // case of a map<A,B> where either A or B does not have default constructor
841  // and thus the compilation of the default constructor for pair<A,B> will
842  // fail (noisily) [This could also apply to any template instance, where it
843  // might have a default constructor definition that can not be compiled due
844  // to the template parameter]
845  if (valcl) {
846  Bool_t wantBuild = kTRUE;
847  if (valcl->Property() & kIsAbstract) wantBuild = kFALSE;
848  if ( (isTransient)
850  && (!valcl->IsLoaded()) ) {
851  // Case where the collection dictionary was not requested and
852  // the content's dictionary was also not requested.
853  // [This is a super set of what we need, but we can't really detect it :(]
854  wantBuild = kFALSE;
855  }
856 
857  if (wantBuild) valcl->BuildRealData(0, isTransient);
858  }
859  } else {
860  void* addrForRecursion = 0;
861  if (GetObjectValidity() == kValidObjectGiven)
862  addrForRecursion = const_cast<void*>(add);
863 
864  dmclass->BuildRealData(addrForRecursion, isTransient);
865  }
866  }
867  }
868  }
869  fRealDataClass->GetListOfRealData()->Add(rd);
870  }
871 }
872 
873 //______________________________________________________________________________
874 //______________________________________________________________________________
875 //______________________________________________________________________________
876 
877 ////////////////////////////////////////////////////////////////////////////////
878 
879 class TAutoInspector : public TMemberInspector {
880 public:
881  Int_t fCount;
882  TBrowser *fBrowser;
883 
884  TAutoInspector(TBrowser *b) {
885  // main constructor.
886  fBrowser = b; fCount = 0; }
887  virtual ~TAutoInspector() { }
889  virtual void Inspect(TClass *cl, const char *parent, const char *name, const void *addr, Bool_t isTransient);
890  virtual Bool_t IsTreatingNonAccessibleTypes() {return kFALSE;}
891 };
892 
893 ////////////////////////////////////////////////////////////////////////////////
894 /// This method is called from ShowMembers() via AutoBrowse().
895 
896 void TAutoInspector::Inspect(TClass *cl, const char *tit, const char *name,
897  const void *addr, Bool_t /* isTransient */)
898 {
899  if(tit && strchr(tit,'.')) return ;
900  if (fCount && !fBrowser) return;
901 
902  TString ts;
903 
904  if (!cl) return;
905  //if (*(cl->GetName()) == 'T') return;
906  if (*name == '*') name++;
907  int ln = strcspn(name,"[ ");
908  TString iname(name,ln);
909 
910  ClassInfo_t *classInfo = cl->GetClassInfo();
911  if (!classInfo) return;
912 
913  // Browse data members
914  DataMemberInfo_t *m = gCling->DataMemberInfo_Factory(classInfo);
915  TString mname;
916 
917  int found=0;
918  while (gCling->DataMemberInfo_Next(m)) { // MemberLoop
919  mname = gCling->DataMemberInfo_Name(m);
920  mname.ReplaceAll("*","");
921  if ((found = (iname==mname))) break;
922  }
923  assert(found);
924 
925  // we skip: non static members and non objects
926  // - the member G__virtualinfo inserted by the CINT RTTI system
927 
928  //Long_t prop = m.Property() | m.Type()->Property();
930  if (prop & kIsStatic) return;
931  if (prop & kIsFundamental) return;
932  if (prop & kIsEnum) return;
933  if (mname == "G__virtualinfo") return;
934 
935  int size = sizeof(void*);
936 
937  int nmax = 1;
938  if (prop & kIsArray) {
939  for (int dim = 0; dim < gCling->DataMemberInfo_ArrayDim(m); dim++) nmax *= gCling->DataMemberInfo_MaxIndex(m,dim);
940  }
941 
944  TClass * clm = TClass::GetClass(clmName.c_str());
945  R__ASSERT(clm);
946  if (!(prop & kIsPointer)) {
947  size = clm->Size();
948  if (size==0) size = gCling->DataMemberInfo_TypeSize(m);
949  }
950 
951 
954 
955  for(int i=0; i<nmax; i++) {
956 
957  char *ptr = (char*)addr + i*size;
958 
959  void *obj = (prop & kIsPointer) ? *((void**)ptr) : (TObject*)ptr;
960 
961  if (!obj) continue;
962 
963  fCount++;
964  if (!fBrowser) return;
965 
966  TString bwname;
967  TClass *actualClass = clm->GetActualClass(obj);
968  if (clm->IsTObject()) {
969  TObject *tobj = (TObject*)clm->DynamicCast(TObject::Class(),obj);
970  bwname = tobj->GetName();
971  } else {
972  bwname = actualClass->GetName();
973  bwname += "::";
974  bwname += mname;
975  }
976 
977  if (!clm->IsTObject() ||
978  bwname.Length()==0 ||
979  strcmp(bwname.Data(),actualClass->GetName())==0) {
980  bwname = name;
981  int l = strcspn(bwname.Data(),"[ ");
982  if (l<bwname.Length() && bwname[l]=='[') {
983  char cbuf[13]; snprintf(cbuf,13,"[%02d]",i);
984  ts.Replace(0,999,bwname,l);
985  ts += cbuf;
986  bwname = (const char*)ts;
987  }
988  }
989 
990  if (proxy==0) {
991 
992  fBrowser->Add(obj,clm,bwname);
993 
994  } else {
995  TClass *valueCl = proxy->GetValueClass();
996 
997  if (valueCl==0) {
998 
999  fBrowser->Add( obj, clm, bwname );
1000 
1001  } else {
1002  TVirtualCollectionProxy::TPushPop env(proxy, obj);
1003  TClass *actualCl = 0;
1004 
1005  int sz = proxy->Size();
1006 
1007  char fmt[] = {"#%09d"};
1008  fmt[3] = '0'+(int)log10(double(sz))+1;
1009  char buf[20];
1010  for (int ii=0;ii<sz;ii++) {
1011  void *p = proxy->At(ii);
1012 
1013  if (proxy->HasPointers()) {
1014  p = *((void**)p);
1015  if(!p) continue;
1016  actualCl = valueCl->GetActualClass(p);
1017  p = actualCl->DynamicCast(valueCl,p,0);
1018  }
1019  fCount++;
1020  snprintf(buf,20,fmt,ii);
1021  ts = bwname;
1022  ts += buf;
1023  fBrowser->Add( p, actualCl, ts );
1024  }
1025  }
1026  }
1027  }
1028 }
1029 
1030 //______________________________________________________________________________
1031 //______________________________________________________________________________
1032 //______________________________________________________________________________
1033 
1034 ClassImp(TClass);
1035 
1036 ////////////////////////////////////////////////////////////////////////////////
1037 
1039  TDictionary(),
1040  fPersistentRef(0),
1042  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1045  fInstanceCount(0), fOnHeap(0),
1047  fTypeInfo(0), fShowMembers(0),
1048  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1049  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1053  fState(kNoInfo),
1056 
1057 {
1058  // Default ctor.
1059 
1061  {
1062  TMmallocDescTemp setreset;
1063  fStreamerInfo = new TObjArray(1, -2);
1064  }
1065  fDeclFileLine = -2; // -2 for standalone TClass (checked in dtor)
1066 }
1067 
1068 ////////////////////////////////////////////////////////////////////////////////
1069 /// Create a TClass object. This object contains the full dictionary
1070 /// of a class. It has list to baseclasses, datamembers and methods.
1071 /// Use this ctor to create a standalone TClass object. Most useful
1072 /// to get a TClass interface to an interpreted class. Used by TTabCom.
1073 /// Normally you would use TClass::GetClass("class") to get access to a
1074 /// TClass object for a certain class.
1075 
1076 TClass::TClass(const char *name, Bool_t silent) :
1077  TDictionary(name),
1078  fPersistentRef(0),
1079  fStreamerInfo(0), fConversionStreamerInfo(0), fRealData(0),
1080  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1081  fAllPubMethod(0), fClassMenuList(0),
1082  fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1083  fInstanceCount(0), fOnHeap(0),
1084  fCheckSum(0), fCollectionProxy(0), fClassVersion(0), fClassInfo(0),
1085  fTypeInfo(0), fShowMembers(0),
1086  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1087  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1088  fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1),
1089  fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1090  fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1091  fState(kNoInfo),
1092  fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0),
1093  fSchemaRules(0), fStreamerImpl(&TClass::StreamerDefault)
1094 {
1096 
1097  if (!gROOT)
1098  ::Fatal("TClass::TClass", "ROOT system not initialized");
1099 
1100  {
1101  TMmallocDescTemp setreset;
1102  fStreamerInfo = new TObjArray(1, -2);
1103  }
1104  fDeclFileLine = -2; // -2 for standalone TClass (checked in dtor)
1105 
1106  SetBit(kLoading);
1107  if (!gInterpreter)
1108  ::Fatal("TClass::TClass", "gInterpreter not initialized");
1109 
1110  gInterpreter->SetClassInfo(this); // sets fClassInfo pointer
1111  if (!silent && !fClassInfo && fName.First('@')==kNPOS)
1112  ::Warning("TClass::TClass", "no dictionary for class %s is available", name);
1113  ResetBit(kLoading);
1114 
1117 }
1118 
1119 ////////////////////////////////////////////////////////////////////////////////
1120 /// Create a TClass object. This object contains the full dictionary
1121 /// of a class. It has list to baseclasses, datamembers and methods.
1122 
1123 TClass::TClass(const char *name, Version_t cversion, Bool_t silent) :
1124  TDictionary(name),
1125  fPersistentRef(0),
1126  fStreamerInfo(0), fConversionStreamerInfo(0), fRealData(0),
1127  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1128  fAllPubMethod(0), fClassMenuList(0),
1129  fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1130  fInstanceCount(0), fOnHeap(0),
1131  fCheckSum(0), fCollectionProxy(0), fClassVersion(0), fClassInfo(0),
1132  fTypeInfo(0), fShowMembers(0),
1133  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1134  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1135  fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1),
1136  fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1137  fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1138  fState(kNoInfo),
1139  fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0),
1140  fSchemaRules(0), fStreamerImpl(&TClass::StreamerDefault)
1141 {
1143  Init(name, cversion, 0, 0, 0, 0, -1, -1, 0, silent);
1144 }
1145 
1146 ////////////////////////////////////////////////////////////////////////////////
1147 /// Create a TClass object. This object does not contain anything. We mimic
1148 /// the case of a class fwd declared in the interpreter.
1149 
1150 TClass::TClass(const char *name, Version_t cversion, EState theState, Bool_t silent) :
1151  TDictionary(name),
1152  fPersistentRef(0),
1153  fStreamerInfo(0), fConversionStreamerInfo(0), fRealData(0),
1154  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1155  fAllPubMethod(0), fClassMenuList(0),
1156  fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1157  fInstanceCount(0), fOnHeap(0),
1158  fCheckSum(0), fCollectionProxy(0), fClassVersion(0), fClassInfo(0),
1159  fTypeInfo(0), fShowMembers(0),
1160  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1161  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1162  fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1),
1163  fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1164  fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1165  fState(theState),
1166  fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0),
1167  fSchemaRules(0), fStreamerImpl(&TClass::StreamerDefault)
1168 {
1170 
1171  // Treat the case in which a TClass instance is created for a namespace
1172  if (theState == kNamespaceForMeta){
1174  theState = kForwardDeclared; // it immediately decays in kForwardDeclared
1175  }
1176 
1177  if (theState != kForwardDeclared && theState != kEmulated)
1178  ::Fatal("TClass::TClass",
1179  "A TClass entry cannot be initialized in a state different from kForwardDeclared or kEmulated.");
1180  Init(name, cversion, 0, 0, 0, 0, -1, -1, 0, silent);
1181 }
1182 
1183 ////////////////////////////////////////////////////////////////////////////////
1184 /// Create a TClass object. This object contains the full dictionary
1185 /// of a class. It has list to baseclasses, datamembers and methods.
1186 /// Use this ctor to create a standalone TClass object. Most useful
1187 /// to get a TClass interface to an interpreted class. Used by TTabCom.
1188 /// Normally you would use TClass::GetClass("class") to get access to a
1189 /// TClass object for a certain class.
1190 ///
1191 /// This copies the ClassInfo (i.e. does *not* take ownership of it).
1192 
1193 TClass::TClass(ClassInfo_t *classInfo, Version_t cversion,
1194  const char *dfil, const char *ifil, Int_t dl, Int_t il, Bool_t silent) :
1195  TDictionary(""),
1196  fPersistentRef(0),
1197  fStreamerInfo(0), fConversionStreamerInfo(0), fRealData(0),
1198  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1199  fAllPubMethod(0), fClassMenuList(0),
1200  fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1201  fInstanceCount(0), fOnHeap(0),
1202  fCheckSum(0), fCollectionProxy(0), fClassVersion(0), fClassInfo(0),
1203  fTypeInfo(0), fShowMembers(0),
1204  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1205  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1206  fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1),
1207  fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1208  fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1209  fState(kNoInfo),
1210  fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0),
1211  fSchemaRules(0), fStreamerImpl(&TClass::StreamerDefault)
1212 {
1214 
1215  if (!gROOT)
1216  ::Fatal("TClass::TClass", "ROOT system not initialized");
1217 
1218  fDeclFileLine = -2; // -2 for standalone TClass (checked in dtor)
1219 
1220  SetBit(kLoading);
1221  if (!gInterpreter)
1222  ::Fatal("TClass::TClass", "gInterpreter not initialized");
1223 
1224  if (!classInfo || !gInterpreter->ClassInfo_IsValid(classInfo)) {
1225  MakeZombie();
1226  fState = kNoInfo;
1227  } else {
1228  fName = gInterpreter->ClassInfo_FullName(classInfo);
1229 
1231  Init(fName, cversion, 0, 0, dfil, ifil, dl, il, classInfo, silent);
1232  }
1233  ResetBit(kLoading);
1234 
1236 }
1237 
1238 
1239 ////////////////////////////////////////////////////////////////////////////////
1240 /// Create a TClass object. This object contains the full dictionary
1241 /// of a class. It has list to baseclasses, datamembers and methods.
1242 
1243 TClass::TClass(const char *name, Version_t cversion,
1244  const char *dfil, const char *ifil, Int_t dl, Int_t il, Bool_t silent) :
1245  TDictionary(name),
1246  fPersistentRef(0),
1247  fStreamerInfo(0), fConversionStreamerInfo(0), fRealData(0),
1248  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1249  fAllPubMethod(0), fClassMenuList(0),
1250  fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1251  fInstanceCount(0), fOnHeap(0),
1252  fCheckSum(0), fCollectionProxy(0), fClassVersion(0), fClassInfo(0),
1253  fTypeInfo(0), fShowMembers(0),
1254  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1255  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1256  fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1),
1257  fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1258  fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1259  fState(kNoInfo),
1260  fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0),
1261  fSchemaRules(0), fStreamerImpl(&TClass::StreamerDefault)
1262 {
1264  Init(name,cversion, 0, 0, dfil, ifil, dl, il, 0, silent);
1265 }
1266 
1267 ////////////////////////////////////////////////////////////////////////////////
1268 /// Create a TClass object. This object contains the full dictionary
1269 /// of a class. It has list to baseclasses, datamembers and methods.
1270 
1271 TClass::TClass(const char *name, Version_t cversion,
1272  const std::type_info &info, TVirtualIsAProxy *isa,
1273  const char *dfil, const char *ifil, Int_t dl, Int_t il,
1274  Bool_t silent) :
1275  TDictionary(name),
1276  fPersistentRef(0),
1277  fStreamerInfo(0), fConversionStreamerInfo(0), fRealData(0),
1278  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1279  fAllPubMethod(0),
1280  fClassMenuList(0),
1281  fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1282  fInstanceCount(0), fOnHeap(0),
1283  fCheckSum(0), fCollectionProxy(0), fClassVersion(0), fClassInfo(0),
1284  fTypeInfo(0), fShowMembers(0),
1285  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1286  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1287  fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1),
1288  fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1289  fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1290  fState(kHasTClassInit),
1291  fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0),
1292  fSchemaRules(0), fStreamerImpl(&TClass::StreamerDefault)
1293 {
1295  // use info
1296  Init(name, cversion, &info, isa, dfil, ifil, dl, il, 0, silent);
1297 }
1298 
1299 ////////////////////////////////////////////////////////////////////////////////
1300 /// we found at least one equivalent.
1301 /// let's force a reload
1302 
1304 {
1305  TClass::RemoveClass(oldcl);
1306 
1307  if (oldcl->CanIgnoreTObjectStreamer()) {
1309  }
1310 
1311  TVirtualStreamerInfo *info;
1312  TIter next(oldcl->GetStreamerInfos());
1313  while ((info = (TVirtualStreamerInfo*)next())) {
1314  info->Clear("build");
1315  info->SetClass(this);
1317  }
1318  oldcl->fStreamerInfo->Clear();
1319 
1320  oldcl->ReplaceWith(this);
1321  delete oldcl;
1322 }
1323 
1324 ////////////////////////////////////////////////////////////////////////////////
1325 /// Initialize a TClass object. This object contains the full dictionary
1326 /// of a class. It has list to baseclasses, datamembers and methods.
1327 
1328 void TClass::Init(const char *name, Version_t cversion,
1329  const std::type_info *typeinfo, TVirtualIsAProxy *isa,
1330  const char *dfil, const char *ifil, Int_t dl, Int_t il,
1331  ClassInfo_t *givenInfo,
1332  Bool_t silent)
1333 {
1334  if (!gROOT)
1335  ::Fatal("TClass::TClass", "ROOT system not initialized");
1336  if (!name || !name[0]) {
1337  ::Error("TClass::Init", "The name parameter is invalid (null or empty)");
1338  MakeZombie();
1339  return;
1340  }
1341  // Always strip the default STL template arguments (from any template argument or the class name)
1343  fClassVersion = cversion;
1344  fDeclFileName = dfil ? dfil : "";
1345  fImplFileName = ifil ? ifil : "";
1346  fDeclFileLine = dl;
1347  fImplFileLine = il;
1348  fTypeInfo = typeinfo;
1349  fIsA = isa;
1350  if ( fIsA ) fIsA->SetClass(this);
1351  // See also TCling::GenerateTClass() which will update fClassVersion after creation!
1352  fStreamerInfo = new TObjArray(fClassVersion+2+10,-1); // +10 to read new data by old
1353  fProperty = -1;
1354  fClassProperty = 0;
1355 
1357 
1358  TClass *oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(fName.Data());
1359 
1361 
1362  if (oldcl && oldcl->TestBit(kLoading)) {
1363  // Do not recreate a class while it is already being created!
1364 
1365  // We can no longer reproduce this case, to check whether we are, we use
1366  // this code:
1367  // Fatal("Init","A bad replacement for %s was requested\n",name);
1368  return;
1369  }
1370 
1371  TClass **persistentRef = 0;
1372  if (oldcl) {
1373 
1374  persistentRef = oldcl->fPersistentRef.exchange(0);
1375 
1376  // The code from here is also in ForceReload.
1377  TClass::RemoveClass(oldcl);
1378  // move the StreamerInfo immediately so that there are
1379  // properly updated!
1380 
1381  if (oldcl->CanIgnoreTObjectStreamer()) {
1383  }
1384  TVirtualStreamerInfo *info;
1385 
1386  TIter next(oldcl->GetStreamerInfos());
1387  while ((info = (TVirtualStreamerInfo*)next())) {
1388  // We need to force a call to BuildOld
1389  info->Clear("build");
1390  info->SetClass(this);
1392  }
1393  oldcl->fStreamerInfo->Clear();
1394  // The code diverges here from ForceReload.
1395 
1396  // Move the Schema Rules too.
1397  fSchemaRules = oldcl->fSchemaRules;
1398  oldcl->fSchemaRules = 0;
1399 
1400  // Move the TFunctions.
1401  fFuncTemplate = oldcl->fFuncTemplate;
1402  if (fFuncTemplate)
1403  fFuncTemplate->fClass = this;
1404  oldcl->fFuncTemplate = nullptr;
1405  fMethod.store( oldcl->fMethod );
1406  if (fMethod)
1407  (*fMethod).fClass = this;
1408  oldcl->fMethod = nullptr;
1409 
1410  }
1411 
1412  SetBit(kLoading);
1413  // Advertise ourself as the loading class for this class name
1414  TClass::AddClass(this);
1415 
1417 
1418  if (!gInterpreter)
1419  ::Fatal("TClass::Init", "gInterpreter not initialized");
1420 
1421  if (givenInfo) {
1422  bool invalid = !gInterpreter->ClassInfo_IsValid(givenInfo);
1423  bool notloaded = !gInterpreter->ClassInfo_IsLoaded(givenInfo);
1424  auto property = gInterpreter->ClassInfo_Property(givenInfo);
1425 
1426  if (invalid || (notloaded && (property & kIsNamespace)) ||
1427  !(property & (kIsClass | kIsStruct | kIsNamespace))) {
1428  if (!TClassEdit::IsSTLCont(fName.Data())) {
1429  MakeZombie();
1430  fState = kNoInfo;
1431  TClass::RemoveClass(this);
1432  return;
1433  }
1434  }
1435 
1436  if (!invalid) {
1437  fClassInfo = gInterpreter->ClassInfo_Factory(givenInfo);
1438  fCanLoadClassInfo = false; // avoids calls to LoadClassInfo() if info is already loaded
1439  if (fState <= kEmulated)
1440  fState = kInterpreted;
1441  }
1442  }
1443 
1444  // We need to check if the class it is not fwd declared for the cases where we
1445  // created a TClass directly in the kForwardDeclared state. Indeed in those cases
1446  // fClassInfo will always be nullptr.
1447  if (fState!=kForwardDeclared && !fClassInfo) {
1448 
1449  if (fState == kHasTClassInit) {
1450  // If the TClass is being generated from a ROOT dictionary,
1451  // even though we do not seem to have a CINT dictionary for
1452  // the class, we will will try to load it anyway UNLESS
1453  // the class is an STL container (or string).
1454  // This is because we do not expect the CINT dictionary
1455  // to be present for all STL classes (and we can handle
1456  // the lack of CINT dictionary in that cases).
1457  // However, the cling the dictionary no longer carries
1458  // an instantiation with it, unless we request the loading
1459  // here *or* the user explicitly instantiate the template
1460  // we would not have a ClassInfo for the template
1461  // instantiation.
1463  // Here we check and grab the info from the rootpcm.
1465  if (proto && proto->FillTClass(this)) {
1467  }
1468  }
1469  if (!fHasRootPcmInfo && gInterpreter->CheckClassInfo(fName, /* autoload = */ kTRUE)) {
1470  gInterpreter->SetClassInfo(this); // sets fClassInfo pointer
1471  if (fClassInfo) {
1472  // This should be moved out of GetCheckSum itself however the last time
1473  // we tried this cause problem, in particular in the end-of-process operation.
1474  // fCheckSum = GetCheckSum(kLatestCheckSum);
1475  } else {
1476  if (!fClassInfo) {
1477  if (IsZombie()) {
1478  TClass::RemoveClass(this);
1479  return;
1480  }
1481  }
1482  }
1483  }
1484  }
1485  if (!silent && (!fClassInfo && !fCanLoadClassInfo) && !isStl && fName.First('@')==kNPOS &&
1487  if (fState == kHasTClassInit) {
1488  if (fImplFileLine == -1 && fClassVersion == 0) {
1489  // We have a 'transient' class with a ClassDefInline and apparently no interpreter
1490  // information. Since it is transient, it is more than likely that the lack
1491  // will be harmles.
1492  } else {
1493  ::Error("TClass::Init", "no interpreter information for class %s is available even though it has a TClass "
1494  "initialization routine.",
1495  fName.Data());
1496  }
1497  } else {
1498  // In this case we initialised this TClass instance starting from the fwd declared state
1499  // and we know we have no dictionary: no need to warn
1500  ::Warning("TClass::Init", "no dictionary for class %s is available", fName.Data());
1501  }
1502  }
1503 
1504  fgClassCount++;
1506 
1507  // Make the typedef-expanded -> original hash table entries.
1508  // There may be several entries for any given key.
1509  // We only make entries if the typedef-expanded name
1510  // is different from the original name.
1511  TString resolvedThis;
1512  if (!givenInfo && strchr (name, '<')) {
1513  if ( fName != name) {
1514  if (!fgClassTypedefHash) {
1515  fgClassTypedefHash = new THashTable (100, 5);
1517  }
1518 
1519  fgClassTypedefHash->Add (new TNameMapNode (name, fName));
1521 
1522  }
1523  resolvedThis = TClassEdit::ResolveTypedef (name, kTRUE);
1524  if (resolvedThis != name) {
1525  if (!fgClassTypedefHash) {
1526  fgClassTypedefHash = new THashTable (100, 5);
1528  }
1529 
1530  fgClassTypedefHash->Add (new TNameMapNode (resolvedThis, fName));
1532  }
1533 
1534  }
1535 
1536  //In case a class with the same name had been created by TVirtualStreamerInfo
1537  //we must delete the old class, importing only the StreamerInfo structure
1538  //from the old dummy class.
1539  if (oldcl) {
1540 
1541  oldcl->ReplaceWith(this);
1542  delete oldcl;
1543 
1544  } else if (!givenInfo && resolvedThis.Length() > 0 && fgClassTypedefHash) {
1545 
1546  // Check for existing equivalent.
1547 
1548  if (resolvedThis != fName) {
1549  oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(resolvedThis);
1550  if (oldcl && oldcl != this) {
1551  persistentRef = oldcl->fPersistentRef.exchange(0);
1552  ForceReload (oldcl);
1553  }
1554  }
1555  TIter next( fgClassTypedefHash->GetListForObject(resolvedThis) );
1556  while ( TNameMapNode* htmp = static_cast<TNameMapNode*> (next()) ) {
1557  if (resolvedThis != htmp->String()) continue;
1558  oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(htmp->fOrigName); // gROOT->GetClass (htmp->fOrigName, kFALSE);
1559  if (oldcl && oldcl != this) {
1560  persistentRef = oldcl->fPersistentRef.exchange(0);
1561  ForceReload (oldcl);
1562  }
1563  }
1564  }
1565  if (fClassInfo) {
1567  if ( fDeclFileName == 0 || fDeclFileName[0] == '\0' ) {
1568  fDeclFileName = kUndeterminedClassInfoName;
1569  // Missing interface:
1570  // fDeclFileLine = gInterpreter->ClassInfo_FileLine( fClassInfo );
1571 
1572  // But really do not want to set ImplFileLine as it is currently the
1573  // marker of being 'loaded' or not (reminder loaded == has a TClass bootstrap).
1574  }
1575  }
1576 
1577  if (persistentRef) {
1578  fPersistentRef = persistentRef;
1579  } else {
1580  fPersistentRef = new TClass*;
1581  }
1582  *fPersistentRef = this;
1583 
1584  if ( isStl || !strncmp(GetName(),"stdext::hash_",13) || !strncmp(GetName(),"__gnu_cxx::hash_",16) ) {
1585  if (fState != kHasTClassInit) {
1586  // If we have a TClass compiled initialization, we can safely assume that
1587  // there will also be a collection proxy.
1589  if (fCollectionProxy) {
1591 
1592  // Numeric Collections have implicit conversions:
1594 
1595  } else if (!silent) {
1596  Warning("Init","Collection proxy for %s was not properly initialized!",GetName());
1597  }
1598  if (fStreamer==0) {
1600  }
1601  }
1602  } else if (!strncmp(GetName(),"std::pair<",10) || !strncmp(GetName(),"pair<",5) ) {
1603  // std::pairs have implicit conversions
1605  }
1606 
1607  ResetBit(kLoading);
1608 }
1609 
1610 ////////////////////////////////////////////////////////////////////////////////
1611 /// TClass dtor. Deletes all list that might have been created.
1612 
1614 {
1616 
1617  // Remove from the typedef hashtables.
1619  TString resolvedThis = TClassEdit::ResolveTypedef (GetName(), kTRUE);
1620  TIter next (fgClassTypedefHash->GetListForObject (resolvedThis));
1621  while ( TNameMapNode* htmp = static_cast<TNameMapNode*> (next()) ) {
1622  if (resolvedThis == htmp->String() && htmp->fOrigName == GetName()) {
1623  fgClassTypedefHash->Remove (htmp);
1624  delete htmp;
1625  break;
1626  }
1627  }
1628  }
1629 
1630  // Not owning lists, don't call Delete()
1631  // But this still need to be done first because the TList destructor
1632  // does access the object contained (via GetObject()->TestBit(kCanDelete))
1633  delete fStreamer; fStreamer =0;
1634  delete fAllPubData; fAllPubData =0;
1635  delete fAllPubMethod; fAllPubMethod=0;
1636 
1637  delete fPersistentRef.load();
1638 
1639  if (fBase.load())
1640  (*fBase).Delete();
1641  delete fBase.load(); fBase = 0;
1642 
1643  if (fData)
1644  fData->Delete();
1645  delete fData; fData = 0;
1646 
1647  if (fEnums.load())
1648  (*fEnums).Delete();
1649  delete fEnums.load(); fEnums = 0;
1650 
1651  if (fFuncTemplate)
1652  fFuncTemplate->Delete();
1653  delete fFuncTemplate; fFuncTemplate = 0;
1654 
1655  if (fMethod.load())
1656  (*fMethod).Delete();
1657  delete fMethod.load(); fMethod=0;
1658 
1659  if (fRealData)
1660  fRealData->Delete();
1661  delete fRealData; fRealData=0;
1662 
1663  if (fStreamerInfo)
1664  fStreamerInfo->Delete();
1665  delete fStreamerInfo; fStreamerInfo = nullptr;
1666 
1667  if (fDeclFileLine >= -1)
1668  TClass::RemoveClass(this);
1669 
1671  fClassInfo=0;
1672 
1673  if (fClassMenuList)
1675  delete fClassMenuList; fClassMenuList=0;
1676 
1678 
1679  if ( fIsA ) delete fIsA;
1680 
1681  if ( fRefProxy ) fRefProxy->Release();
1682  fRefProxy = 0;
1683 
1684  delete fStreamer;
1685  delete fCollectionProxy;
1686  delete fIsAMethod.load();
1687  delete fSchemaRules;
1688  if (fConversionStreamerInfo.load()) {
1689  std::map<std::string, TObjArray*>::iterator it;
1690  std::map<std::string, TObjArray*>::iterator end = (*fConversionStreamerInfo).end();
1691  for( it = (*fConversionStreamerInfo).begin(); it != end; ++it ) {
1692  delete it->second;
1693  }
1694  delete fConversionStreamerInfo.load();
1695  }
1696 }
1697 
1698 ////////////////////////////////////////////////////////////////////////////////
1699 
1700 namespace {
1701  Int_t ReadRulesContent(FILE *f)
1702  {
1703  // Read a class.rules file which contains one rule per line with comment
1704  // starting with a #
1705  // Returns the number of rules loaded.
1706  // Returns -1 in case of error.
1707 
1708  R__ASSERT(f!=0);
1709  TString rule(1024);
1710  int c, state = 0;
1711  Int_t count = 0;
1712 
1713  while ((c = fgetc(f)) != EOF) {
1714  if (c == 13) // ignore CR
1715  continue;
1716  if (c == '\n') {
1717  if (state != 3) {
1718  state = 0;
1719  if (rule.Length() > 0) {
1720  if (TClass::AddRule(rule)) {
1721  ++count;
1722  }
1723  rule.Clear();
1724  }
1725  }
1726  continue;
1727  }
1728  switch (state) {
1729  case 0: // start of line
1730  switch (c) {
1731  case ' ':
1732  case '\t':
1733  break;
1734  case '#':
1735  state = 1;
1736  break;
1737  default:
1738  state = 2;
1739  break;
1740  }
1741  break;
1742 
1743  case 1: // comment
1744  break;
1745 
1746  case 2: // rule
1747  switch (c) {
1748  case '\\':
1749  state = 3; // Continuation request
1750  default:
1751  break;
1752  }
1753  break;
1754  }
1755  switch (state) {
1756  case 2:
1757  rule.Append(c);
1758  break;
1759  }
1760  }
1761  return count;
1762  }
1763 }
1764 
1765 ////////////////////////////////////////////////////////////////////////////////
1766 /// Read the class.rules files from the default location:.
1767 /// $ROOTSYS/etc/class.rules (or ROOTETCDIR/class.rules)
1768 
1770 {
1771  static const char *suffix = "class.rules";
1772  TString sname = suffix;
1774 
1775  Int_t res = -1;
1776 
1777  FILE * f = fopen(sname,"r");
1778  if (f != 0) {
1779  res = ReadRulesContent(f);
1780  fclose(f);
1781  } else {
1782  ::Error("TClass::ReadRules()", "Cannot find rules file %s", sname.Data());
1783  }
1784  return res;
1785 }
1786 
1787 ////////////////////////////////////////////////////////////////////////////////
1788 /// Read a class.rules file which contains one rule per line with comment
1789 /// starting with a #
1790 /// - Returns the number of rules loaded.
1791 /// - Returns -1 in case of error.
1792 
1793 Int_t TClass::ReadRules( const char *filename )
1794 {
1795  if (!filename || !filename[0]) {
1796  ::Error("TClass::ReadRules", "no file name specified");
1797  return -1;
1798  }
1799 
1800  FILE * f = fopen(filename,"r");
1801  if (f == 0) {
1802  ::Error("TClass::ReadRules","Failed to open %s\n",filename);
1803  return -1;
1804  }
1805  Int_t count = ReadRulesContent(f);
1806 
1807  fclose(f);
1808  return count;
1809 
1810 }
1811 
1812 ////////////////////////////////////////////////////////////////////////////////
1813 /// Add a schema evolution customization rule.
1814 /// The syntax of the rule can be either the short form:
1815 /// ~~~ {.cpp}
1816 /// [type=Read] classname membername [attributes=... ] [version=[...] ] [checksum=[...] ] [oldtype=...] [code={...}]
1817 /// ~~~
1818 /// or the long form
1819 /// ~~~ {.cpp}
1820 /// [type=Read] sourceClass=classname [targetclass=newClassname] [ source="type membername; [type2 membername2]" ]
1821 /// [target="membername3;membername4"] [attributes=... ] [version=...] [checksum=...] [code={...}|functionname]
1822 /// ~~~
1823 ///
1824 /// For example to set HepMC::GenVertex::m_event to _not_ owned the object it is pointing to:
1825 /// HepMC::GenVertex m_event attributes=NotOwner
1826 ///
1827 /// Semantic of the tags:
1828 /// - type : the type of the rule, valid values: Read, ReadRaw, Write, WriteRaw, the default is 'Read'.
1829 /// - sourceClass : the name of the class as it is on the rule file
1830 /// - targetClass : the name of the class as it is in the current code ; defaults to the value of sourceClass
1831 /// - source : the types and names of the data members from the class on file that are needed, the list is separated by semi-colons ';'
1832 /// - oldtype: in the short form only, indicates the type on disk of the data member.
1833 /// - target : the names of the data members updated by this rule, the list is separated by semi-colons ';'
1834 /// - attributes : list of possible qualifiers among: Owner, NotOwner
1835 /// - version : list of the version of the class layout that this rule applies to. The syntax can be [1,4,5] or [2-] or [1-3] or [-3]
1836 /// - checksum : comma delimited list of the checksums of the class layout that this rule applies to.
1837 /// - code={...} : code to be executed for the rule or name of the function implementing it.
1838 
1839 Bool_t TClass::AddRule( const char *rule )
1840 {
1841  ROOT::TSchemaRule *ruleobj = new ROOT::TSchemaRule();
1842  if (! ruleobj->SetFromRule( rule ) ) {
1843  delete ruleobj;
1844  return kFALSE;
1845  }
1846 
1848 
1849  TClass *cl = TClass::GetClass( ruleobj->GetTargetClass() );
1850  if (!cl) {
1851  // Create an empty emulated class for now.
1852  cl = gInterpreter->GenerateTClass(ruleobj->GetTargetClass(), /* emulation = */ kTRUE, /*silent = */ kTRUE);
1853  }
1855 
1856  TString errmsg;
1857  if( !rset->AddRule( ruleobj, ROOT::Detail::TSchemaRuleSet::kCheckConflict, &errmsg ) ) {
1858  ::Warning( "TClass::AddRule", "The rule for class: \"%s\": version, \"%s\" and data members: \"%s\" has been skipped because it conflicts with one of the other rules (%s).",
1859  ruleobj->GetTargetClass(), ruleobj->GetVersion(), ruleobj->GetTargetString(), errmsg.Data() );
1860  delete ruleobj;
1861  return kFALSE;
1862  }
1863  return kTRUE;
1864 }
1865 
1866 ////////////////////////////////////////////////////////////////////////////////
1867 /// Adopt a new set of Data Model Evolution rules.
1868 
1870 {
1872 
1873  delete fSchemaRules;
1874  fSchemaRules = rules;
1875  fSchemaRules->SetClass( this );
1876 }
1877 
1878 ////////////////////////////////////////////////////////////////////////////////
1879 /// Return the set of the schema rules if any.
1880 
1882 {
1883  return fSchemaRules;
1884 }
1885 
1886 ////////////////////////////////////////////////////////////////////////////////
1887 /// Return the set of the schema rules if any.
1888 /// If create is true, create an empty set
1889 
1891 {
1892  if (create && fSchemaRules == 0) {
1894  fSchemaRules->SetClass( this );
1895  }
1896  return fSchemaRules;
1897 }
1898 
1899 ////////////////////////////////////////////////////////////////////////////////
1900 
1901 void TClass::AddImplFile(const char* filename, int line) {
1902  // Currently reset the implementation file and line.
1903  // In the close future, it will actually add this file and line
1904  // to a "list" of implementation files.
1905 
1906  fImplFileName = filename;
1907  fImplFileLine = line;
1908 }
1909 
1910 ////////////////////////////////////////////////////////////////////////////////
1911 /// Browse external object inherited from TObject.
1912 /// It passes through inheritance tree and calls TBrowser::Add
1913 /// in appropriate cases. Static function.
1914 
1916 {
1917  if (!obj) return 0;
1918 
1919  TAutoInspector insp(b);
1920  obj->ShowMembers(insp);
1921  return insp.fCount;
1922 }
1923 
1924 ////////////////////////////////////////////////////////////////////////////////
1925 /// Browse objects of of the class described by this TClass object.
1926 
1927 Int_t TClass::Browse(void *obj, TBrowser *b) const
1928 {
1929  if (!obj) return 0;
1930 
1931  TClass *actual = GetActualClass(obj);
1932  if (IsTObject()) {
1933  // Call TObject::Browse.
1934 
1935  if (!fIsOffsetStreamerSet) {
1937  }
1938  TObject* realTObject = (TObject*)((size_t)obj + fOffsetStreamer);
1939  realTObject->Browse(b);
1940  return 1;
1941  } else if (actual != this) {
1942  return actual->Browse(obj, b);
1943  } else if (GetCollectionProxy()) {
1944 
1945  // do something useful.
1946 
1947  } else {
1948  TAutoInspector insp(b);
1949  CallShowMembers(obj,insp,kFALSE);
1950  return insp.fCount;
1951  }
1952 
1953  return 0;
1954 }
1955 
1956 ////////////////////////////////////////////////////////////////////////////////
1957 /// This method is called by a browser to get the class information.
1958 
1960 {
1961  if (!HasInterpreterInfo()) return;
1962 
1963  if (b) {
1964  if (!fRealData) BuildRealData();
1965 
1966  b->Add(GetListOfDataMembers(), "Data Members");
1967  b->Add(GetListOfRealData(), "Real Data Members");
1968  b->Add(GetListOfMethods(), "Methods");
1969  b->Add(GetListOfBases(), "Base Classes");
1970  }
1971 }
1972 
1973 ////////////////////////////////////////////////////////////////////////////////
1974 /// Build a full list of persistent data members.
1975 /// Scans the list of all data members in the class itself and also
1976 /// in all base classes. For each persistent data member, inserts a
1977 /// TRealData object in the list fRealData.
1978 ///
1979 
1980 void TClass::BuildRealData(void* pointer, Bool_t isTransient)
1981 {
1982 
1984 
1985  // Only do this once.
1986  if (fRealData) {
1987  return;
1988  }
1989 
1990  if (fClassVersion == 0) {
1991  isTransient = kTRUE;
1992  }
1993 
1994  // When called via TMapFile (e.g. Update()) make sure that the dictionary
1995  // gets allocated on the heap and not in the mapped file.
1996  TMmallocDescTemp setreset;
1997 
1998  // Handle emulated classes and STL containers specially.
2000  // We are an emulated class or an STL container.
2001  fRealData = new TList;
2002  BuildEmulatedRealData("", 0, this);
2003  return;
2004  }
2005 
2006  // return early on string
2007  static TClassRef clRefString("std::string");
2008  if (clRefString == this) {
2009  return;
2010  }
2011 
2012  // Complain about stl classes ending up here (unique_ptr etc) - except for
2013  // pair where we will build .first, .second just fine
2014  // and those for which the user explicitly requested a dictionary.
2015  if (!isTransient && GetState() != kHasTClassInit
2017  && strncmp(GetName(), "pair<", 5) != 0) {
2018  Error("BuildRealData", "Inspection for %s not supported!", GetName());
2019  }
2020 
2021  // The following statement will recursively call
2022  // all the subclasses of this class.
2023  fRealData = new TList;
2024  TBuildRealData brd(pointer, this);
2025 
2026  // CallShowMember will force a call to InheritsFrom, which indirectly
2027  // calls TClass::GetClass. It forces the loading of new typedefs in
2028  // case some of them were not yet loaded.
2029  if ( ! CallShowMembers(pointer, brd, isTransient) ) {
2030  if ( isTransient ) {
2031  // This is a transient data member, so it is probably fine to not have
2032  // access to its content. However let's no mark it as definitively setup,
2033  // since another class might use this class for a persistent data member and
2034  // in this case we really want the error message.
2035  delete fRealData;
2036  fRealData = 0;
2037  } else {
2038  Error("BuildRealData", "Cannot find any ShowMembers function for %s!", GetName());
2039  }
2040  }
2041 
2042  // Take this opportunity to build the real data for base classes.
2043  // In case one base class is abstract, it would not be possible later
2044  // to create the list of real data for this abstract class.
2045  TBaseClass* base = 0;
2046  TIter next(GetListOfBases());
2047  while ((base = (TBaseClass*) next())) {
2048  if (base->IsSTLContainer()) {
2049  continue;
2050  }
2051  TClass* c = base->GetClassPointer();
2052  if (c) {
2053  c->BuildRealData(0, isTransient);
2054  }
2055  }
2056 }
2057 
2058 ////////////////////////////////////////////////////////////////////////////////
2059 /// Build the list of real data for an emulated class
2060 
2061 void TClass::BuildEmulatedRealData(const char *name, Long_t offset, TClass *cl)
2062 {
2064 
2065  TVirtualStreamerInfo *info;
2066  if (Property() & kIsAbstract) {
2068  } else {
2069  info = GetStreamerInfo();
2070  }
2071  if (!info) {
2072  // This class is abstract, but we don't yet have a SteamerInfo for it ...
2073  Error("BuildEmulatedRealData","Missing StreamerInfo for %s",GetName());
2074  // Humm .. no information ... let's bail out
2075  return;
2076  }
2077 
2078  TIter next(info->GetElements());
2079  TStreamerElement *element;
2080  while ((element = (TStreamerElement*)next())) {
2081  Int_t etype = element->GetType();
2082  Long_t eoffset = element->GetOffset();
2083  TClass *cle = element->GetClassPointer();
2084  if (element->IsBase() || etype == TVirtualStreamerInfo::kBase) {
2085  //base class are skipped in this loop, they will be added at the end.
2086  continue;
2087  } else if (etype == TVirtualStreamerInfo::kTObject ||
2088  etype == TVirtualStreamerInfo::kTNamed ||
2089  etype == TVirtualStreamerInfo::kObject ||
2090  etype == TVirtualStreamerInfo::kAny) {
2091  //member class
2092  TString rdname; rdname.Form("%s%s",name,element->GetFullName());
2093  TRealData *rd = new TRealData(rdname,offset+eoffset,0);
2094  if (gDebug > 0) printf(" Class: %s, adding TRealData=%s, offset=%ld\n",cl->GetName(),rd->GetName(),rd->GetThisOffset());
2095  cl->GetListOfRealData()->Add(rd);
2096  // Now we a dot
2097  rdname.Form("%s%s.",name,element->GetFullName());
2098  if (cle) cle->BuildEmulatedRealData(rdname,offset+eoffset,cl);
2099  } else {
2100  //others
2101  TString rdname; rdname.Form("%s%s",name,element->GetFullName());
2102  TRealData *rd = new TRealData(rdname,offset+eoffset,0);
2103  if (gDebug > 0) printf(" Class: %s, adding TRealData=%s, offset=%ld\n",cl->GetName(),rd->GetName(),rd->GetThisOffset());
2104  cl->GetListOfRealData()->Add(rd);
2105  }
2106  //if (fClassInfo==0 && element->IsBase()) {
2107  // if (fBase==0) fBase = new TList;
2108  // TClass *base = element->GetClassPointer();
2109  // fBase->Add(new TBaseClass(this, cl, eoffset));
2110  //}
2111  }
2112  // The base classes must added last on the list of real data (to help with ambiguous data member names)
2113  next.Reset();
2114  while ((element = (TStreamerElement*)next())) {
2115  Int_t etype = element->GetType();
2116  if (element->IsBase() || etype == TVirtualStreamerInfo::kBase) {
2117  //base class
2118  Long_t eoffset = element->GetOffset();
2119  TClass *cle = element->GetClassPointer();
2120  if (cle) cle->BuildEmulatedRealData(name,offset+eoffset,cl);
2121  }
2122  }
2123 }
2124 
2125 
2126 ////////////////////////////////////////////////////////////////////////////////
2127 /// Calculate the offset between an object of this class to
2128 /// its base class TObject. The pointer can be adjusted by
2129 /// that offset to access any virtual method of TObject like
2130 /// Streamer() and ShowMembers().
2131 
2133 {
2136  // When called via TMapFile (e.g. Update()) make sure that the dictionary
2137  // gets allocated on the heap and not in the mapped file.
2138 
2139  TMmallocDescTemp setreset;
2141  if (fStreamerType == kTObject) {
2143  }
2145  }
2146 }
2147 
2148 
2149 ////////////////////////////////////////////////////////////////////////////////
2150 /// Call ShowMembers() on the obj of this class type, passing insp and parent.
2151 /// isATObject is -1 if unknown, 0 if it is not a TObject, and 1 if it is a TObject.
2152 /// The function returns whether it was able to call ShowMembers().
2153 
2154 Bool_t TClass::CallShowMembers(const void* obj, TMemberInspector &insp, Bool_t isTransient) const
2155 {
2156  if (fShowMembers) {
2157  // This should always works since 'pointer' should be pointing
2158  // to an object of the actual type of this TClass object.
2159  fShowMembers(obj, insp, isTransient);
2160  return kTRUE;
2161  } else {
2162 
2164  if (fClassInfo) {
2165 
2166  if (strcmp(GetName(), "string") == 0) {
2167  // For std::string we know that we do not have a ShowMembers
2168  // function and that it's okay.
2169  return kTRUE;
2170  }
2171  // Since we do have some dictionary information, let's
2172  // call the interpreter's ShowMember.
2173  // This works with Cling to support interpreted classes.
2174  gInterpreter->InspectMembers(insp, obj, this, isTransient);
2175  return kTRUE;
2176 
2177  } else if (TVirtualStreamerInfo* sinfo = GetStreamerInfo()) {
2178  sinfo->CallShowMembers(obj, insp, isTransient);
2179  return kTRUE;
2180  } // isATObject
2181  } // fShowMembers is set
2182 
2183  return kFALSE;
2184 }
2185 
2186 ////////////////////////////////////////////////////////////////////////////////
2187 /// Do a ShowMembers() traversal of all members and base classes' members
2188 /// using the reflection information from the interpreter. Works also for
2189 /// interpreted objects.
2190 
2191 void TClass::InterpretedShowMembers(void* obj, TMemberInspector &insp, Bool_t isTransient)
2192 {
2193  return gInterpreter->InspectMembers(insp, obj, this, isTransient);
2194 }
2195 
2197 {
2198  if (fCanSplit >= 0) {
2199  return ! ( fCanSplit & 0x2 );
2200  }
2201 
2203 
2204  if (GetCollectionProxy() != nullptr) {
2205  // A collection can never affect its derived class 'splittability'
2206  return kTRUE;
2207  }
2208 
2209  if (this == TRef::Class()) { fCanSplit = 2; return kFALSE; }
2210  if (this == TRefArray::Class()) { fCanSplit = 2; return kFALSE; }
2211  if (this == TArray::Class()) { fCanSplit = 2; return kFALSE; }
2212  if (this == TClonesArray::Class()) { fCanSplit = 1; return kTRUE; }
2213  if (this == TCollection::Class()) { fCanSplit = 2; return kFALSE; }
2214 
2215  // TTree is not always available (for example in rootcling), so we need
2216  // to grab it silently.
2217  auto refTreeClass( TClass::GetClass("TTree",kTRUE,kTRUE) );
2218  if (this == refTreeClass) { fCanSplit = 2; return kFALSE; }
2219 
2220  if (!HasDataMemberInfo()) {
2221  TVirtualStreamerInfo *sinfo = ((TClass *)this)->GetCurrentStreamerInfo();
2222  if (sinfo==0) sinfo = GetStreamerInfo();
2223  TIter next(sinfo->GetElements());
2224  TStreamerElement *element;
2225  while ((element = (TStreamerElement*)next())) {
2226  if (element->IsA() == TStreamerBase::Class()) {
2227  TClass *clbase = element->GetClassPointer();
2228  if (!clbase) {
2229  // If there is a missing base class, we can't split the immediate
2230  // derived class.
2231  fCanSplit = 0;
2232  return kFALSE;
2233  } else if (!clbase->CanSplitBaseAllow()) {
2234  fCanSplit = 2;
2235  return kFALSE;
2236  }
2237  }
2238  }
2239  }
2240 
2241  // If we don't have data member info there is no more information
2242  // we can find out.
2243  if (!HasDataMemberInfo()) return kTRUE;
2244 
2245  TObjLink *lnk = GetListOfBases() ? fBase.load()->FirstLink() : 0;
2246 
2247  // Look at inheritance tree
2248  while (lnk) {
2249  TClass *c;
2250  TBaseClass *base = (TBaseClass*) lnk->GetObject();
2251  c = base->GetClassPointer();
2252  if(!c) {
2253  // If there is a missing base class, we can't split the immediate
2254  // derived class.
2255  fCanSplit = 0;
2256  return kFALSE;
2257  } else if (!c->CanSplitBaseAllow()) {
2258  fCanSplit = 2;
2259  return kFALSE;
2260  }
2261  lnk = lnk->Next();
2262  }
2263  return kTRUE;
2264 }
2265 
2266 ////////////////////////////////////////////////////////////////////////////////
2267 /// Return true if the data member of this TClass can be saved separately.
2268 
2270 {
2271  // Note: add the possibility to set it for the class and the derived class.
2272  // save the info in TVirtualStreamerInfo
2273  // deal with the info in MakeProject
2274  if (fCanSplit >= 0) {
2275  // The user explicitly set the value
2276  return (fCanSplit & 0x1) == 1;
2277  }
2278 
2280  TClass *This = const_cast<TClass*>(this);
2281 
2282  if (this == TObject::Class()) { This->fCanSplit = 1; return kTRUE; }
2283  if (fName == "TClonesArray") { This->fCanSplit = 1; return kTRUE; }
2284  if (fRefProxy) { This->fCanSplit = 0; return kFALSE; }
2285  if (fName.BeginsWith("TVectorT<")) { This->fCanSplit = 0; return kFALSE; }
2286  if (fName.BeginsWith("TMatrixT<")) { This->fCanSplit = 0; return kFALSE; }
2287  if (fName == "string") { This->fCanSplit = 0; return kFALSE; }
2288  if (fName == "std::string") { This->fCanSplit = 0; return kFALSE; }
2289 
2290  if (GetCollectionProxy()!=0) {
2291  // For STL collection we need to look inside.
2292 
2293  // However we do not split collections of collections
2294  // nor collections of strings
2295  // nor collections of pointers (unless explicit request (see TBranchSTL)).
2296 
2297  if (GetCollectionProxy()->HasPointers()) { This->fCanSplit = 0; return kFALSE; }
2298 
2299  TClass *valueClass = GetCollectionProxy()->GetValueClass();
2300  if (valueClass == 0) { This->fCanSplit = 0; return kFALSE; }
2301  static TClassRef stdStringClass("std::string");
2302  if (valueClass==TString::Class() || valueClass==stdStringClass)
2303  { This->fCanSplit = 0; return kFALSE; }
2304  if (!valueClass->CanSplit()) { This->fCanSplit = 0; return kFALSE; }
2305  if (valueClass->GetCollectionProxy() != 0) { This->fCanSplit = 0; return kFALSE; }
2306 
2307  Int_t stl = -TClassEdit::IsSTLCont(GetName(), 0);
2308  if ((stl==ROOT::kSTLmap || stl==ROOT::kSTLmultimap)
2309  && !valueClass->HasDataMemberInfo())
2310  {
2311  This->fCanSplit = 0;
2312  return kFALSE;
2313  }
2314 
2315  This->fCanSplit = 1;
2316  return kTRUE;
2317 
2318  }
2319 
2320  if (GetStreamer() != nullptr || fStreamerFunc != nullptr) {
2321 
2322  // We have an external custom streamer provided by the user, we must not
2323  // split it.
2324  This->fCanSplit = 0;
2325  return kFALSE;
2326 
2327  } else if ( TestBit(TClass::kHasCustomStreamerMember) ) {
2328 
2329  // We have a custom member function streamer or
2330  // an older (not StreamerInfo based) automatic streamer.
2331  This->fCanSplit = 0;
2332  return kFALSE;
2333  }
2334 
2335  if (Size()==1) {
2336  // 'Empty' class there is nothing to split!.
2337  This->fCanSplit = 0;
2338  return kFALSE;
2339  }
2340 
2341 
2342  if ( !This->CanSplitBaseAllow() ) {
2343  return kFALSE;
2344  }
2345 
2346  This->fCanSplit = 1;
2347  return kTRUE;
2348 }
2349 
2350 ////////////////////////////////////////////////////////////////////////////////
2351 /// Return the C++ property of this class, eg. is abstract, has virtual base
2352 /// class, see EClassProperty in TDictionary.h
2353 
2355 {
2356  if (fProperty == -1) Property();
2357  return fClassProperty;
2358 }
2359 
2360 ////////////////////////////////////////////////////////////////////////////////
2361 /// Create a Clone of this TClass object using a different name but using the same 'dictionary'.
2362 /// This effectively creates a hard alias for the class name.
2363 
2364 TObject *TClass::Clone(const char *new_name) const
2365 {
2366  if (new_name == 0 || new_name[0]=='\0' || fName == new_name) {
2367  Error("Clone","The name of the class must be changed when cloning a TClass object.");
2368  return 0;
2369  }
2370 
2371  // Need to lock access to TROOT::GetListOfClasses so the cloning happens atomically
2373  // Temporarily remove the original from the list of classes.
2374  TClass::RemoveClass(const_cast<TClass*>(this));
2375 
2376  TClass *copy;
2377  if (fTypeInfo) {
2378  copy = new TClass(GetName(),
2379  fClassVersion,
2380  *fTypeInfo,
2381  new TIsAProxy(*fTypeInfo),
2382  GetDeclFileName(),
2383  GetImplFileName(),
2384  GetDeclFileLine(),
2385  GetImplFileLine());
2386  } else {
2387  copy = new TClass(GetName(),
2388  fClassVersion,
2389  GetDeclFileName(),
2390  GetImplFileName(),
2391  GetDeclFileLine(),
2392  GetImplFileLine());
2393  }
2394  copy->fShowMembers = fShowMembers;
2395  // Remove the copy before renaming it
2396  TClass::RemoveClass(copy);
2397  copy->fName = new_name;
2398  TClass::AddClass(copy);
2399 
2400  copy->SetNew(fNew);
2401  copy->SetNewArray(fNewArray);
2402  copy->SetDelete(fDelete);
2404  copy->SetDestructor(fDestructor);
2406  copy->fStreamerFunc = fStreamerFunc;
2408  if (fStreamer) {
2409  copy->AdoptStreamer(fStreamer->Generate());
2410  }
2411  // If IsZombie is true, something went wrong and we will not be
2412  // able to properly copy the collection proxy
2413  if (fCollectionProxy && !copy->IsZombie()) {
2415  }
2416  copy->SetClassSize(fSizeof);
2417  if (fRefProxy) {
2418  copy->AdoptReferenceProxy( fRefProxy->Clone() );
2419  }
2420  TClass::AddClass(const_cast<TClass*>(this));
2421  return copy;
2422 }
2423 
2424 ////////////////////////////////////////////////////////////////////////////////
2425 /// Copy the argument.
2426 
2428 {
2429 // // This code was used too quickly test the STL Emulation layer
2430 // Int_t k = TClassEdit::IsSTLCont(GetName());
2431 // if (k==1||k==-1) return;
2432 
2433  delete fCollectionProxy;
2434  fCollectionProxy = orig.Generate();
2435 }
2436 
2437 ////////////////////////////////////////////////////////////////////////////////
2438 /// Draw detailed class inheritance structure.
2439 /// If a class B inherits from a class A, the description of B is drawn
2440 /// on the right side of the description of A.
2441 /// Member functions overridden by B are shown in class A with a blue line
2442 /// erasing the corresponding member function
2443 
2444 void TClass::Draw(Option_t *option)
2445 {
2446  if (!HasInterpreterInfo()) return;
2447 
2448  TVirtualPad *padsav = gPad;
2449 
2450  // Should we create a new canvas?
2451  TString opt=option;
2452  if (!padsav || !opt.Contains("same")) {
2453  TVirtualPad *padclass = (TVirtualPad*)(gROOT->GetListOfCanvases())->FindObject("R__class");
2454  if (!padclass) {
2455  gROOT->ProcessLine("new TCanvas(\"R__class\",\"class\",20,20,1000,750);");
2456  } else {
2457  padclass->cd();
2458  }
2459  }
2460 
2461  if (gPad) gPad->DrawClassObject(this,option);
2462 
2463  if (padsav) padsav->cd();
2464 }
2465 
2466 ////////////////////////////////////////////////////////////////////////////////
2467 /// Dump contents of object on stdout.
2468 /// Using the information in the object dictionary
2469 /// each data member is interpreted.
2470 /// If a data member is a pointer, the pointer value is printed
2471 /// 'obj' is assume to point to an object of the class describe by this TClass
2472 ///
2473 /// The following output is the Dump of a TArrow object:
2474 /// ~~~ {.cpp}
2475 /// fAngle 0 Arrow opening angle (degrees)
2476 /// fArrowSize 0.2 Arrow Size
2477 /// fOption.*fData
2478 /// fX1 0.1 X of 1st point
2479 /// fY1 0.15 Y of 1st point
2480 /// fX2 0.67 X of 2nd point
2481 /// fY2 0.83 Y of 2nd point
2482 /// fUniqueID 0 object unique identifier
2483 /// fBits 50331648 bit field status word
2484 /// fLineColor 1 line color
2485 /// fLineStyle 1 line style
2486 /// fLineWidth 1 line width
2487 /// fFillColor 19 fill area color
2488 /// fFillStyle 1001 fill area style
2489 /// ~~~
2490 ///
2491 /// If noAddr is true, printout of all pointer values is skipped.
2492 
2493 void TClass::Dump(const void *obj, Bool_t noAddr /*=kFALSE*/) const
2494 {
2495 
2496  Long_t prObj = noAddr ? 0 : (Long_t)obj;
2497  if (IsTObject()) {
2498  if (!fIsOffsetStreamerSet) {
2500  }
2501  TObject *tobj = (TObject*)((Long_t)obj + fOffsetStreamer);
2502 
2503 
2504  if (sizeof(this) == 4)
2505  Printf("==> Dumping object at: 0x%08lx, name=%s, class=%s\n",prObj,tobj->GetName(),GetName());
2506  else
2507  Printf("==> Dumping object at: 0x%016lx, name=%s, class=%s\n",prObj,tobj->GetName(),GetName());
2508  } else {
2509 
2510  if (sizeof(this) == 4)
2511  Printf("==> Dumping object at: 0x%08lx, class=%s\n",prObj,GetName());
2512  else
2513  Printf("==> Dumping object at: 0x%016lx, class=%s\n",prObj,GetName());
2514  }
2515 
2516  TDumpMembers dm(noAddr);
2517  if (!CallShowMembers(obj, dm, kFALSE)) {
2518  Info("Dump", "No ShowMembers function, dumping disabled");
2519  }
2520 }
2521 
2522 ////////////////////////////////////////////////////////////////////////////////
2523 /// Introduce an escape character (@) in front of a special chars.
2524 /// You need to use the result immediately before it is being overwritten.
2525 
2526 char *TClass::EscapeChars(const char *text) const
2527 {
2528  static const UInt_t maxsize = 255;
2529  static char name[maxsize+2]; //One extra if last char needs to be escaped
2530 
2531  UInt_t nch = strlen(text);
2532  UInt_t icur = 0;
2533  for (UInt_t i = 0; i < nch && icur < maxsize; ++i, ++icur) {
2534  if (text[i] == '\"' || text[i] == '[' || text[i] == '~' ||
2535  text[i] == ']' || text[i] == '&' || text[i] == '#' ||
2536  text[i] == '!' || text[i] == '^' || text[i] == '<' ||
2537  text[i] == '?' || text[i] == '>') {
2538  name[icur] = '@';
2539  ++icur;
2540  }
2541  name[icur] = text[i];
2542  }
2543  name[icur] = 0;
2544  return name;
2545 }
2546 
2547 ////////////////////////////////////////////////////////////////////////////////
2548 /// Return a pointer the the real class of the object.
2549 /// This is equivalent to object->IsA() when the class has a ClassDef.
2550 /// It is REQUIRED that object is coming from a proper pointer to the
2551 /// class represented by 'this'.
2552 /// Example: Special case:
2553 /// ~~~ {.cpp}
2554 /// class MyClass : public AnotherClass, public TObject
2555 /// ~~~
2556 /// then on return, one must do:
2557 /// ~~~ {.cpp}
2558 /// TObject *obj = (TObject*)((void*)myobject)directory->Get("some object of MyClass");
2559 /// MyClass::Class()->GetActualClass(obj); // this would be wrong!!!
2560 /// ~~~
2561 /// Also if the class represented by 'this' and NONE of its parents classes
2562 /// have a virtual ptr table, the result will be 'this' and NOT the actual
2563 /// class.
2564 
2565 TClass *TClass::GetActualClass(const void *object) const
2566 {
2567  if (object==0) return (TClass*)this;
2568  if (fIsA) {
2569  return (*fIsA)(object); // ROOT::IsA((ThisClass*)object);
2570  } else if (fGlobalIsA) {
2571  return fGlobalIsA(this,object);
2572  } else {
2573  if (IsTObject()) {
2574 
2575  if (!fIsOffsetStreamerSet) {
2577  }
2578  TObject* realTObject = (TObject*)((size_t)object + fOffsetStreamer);
2579 
2580  return realTObject->IsA();
2581  }
2582 
2583  if (HasInterpreterInfo()) {
2584 
2585  TVirtualIsAProxy *isa = 0;
2587  isa = (TVirtualIsAProxy*)gROOT->ProcessLineFast(TString::Format("new ::TInstrumentedIsAProxy<%s>(0);",GetName()));
2588  }
2589  else {
2590  isa = (TVirtualIsAProxy*)gROOT->ProcessLineFast(TString::Format("new ::TIsAProxy(typeid(%s));",GetName()));
2591  }
2592  if (isa) {
2594  const_cast<TClass*>(this)->fIsA = isa;
2595  }
2596  if (fIsA) {
2597  return (*fIsA)(object); // ROOT::IsA((ThisClass*)object);
2598  }
2599  }
2601  if (sinfo) {
2602  return sinfo->GetActualClass(object);
2603  }
2604  return (TClass*)this;
2605  }
2606 }
2607 
2608 ////////////////////////////////////////////////////////////////////////////////
2609 /// Return pointer to the base class "classname". Returns 0 in case
2610 /// "classname" is not a base class. Takes care of multiple inheritance.
2611 
2612 TClass *TClass::GetBaseClass(const char *classname)
2613 {
2614  // check if class name itself is equal to classname
2615  if (strcmp(GetName(), classname) == 0) return this;
2616 
2617  if (!HasDataMemberInfo()) return 0;
2618 
2619  // Make sure we deal with possible aliases, we could also have normalized
2620  // the name.
2621  TClass *search = TClass::GetClass(classname,kTRUE,kTRUE);
2622 
2623  if (search) return GetBaseClass(search);
2624  else return 0;
2625 }
2626 
2627 ////////////////////////////////////////////////////////////////////////////////
2628 /// Return pointer to the base class "cl". Returns 0 in case "cl"
2629 /// is not a base class. Takes care of multiple inheritance.
2630 
2632 {
2633  // check if class name itself is equal to classname
2634  if (cl == this) return this;
2635 
2636  if (!HasDataMemberInfo()) return 0;
2637 
2638  TObjLink *lnk = GetListOfBases() ? fBase.load()->FirstLink() : 0;
2639 
2640  // otherwise look at inheritance tree
2641  while (lnk) {
2642  TClass *c, *c1;
2643  TBaseClass *base = (TBaseClass*) lnk->GetObject();
2644  c = base->GetClassPointer();
2645  if (c) {
2646  if (cl == c) return c;
2647  c1 = c->GetBaseClass(cl);
2648  if (c1) return c1;
2649  }
2650  lnk = lnk->Next();
2651  }
2652  return 0;
2653 }
2654 
2655 ////////////////////////////////////////////////////////////////////////////////
2656 /// Return data member offset to the base class "cl".
2657 /// - Returns -1 in case "cl" is not a base class.
2658 /// - Returns -2 if cl is a base class, but we can't find the offset
2659 /// because it's virtual.
2660 /// Takes care of multiple inheritance.
2661 
2663 {
2664  // check if class name itself is equal to classname
2665  if (cl == this) return 0;
2666 
2667  if (!fBase.load()) {
2669  // If the information was not provided by the root pcm files and
2670  // if we can not find the ClassInfo, we have to fall back to the
2671  // StreamerInfo
2672  if (!fClassInfo) {
2674  if (!sinfo) return -1;
2675  TStreamerElement *element;
2676  Int_t offset = 0;
2677 
2678  TObjArray &elems = *(sinfo->GetElements());
2679  Int_t size = elems.GetLast()+1;
2680  for(Int_t i=0; i<size; i++) {
2681  element = (TStreamerElement*)elems[i];
2682  if (element->IsBase()) {
2683  if (element->IsA() == TStreamerBase::Class()) {
2684  TStreamerBase *base = (TStreamerBase*)element;
2685  TClass *baseclass = base->GetClassPointer();
2686  if (!baseclass) return -1;
2687  Int_t subOffset = baseclass->GetBaseClassOffsetRecurse(cl);
2688  if (subOffset == -2) return -2;
2689  if (subOffset != -1) return offset+subOffset;
2690  offset += baseclass->Size();
2691  } else if (element->IsA() == TStreamerSTL::Class()) {
2692  TStreamerSTL *base = (TStreamerSTL*)element;
2693  TClass *baseclass = base->GetClassPointer();
2694  if (!baseclass) return -1;
2695  Int_t subOffset = baseclass->GetBaseClassOffsetRecurse(cl);
2696  if (subOffset == -2) return -2;
2697  if (subOffset != -1) return offset+subOffset;
2698  offset += baseclass->Size();
2699 
2700  } else {
2701  Error("GetBaseClassOffsetRecurse","Unexpected element type for base class: %s\n",element->IsA()->GetName());
2702  }
2703  }
2704  }
2705  return -1;
2706  }
2707  }
2708 
2709  TClass *c;
2710  Int_t off;
2711  TBaseClass *inh;
2712  TObjLink *lnk = 0;
2713  if (fBase.load() == 0)
2714  lnk = GetListOfBases()->FirstLink();
2715  else
2716  lnk = fBase.load()->FirstLink();
2717 
2718  // otherwise look at inheritance tree
2719  while (lnk) {
2720  inh = (TBaseClass *)lnk->GetObject();
2721  //use option load=kFALSE to avoid a warning like:
2722  //"Warning in <TClass::TClass>: no dictionary for class TRefCnt is available"
2723  //We can not afford to not have the class if it exist, so we
2724  //use kTRUE.
2725  c = inh->GetClassPointer(kTRUE); // kFALSE);
2726  if (c) {
2727  if (cl == c) {
2728  if ((inh->Property() & kIsVirtualBase) != 0)
2729  return -2;
2730  return inh->GetDelta();
2731  }
2732  off = c->GetBaseClassOffsetRecurse(cl);
2733  if (off == -2) return -2;
2734  if (off != -1) {
2735  return off + inh->GetDelta();
2736  }
2737  }
2738  lnk = lnk->Next();
2739  }
2740  return -1;
2741 }
2742 
2743 ////////////////////////////////////////////////////////////////////////////////
2744 /// - Return data member offset to the base class "cl".
2745 /// - Returns -1 in case "cl" is not a base class.
2746 /// Takes care of multiple inheritance.
2747 
2748 Int_t TClass::GetBaseClassOffset(const TClass *toBase, void *address, bool isDerivedObject)
2749 {
2750  // Warning("GetBaseClassOffset","Requires the use of fClassInfo for %s to %s",GetName(),toBase->GetName());
2751 
2752  if (this == toBase) return 0;
2753 
2754  if ((!address /* || !has_virtual_base */) &&
2756  // At least of the ClassInfo have not been loaded in memory yet and
2757  // since there is no virtual base class (or we don't have enough so it
2758  // would not make a difference) we can use the 'static' information
2759  Int_t offset = GetBaseClassOffsetRecurse (toBase);
2760  if (offset != -2) {
2761  return offset;
2762  }
2763  return offset;
2764  }
2765 
2766  ClassInfo_t* derived = GetClassInfo();
2767  ClassInfo_t* base = toBase->GetClassInfo();
2768  if(derived && base) {
2769  // TClingClassInfo::GetBaseOffset takes the lock.
2770  return gCling->ClassInfo_GetBaseOffset(derived, base, address, isDerivedObject);
2771  }
2772  else {
2773  Int_t offset = GetBaseClassOffsetRecurse (toBase);
2774  if (offset != -2) {
2775  return offset;
2776  }
2777  }
2778  return -1;
2779 }
2780 
2781 ////////////////////////////////////////////////////////////////////////////////
2782 /// Return pointer to (base) class that contains datamember.
2783 
2784 TClass *TClass::GetBaseDataMember(const char *datamember)
2785 {
2786  if (!HasDataMemberInfo()) return 0;
2787 
2788  // Check if data member exists in class itself
2789  TDataMember *dm = GetDataMember(datamember);
2790  if (dm) return this;
2791 
2792  // if datamember not found in class, search in next base classes
2793  TBaseClass *inh;
2794  TIter next(GetListOfBases());
2795  while ((inh = (TBaseClass *) next())) {
2796  TClass *c = inh->GetClassPointer();
2797  if (c) {
2798  TClass *cdm = c->GetBaseDataMember(datamember);
2799  if (cdm) return cdm;
2800  }
2801  }
2802 
2803  return 0;
2804 }
2805 
2806 namespace {
2807  // A local Helper class used to keep 2 pointer (the collection proxy
2808  // and the class streamer) in the thread local storage.
2809 
2810  struct TClassLocalStorage {
2811  TClassLocalStorage() : fCollectionProxy(0), fStreamer(0) {};
2812 
2813  TVirtualCollectionProxy *fCollectionProxy;
2814  TClassStreamer *fStreamer;
2815 
2816  static TClassLocalStorage *GetStorage(const TClass *cl)
2817  {
2818  // Return the thread storage for the TClass.
2819 
2820  void **thread_ptr = (*gThreadTsd)(0,ROOT::kClassThreadSlot);
2821  if (thread_ptr) {
2822  if (*thread_ptr==0) *thread_ptr = new TExMap();
2823  TExMap *lmap = (TExMap*)(*thread_ptr);
2824  ULong_t hash = TString::Hash(&cl, sizeof(void*));
2825  ULong_t local = 0;
2826  UInt_t slot;
2827  if ((local = (ULong_t)lmap->GetValue(hash, (Long_t)cl, slot)) != 0) {
2828  } else {
2829  local = (ULong_t) new TClassLocalStorage();
2830  lmap->AddAt(slot, hash, (Long_t)cl, local);
2831  }
2832  return (TClassLocalStorage*)local;
2833  }
2834  return 0;
2835  }
2836  };
2837 }
2838 
2839 ////////////////////////////////////////////////////////////////////////////////
2840 /// Return the 'type' of the STL the TClass is representing.
2841 /// and return ROOT::kNotSTL if it is not representing an STL collection.
2842 
2844 {
2845  auto proxy = GetCollectionProxy();
2846  if (proxy) return (ROOT::ESTLType)proxy->GetCollectionType();
2847  return ROOT::kNotSTL;
2848 }
2849 
2850 
2851 ////////////////////////////////////////////////////////////////////////////////
2852 /// Return the proxy describing the collection (if any).
2853 
2855 {
2856  // Use assert, so that this line (slow because of the TClassEdit) is completely
2857  // removed in optimized code.
2858  //assert(TestBit(kLoading) || !TClassEdit::IsSTLCont(fName) || fCollectionProxy || 0 == "The TClass for the STL collection has no collection proxy!");
2859  if (gThreadTsd && fCollectionProxy) {
2860  TClassLocalStorage *local = TClassLocalStorage::GetStorage(this);
2861  if (local == 0) return fCollectionProxy;
2862  if (local->fCollectionProxy==0) local->fCollectionProxy = fCollectionProxy->Generate();
2863  return local->fCollectionProxy;
2864  }
2865  return fCollectionProxy;
2866 }
2867 
2868 ////////////////////////////////////////////////////////////////////////////////
2869 /// Return the Streamer Class allowing streaming (if any).
2870 
2872 {
2873  if (gThreadTsd && fStreamer) {
2874  TClassLocalStorage *local = TClassLocalStorage::GetStorage(this);
2875  if (local==0) return fStreamer;
2876  if (local->fStreamer==0) {
2877  local->fStreamer = fStreamer->Generate();
2878  const std::type_info &orig = ( typeid(*fStreamer) );
2879  if (!local->fStreamer) {
2880  Warning("GetStreamer","For %s, the TClassStreamer (%s) passed's call to Generate failed!",GetName(),orig.name());
2881  } else {
2882  const std::type_info &copy = ( typeid(*local->fStreamer) );
2883  if (strcmp(orig.name(),copy.name())!=0) {
2884  Warning("GetStreamer","For %s, the TClassStreamer passed does not properly implement the Generate method (%s vs %s)\n",GetName(),orig.name(),copy.name());
2885  }
2886  }
2887  }
2888  return local->fStreamer;
2889  }
2890  return fStreamer;
2891 }
2892 
2893 ////////////////////////////////////////////////////////////////////////////////
2894 /// Get a wrapper/accessor function around this class custom streamer (member function).
2895 
2897 {
2898  return fStreamerFunc;
2899 }
2900 
2901 ////////////////////////////////////////////////////////////////////////////////
2902 /// Get a wrapper/accessor function around this class custom conversion streamer (member function).
2903 
2905 {
2906  return fConvStreamerFunc;
2907 }
2908 
2909 ////////////////////////////////////////////////////////////////////////////////
2910 /// Return the proxy implementing the IsA functionality.
2911 
2913 {
2914  return fIsA;
2915 }
2916 
2917 ////////////////////////////////////////////////////////////////////////////////
2918 /// Static method returning pointer to TClass of the specified class name.
2919 /// If load is true an attempt is made to obtain the class by loading
2920 /// the appropriate shared library (directed by the rootmap file).
2921 /// If silent is 'true', do not warn about missing dictionary for the class.
2922 /// (typically used for class that are used only for transient members)
2923 /// Returns 0 in case class is not found.
2924 
2925 TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent)
2926 {
2927  if (!name || !name[0]) return 0;
2928 
2929  if (strstr(name, "(anonymous)")) return 0;
2930  if (strncmp(name,"class ",6)==0) name += 6;
2931  if (strncmp(name,"struct ",7)==0) name += 7;
2932 
2933  if (!gROOT->GetListOfClasses()) return 0;
2934 
2935  // FindObject will take the read lock before actually getting the
2936  // TClass pointer so we will need not get a partially initialized
2937  // object.
2938  TClass *cl = (TClass*)gROOT->GetListOfClasses()->FindObject(name);
2939 
2940  // Early return to release the lock without having to execute the
2941  // long-ish normalization.
2942  if (cl && (cl->IsLoaded() || cl->TestBit(kUnloading))) return cl;
2943 
2945 
2946  // Now that we got the write lock, another thread may have constructed the
2947  // TClass while we were waiting, so we need to do the checks again.
2948 
2949  cl = (TClass*)gROOT->GetListOfClasses()->FindObject(name);
2950  if (cl) {
2951  if (cl->IsLoaded() || cl->TestBit(kUnloading)) return cl;
2952 
2953  // We could speed-up some of the search by adding (the equivalent of)
2954  //
2955  // if (cl->GetState() == kInterpreter) return cl
2956  //
2957  // In this case, if a ROOT dictionary was available when the TClass
2958  // was first requested it would have been used and if a ROOT dictionary is
2959  // loaded later on TClassTable::Add will take care of updating the TClass.
2960  // So as far as ROOT dictionary are concerned, if the current TClass is
2961  // in interpreted state, we are sure there is nothing to load.
2962  //
2963  // However (see TROOT::LoadClass), the TClass can also be loaded/provided
2964  // by a user provided TClassGenerator. We have no way of knowing whether
2965  // those do (or even can) behave the same way as the ROOT dictionary and
2966  // have the 'dictionary is now available for use' step informs the existing
2967  // TClass that their dictionary is now available.
2968 
2969  //we may pass here in case of a dummy class created by TVirtualStreamerInfo
2970  load = kTRUE;
2971  }
2972 
2973  // To avoid spurious auto parsing, let's check if the name as-is is
2974  // known in the TClassTable.
2976  if (dict) {
2977  // The name is normalized, so the result of the first search is
2978  // authoritative.
2979  if (!cl && !load) return 0;
2980 
2981  TClass *loadedcl = (dict)();
2982  if (loadedcl) {
2983  loadedcl->PostLoadCheck();
2984  return loadedcl;
2985  }
2986 
2987  // We should really not fall through to here, but if we do, let's just
2988  // continue as before ...
2989  }
2990 
2991  std::string normalizedName;
2992  Bool_t checkTable = kFALSE;
2993 
2994  if (!cl) {
2995  {
2997  TClassEdit::GetNormalizedName(normalizedName, name);
2998  }
2999  // Try the normalized name.
3000  if (normalizedName != name) {
3001  cl = (TClass*)gROOT->GetListOfClasses()->FindObject(normalizedName.c_str());
3002 
3003  if (cl) {
3004  if (cl->IsLoaded() || cl->TestBit(kUnloading)) return cl;
3005 
3006  //we may pass here in case of a dummy class created by TVirtualStreamerInfo
3007  load = kTRUE;
3008  }
3009  checkTable = kTRUE;
3010  }
3011  } else {
3012  normalizedName = cl->GetName(); // Use the fact that all TClass names are normalized.
3013  checkTable = load && (normalizedName != name);
3014  }
3015 
3016  if (!load) return 0;
3017 
3018 // This assertion currently fails because of
3019 // TClass *c1 = TClass::GetClass("basic_iostream<char,char_traits<char> >");
3020 // TClass *c2 = TClass::GetClass("std::iostream");
3021 // where the TClassEdit normalized name of iostream is basic_iostream<char>
3022 // i.e missing the addition of the default parameter. This is because TClingLookupHelper
3023 // uses only 'part' of TMetaUtils::GetNormalizedName.
3024 
3025 // if (!cl) {
3026 // TDataType* dataType = (TDataType*)gROOT->GetListOfTypes()->FindObject(name);
3027 // TClass *altcl = dataType ? (TClass*)gROOT->GetListOfClasses()->FindObject(dataType->GetFullTypeName()) : 0;
3028 // if (altcl && normalizedName != altcl->GetName())
3029 // ::Fatal("TClass::GetClass","The existing name (%s) for %s is different from the normalized name: %s\n",
3030 // altcl->GetName(), name, normalizedName.c_str());
3031 // }
3032 
3033  TClass *loadedcl = 0;
3034  if (checkTable) {
3035  loadedcl = LoadClassDefault(normalizedName.c_str(),silent);
3036  } else {
3037  if (gInterpreter->AutoLoad(normalizedName.c_str(),kTRUE)) {
3038  loadedcl = LoadClassDefault(normalizedName.c_str(),silent);
3039  }
3040  // Maybe this was a typedef: let's try to see if this is the case
3041  if (!loadedcl){
3042  if (TDataType* theDataType = gROOT->GetType(normalizedName.c_str())){
3043  // We have a typedef: we get the name of the underlying type
3044  auto underlyingTypeName = theDataType->GetTypeName();
3045  // We see if we can bootstrap a class with it
3046  auto underlyingTypeDict = TClassTable::GetDictNorm(underlyingTypeName.Data());
3047  if (underlyingTypeDict){
3048  loadedcl = underlyingTypeDict();
3049  }
3050 
3051  }
3052  }
3053  }
3054  if (loadedcl) return loadedcl;
3055 
3056  // See if the TClassGenerator can produce the TClass we need.
3057  loadedcl = LoadClassCustom(normalizedName.c_str(),silent);
3058  if (loadedcl) return loadedcl;
3059 
3060  // We have not been able to find a loaded TClass, return the Emulated
3061  // TClass if we have one.
3062  if (cl) return cl;
3063 
3064  if (TClassEdit::IsSTLCont( normalizedName.c_str() )) {
3065 
3066  return gInterpreter->GenerateTClass(normalizedName.c_str(), kTRUE, silent);
3067  }
3068 
3069  // Check the interpreter only after autoparsing the template if any.
3070  {
3071  std::string::size_type posLess = normalizedName.find('<');
3072  if (posLess != std::string::npos) {
3073  gCling->AutoParse(normalizedName.substr(0, posLess).c_str());
3074  }
3075  }
3076 
3077  //last attempt. Look in CINT list of all (compiled+interpreted) classes
3078  if (gDebug>0){
3079  printf("TClass::GetClass: Header Parsing - The representation of %s was not found in the type system. A lookup in the interpreter is about to be tried: this can cause parsing. This can be avoided selecting %s in the linkdef/selection file.\n",normalizedName.c_str(), normalizedName.c_str());
3080  }
3081  if (normalizedName.length()) {
3082  auto cci = gInterpreter->CheckClassInfo(normalizedName.c_str(), kTRUE /* autoload */,
3083  kTRUE /*Only class, structs and ns*/);
3084 
3085  // We could have an interpreted class with an inline ClassDef, in this case we do not
3086  // want to create an 'interpreted' TClass but we want the one triggered via the call to
3087  // the Dictionary member. If we go ahead and generate the 'interpreted' version it will
3088  // replace if/when there is a call to IsA on an object of this type.
3089 
3090  if (cci == TInterpreter::kWithClassDefInline) {
3091  auto ci = gInterpreter->ClassInfo_Factory(normalizedName.c_str());
3092  auto funcDecl = gInterpreter->GetFunctionWithPrototype(ci, "Dictionary", "", false, ROOT::kExactMatch);
3093  auto method = gInterpreter->MethodInfo_Factory(funcDecl);
3094  typedef void (*tcling_callfunc_Wrapper_t)(void *, int, void **, void *);
3095  auto funcPtr = (tcling_callfunc_Wrapper_t)gInterpreter->MethodInfo_InterfaceMethod(method);
3096 
3097  TClass *res = nullptr;
3098  if (funcPtr)
3099  funcPtr(0, 0, nullptr, &res);
3100  // else
3101  // We could fallback to the interpreted case ...
3102  // For now just 'fail' (return nullptr)
3103 
3104  gInterpreter->MethodInfo_Delete(method);
3105  gInterpreter->ClassInfo_Delete(ci);
3106 
3107  return res;
3108  } else if (cci) {
3109  // Get the normalized name based on the decl (currently the only way
3110  // to get the part to add or drop the default arguments as requested by the user)
3111  std::string alternative;
3112  gInterpreter->GetInterpreterTypeName(normalizedName.c_str(), alternative, kTRUE);
3113  const char *altname = alternative.c_str();
3114  if (strncmp(altname, "std::", 5) == 0) {
3115  // For namespace (for example std::__1), GetInterpreterTypeName does
3116  // not strip std::, so we must do it explicitly here.
3117  altname += 5;
3118  }
3119  if (altname != normalizedName && strcmp(altname, name) != 0) {
3120  // altname now contains the full name of the class including a possible
3121  // namespace if there has been a using namespace statement.
3122 
3123  // At least in the case C<string [2]> (normalized) vs C<string[2]> (altname)
3124  // the TClassEdit normalization and the TMetaUtils normalization leads to
3125  // two different space layout. To avoid an infinite recursion, we also
3126  // add the test on (altname != name)
3127 
3128  return GetClass(altname, load);
3129  }
3130 
3131  TClass *ncl = gInterpreter->GenerateTClass(normalizedName.c_str(), /* emulation = */ kFALSE, silent);
3132  if (!ncl->IsZombie()) {
3133  return ncl;
3134  }
3135  delete ncl;
3136  }
3137  }
3138  return nullptr;
3139 }
3140 
3141 ////////////////////////////////////////////////////////////////////////////////
3142 /// Return pointer to class with name.
3143 
3144 TClass *TClass::GetClass(const std::type_info& typeinfo, Bool_t load, Bool_t /* silent */)
3145 {
3146  if (!gROOT->GetListOfClasses())
3147  return 0;
3148 
3149  //protect access to TROOT::GetIdMap
3151 
3152  TClass* cl = GetIdMap()->Find(typeinfo.name());
3153 
3154  if (cl && cl->IsLoaded()) return cl;
3155 
3157 
3158  // Now that we got the write lock, another thread may have constructed the
3159  // TClass while we were waiting, so we need to do the checks again.
3160 
3161  cl = GetIdMap()->Find(typeinfo.name());
3162 
3163  if (cl) {
3164  if (cl->IsLoaded()) return cl;
3165  //we may pass here in case of a dummy class created by TVirtualStreamerInfo
3166  load = kTRUE;
3167  } else {
3168  // Note we might need support for typedefs and simple types!
3169 
3170  // TDataType *objType = GetType(name, load);
3171  //if (objType) {
3172  // const char *typdfName = objType->GetTypeName();
3173  // if (typdfName && strcmp(typdfName, name)) {
3174  // cl = GetClass(typdfName, load);
3175  // return cl;
3176  // }
3177  // }
3178  }
3179 
3180  if (!load) return 0;
3181 
3182  DictFuncPtr_t dict = TClassTable::GetDict(typeinfo);
3183  if (dict) {
3184  cl = (dict)();
3185  if (cl) cl->PostLoadCheck();
3186  return cl;
3187  }
3188  if (cl) return cl;
3189 
3190  TIter next(gROOT->GetListOfClassGenerators());
3191  TClassGenerator *gen;
3192  while( (gen = (TClassGenerator*) next()) ) {
3193  cl = gen->GetClass(typeinfo,load);
3194  if (cl) {
3195  cl->PostLoadCheck();
3196  return cl;
3197  }
3198  }
3199 
3200  // try AutoLoading the typeinfo
3201  int autoload_old = gCling->SetClassAutoLoading(1);
3202  if (!autoload_old) {
3203  // Re-disable, we just meant to test
3205  }
3206  if (autoload_old && gInterpreter->AutoLoad(typeinfo,kTRUE)) {
3207  // Disable autoload to avoid potential infinite recursion
3209  cl = GetClass(typeinfo, load);
3210  if (cl) {
3211  return cl;
3212  }
3213  }
3214 
3215  // last attempt. Look in the interpreter list of all (compiled+interpreted)
3216  // classes
3217  cl = gInterpreter->GetClass(typeinfo, load);
3218 
3219  return cl; // Can be zero.
3220 }
3221 
3222 ////////////////////////////////////////////////////////////////////////////////
3223 /// Static method returning pointer to TClass of the specified ClassInfo.
3224 /// If load is true an attempt is made to obtain the class by loading
3225 /// the appropriate shared library (directed by the rootmap file).
3226 /// If silent is 'true', do not warn about missing dictionary for the class.
3227 /// (typically used for class that are used only for transient members)
3228 /// Returns 0 in case class is not found.
3229 
3230 TClass *TClass::GetClass(ClassInfo_t *info, Bool_t load, Bool_t silent)
3231 {
3232  if (!info || !gCling->ClassInfo_IsValid(info)) return 0;
3233  if (!gROOT->GetListOfClasses()) return 0;
3234 
3235  // Technically we need the write lock only for the call to ClassInfo_FullName
3236  // and GenerateTClass but FindObject will take the read lock (and LoadClass will
3237  // take the write lock). Since taking/releasing the lock is expensive, let just
3238  // take the write guard and keep it.
3240 
3241  // Get the normalized name.
3243 
3244  TClass *cl = (TClass*)gROOT->GetListOfClasses()->FindObject(name);
3245 
3246  if (cl) {
3247  if (cl->IsLoaded()) return cl;
3248 
3249  //we may pass here in case of a dummy class created by TVirtualStreamerInfo
3250  load = kTRUE;
3251 
3252  }
3253 
3254  if (!load) return 0;
3255 
3256  TClass *loadedcl = 0;
3257  if (cl) loadedcl = gROOT->LoadClass(cl->GetName(),silent);
3258  else loadedcl = gROOT->LoadClass(name,silent);
3259 
3260  if (loadedcl) return loadedcl;
3261 
3262  if (cl) return cl; // If we found the class but we already have a dummy class use it.
3263 
3264  // We did not find a proper TClass but we do know (we have a valid
3265  // ClassInfo) that the class is known to the interpreter.
3266  TClass *ncl = gInterpreter->GenerateTClass(info, silent);
3267  if (!ncl->IsZombie()) {
3268  return ncl;
3269  } else {
3270  delete ncl;
3271  return 0;
3272  }
3273 }
3274 
3275 ////////////////////////////////////////////////////////////////////////////////
3276 
3279 }
3280 
3281 ////////////////////////////////////////////////////////////////////////////////
3282 
3283 Bool_t TClass::GetClass(DeclId_t id, std::vector<TClass*> &classes)
3284 {
3285  if (!gROOT->GetListOfClasses()) return 0;
3286 
3287  DeclIdMap_t* map = GetDeclIdMap();
3288  // Get all the TClass pointer that have the same DeclId.
3289  DeclIdMap_t::equal_range iter = map->Find(id);
3290  if (iter.first == iter.second) return false;
3291  std::vector<TClass*>::iterator vectIt = classes.begin();
3292  for (DeclIdMap_t::const_iterator it = iter.first; it != iter.second; ++it)
3293  vectIt = classes.insert(vectIt, it->second);
3294  return true;
3295 }
3296 
3297 ////////////////////////////////////////////////////////////////////////////////
3298 /// Return a pointer to the dictionary loading function generated by
3299 /// rootcint
3300 
3301 DictFuncPtr_t TClass::GetDict (const char *cname)
3302 {
3303  return TClassTable::GetDict(cname);
3304 }
3305 
3306 ////////////////////////////////////////////////////////////////////////////////
3307 /// Return a pointer to the dictionary loading function generated by
3308 /// rootcint
3309 
3310 DictFuncPtr_t TClass::GetDict (const std::type_info& info)
3311 {
3312  return TClassTable::GetDict(info);
3313 }
3314 
3315 ////////////////////////////////////////////////////////////////////////////////
3316 /// Return pointer to datamember object with name "datamember".
3317 
3318 TDataMember *TClass::GetDataMember(const char *datamember) const
3319 {
3320  if ((!(fData && fData->IsLoaded()) && !HasInterpreterInfo())
3321  || datamember == 0) return 0;
3322 
3323  // Strip off leading *'s and trailing [
3324  const char *start_name = datamember;
3325  while (*start_name == '*') ++start_name;
3326 
3327  // Empty name are 'legal', they represent anonymous unions.
3328  // if (*start_name == 0) return 0;
3329 
3330  if (const char *s = strchr(start_name, '[')){
3331  UInt_t len = s-start_name;
3332  TString name(start_name,len);
3333  return (TDataMember *)((TClass*)this)->GetListOfDataMembers(kFALSE)->FindObject(name.Data());
3334  } else {
3335  return (TDataMember *)((TClass*)this)->GetListOfDataMembers(kFALSE)->FindObject(start_name);
3336  }
3337 }
3338 
3339 ////////////////////////////////////////////////////////////////////////////////
3340 /// Return name of the file containing the declaration of this class.
3341 
3342 const char *TClass::GetDeclFileName() const
3343 {
3344  if (fDeclFileName == kUndeterminedClassInfoName)
3345  return gInterpreter->ClassInfo_FileName( fClassInfo );
3346  return fDeclFileName;
3347 }
3348 
3349 ////////////////////////////////////////////////////////////////////////////////
3350 /// return offset for member name. name can be a data member in
3351 /// the class itself, one of its base classes, or one member in
3352 /// one of the aggregated classes.
3353 ///
3354 /// In case of an emulated class, the list of emulated TRealData is built
3355 
3357 {
3358  TRealData *rd = GetRealData(name);
3359  if (rd) return rd->GetThisOffset();
3360  if (strchr(name,'[')==0) {
3361  // If this is a simple name there is a chance to find it in the
3362  // StreamerInfo even if we did not find it in the RealData.
3363  // For example an array name would be fArray[3] in RealData but
3364  // just fArray in the streamerInfo.
3365  TVirtualStreamerInfo *info = const_cast<TClass*>(this)->GetCurrentStreamerInfo();
3366  if (info) {
3367  return info->GetOffset(name);
3368  }
3369  }
3370  return 0;
3371 }
3372 
3373 ////////////////////////////////////////////////////////////////////////////////
3374 /// Return pointer to TRealData element with name "name".
3375 ///
3376 /// Name can be a data member in the class itself,
3377 /// one of its base classes, or a member in
3378 /// one of the aggregated classes.
3379 ///
3380 /// In case of an emulated class, the list of emulated TRealData is built.
3381 
3383 {
3384  if (!fRealData) {
3385  const_cast<TClass*>(this)->BuildRealData();
3386  }
3387 
3388  if (!fRealData) {
3389  return 0;
3390  }
3391 
3392  if (!name) {
3393  return 0;
3394  }
3395 
3396  // First try just the whole name.
3398  if (rd) {
3399  return rd;
3400  }
3401 
3402  std::string givenName(name);
3403 
3404  // Try ignoring the array dimensions.
3405  std::string::size_type firstBracket = givenName.find_first_of("[");
3406  if (firstBracket != std::string::npos) {
3407  // -- We are looking for an array data member.
3408  std::string nameNoDim(givenName.substr(0, firstBracket));
3409  TObjLink* lnk = fRealData->FirstLink();
3410  while (lnk) {
3411  TObject* obj = lnk->GetObject();
3412  std::string objName(obj->GetName());
3413  std::string::size_type pos = objName.find_first_of("[");
3414  // Only match arrays to arrays for now.
3415  if (pos != std::string::npos) {
3416  objName.erase(pos);
3417  if (objName == nameNoDim) {
3418  return static_cast<TRealData*>(obj);
3419  }
3420  }
3421  lnk = lnk->Next();
3422  }
3423  }
3424 
3425  // Now try it as a pointer.
3426  std::ostringstream ptrname;
3427  ptrname << "*" << givenName;
3428  rd = (TRealData*) fRealData->FindObject(ptrname.str().c_str());
3429  if (rd) {
3430  return rd;
3431  }
3432 
3433  // Check for a dot in the name.
3434  std::string::size_type firstDot = givenName.find_first_of(".");
3435  if (firstDot == std::string::npos) {
3436  // -- Not found, a simple name, all done.
3437  return 0;
3438  }
3439 
3440  //
3441  // At this point the name has a dot in it, so it is the name
3442  // of some contained sub-object.
3443  //
3444 
3445  // May be a pointer like in TH1: fXaxis.fLabels (in TRealdata is named fXaxis.*fLabels)
3446  std::string::size_type lastDot = givenName.find_last_of(".");
3447  std::ostringstream starname;
3448  starname << givenName.substr(0, lastDot) << ".*" << givenName.substr(lastDot + 1);
3449  rd = (TRealData*) fRealData->FindObject(starname.str().c_str());
3450  if (rd) {
3451  return rd;
3452  }
3453 
3454  // Strip the first component, it may be the name of
3455  // the branch (old TBranchElement code), and try again.
3456  std::string firstDotName(givenName.substr(firstDot + 1));
3457 
3458  // New attempt starting after the first "." if any,
3459  // this allows for the case that the first component
3460  // may have been a branch name (for TBranchElement).
3461  rd = (TRealData*) fRealData->FindObject(firstDotName.c_str());
3462  if (rd) {
3463  return rd;
3464  }
3465 
3466  // New attempt starting after the first "." if any,
3467  // but this time try ignoring the array dimensions.
3468  // Again, we are allowing for the case that the first
3469  // component may have been a branch name (for TBranchElement).
3470  std::string::size_type firstDotBracket = firstDotName.find_first_of("[");
3471  if (firstDotBracket != std::string::npos) {
3472  // -- We are looking for an array data member.
3473  std::string nameNoDim(firstDotName.substr(0, firstDotBracket));
3474  TObjLink* lnk = fRealData->FirstLink();
3475  while (lnk) {
3476  TObject* obj = lnk->GetObject();
3477  std::string objName(obj->GetName());
3478  std::string::size_type pos = objName.find_first_of("[");
3479  // Only match arrays to arrays for now.
3480  if (pos != std::string::npos) {
3481  objName.erase(pos);
3482  if (objName == nameNoDim) {
3483  return static_cast<TRealData*>(obj);
3484  }
3485  }
3486  lnk = lnk->Next();
3487  }
3488  }
3489 
3490  // New attempt starting after the first "." if any,
3491  // but this time check for a pointer type. Again, we
3492  // are allowing for the case that the first component
3493  // may have been a branch name (for TBranchElement).
3494  ptrname.str("");
3495  ptrname << "*" << firstDotName;
3496  rd = (TRealData*) fRealData->FindObject(ptrname.str().c_str());
3497  if (rd) {
3498  return rd;
3499  }
3500 
3501  // Last attempt in case a member has been changed from
3502  // a static array to a pointer, for example the member
3503  // was arr[20] and is now *arr.
3504  //
3505  // Note: In principle, one could also take into account
3506  // the opposite situation where a member like *arr has
3507  // been converted to arr[20].
3508  //
3509  // FIXME: What about checking after the first dot as well?
3510  //
3511  std::string::size_type bracket = starname.str().find_first_of("[");
3512  if (bracket == std::string::npos) {
3513  return 0;
3514  }
3515  rd = (TRealData*) fRealData->FindObject(starname.str().substr(0, bracket).c_str());
3516  if (rd) {
3517  return rd;
3518  }
3519 
3520  // Not found;
3521  return 0;
3522 }
3523 
3524 ////////////////////////////////////////////////////////////////////////////////
3525 
3527 {
3528  if (!gInterpreter || !HasInterpreterInfo()) return 0;
3529 
3530  // The following
3532 
3534 }
3535 
3536 ////////////////////////////////////////////////////////////////////////////////
3537 /// Get the list of shared libraries containing the code for class cls.
3538 /// The first library in the list is the one containing the class, the
3539 /// others are the libraries the first one depends on. Returns 0
3540 /// in case the library is not found.
3541 
3543 {
3544  if (!gInterpreter) return 0;
3545 
3546  if (fSharedLibs.IsNull())
3547  fSharedLibs = gInterpreter->GetClassSharedLibs(fName);
3548 
3549  return !fSharedLibs.IsNull() ? fSharedLibs.Data() : 0;
3550 }
3551 
3552 ////////////////////////////////////////////////////////////////////////////////
3553 /// Return list containing the TBaseClass(es) of a class.
3554 
3556 {
3557  if (!fBase.load()) {
3558  if (fCanLoadClassInfo) {
3559  if (fState == kHasTClassInit) {
3560 
3562  // NOTE: Add test to prevent redo if another thread has already done the work.
3563  // if (!fHasRootPcmInfo) {
3564 
3565  // The bases are in our ProtoClass; we don't need the class info.
3567  if (proto && proto->FillTClass(this)) {
3568  // Not sure this code is still needed
3569  // R__ASSERT(kFALSE);
3570 
3572  }
3573  }
3574  // We test again on fCanLoadClassInfo has another thread may have executed it.
3576  LoadClassInfo();
3577  }
3578  }
3579  if (!fClassInfo) return 0;
3580 
3581  if (!gInterpreter)
3582  Fatal("GetListOfBases", "gInterpreter not initialized");
3583 
3585  if (!fBase.load()) {
3586  gInterpreter->CreateListOfBaseClasses(this);
3587  }
3588  }
3589  return fBase;
3590 }
3591 
3592 ////////////////////////////////////////////////////////////////////////////////
3593 /// Return a list containing the TEnums of a class.
3594 ///
3595 /// The list returned is safe to use from multiple thread without explicitly
3596 /// taking the ROOT global lock.
3597 ///
3598 /// In the case the TClass represents a namespace, the returned list will
3599 /// implicit take the ROOT global lock upon any access (see TListOfEnumsWithLock)
3600 ///
3601 /// In the case the TClass represents a class or struct and requestListLoading
3602 /// is true, the list is immutable (and thus safe to access from multiple thread
3603 /// without taking the global lock at all).
3604 ///
3605 /// In the case the TClass represents a class or struct and requestListLoading
3606 /// is false, the list is mutable and thus we return a TListOfEnumsWithLock
3607 /// which will implicit take the ROOT global lock upon any access.
3608 
3609 TList *TClass::GetListOfEnums(Bool_t requestListLoading /* = kTRUE */)
3610 {
3611  auto temp = fEnums.load();
3612  if (temp) {
3613  if (requestListLoading) {
3614  if (fProperty == -1) Property();
3615  if (! ((kIsClass | kIsStruct | kIsUnion) & fProperty) ) {
3617  temp->Load();
3618  } else if ( temp->IsA() == TListOfEnumsWithLock::Class() ) {
3619  // We have a class for which the list was not loaded fully at
3620  // first use.
3622  temp->Load();
3623  }
3624  }
3625  return temp;
3626  }
3627 
3628  if (!requestListLoading) {
3629  if (fProperty == -1) Property();
3631  if (fEnums.load()) {
3632  return fEnums.load();
3633  }
3634 
3635  static bool fromRootCling = dlsym(RTLD_DEFAULT, "usedToIdentifyRootClingByDlSym");
3636 
3637  if (fromRootCling) // rootcling is single thread (this save some space in the rootpcm).
3638  fEnums = new TListOfEnums(this);
3639  else
3640  fEnums = new TListOfEnumsWithLock(this);
3641  return fEnums;
3642  }
3643 
3645  if (fEnums.load()) {
3646  (*fEnums).Load();
3647  return fEnums.load();
3648  }
3649  if (fProperty == -1) Property();
3650  if ( (kIsClass | kIsStruct | kIsUnion) & fProperty) {
3651  // For this case, the list will be immutable
3652  temp = new TListOfEnums(this);
3653  } else {
3654  //namespaces can have enums added to them
3655  temp = new TListOfEnumsWithLock(this);
3656  }
3657  temp->Load();
3658  fEnums = temp;
3659  return temp;
3660 }
3661 
3662 ////////////////////////////////////////////////////////////////////////////////
3663 /// Return list containing the TDataMembers of a class.
3664 
3666 {
3668 
3669  if (!fData) {
3671  // NOTE: Add test to prevent redo if another thread has already done the work.
3672  // if (!fHasRootPcmInfo) {
3673 
3674  // The members are in our ProtoClass; we don't need the class info.
3676  if (proto && proto->FillTClass(this)) {
3677  // Not sure this code is still needed
3678  // R__ASSERT(kFALSE);
3679 
3681  return fData;
3682  }
3683  }
3684  fData = new TListOfDataMembers(this);
3685  }
3686  if (Property() & (kIsClass|kIsStruct|kIsUnion)) {
3687  // If the we have a class or struct or union, the order
3688  // of data members is the list is essential since it determines their
3689  // order on file. So we must always load. Also, the list is fixed
3690  // since the language does not allow to add members.
3691  if (!fData->IsLoaded()) fData->Load();
3692 
3693  } else if (load) fData->Load();
3694  return fData;
3695 }
3696 
3697 ////////////////////////////////////////////////////////////////////////////////
3698 /// Return TListOfFunctionTemplates for a class.
3699 
3701 {
3703 
3705  if (load) fFuncTemplate->Load();
3706  return fFuncTemplate;
3707 }
3708 
3709 ////////////////////////////////////////////////////////////////////////////////
3710 /// Return list containing the TMethods of a class.
3711 /// If load is true, the list is populated with all the defined function
3712 /// and currently instantiated function template.
3713 
3715 {
3717 
3718  if (!fMethod.load()) GetMethodList();
3719  if (load) {
3720  if (gDebug>0) Info("GetListOfMethods","Header Parsing - Asking for all the methods of class %s: this can involve parsing.",GetName());
3721  (*fMethod).Load();
3722  }
3723  return fMethod;
3724 }
3725 
3726 ////////////////////////////////////////////////////////////////////////////////
3727 /// Return the collection of functions named "name".
3728 
3730 {
3731  return const_cast<TClass*>(this)->GetMethodList()->GetListForObject(name);
3732 }
3733 
3734 
3735 ////////////////////////////////////////////////////////////////////////////////
3736 /// Returns a list of all public methods of this class and its base classes.
3737 /// Refers to a subset of the methods in GetListOfMethods() so don't do
3738 /// GetListOfAllPublicMethods()->Delete().
3739 /// Algorithm used to get the list is:
3740 /// - put all methods of the class in the list (also protected and private
3741 /// ones).
3742 /// - loop over all base classes and add only those methods not already in the
3743 /// list (also protected and private ones).
3744 /// - once finished, loop over resulting list and remove all private and
3745 /// protected methods.
3746 
3748 {
3750 
3751  if (!fAllPubMethod) fAllPubMethod = new TViewPubFunctions(this);
3752  if (load) {
3753  if (gDebug>0) Info("GetListOfAllPublicMethods","Header Parsing - Asking for all the methods of class %s: this can involve parsing.",GetName());
3754  fAllPubMethod->Load();
3755  }
3756  return fAllPubMethod;
3757 }
3758 
3759 ////////////////////////////////////////////////////////////////////////////////
3760 /// Returns a list of all public data members of this class and its base
3761 /// classes. Refers to a subset of the data members in GetListOfDatamembers()
3762 /// so don't do GetListOfAllPublicDataMembers()->Delete().
3763 
3765 {
3767 
3768  if (!fAllPubData) fAllPubData = new TViewPubDataMembers(this);
3769  if (load) fAllPubData->Load();
3770  return fAllPubData;
3771 }
3772 
3773 ////////////////////////////////////////////////////////////////////////////////
3774 /// Returns list of methods accessible by context menu.
3775 
3777 {
3778  if (!HasInterpreterInfo()) return;
3779 
3780  // get the base class
3781  TIter nextBase(GetListOfBases(), kIterBackward);
3782  TBaseClass *baseClass;
3783  while ((baseClass = (TBaseClass *) nextBase())) {
3784  TClass *base = baseClass->GetClassPointer();
3785  if (base) base->GetMenuItems(list);
3786  }
3787 
3788  // remove methods redefined in this class with no menu
3789  TMethod *method, *m;
3791  while ((method = (TMethod*)next())) {
3792  m = (TMethod*)list->FindObject(method->GetName());
3793  if (method->IsMenuItem() != kMenuNoMenu) {
3794  if (!m)
3795  list->AddFirst(method);
3796  } else {
3797  if (m && m->GetNargs() == method->GetNargs())
3798  list->Remove(m);
3799  }
3800  }
3801 }
3802 
3803 ////////////////////////////////////////////////////////////////////////////////
3804 /// Check whether a class has a dictionary or not.
3805 /// This is equivalent to ask if a class is coming from a bootstrapping
3806 /// procedure initiated during the loading of a library.
3807 
3809 {
3810  return IsLoaded();
3811 }
3812 
3813 ////////////////////////////////////////////////////////////////////////////////
3814 /// Check whether a class has a dictionary or ROOT can load one.
3815 /// This is equivalent to ask HasDictionary() or whether a library is known
3816 /// where it can be loaded from, or whether a Dictionary function is
3817 /// available because the class's dictionary library was already loaded.
3818 
3820 {
3821  if (TClass* cl = (TClass*)gROOT->GetListOfClasses()->FindObject(clname))
3822  return cl->IsLoaded();
3823  return gClassTable->GetDict(clname) || gInterpreter->GetClassSharedLibs(clname);
3824 }
3825 
3826 ////////////////////////////////////////////////////////////////////////////////
3827 /// Verify the base classes always.
3828 
3830 {
3831  TList* lb = GetListOfBases();
3832  if (!lb) return;
3833  TIter nextBase(lb);
3834  TBaseClass* base = 0;
3835  while ((base = (TBaseClass*)nextBase())) {
3836  TClass* baseCl = base->GetClassPointer();
3837  if (baseCl) {
3838  baseCl->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3839  }
3840  }
3841 }
3842 
3843 ////////////////////////////////////////////////////////////////////////////////
3844 /// Verify the Data Members.
3845 
3847 {
3849  if (!ldm) return ;
3850  TIter nextMemb(ldm);
3851  TDataMember * dm = 0;
3852  while ((dm = (TDataMember*)nextMemb())) {
3853  // If it is a transient
3854  if(!dm->IsPersistent()) {
3855  continue;
3856  }
3857  if (dm->Property() & kIsStatic) {
3858  continue;
3859  }
3860  // If it is a built-in data type.
3861  TClass* dmTClass = 0;
3862  if (dm->GetDataType()) {
3863  // We have a basic datatype.
3864  dmTClass = nullptr;
3865  // Otherwise get the string representing the type.
3866  } else if (dm->GetTypeName()) {
3867  dmTClass = TClass::GetClass(dm->GetTypeName());
3868  }
3869  if (dmTClass) {
3870  dmTClass->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3871  }
3872  }
3873 }
3874 
3876 {
3877  // Pair is a special case and we have to check its elements for missing dictionaries
3878  // Pair is a transparent container so we should always look at its.
3879 
3881  for (int i = 0; i < 2; i++) {
3882  TClass* pairElement = ((TStreamerElement*)SI->GetElements()->At(i))->GetClass();
3883  if (pairElement) {
3884  pairElement->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3885  }
3886  }
3887 }
3888 
3889 ////////////////////////////////////////////////////////////////////////////////
3890 /// From the second level of recursion onwards it is different state check.
3891 
3893 {
3894  if (result.FindObject(this) || visited.FindObject(this)) return;
3895 
3896  static TClassRef sCIString("string");
3897  if (this == sCIString) return;
3898 
3899  TClassEdit::TSplitType splitType(fName);
3900  if (splitType.IsTemplate()) {
3901  // We now treat special cases:
3902  // - pair
3903  // - unique_ptr
3904  // - array
3905  // - tuple
3906 
3907  // Small helper to get the TClass instance from a classname and recursively
3908  // investigate it
3909  auto checkDicts = [&](const string &clName){
3910  auto cl = TClass::GetClass(clName.c_str());
3911  if (!cl) {
3912  // We try to remove * and const from the type name if any
3913  const auto clNameShortType = TClassEdit::ShortType(clName.c_str(), 1);
3914  cl = TClass::GetClass(clNameShortType.c_str());
3915  }
3916  if (cl && !cl->HasDictionary()) {
3917  cl->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3918  }
3919  };
3920 
3921  const auto &elements = splitType.fElements;
3922  const auto &templName = elements[0];
3923 
3924  // Special treatment for pair.
3925  if (templName == "pair") {
3926  GetMissingDictionariesForPairElements(result, visited, recurse);
3927  return;
3928  }
3929 
3930  // Special treatment of unique_ptr or array
3931  // They are treated together since they have 1 single template argument
3932  // which is interesting when checking for missing dictionaries.
3933  if (templName == "unique_ptr" || templName == "array") {
3934  checkDicts(elements[1]);
3935  return;
3936  }
3937 
3938  // Special treatment of tuple
3939  // This type must be treated separately since it can have N template
3940  // arguments which are interesting, unlike unique_ptr or array.
3941  if (templName == "tuple") {
3942  // -1 because the elements end with a list of the "stars", i.e. number of
3943  // * after the type name
3944  const auto nTemplArgs = elements.size() - 1;
3945  // loop starts at 1 because the first element is the template name
3946  for (auto iTemplArg = 1U; iTemplArg < nTemplArgs; ++iTemplArg) {
3947  checkDicts(elements[iTemplArg]);
3948  }
3949  return;
3950  }
3951  } // this is not a template
3952 
3953  if (!HasDictionary()) {
3954  result.Add(this);
3955  }
3956 
3957  visited.Add(this);
3958  //Check whether a custom streamer
3960  if (GetCollectionProxy()) {
3961  // We need to look at the collection's content
3962  // The collection has different kind of elements the check would be required.
3963  TClass* t = 0;
3964  if ((t = GetCollectionProxy()->GetValueClass())) {
3965  if (!t->HasDictionary()) {
3966  t->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3967  }
3968  }
3969  } else {
3970  if (recurse) {
3971  GetMissingDictionariesForMembers(result, visited, recurse);
3972  }
3973  GetMissingDictionariesForBaseClasses(result, visited, recurse);
3974  }
3975  }
3976 }
3977 
3978 ////////////////////////////////////////////////////////////////////////////////
3979 /// Get the classes that have a missing dictionary starting from this one.
3980 /// - With recurse = false the classes checked for missing dictionaries are:
3981 /// the class itself, all base classes, direct data members,
3982 /// and for collection proxies the container's
3983 /// elements without iterating over the element's data members;
3984 /// - With recurse = true the classes checked for missing dictionaries are:
3985 /// the class itself, all base classes, recursing on the data members,
3986 /// and for the collection proxies recursion on the elements of the
3987 /// collection and iterating over the element's data members.
3988 
3989 void TClass::GetMissingDictionaries(THashTable& result, bool recurse)
3990 {
3991  // Top level recursion it different from the following levels of recursion.
3992 
3993  if (result.FindObject(this)) return;
3994 
3995  static TClassRef sCIString("string");
3996  if (this == sCIString) return;
3997 
3998  THashTable visited;
3999 
4000  if (strncmp(fName, "pair<", 5) == 0) {
4001  GetMissingDictionariesForPairElements(result, visited, recurse);
4002  return;
4003  }
4004 
4005  if (strncmp(fName, "unique_ptr<", 11) == 0 || strncmp(fName, "array<", 6) == 0 || strncmp(fName, "tuple<", 6) == 0) {
4006  GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
4007  return;
4008  }
4009 
4010  if (!HasDictionary()) {
4011  result.Add(this);
4012  }
4013 
4014  visited.Add(this);
4015 
4016  //Check whether a custom streamer
4018  if (GetCollectionProxy()) {
4019  // We need to look at the collection's content
4020  // The collection has different kind of elements the check would be required.
4021  TClass* t = 0;
4022  if ((t = GetCollectionProxy()->GetValueClass())) {
4023  if (!t->HasDictionary()) {
4024  t->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
4025  }
4026  }
4027  } else {
4028  GetMissingDictionariesForMembers(result, visited, recurse);
4029  GetMissingDictionariesForBaseClasses(result, visited, recurse);
4030  }
4031  }
4032 }
4033 
4034 ////////////////////////////////////////////////////////////////////////////////
4035 /// Return kTRUE if the class has elements.
4036 
4037 Bool_t TClass::IsFolder(void *obj) const
4038 {
4039  return Browse(obj,(TBrowser*)0);
4040 }
4041 
4042 //______________________________________________________________________________
4043 //______________________________________________________________________________
4044 void TClass::ReplaceWith(TClass *newcl) const
4045 {
4046  // Inform the other objects to replace this object by the new TClass (newcl)
4047 
4049  //we must update the class pointers pointing to 'this' in all TStreamerElements
4050  TIter nextClass(gROOT->GetListOfClasses());
4051  TClass *acl;
4052  TVirtualStreamerInfo *info;
4053  TList tobedeleted;
4054 
4055  // Since we are in the process of replacing a TClass by a TClass
4056  // coming from a dictionary, there is no point in loading any
4057  // libraries during this search.
4059  while ((acl = (TClass*)nextClass())) {
4060  if (acl == newcl) continue;
4061 
4062  TIter nextInfo(acl->GetStreamerInfos());
4063  while ((info = (TVirtualStreamerInfo*)nextInfo())) {
4064 
4065  info->Update(this, newcl);
4066  }
4067  }
4068 
4069  TIter delIter( &tobedeleted );
4070  while ((acl = (TClass*)delIter())) {
4071  delete acl;
4072  }
4073  gInterpreter->UnRegisterTClassUpdate(this);
4074 }
4075 
4076 ////////////////////////////////////////////////////////////////////////////////
4077 /// Make sure that the current ClassInfo is up to date.
4078 
4079 void TClass::ResetClassInfo(Long_t /* tagnum */)
4080 {
4081  Warning("ResetClassInfo(Long_t tagnum)","Call to deprecated interface (does nothing)");
4082 }
4083 
4084 ////////////////////////////////////////////////////////////////////////////////
4085 /// Make sure that the current ClassInfo is up to date.
4086 
4088 {
4090 
4092 
4093  if (fClassInfo) {
4095  gInterpreter->ClassInfo_Delete(fClassInfo);
4096  fClassInfo = 0;
4097  }
4098  // We can not check at this point whether after the unload there will
4099  // still be interpreter information about this class (as v5 was doing),
4100  // instead this function must only be called if the definition is (about)
4101  // to be unloaded.
4102 
4103  ResetCaches();
4104 
4105  // We got here because the definition Decl is about to be unloaded.
4106  if (fState != TClass::kHasTClassInit) {
4107  if (fStreamerInfo->GetEntries() != 0) {
4109  } else {
4111  }
4112  } else {
4113  // if the ClassInfo was loaded for a class with a TClass Init and it
4114  // gets unloaded, should we guess it can be reloaded?
4116  }
4117 }
4118 
4119 ////////////////////////////////////////////////////////////////////////////////
4120 /// To clean out all caches.
4121 
4123 {
4124  R__ASSERT(!TestBit(kLoading) && "Resetting the caches does not make sense during loading!" );
4125 
4126  // Not owning lists, don't call Delete(), but unload
4127  if (fData)
4128  fData->Unload();
4129  if (fEnums.load())
4130  (*fEnums).Unload();
4131  if (fMethod.load())
4132  (*fMethod).Unload();
4133 
4134  delete fAllPubData; fAllPubData = 0;
4135 
4136  if (fBase.load())
4137  (*fBase).Delete();
4138  delete fBase.load(); fBase = 0;
4139 
4140  if (fRealData)
4141  fRealData->Delete();
4142  delete fRealData; fRealData=0;
4143 }
4144 
4145 ////////////////////////////////////////////////////////////////////////////////
4146 /// Resets the menu list to it's standard value.
4147 
4149 {
4150  if (fClassMenuList)
4152  else
4153  fClassMenuList = new TList();
4155 }
4156 
4157 ////////////////////////////////////////////////////////////////////////////////
4158 /// The ls function lists the contents of a class on stdout. Ls output
4159 /// is typically much less verbose then Dump().
4160 /// If options contains 'streamerinfo', run ls on the list of streamerInfos
4161 /// and the list of conversion streamerInfos.
4162 
4163 void TClass::ls(Option_t *options) const
4164 {
4165  TNamed::ls(options);
4166  if (options==0 || options[0]==0) return;
4167 
4168  if (strstr(options,"streamerinfo")!=0) {
4169  GetStreamerInfos()->ls(options);
4170 
4171  if (fConversionStreamerInfo.load()) {
4172  std::map<std::string, TObjArray*>::iterator it;
4173  std::map<std::string, TObjArray*>::iterator end = (*fConversionStreamerInfo).end();
4174  for( it = (*fConversionStreamerInfo).begin(); it != end; ++it ) {
4175  it->second->ls(options);
4176  }
4177  }
4178  }
4179 }
4180 
4181 ////////////////////////////////////////////////////////////////////////////////
4182 /// Makes a customizable version of the popup menu list, i.e. makes a list
4183 /// of TClassMenuItem objects of methods accessible by context menu.
4184 /// The standard (and different) way consists in having just one element
4185 /// in this list, corresponding to the whole standard list.
4186 /// Once the customizable version is done, one can remove or add elements.
4187 
4189 {
4191  TClassMenuItem *menuItem;
4192 
4193  // Make sure fClassMenuList is initialized and empty.
4194  GetMenuList()->Delete();
4195 
4196  TList* methodList = new TList;
4197  GetMenuItems(methodList);
4198 
4199  TMethod *method;
4200  TMethodArg *methodArg;
4201  TClass *classPtr = 0;
4202  TIter next(methodList);
4203 
4204  while ((method = (TMethod*) next())) {
4205  // if go to a mother class method, add separator
4206  if (classPtr != method->GetClass()) {
4207  menuItem = new TClassMenuItem(TClassMenuItem::kPopupSeparator, this);
4208  fClassMenuList->AddLast(menuItem);
4209  classPtr = method->GetClass();
4210  }
4211  // Build the signature of the method
4212  TString sig;
4213  TList* margsList = method->GetListOfMethodArgs();
4214  TIter nextarg(margsList);
4215  while ((methodArg = (TMethodArg*)nextarg())) {
4216  sig = sig+","+methodArg->GetFullTypeName();
4217  }
4218  if (sig.Length()!=0) sig.Remove(0,1); // remove first comma
4220  method->GetName(), method->GetName(),0,
4221  sig.Data(),-1,TClassMenuItem::kIsSelf);
4222  if (method->IsMenuItem() == kMenuToggle) menuItem->SetToggle();
4223  fClassMenuList->Add(menuItem);
4224  }
4225  delete methodList;
4226 }
4227 
4228 ////////////////////////////////////////////////////////////////////////////////
4229 /// Register the fact that an object was moved from the memory location
4230 /// 'arenaFrom' to the memory location 'arenaTo'.
4231 
4232 void TClass::Move(void *arenaFrom, void *arenaTo) const
4233 {
4234  // If/when we have access to a copy constructor (or better to a move
4235  // constructor), this function should also perform the data move.
4236  // For now we just information the repository.
4237 
4238  if ((GetState() <= kEmulated) && !fCollectionProxy) {
4239  MoveAddressInRepository("TClass::Move",arenaFrom,arenaTo,this);
4240  }
4241 }
4242 
4243 ////////////////////////////////////////////////////////////////////////////////
4244 /// Return the list of menu items associated with the class.
4245 
4247  if (!fClassMenuList) {
4248  fClassMenuList = new TList();
4250  }
4251  return fClassMenuList;
4252 }
4253 
4254 ////////////////////////////////////////////////////////////////////////////////
4255 /// Return (create an empty one if needed) the list of functions.
4256 /// The major difference with GetListOfMethod is that this returns
4257 /// the internal type of fMethod and thus can not be made public.
4258 /// It also never 'loads' the content of the list.
4259 
4261 {
4262  if (!fMethod.load()) {
4263  std::unique_ptr<TListOfFunctions> temp{ new TListOfFunctions(this) };
4264  TListOfFunctions* expected = nullptr;
4265  if(fMethod.compare_exchange_strong(expected, temp.get()) ) {
4266  temp.release();
4267  }
4268  }
4269  return fMethod;
4270 }
4271 
4272 
4273 ////////////////////////////////////////////////////////////////////////////////
4274 /// Return pointer to method without looking at parameters.
4275 /// Does not look in (possible) base classes.
4276 /// Has the side effect of loading all the TMethod object in the list
4277 /// of the class.
4278 
4279 TMethod *TClass::GetMethodAny(const char *method)
4280 {
4281  if (!HasInterpreterInfo()) return 0;
4282  return (TMethod*) GetMethodList()->FindObject(method);
4283 }
4284 
4285 ////////////////////////////////////////////////////////////////////////////////
4286 /// Return pointer to method without looking at parameters.
4287 /// Does look in all base classes.
4288 
4289 TMethod *TClass::GetMethodAllAny(const char *method)
4290 {
4291  if (!HasInterpreterInfo()) return 0;
4292 
4293  TMethod* m = GetMethodAny(method);
4294  if (m) return m;
4295 
4296  TBaseClass *base;
4297  TIter nextb(GetListOfBases());
4298  while ((base = (TBaseClass *) nextb())) {
4299  TClass *c = base->GetClassPointer();
4300  if (c) {
4301  m = c->GetMethodAllAny(method);
4302  if (m) return m;
4303  }
4304  }
4305 
4306  return 0;
4307 }
4308 
4309 ////////////////////////////////////////////////////////////////////////////////
4310 /// Find the best method (if there is one) matching the parameters.
4311 /// The params string must contain argument values, like "3189, \"aap\", 1.3".
4312 /// The function invokes GetClassMethod to search for a possible method
4313 /// in the class itself or in its base classes. Returns 0 in case method
4314 /// is not found.
4315 
4316 TMethod *TClass::GetMethod(const char *method, const char *params,
4317  Bool_t objectIsConst /* = kFALSE */)
4318 {
4320  if (!fClassInfo) return 0;
4321 
4322  if (!gInterpreter)
4323  Fatal("GetMethod", "gInterpreter not initialized");
4324 
4325  TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithValues(fClassInfo,
4326  method, params,
4327  objectIsConst);
4328 
4329  if (!decl) return 0;
4330 
4331  // search recursively in this class or its base classes
4333  if (f) return f;
4334 
4335  Error("GetMethod",
4336  "\nDid not find matching TMethod <%s> with \"%s\" %sfor %s",
4337  method,params,objectIsConst ? "const " : "", GetName());
4338  return 0;
4339 }
4340 
4341 
4342 ////////////////////////////////////////////////////////////////////////////////
4343 /// Find a method with decl id in this class or its bases.
4344 
4346  if (TFunction* method = GetMethodList()->Get(declId))
4347  return static_cast<TMethod *>(method);
4348 
4349  for (auto item : *GetListOfBases())
4350  if (auto base = static_cast<TBaseClass *>(item)->GetClassPointer())
4351  if (TFunction* method = base->FindClassOrBaseMethodWithId(declId))
4352  return static_cast<TMethod *>(method);
4353 
4354  return nullptr;
4355 }
4356 
4357 ////////////////////////////////////////////////////////////////////////////////
4358 /// Find the method with a given prototype. The proto string must be of the
4359 /// form: "char*,int,double". Returns 0 in case method is not found.
4360 
4361 TMethod *TClass::GetMethodWithPrototype(const char *method, const char *proto,
4362  Bool_t objectIsConst /* = kFALSE */,
4363  ROOT::EFunctionMatchMode mode /* = ROOT::kConversionMatch */)
4364 {
4366  if (!fClassInfo) return 0;
4367 
4368  if (!gInterpreter)
4369  Fatal("GetMethodWithPrototype", "gInterpreter not initialized");
4370 
4371  TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithPrototype(fClassInfo,
4372  method, proto,
4373  objectIsConst, mode);
4374 
4375  if (!decl) return 0;
4377  if (f) return f;
4378  Error("GetMethodWithPrototype",
4379  "\nDid not find matching TMethod <%s> with \"%s\" %sfor %s",
4380  method,proto,objectIsConst ? "const " : "", GetName());
4381  return 0;
4382 }
4383 
4384 ////////////////////////////////////////////////////////////////////////////////
4385 /// Look for a method in this class that has the interface function
4386 /// address faddr.
4387 
4389 {
4390  if (!HasInterpreterInfo()) return 0;
4391 
4392  TMethod *m;
4393  TIter next(GetListOfMethods());
4394  while ((m = (TMethod *) next())) {
4395  if (faddr == (Long_t)m->InterfaceMethod())
4396  return m;
4397  }
4398  return 0;
4399 }
4400 
4401 ////////////////////////////////////////////////////////////////////////////////
4402 /// Look for a method in this class that has the name and matches the parameters.
4403 /// The params string must contain argument values, like "3189, \"aap\", 1.3".
4404 /// Returns 0 in case method is not found.
4405 /// See TClass::GetMethod to also search the base classes.
4406 
4407 TMethod *TClass::GetClassMethod(const char *name, const char* params,
4408  Bool_t objectIsConst /* = kFALSE */)
4409 {
4411  if (!fClassInfo) return 0;
4412 
4413  if (!gInterpreter)
4414  Fatal("GetClassMethod", "gInterpreter not initialized");
4415 
4416  TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithValues(fClassInfo,
4417  name, params,
4418  objectIsConst);
4419 
4420  if (!decl) return 0;
4421 
4422  TFunction *f = GetMethodList()->Get(decl);
4423 
4424  return (TMethod*)f; // Could be zero if the decl is actually in a base class.
4425 }
4426 
4427 ////////////////////////////////////////////////////////////////////////////////
4428 /// Find the method with a given prototype. The proto string must be of the
4429 /// form: "char*,int,double". Returns 0 in case method is not found.
4430 /// See TClass::GetMethodWithPrototype to also search the base classes.
4431 
4433  Bool_t objectIsConst /* = kFALSE */,
4434  ROOT::EFunctionMatchMode mode /* = ROOT::kConversionMatch */)
4435 {
4437  if (!fClassInfo) return 0;
4438 
4439  if (!gInterpreter)
4440  Fatal("GetClassMethodWithPrototype", "gInterpreter not initialized");
4441 
4442  TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithPrototype(fClassInfo,
4443  name, proto,
4444  objectIsConst,
4445  mode);
4446 
4447  if (!decl) return 0;
4448 
4449  TFunction *f = GetMethodList()->Get(decl);
4450 
4451  return (TMethod*)f; // Could be zero if the decl is actually in a base class.
4452 }
4453 
4454 ////////////////////////////////////////////////////////////////////////////////
4455 /// Return the number of data members of this class
4456 /// Note that in case the list of data members is not yet created, it will be done
4457 /// by GetListOfDataMembers().
4458 
4460 {
4461  if (!HasDataMemberInfo()) return 0;
4462 
4463  TList *lm = GetListOfDataMembers();
4464  if (lm)
4465  return lm->GetSize();
4466  else
4467  return 0;
4468 }
4469 
4470 ////////////////////////////////////////////////////////////////////////////////
4471 /// Return the number of methods of this class
4472 /// Note that in case the list of methods is not yet created, it will be done
4473 /// by GetListOfMethods().
4474 /// This will also load/populate the list of methods, to get 'just' the
4475 /// number of currently loaded methods use:
4476 /// cl->GetListOfMethods(false)->GetSize();
4477 
4479 {
4480  if (!HasInterpreterInfo()) return 0;
4481 
4482  TList *lm = GetListOfMethods();
4483  if (lm)
4484  return lm->GetSize();
4485  else
4486  return 0;
4487 }
4488 
4489 ////////////////////////////////////////////////////////////////////////////////
4490 /// returns a pointer to the TVirtualStreamerInfo object for version
4491 /// If the object does not exist, it is created
4492 ///
4493 /// Note: There are two special version numbers:
4494 ///
4495 /// - 0: Use the class version from the currently loaded class library.
4496 /// - -1: Assume no class library loaded (emulated class).
4497 ///
4498 /// Warning: If we create a new streamer info, whether or not the build
4499 /// optimizes is controlled externally to us by a global variable!
4500 /// Don't call us unless you have set that variable properly
4501 /// with TStreamer::Optimize()!
4502 ///
4503 
4505 {
4507 
4508  // Version 0 is special, it means the currently loaded version.
4509  // We need to set it at the beginning to be able to guess it correctly.
4510 
4511  if (version == 0)
4512  version = fClassVersion;
4513 
4514  // If the StreamerInfo is assigned to the fLastReadInfo, we are
4515  // guaranteed it was built and compiled.
4516  if (sinfo && sinfo->GetClassVersion() == version)
4517  return sinfo;
4518 
4519  // Note that the access to fClassVersion above is technically not thread-safe with a low probably of problems.
4520  // fClassVersion is not an atomic and is modified TClass::SetClassVersion (called from RootClassVersion via
4521  // ROOT::ResetClassVersion) and is 'somewhat' protected by the atomic fVersionUsed.
4522  // However, direct access to fClassVersion should be replaced by calls to GetClassVersion to set fVersionUsed.
4523  // Even with such a change the code here and in these functions need to be reviewed as a cursory look seem
4524  // to indicates they are not yet properly protection against mutli-thread access.
4525  //
4526  // However, the use of these functions is rare and mostly done at library loading time which should
4527  // in almost all cases preceeds the possibility of GetStreamerInfo being called from multiple thread
4528  // on that same TClass object.
4529  //
4530  // Summary: need careful review but risk of problem is extremely low.
4531 
4533 
4534  // Warning: version may be -1 for an emulated class, or -2 if the
4535  // user requested the emulated streamerInfo for an abstract
4536  // base class, even though we have a dictionary for it.
4537 
4538  if ((version < -1) || (version >= fStreamerInfo->GetSize())) {
4539  Error("GetStreamerInfo", "class: %s, attempting to access a wrong version: %d", GetName(), version);
4540  // FIXME: Shouldn't we go to -1 here, or better just abort?
4541  version = fClassVersion;
4542  }
4543 
4544  sinfo = (TVirtualStreamerInfo *)fStreamerInfo->At(version);
4545 
4546  if (!sinfo && (version != fClassVersion)) {
4547  // When the requested version does not exist we return
4548  // the TVirtualStreamerInfo for the currently loaded class version.
4549  // FIXME: This arguably makes no sense, we should warn and return nothing instead.
4550  // Note: This is done for STL collections
4551  // Note: fClassVersion could be -1 here (for an emulated class).
4552  // This is also the code path take for unversioned classes.
4554  }
4555 
4556  if (!sinfo) {
4557  // We just were not able to find a streamer info, we have to make a new one.
4558  TMmallocDescTemp setreset;
4559  sinfo = TVirtualStreamerInfo::Factory()->NewInfo(const_cast<TClass*>(this));
4561  if (gDebug > 0) {
4562  printf("Creating StreamerInfo for class: %s, version: %d\n", GetName(), fClassVersion);
4563  }
4565  // If we do not have a StreamerInfo for this version and we do not
4566  // have dictionary information nor a proxy, there is nothing to build!
4567  sinfo->Build();
4568  }
4569  } else {
4570  if (!sinfo->IsCompiled()) {
4571  // Streamer info has not been compiled, but exists.
4572  // Therefore it was read in from a file and we have to do schema evolution?
4573  // Or it didn't have a dictionary before, but does now?
4574  sinfo->BuildOld();
4575  }
4576  }
4577 
4578  // Cache the current info if we now have it.
4579  if (version == fClassVersion)
4580  fCurrentInfo = sinfo;
4581 
4582  // If the compilation succeeded, remember this StreamerInfo.
4583  if (sinfo->IsCompiled())
4584  fLastReadInfo = sinfo;
4585 
4586  return sinfo;
4587 }
4588 
4589 ////////////////////////////////////////////////////////////////////////////////
4590 /// For the case where the requestor class is emulated and this class is abstract,
4591 /// returns a pointer to the TVirtualStreamerInfo object for version with an emulated
4592 /// representation whether or not the class is loaded.
4593 ///
4594 /// If the object does not exist, it is created
4595 ///
4596 /// Note: There are two special version numbers:
4597 ///
4598 /// - 0: Use the class version from the currently loaded class library.
4599 /// - -1: Assume no class library loaded (emulated class).
4600 ///
4601 /// Warning: If we create a new streamer info, whether or not the build
4602 /// optimizes is controlled externally to us by a global variable!
4603 /// Don't call us unless you have set that variable properly
4604 /// with TStreamer::Optimize()!
4605 ///
4606 
4608 {
4609  TVirtualStreamerInfo *sinfo = nullptr;
4610 
4611  TString newname(GetName());
4612  newname += "@@emulated";
4613 
4615 
4616  TClass *emulated = TClass::GetClass(newname);
4617 
4618  if (emulated)
4619  sinfo = emulated->GetStreamerInfo(version);
4620 
4621  if (!sinfo) {
4622  // The emulated version of the streamerInfo is explicitly requested and has
4623  // not been built yet.
4624 
4625  sinfo = (TVirtualStreamerInfo*) fStreamerInfo->At(version);
4626 
4627  if (!sinfo && (version != fClassVersion)) {
4628  // When the requested version does not exist we return
4629  // the TVirtualStreamerInfo for the currently loaded class version.
4630  // FIXME: This arguably makes no sense, we should warn and return nothing instead.
4632  }
4633 
4634  if (!sinfo) {
4635  // Let's take the first available StreamerInfo as a start
4636  Int_t ninfos = fStreamerInfo->GetEntriesFast() - 1;
4637  for (Int_t i = -1; sinfo == 0 && i < ninfos; ++i)
4639  }
4640 
4641  if (sinfo) {
4642  sinfo = dynamic_cast<TVirtualStreamerInfo *>(sinfo->Clone());
4643  if (sinfo) {
4644  sinfo->SetClass(0);
4645  sinfo->SetName(newname);
4646  sinfo->BuildCheck();
4647  sinfo->BuildOld();
4648  sinfo->GetClass()->AddRule(TString::Format("sourceClass=%s targetClass=%s",GetName(),newname.Data()));
4649  } else {
4650  Error("GetStreamerInfoAbstractEmulated", "could not create TVirtualStreamerInfo");
4651  }
4652  }
4653  }
4654  return sinfo;
4655 }
4656 
4657 ////////////////////////////////////////////////////////////////////////////////
4658 /// For the case where the requestor class is emulated and this class is abstract,
4659 /// returns a pointer to the TVirtualStreamerInfo object for version with an emulated
4660 /// representation whether or not the class is loaded.
4661 ///
4662 /// If the object does not exist, it is created
4663 ///
4664 /// Warning: If we create a new streamer info, whether or not the build
4665 /// optimizes is controlled externally to us by a global variable!
4666 /// Don't call us unless you have set that variable properly
4667 /// with TStreamer::Optimize()!
4668 ///
4669 
4671 {
4672  TVirtualStreamerInfo *sinfo = nullptr;
4673 
4674  TString newname(GetName());
4675  newname += "@@emulated";
4676 
4678 
4679  TClass *emulated = TClass::GetClass(newname);
4680 
4681  if (emulated)
4682  sinfo = emulated->FindStreamerInfo(checksum);
4683 
4684  if (!sinfo) {
4685  // The emulated version of the streamerInfo is explicitly requested and has
4686  // not been built yet.
4687 
4688  sinfo = (TVirtualStreamerInfo*) FindStreamerInfo(checksum);
4689 
4690  if (!sinfo && (checksum != fCheckSum)) {
4691  // When the requested version does not exist we return
4692  // the TVirtualStreamerInfo for the currently loaded class version.
4693  // FIXME: This arguably makes no sense, we should warn and return nothing instead.
4695  }
4696 
4697  if (!sinfo) {
4698  // Let's take the first available StreamerInfo as a start
4699  Int_t ninfos = fStreamerInfo->GetEntriesFast() - 1;
4700  for (Int_t i = -1; sinfo == 0 && i < ninfos; ++i)
4702  }
4703 
4704  if (sinfo) {
4705  sinfo = dynamic_cast<TVirtualStreamerInfo*>( sinfo->Clone() );
4706  if (sinfo) {
4707  sinfo->SetClass(0);
4708  sinfo->SetName( newname );
4709  sinfo->BuildCheck();
4710  sinfo->BuildOld();
4711  sinfo->GetClass()->AddRule(TString::Format("sourceClass=%s targetClass=%s",GetName(),newname.Data()));
4712  } else {
4713  Error("GetStreamerInfoAbstractEmulated", "could not create TVirtualStreamerInfo");
4714  }
4715  }
4716  }
4717  return sinfo;
4718 }
4719 
4720 ////////////////////////////////////////////////////////////////////////////////
4721 /// When the class kIgnoreTObjectStreamer bit is set, the automatically
4722 /// generated Streamer will not call TObject::Streamer.
4723 /// This option saves the TObject space overhead on the file.
4724 /// However, the information (fBits, fUniqueID) of TObject is lost.
4725 ///
4726 /// Note that to be effective for objects streamed object-wise this function
4727 /// must be called for the class deriving directly from TObject, eg, assuming
4728 /// that BigTrack derives from Track and Track derives from TObject, one must do:
4729 /// ~~~ {.cpp}
4730 /// Track::Class()->IgnoreTObjectStreamer();
4731 /// ~~~
4732 /// and not:
4733 /// ~~~ {.cpp}
4734 /// BigTrack::Class()->IgnoreTObjectStreamer();
4735 /// ~~~
4736 /// To be effective for object streamed member-wise or split in a TTree,
4737 /// this function must be called for the most derived class (i.e. BigTrack).
4738 
4740 {
4741  // We need to tak the lock since we are test and then setting fBits
4742  // and TStreamerInfo::fBits (and the StreamerInfo state in general)
4743  // which can also be modified by another thread.
4745 
4746  if ( doIgnore && TestBit(kIgnoreTObjectStreamer)) return;
4747  if (!doIgnore && !TestBit(kIgnoreTObjectStreamer)) return;
4749  if (sinfo) {
4750  if (sinfo->IsCompiled()) {
4751  // -- Warn the user that what they are doing cannot work.
4752  // Note: The reason is that TVirtualStreamerInfo::Build() examines
4753  // the kIgnoreTObjectStreamer bit and sets the TStreamerElement
4754  // type for the TObject base class streamer element it creates
4755  // to -1 as a flag. Later on the TStreamerInfo::Compile()
4756  // member function sees the flag and does not insert the base
4757  // class element into the compiled streamer info. None of this
4758  // machinery works correctly if we are called after the streamer
4759  // info has already been built and compiled.
4760  Error("IgnoreTObjectStreamer","Must be called before the creation of StreamerInfo");
4761  return;
4762  }
4763  }
4764  if (doIgnore) SetBit (kIgnoreTObjectStreamer);
4766 }
4767 
4768 ////////////////////////////////////////////////////////////////////////////////
4769 /// Return kTRUE if this class inherits from a class with name "classname".
4770 /// note that the function returns kTRUE in case classname is the class itself
4771 
4772 Bool_t TClass::InheritsFrom(const char *classname) const
4773 {
4774  if (strcmp(GetName(), classname) == 0) return kTRUE;
4775 
4776  return InheritsFrom(TClass::GetClass(classname,kTRUE,kTRUE));
4777 }
4778 
4779 ////////////////////////////////////////////////////////////////////////////////
4780 /// Return kTRUE if this class inherits from class cl.
4781 /// note that the function returns KTRUE in case cl is the class itself
4782 
4784 {
4785  if (!cl) return kFALSE;
4786  if (cl == this) return kTRUE;
4787 
4788  if (!HasDataMemberInfo()) {
4789  TVirtualStreamerInfo *sinfo = ((TClass *)this)->GetCurrentStreamerInfo();
4790  if (sinfo==0) sinfo = GetStreamerInfo();
4791  TIter next(sinfo->GetElements());
4792  TStreamerElement *element;
4793  while ((element = (TStreamerElement*)next())) {
4794  if (element->IsA() == TStreamerBase::Class()) {
4795  TClass *clbase = element->GetClassPointer();
4796  if (!clbase) return kFALSE; //missing class
4797  if (clbase->InheritsFrom(cl)) return kTRUE;
4798  }
4799  }
4800  return kFALSE;
4801  }
4802  // cast const away (only for member fBase which can be set in GetListOfBases())
4803  if (((TClass *)this)->GetBaseClass(cl)) return kTRUE;
4804  return kFALSE;
4805 }
4806 
4807 ////////////////////////////////////////////////////////////////////////////////
4808 /// Cast obj of this class type up to baseclass cl if up is true.
4809 /// Cast obj of this class type down from baseclass cl if up is false.
4810 /// If this class is not a baseclass of cl return 0, else the pointer
4811 /// to the cl part of this (up) or to this (down).
4812 
4813 void *TClass::DynamicCast(const TClass *cl, void *obj, Bool_t up)
4814 {
4815  if (cl == this) return obj;
4816 
4817  if (!HasDataMemberInfo()) return 0;
4818 
4819  Int_t off;
4820  if ((off = GetBaseClassOffset(cl, obj)) != -1) {
4821  if (up)
4822  return (void*)((Long_t)obj+off);
4823  else
4824  return (void*)((Long_t)obj-off);
4825  }
4826  return 0;
4827 }
4828 
4829 ////////////////////////////////////////////////////////////////////////////////
4830 /// Cast obj of this class type up to baseclass cl if up is true.
4831 /// Cast obj of this class type down from baseclass cl if up is false.
4832 /// If this class is not a baseclass of cl return 0, else the pointer
4833 /// to the cl part of this (up) or to this (down).
4834 
4835 const void *TClass::DynamicCast(const TClass *cl, const void *obj, Bool_t up)
4836 {
4837  return DynamicCast(cl,const_cast<void*>(obj),up);
4838 }
4839 
4840 ////////////////////////////////////////////////////////////////////////////////
4841 /// Return a pointer to a newly allocated object of this class.
4842 /// The class must have a default constructor. For meaning of
4843 /// defConstructor, see TClass::IsCallingNew().
4844 ///
4845 /// If quiet is true, do no issue a message via Error on case
4846 /// of problems, just return 0.
4847 ///
4848 /// The constructor actually called here can be customized by
4849 /// using the rootcint pragma:
4850 /// ~~~ {.cpp}
4851 /// #pragma link C++ ioctortype UserClass;
4852 /// ~~~
4853 /// For example, with this pragma and a class named MyClass,
4854 /// this method will called the first of the following 3
4855 /// constructors which exists and is public:
4856 /// ~~~ {.cpp}
4857 /// MyClass(UserClass*);
4858 /// MyClass(TRootIOCtor*);
4859 /// MyClass(); // Or a constructor with all its arguments defaulted.
4860 /// ~~~
4861 ///
4862 /// When more than one pragma ioctortype is used, the first seen as priority
4863 /// For example with:
4864 /// ~~~ {.cpp}
4865 /// #pragma link C++ ioctortype UserClass1;
4866 /// #pragma link C++ ioctortype UserClass2;
4867 /// ~~~
4868 /// We look in the following order:
4869 /// ~~~ {.cpp}
4870 /// MyClass(UserClass1*);
4871 /// MyClass(UserClass2*);
4872 /// MyClass(TRootIOCtor*);
4873 /// MyClass(); // Or a constructor with all its arguments defaulted.
4874 /// ~~~
4875 
4876 void *TClass::New(ENewType defConstructor, Bool_t quiet) const
4877 {
4878  void* p = 0;
4879 
4880  if (fNew) {
4881  // We have the new operator wrapper function,
4882  // so there is a dictionary and it was generated
4883  // by rootcint, so there should be a default
4884  // constructor we can call through the wrapper.
4885  TClass__GetCallingNew() = defConstructor;
4886  p = fNew(0);
4888  if (!p && !quiet) {
4889  //Error("New", "cannot create object of class %s version %d", GetName(), fClassVersion);
4890  Error("New", "cannot create object of class %s", GetName());
4891  }
4892  } else if (HasInterpreterInfo()) {
4893  // We have the dictionary but do not have the
4894  // constructor wrapper, so the dictionary was
4895  // not generated by rootcint. Let's try to
4896  // create the object by having the interpreter
4897  // call the new operator, hopefully the class
4898  // library is loaded and there will be a default
4899  // constructor we can call.
4900  // [This is very unlikely to work, but who knows!]
4901  TClass__GetCallingNew() = defConstructor;
4904  if (!p && !quiet) {
4905  //Error("New", "cannot create object of class %s version %d", GetName(), fClassVersion);
4906  Error("New", "cannot create object of class %s", GetName());
4907  }
4908  } else if (!HasInterpreterInfo() && fCollectionProxy) {
4909  // There is no dictionary at all, so this is an emulated
4910  // class; however we do have the services of a collection proxy,
4911  // so this is an emulated STL class.
4912  TClass__GetCallingNew() = defConstructor;
4913  p = fCollectionProxy->New();
4915  if (!p && !quiet) {
4916  //Error("New", "cannot create object of class %s version %d", GetName(), fClassVersion);
4917  Error("New", "cannot create object of class %s", GetName());
4918  }
4919  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
4920  // There is no dictionary at all and we do not have
4921  // the services of a collection proxy available, so
4922  // use the streamer info to approximate calling a
4923  // constructor (basically we just make sure that the
4924  // pointer data members are null, unless they are marked
4925  // as preallocated with the "->" comment, in which case
4926  // we default-construct an object to point at).
4927 
4928  // Do not register any TObject's that we create
4929  // as a result of creating this object.
4930  // FIXME: Why do we do this?
4931  // FIXME: Partial Answer: Is this because we may never actually deregister them???
4932 
4933  Bool_t statsave = GetObjectStat();
4934  if(statsave) {
4936  }
4938  if (!sinfo && !quiet) {
4939  Error("New", "Cannot construct class '%s' version %d, no streamer info available!", GetName(), fClassVersion);
4940  return 0;
4941  }
4942 
4943  TClass__GetCallingNew() = defConstructor;
4944  p = sinfo->New();
4946 
4947  // FIXME: Mistake? See note above at the GetObjectStat() call.
4948  // Allow TObject's to be registered again.
4949  if(statsave) {
4950  SetObjectStat(statsave);
4951  }
4952 
4953  // Register the object for special handling in the destructor.
4954  if (p) {
4955  RegisterAddressInRepository("New",p,this);
4956  } else {
4957  Error("New", "Failed to construct class '%s' using streamer info", GetName());
4958  }
4959  } else {
4960  Fatal("New", "This cannot happen!");
4961  }
4962 
4963  return p;
4964 }
4965 
4966 ////////////////////////////////////////////////////////////////////////////////
4967 /// Return a pointer to a newly allocated object of this class.
4968 /// The class must have a default constructor. For meaning of
4969 /// defConstructor, see TClass::IsCallingNew().
4970 
4971 void *TClass::New(void *arena, ENewType defConstructor) const
4972 {
4973  void* p = 0;
4974 
4975  if (fNew) {
4976  // We have the new operator wrapper function,
4977  // so there is a dictionary and it was generated
4978  // by rootcint, so there should be a default
4979  // constructor we can call through the wrapper.
4980  TClass__GetCallingNew() = defConstructor;
4981  p = fNew(arena);
4983  if (!p) {
4984  Error("New with placement", "cannot create object of class %s version %d at address %p", GetName(), fClassVersion, arena);
4985  }
4986  } else if (HasInterpreterInfo()) {
4987  // We have the dictionary but do not have the
4988  // constructor wrapper, so the dictionary was
4989  // not generated by rootcint. Let's try to
4990  // create the object by having the interpreter
4991  // call the new operator, hopefully the class
4992  // library is loaded and there will be a default
4993  // constructor we can call.
4994  // [This is very unlikely to work, but who knows!]
4995  TClass__GetCallingNew() = defConstructor;
4996  p = gCling->ClassInfo_New(GetClassInfo(),arena);
4998  if (!p) {
4999  Error("New with placement", "cannot create object of class %s version %d at address %p", GetName(), fClassVersion, arena);
5000  }
5001  } else if (!HasInterpreterInfo() && fCollectionProxy) {
5002  // There is no dictionary at all, so this is an emulated
5003  // class; however we do have the services of a collection proxy,
5004  // so this is an emulated STL class.
5005  TClass__GetCallingNew() = defConstructor;
5006  p = fCollectionProxy->New(arena);
5008  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
5009  // There is no dictionary at all and we do not have
5010  // the services of a collection proxy available, so
5011  // use the streamer info to approximate calling a
5012  // constructor (basically we just make sure that the
5013  // pointer data members are null, unless they are marked
5014  // as preallocated with the "->" comment, in which case
5015  // we default-construct an object to point at).
5016 
5017  // ???BUG??? ???WHY???
5018  // Do not register any TObject's that we create
5019  // as a result of creating this object.
5020  Bool_t statsave = GetObjectStat();
5021  if(statsave) {
5023  }
5024 
5026  if (!sinfo) {
5027  Error("New with placement", "Cannot construct class '%s' version %d at address %p, no streamer info available!", GetName(), fClassVersion, arena);
5028  return 0;
5029  }
5030 
5031  TClass__GetCallingNew() = defConstructor;
5032  p = sinfo->New(arena);
5034 
5035  // ???BUG???
5036  // Allow TObject's to be registered again.
5037  if(statsave) {
5038  SetObjectStat(statsave);
5039  }
5040 
5041  // Register the object for special handling in the destructor.
5042  if (p) {
5043  RegisterAddressInRepository("TClass::New with placement",p,this);
5044  }
5045  } else {
5046  Error("New with placement", "This cannot happen!");
5047  }
5048 
5049  return p;
5050 }
5051 
5052 ////////////////////////////////////////////////////////////////////////////////
5053 /// Return a pointer to a newly allocated array of objects
5054 /// of this class.
5055 /// The class must have a default constructor. For meaning of
5056 /// defConstructor, see TClass::IsCallingNew().
5057 
5058 void *TClass::NewArray(Long_t nElements, ENewType defConstructor) const
5059 {
5060  void* p = 0;
5061 
5062  if (fNewArray) {
5063  // We have the new operator wrapper function,
5064  // so there is a dictionary and it was generated
5065  // by rootcint, so there should be a default
5066  // constructor we can call through the wrapper.
5067  TClass__GetCallingNew() = defConstructor;
5068  p = fNewArray(nElements, 0);
5070  if (!p) {
5071  Error("NewArray", "cannot create object of class %s version %d", GetName(), fClassVersion);
5072  }
5073  } else if (HasInterpreterInfo()) {
5074  // We have the dictionary but do not have the
5075  // constructor wrapper, so the dictionary was
5076  // not generated by rootcint. Let's try to
5077  // create the object by having the interpreter
5078  // call the new operator, hopefully the class
5079  // library is loaded and there will be a default
5080  // constructor we can call.
5081  // [This is very unlikely to work, but who knows!]
5082  TClass__GetCallingNew() = defConstructor;
5083  p = gCling->ClassInfo_New(GetClassInfo(),nElements);
5085  if (!p) {
5086  Error("NewArray", "cannot create object of class %s version %d", GetName(), fClassVersion);
5087  }
5088  } else if (!HasInterpreterInfo() && fCollectionProxy) {
5089  // There is no dictionary at all, so this is an emulated
5090  // class; however we do have the services of a collection proxy,
5091  // so this is an emulated STL class.
5092  TClass__GetCallingNew() = defConstructor;
5093  p = fCollectionProxy->NewArray(nElements);
5095  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
5096  // There is no dictionary at all and we do not have
5097  // the services of a collection proxy available, so
5098  // use the streamer info to approximate calling a
5099  // constructor (basically we just make sure that the
5100  // pointer data members are null, unless they are marked
5101  // as preallocated with the "->" comment, in which case
5102  // we default-construct an object to point at).
5103 
5104  // ???BUG??? ???WHY???
5105  // Do not register any TObject's that we create
5106  // as a result of creating this object.
5107  Bool_t statsave = GetObjectStat();
5108  if(statsave) {
5110  }
5111 
5113  if (!sinfo) {
5114  Error("NewArray", "Cannot construct class '%s' version %d, no streamer info available!", GetName(), fClassVersion);
5115  return 0;
5116  }
5117 
5118  TClass__GetCallingNew() = defConstructor;
5119  p = sinfo->NewArray(nElements);
5121 
5122  // ???BUG???
5123  // Allow TObject's to be registered again.
5124  if(statsave) {
5125  SetObjectStat(statsave);
5126  }
5127 
5128  // Register the object for special handling in the destructor.
5129  if (p) {
5130  RegisterAddressInRepository("TClass::NewArray",p,this);
5131  }
5132  } else {
5133  Error("NewArray", "This cannot happen!");
5134  }
5135 
5136  return p;
5137 }
5138 
5139 ////////////////////////////////////////////////////////////////////////////////
5140 /// Return a pointer to a newly allocated object of this class.
5141 /// The class must have a default constructor. For meaning of
5142 /// defConstructor, see TClass::IsCallingNew().
5143 
5144 void *TClass::NewArray(Long_t nElements, void *arena, ENewType defConstructor) const
5145 {
5146  void* p = 0;
5147 
5148  if (fNewArray) {
5149  // We have the new operator wrapper function,
5150  // so there is a dictionary and it was generated
5151  // by rootcint, so there should be a default
5152  // constructor we can call through the wrapper.
5153  TClass__GetCallingNew() = defConstructor;
5154  p = fNewArray(nElements, arena);
5156  if (!p) {
5157  Error("NewArray with placement", "cannot create object of class %s version %d at address %p", GetName(), fClassVersion, arena);
5158  }
5159  } else if (HasInterpreterInfo()) {
5160  // We have the dictionary but do not have the constructor wrapper,
5161  // so the dictionary was not generated by rootcint (it was made either
5162  // by cint or by some external mechanism). Let's try to create the
5163  // object by having the interpreter call the new operator, either the
5164  // class library is loaded and there is a default constructor we can
5165  // call, or the class is interpreted and we will call the default
5166  // constructor that way, or no default constructor is available and
5167  // we fail.
5168  TClass__GetCallingNew() = defConstructor;
5169  p = gCling->ClassInfo_New(GetClassInfo(),nElements, arena);
5171  if (!p) {
5172  Error("NewArray with placement", "cannot create object of class %s version %d at address %p", GetName(), fClassVersion, arena);
5173  }
5174  } else if (!HasInterpreterInfo() && fCollectionProxy) {
5175  // There is no dictionary at all, so this is an emulated
5176  // class; however we do have the services of a collection proxy,
5177  // so this is an emulated STL class.
5178  TClass__GetCallingNew() = defConstructor;
5179  p = fCollectionProxy->NewArray(nElements, arena);
5181  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
5182  // There is no dictionary at all and we do not have
5183  // the services of a collection proxy available, so
5184  // use the streamer info to approximate calling a
5185  // constructor (basically we just make sure that the
5186  // pointer data members are null, unless they are marked
5187  // as preallocated with the "->" comment, in which case
5188  // we default-construct an object to point at).
5189 
5190  // ???BUG??? ???WHY???
5191  // Do not register any TObject's that we create
5192  // as a result of creating this object.
5193  Bool_t statsave = GetObjectStat();
5194  if(statsave) {
5196  }
5197 
5199  if (!sinfo) {
5200  Error("NewArray with placement", "Cannot construct class '%s' version %d at address %p, no streamer info available!", GetName(), fClassVersion, arena);
5201  return 0;
5202  }
5203 
5204  TClass__GetCallingNew() = defConstructor;
5205  p = sinfo->NewArray(nElements, arena);
5207 
5208  // ???BUG???
5209  // Allow TObject's to be registered again.
5210  if(statsave) {
5211  SetObjectStat(statsave);
5212  }
5213 
5215  // We always register emulated objects, we need to always
5216  // use the streamer info to destroy them.
5217  }
5218 
5219  // Register the object for special handling in the destructor.
5220  if (p) {
5221  RegisterAddressInRepository("TClass::NewArray with placement",p,this);
5222  }
5223  } else {
5224  Error("NewArray with placement", "This cannot happen!");
5225  }
5226 
5227  return p;
5228 }
5229 
5230 ////////////////////////////////////////////////////////////////////////////////
5231 /// Explicitly call destructor for object.
5232 
5233 void TClass::Destructor(void *obj, Bool_t dtorOnly)
5234 {
5235  // Do nothing if passed a null pointer.
5236  if (obj == 0) return;
5237 
5238  void* p = obj;
5239 
5240  if (dtorOnly && fDestructor) {
5241  // We have the destructor wrapper, use it.
5242  fDestructor(p);
5243  } else if ((!dtorOnly) && fDelete) {
5244  // We have the delete wrapper, use it.
5245  fDelete(p);
5246  } else if (HasInterpreterInfo()) {
5247  // We have the dictionary but do not have the
5248  // destruct/delete wrapper, so the dictionary was
5249  // not generated by rootcint (it could have been
5250  // created by cint or by some external mechanism).
5251  // Let's have the interpreter call the destructor,
5252  // either the code will be in a loaded library,
5253  // or it will be interpreted, otherwise we fail
5254  // because there is no destructor code at all.
5255  if (dtorOnly) {
5257  } else {
5259  }
5260  } else if (!HasInterpreterInfo() && fCollectionProxy) {
5261  // There is no dictionary at all, so this is an emulated
5262  // class; however we do have the services of a collection proxy,
5263  // so this is an emulated STL class.
5264  fCollectionProxy->Destructor(p, dtorOnly);
5265  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
5266  // There is no dictionary at all and we do not have
5267  // the services of a collection proxy available, so
5268  // use the streamer info to approximate calling a
5269  // destructor.
5270 
5271  Bool_t inRepo = kTRUE;
5272  Bool_t verFound = kFALSE;
5273 
5274  // Was this object allocated through TClass?
5275  std::multiset<Version_t> knownVersions;
5277 
5278  {
5279  RepoCont_t::iterator iter = gObjectVersionRepository.find(p);
5280  if (iter == gObjectVersionRepository.end()) {
5281  // No, it wasn't, skip special version handling.
5282  //Error("Destructor2", "Attempt to delete unregistered object of class '%s' at address %p!", GetName(), p);
5283  inRepo = kFALSE;
5284  } else {
5285  //objVer = iter->second;
5286  for (; (iter != gObjectVersionRepository.end()) && (iter->first == p); ++iter) {
5287  Version_t ver = iter->second.fVersion;
5288  knownVersions.insert(ver);
5289  if (ver == fClassVersion && this == iter->second.fClass) {
5290  verFound = kTRUE;
5291  }
5292  }
5293  }
5294  }
5295 
5296  if (!inRepo || verFound) {
5297  // The object was allocated using code for the same class version
5298  // as is loaded now. We may proceed without worry.
5300  if (si) {
5301  si->Destructor(p, dtorOnly);
5302  } else {
5303  Error("Destructor", "No streamer info available for class '%s' version %d at address %p, cannot destruct emulated object!", GetName(), fClassVersion, p);
5304  Error("Destructor", "length of fStreamerInfo is %d", fStreamerInfo->GetSize());
5306  for (Int_t v = 0; v < fStreamerInfo->GetSize(); ++v, ++i) {
5307  Error("Destructor", "fStreamerInfo->At(%d): %p", i, fStreamerInfo->At(i));
5308  if (fStreamerInfo->At(i) != 0) {
5309  Error("Destructor", "Doing Dump() ...");
5311  }
5312  }
5313  }
5314  } else {
5315  // The loaded class version is not the same as the version of the code
5316  // which was used to allocate this object. The best we can do is use
5317  // the TVirtualStreamerInfo to try to free up some of the allocated memory.
5318  Error("Destructor", "Loaded class %s version %d is not registered for addr %p", GetName(), fClassVersion, p);
5319 #if 0
5321  if (si) {
5322  si->Destructor(p, dtorOnly);
5323  } else {
5324  Error("Destructor2", "No streamer info available for class '%s' version %d, cannot destruct object at addr: %p", GetName(), objVer, p);
5325  Error("Destructor2", "length of fStreamerInfo is %d", fStreamerInfo->GetSize());
5327  for (Int_t v = 0; v < fStreamerInfo->GetSize(); ++v, ++i) {
5328  Error("Destructor2", "fStreamerInfo->At(%d): %p", i, fStreamerInfo->At(i));
5329  if (fStreamerInfo->At(i) != 0) {
5330  // Do some debugging output.
5331  Error("Destructor2", "Doing Dump() ...");
5333  }
5334  }
5335  }
5336 #endif
5337  }
5338 
5339  if (inRepo && verFound && p) {
5340  UnregisterAddressInRepository("TClass::Destructor",p,this);
5341  }
5342  } else {
5343  Error("Destructor", "This cannot happen! (class %s)", GetName());
5344  }
5345 }
5346 
5347 ////////////////////////////////////////////////////////////////////////////////
5348 /// Explicitly call operator delete[] for an array.
5349 
5350 void TClass::DeleteArray(void *ary, Bool_t dtorOnly)
5351 {
5352  // Do nothing if passed a null pointer.
5353  if (ary == 0) return;
5354 
5355  // Make a copy of the address.
5356  void* p = ary;
5357 
5358  if (fDeleteArray) {
5359  if (dtorOnly) {
5360  Error("DeleteArray", "Destructor only is not supported!");
5361  } else {
5362  // We have the array delete wrapper, use it.
5363  fDeleteArray(ary);
5364  }
5365  } else if (HasInterpreterInfo()) {
5366  // We have the dictionary but do not have the
5367  // array delete wrapper, so the dictionary was
5368  // not generated by rootcint. Let's try to
5369  // delete the array by having the interpreter
5370  // call the array delete operator, hopefully
5371  // the class library is loaded and there will be
5372  // a destructor we can call.
5373  gCling->ClassInfo_DeleteArray(GetClassInfo(),ary, dtorOnly);
5374  } else if (!HasInterpreterInfo() && fCollectionProxy) {
5375  // There is no dictionary at all, so this is an emulated
5376  // class; however we do have the services of a collection proxy,
5377  // so this is an emulated STL class.
5378  fCollectionProxy->DeleteArray(ary, dtorOnly);
5379  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
5380  // There is no dictionary at all and we do not have
5381  // the services of a collection proxy available, so
5382  // use the streamer info to approximate calling the
5383  // array destructor.
5384 
5385  Bool_t inRepo = kTRUE;
5386  Bool_t verFound = kFALSE;
5387 
5388  // Was this array object allocated through TClass?
5389  std::multiset<Version_t> knownVersions;
5390  {
5392  RepoCont_t::iterator iter = gObjectVersionRepository.find(p);
5393  if (iter == gObjectVersionRepository.end()) {
5394  // No, it wasn't, we cannot know what to do.
5395  //Error("DeleteArray", "Attempt to delete unregistered array object, element type '%s', at address %p!", GetName(), p);
5396  inRepo = kFALSE;
5397  } else {
5398  for (; (iter != gObjectVersionRepository.end()) && (iter->first == p); ++iter) {
5399  Version_t ver = iter->second.fVersion;
5400  knownVersions.insert(ver);
5401  if (ver == fClassVersion && this == iter->second.fClass ) {
5402  verFound = kTRUE;
5403  }
5404  }
5405  }
5406  }
5407 
5408  if (!inRepo || verFound) {
5409  // The object was allocated using code for the same class version
5410  // as is loaded now. We may proceed without worry.
5412  if (si) {
5413  si->DeleteArray(ary, dtorOnly);
5414  } else {
5415  Error("DeleteArray", "No streamer info available for class '%s' version %d at address %p, cannot destruct object!", GetName(), fClassVersion, ary);
5416  Error("DeleteArray", "length of fStreamerInfo is %d", fStreamerInfo->GetSize());
5418  for (Int_t v = 0; v < fStreamerInfo->GetSize(); ++v, ++i) {
5419  Error("DeleteArray", "fStreamerInfo->At(%d): %p", v, fStreamerInfo->At(i));
5420  if (fStreamerInfo->At(i)) {
5421  Error("DeleteArray", "Doing Dump() ...");
5423  }
5424  }
5425  }
5426  } else {
5427  // The loaded class version is not the same as the version of the code
5428  // which was used to allocate this array. The best we can do is use
5429  // the TVirtualStreamerInfo to try to free up some of the allocated memory.
5430  Error("DeleteArray", "Loaded class version %d is not registered for addr %p", fClassVersion, p);
5431 
5432 
5433 
5434 #if 0
5436  if (si) {
5437  si->DeleteArray(ary, dtorOnly);
5438  } else {
5439  Error("DeleteArray", "No streamer info available for class '%s' version %d at address %p, cannot destruct object!", GetName(), objVer, ary);
5440  Error("DeleteArray", "length of fStreamerInfo is %d", fStreamerInfo->GetSize());
5442  for (Int_t v = 0; v < fStreamerInfo->GetSize(); ++v, ++i) {
5443  Error("DeleteArray",