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