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