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