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