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