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);
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);
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 // main constructor.
908 fBrowser = b; fCount = 0; }
909 virtual ~TAutoInspector() { }
911 virtual void Inspect(TClass *cl, const char *parent, const char *name, const void *addr, Bool_t isTransient);
913};
914
915////////////////////////////////////////////////////////////////////////////////
916/// This method is called from ShowMembers() via AutoBrowse().
917
918void TAutoInspector::Inspect(TClass *cl, const char *tit, const char *name,
919 const void *addr, Bool_t /* isTransient */)
920{
921 if(tit && strchr(tit,'.')) return ;
922 if (fCount && !fBrowser) return;
923
924 TString ts;
925
926 if (!cl) return;
927 //if (*(cl->GetName()) == 'T') return;
928 if (*name == '*') name++;
929 int ln = strcspn(name,"[ ");
930 TString iname(name,ln);
931
932 ClassInfo_t *classInfo = cl->GetClassInfo();
933 if (!classInfo) return;
934
935 // Browse data members
937 TString mname;
938
939 int found=0;
940 while (gCling->DataMemberInfo_Next(m)) { // MemberLoop
941 mname = gCling->DataMemberInfo_Name(m);
942 mname.ReplaceAll("*","");
943 if ((found = (iname==mname))) break;
944 }
945 assert(found);
946
947 // we skip: non static members and non objects
948 // - the member G__virtualinfo inserted by the CINT RTTI system
949
950 //Long_t prop = m.Property() | m.Type()->Property();
952 if (prop & kIsStatic) return;
953 if (prop & kIsFundamental) return;
954 if (prop & kIsEnum) return;
955 if (mname == "G__virtualinfo") return;
956
957 int size = sizeof(void*);
958
959 int nmax = 1;
960 if (prop & kIsArray) {
961 for (int dim = 0; dim < gCling->DataMemberInfo_ArrayDim(m); dim++) nmax *= gCling->DataMemberInfo_MaxIndex(m,dim);
962 }
963
966 TClass * clm = TClass::GetClass(clmName.c_str());
967 R__ASSERT(clm);
968 if (!(prop & kIsPointer)) {
969 size = clm->Size();
971 }
972
973
976
977 for(int i=0; i<nmax; i++) {
978
979 char *ptr = (char*)addr + i*size;
980
981 void *obj = (prop & kIsPointer) ? *((void**)ptr) : (TObject*)ptr;
982
983 if (!obj) continue;
984
985 fCount++;
986 if (!fBrowser) return;
987
988 TString bwname;
989 TClass *actualClass = clm->GetActualClass(obj);
990 if (clm->IsTObject()) {
991 TObject *tobj = (TObject*)clm->DynamicCast(TObject::Class(),obj);
992 bwname = tobj->GetName();
993 } else {
994 bwname = actualClass->GetName();
995 bwname += "::";
996 bwname += mname;
997 }
998
999 if (!clm->IsTObject() ||
1000 bwname.Length()==0 ||
1001 strcmp(bwname.Data(),actualClass->GetName())==0) {
1002 bwname = name;
1003 int l = strcspn(bwname.Data(),"[ ");
1004 if (l<bwname.Length() && bwname[l]=='[') {
1005 char cbuf[13]; snprintf(cbuf,13,"[%02d]",i);
1006 ts.Replace(0,999,bwname,l);
1007 ts += cbuf;
1008 bwname = (const char*)ts;
1009 }
1010 }
1011
1012 if (proxy==nullptr) {
1013
1014 fBrowser->Add(obj,clm,bwname);
1015
1016 } else {
1017 TClass *valueCl = proxy->GetValueClass();
1018
1019 if (valueCl==nullptr) {
1020
1021 fBrowser->Add( obj, clm, bwname );
1022
1023 } else {
1024 TVirtualCollectionProxy::TPushPop env(proxy, obj);
1025 TClass *actualCl = nullptr;
1026
1027 int sz = proxy->Size();
1028
1029 char fmt[] = {"#%09d"};
1030 fmt[3] = '0'+(int)log10(double(sz))+1;
1031 char buf[20];
1032 for (int ii=0;ii<sz;ii++) {
1033 void *p = proxy->At(ii);
1034
1035 if (proxy->HasPointers()) {
1036 p = *((void**)p);
1037 if(!p) continue;
1038 actualCl = valueCl->GetActualClass(p);
1039 p = actualCl->DynamicCast(valueCl,p,0);
1040 }
1041 fCount++;
1042 snprintf(buf,20,fmt,ii);
1043 ts = bwname;
1044 ts += buf;
1045 fBrowser->Add( p, actualCl, ts );
1046 }
1047 }
1048 }
1049 }
1050}
1051
1052//______________________________________________________________________________
1053//______________________________________________________________________________
1054//______________________________________________________________________________
1055
1057
1058////////////////////////////////////////////////////////////////////////////////
1059/// Internal, default constructor.
1060///
1061/// \note Use `TClass::GetClass("ClassName")` to get access to a TClass object for a certain class!
1062
1064 TDictionary(),
1065 fPersistentRef(nullptr),
1066 fStreamerInfo(nullptr), fConversionStreamerInfo(nullptr), fRealData(nullptr),
1067 fBase(nullptr), fData(nullptr), fUsingData(nullptr), fEnums(nullptr), fFuncTemplate(nullptr), fMethod(nullptr), fAllPubData(nullptr),
1068 fAllPubMethod(nullptr), fClassMenuList(nullptr),
1070 fInstanceCount(0), fOnHeap(0),
1071 fCheckSum(0), fCollectionProxy(nullptr), fClassVersion(0), fClassInfo(nullptr),
1072 fTypeInfo(nullptr), fShowMembers(nullptr),
1073 fStreamer(nullptr), fIsA(nullptr), fGlobalIsA(nullptr), fIsAMethod(nullptr),
1074 fMerge(nullptr), fResetAfterMerge(nullptr), fNew(nullptr), fNewArray(nullptr), fDelete(nullptr), fDeleteArray(nullptr),
1075 fDestructor(nullptr), fDirAutoAdd(nullptr), fStreamerFunc(nullptr), fConvStreamerFunc(nullptr), fSizeof(-1),
1078 fState(kNoInfo),
1079 fCurrentInfo(nullptr), fLastReadInfo(nullptr), fRefProxy(nullptr),
1081
1082{
1083 // Default ctor.
1084
1086 {
1087 TMmallocDescTemp setreset;
1088 fStreamerInfo = new TObjArray(1, -2);
1089 }
1090 fDeclFileLine = -2; // -2 for standalone TClass (checked in dtor)
1091}
1092
1093////////////////////////////////////////////////////////////////////////////////
1094/// Create a TClass object. This object contains the full dictionary
1095/// of a class. It has list to baseclasses, datamembers and methods.
1096/// Use this ctor to create a standalone TClass object. Only useful
1097/// to get a temporary TClass interface to an interpreted class. Used by TTabCom.
1098///
1099/// \note Use `TClass::GetClass("ClassName")` to get access to a TClass object for a certain class!
1100
1101TClass::TClass(const char *name, Bool_t silent) :
1103 fPersistentRef(nullptr),
1104 fStreamerInfo(nullptr), fConversionStreamerInfo(nullptr), fRealData(nullptr),
1105 fBase(nullptr), fData(nullptr), fUsingData(nullptr), fEnums(nullptr), fFuncTemplate(nullptr), fMethod(nullptr), fAllPubData(nullptr),
1106 fAllPubMethod(nullptr), fClassMenuList(nullptr),
1107 fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1108 fInstanceCount(0), fOnHeap(0),
1109 fCheckSum(0), fCollectionProxy(nullptr), fClassVersion(0), fClassInfo(nullptr),
1110 fTypeInfo(nullptr), fShowMembers(nullptr),
1111 fStreamer(nullptr), fIsA(nullptr), fGlobalIsA(nullptr), fIsAMethod(nullptr),
1112 fMerge(nullptr), fResetAfterMerge(nullptr), fNew(nullptr), fNewArray(nullptr), fDelete(nullptr), fDeleteArray(nullptr),
1113 fDestructor(nullptr), fDirAutoAdd(nullptr), fStreamerFunc(nullptr), fConvStreamerFunc(nullptr), fSizeof(-1),
1114 fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1115 fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1116 fState(kNoInfo),
1117 fCurrentInfo(nullptr), fLastReadInfo(nullptr), fRefProxy(nullptr),
1118 fSchemaRules(nullptr), fStreamerImpl(&TClass::StreamerDefault)
1119{
1121
1122 if (!gROOT)
1123 ::Fatal("TClass::TClass", "ROOT system not initialized");
1124
1125 {
1126 TMmallocDescTemp setreset;
1127 fStreamerInfo = new TObjArray(1, -2);
1128 }
1129 fDeclFileLine = -2; // -2 for standalone TClass (checked in dtor)
1130
1132 if (!gInterpreter)
1133 ::Fatal("TClass::TClass", "gInterpreter not initialized");
1134
1135 gInterpreter->SetClassInfo(this); // sets fClassInfo pointer
1136 if (!silent && !fClassInfo && !TClassEdit::IsArtificial(name))
1137 ::Warning("TClass::TClass", "no dictionary for class %s is available", name);
1139
1141 fConversionStreamerInfo = nullptr;
1142}
1143
1144////////////////////////////////////////////////////////////////////////////////
1145/// Internal constructor.
1146///
1147/// \note Use `TClass::GetClass("ClassName")` to get access to a TClass object for a certain class!
1148
1149TClass::TClass(const char *name, Version_t cversion, Bool_t silent) :
1151 fPersistentRef(nullptr),
1152 fStreamerInfo(nullptr), fConversionStreamerInfo(nullptr), fRealData(nullptr),
1153 fBase(nullptr), fData(nullptr), fUsingData(nullptr), fEnums(nullptr), fFuncTemplate(nullptr), fMethod(nullptr), fAllPubData(nullptr),
1154 fAllPubMethod(nullptr), fClassMenuList(nullptr),
1155 fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1156 fInstanceCount(0), fOnHeap(0),
1157 fCheckSum(0), fCollectionProxy(nullptr), fClassVersion(0), fClassInfo(nullptr),
1158 fTypeInfo(nullptr), fShowMembers(nullptr),
1159 fStreamer(nullptr), fIsA(nullptr), fGlobalIsA(nullptr), fIsAMethod(nullptr),
1160 fMerge(nullptr), fResetAfterMerge(nullptr), fNew(nullptr), fNewArray(nullptr), fDelete(nullptr), fDeleteArray(nullptr),
1161 fDestructor(nullptr), fDirAutoAdd(nullptr), fStreamerFunc(nullptr), fConvStreamerFunc(nullptr), fSizeof(-1),
1162 fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1163 fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1164 fState(kNoInfo),
1165 fCurrentInfo(nullptr), fLastReadInfo(nullptr), fRefProxy(nullptr),
1166 fSchemaRules(nullptr), fStreamerImpl(&TClass::StreamerDefault)
1167{
1169 Init(name, cversion, nullptr, nullptr, nullptr, nullptr, -1, -1, nullptr, silent);
1170}
1171
1172////////////////////////////////////////////////////////////////////////////////
1173/// Internal constructor, mimicing the case of a class fwd declared in the interpreter.
1174///
1175/// \note Use `TClass::GetClass("ClassName")` to get access to a TClass object for a certain class!
1176
1177TClass::TClass(const char *name, Version_t cversion, EState theState, Bool_t silent) :
1179 fPersistentRef(nullptr),
1180 fStreamerInfo(nullptr), fConversionStreamerInfo(nullptr), fRealData(nullptr),
1181 fBase(nullptr), fData(nullptr), fUsingData(nullptr), fEnums(nullptr), fFuncTemplate(nullptr), fMethod(nullptr), fAllPubData(nullptr),
1182 fAllPubMethod(nullptr), fClassMenuList(nullptr),
1183 fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1184 fInstanceCount(0), fOnHeap(0),
1185 fCheckSum(0), fCollectionProxy(nullptr), fClassVersion(0), fClassInfo(nullptr),
1186 fTypeInfo(nullptr), fShowMembers(nullptr),
1187 fStreamer(nullptr), fIsA(nullptr), fGlobalIsA(nullptr), fIsAMethod(nullptr),
1188 fMerge(nullptr), fResetAfterMerge(nullptr), fNew(nullptr), fNewArray(nullptr), fDelete(nullptr), fDeleteArray(nullptr),
1189 fDestructor(nullptr), fDirAutoAdd(nullptr), fStreamerFunc(nullptr), fConvStreamerFunc(nullptr), fSizeof(-1),
1190 fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1191 fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1192 fState(theState),
1193 fCurrentInfo(nullptr), fLastReadInfo(nullptr), fRefProxy(nullptr),
1194 fSchemaRules(nullptr), fStreamerImpl(&TClass::StreamerDefault)
1195{
1197
1198 // Treat the case in which a TClass instance is created for a namespace
1199 if (theState == kNamespaceForMeta){
1201 theState = kForwardDeclared; // it immediately decays in kForwardDeclared
1202 }
1203
1204 if (theState != kForwardDeclared && theState != kEmulated)
1205 ::Fatal("TClass::TClass",
1206 "A TClass entry cannot be initialized in a state different from kForwardDeclared or kEmulated.");
1207 Init(name, cversion, nullptr, nullptr, nullptr, nullptr, -1, -1, nullptr, silent);
1208}
1209
1210////////////////////////////////////////////////////////////////////////////////
1211/// Internal constructor.
1212///
1213/// Create a TClass object. This object contains the full dictionary
1214/// of a class. It has list to baseclasses, datamembers and methods.
1215/// Use this ctor to create a standalone TClass object. Most useful
1216/// to get a TClass interface to an interpreted class. Used by TTabCom.
1217///
1218/// This copies the ClassInfo (i.e. does *not* take ownership of it).
1219///
1220/// \note Use `TClass::GetClass("class")` to get access to a TClass object for a certain class!
1221
1222TClass::TClass(ClassInfo_t *classInfo, Version_t cversion,
1223 const char *dfil, const char *ifil, Int_t dl, Int_t il, Bool_t silent) :
1224 TDictionary(""),
1225 fPersistentRef(nullptr),
1226 fStreamerInfo(nullptr), fConversionStreamerInfo(nullptr), fRealData(nullptr),
1227 fBase(nullptr), fData(nullptr), fUsingData(nullptr), fEnums(nullptr), fFuncTemplate(nullptr), fMethod(nullptr), fAllPubData(nullptr),
1228 fAllPubMethod(nullptr), fClassMenuList(nullptr),
1229 fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1230 fInstanceCount(0), fOnHeap(0),
1231 fCheckSum(0), fCollectionProxy(nullptr), fClassVersion(0), fClassInfo(nullptr),
1232 fTypeInfo(nullptr), fShowMembers(nullptr),
1233 fStreamer(nullptr), fIsA(nullptr), fGlobalIsA(nullptr), fIsAMethod(nullptr),
1234 fMerge(nullptr), fResetAfterMerge(nullptr), fNew(nullptr), fNewArray(nullptr), fDelete(nullptr), fDeleteArray(nullptr),
1235 fDestructor(nullptr), fDirAutoAdd(nullptr), fStreamerFunc(nullptr), fConvStreamerFunc(nullptr), fSizeof(-1),
1236 fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1237 fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1238 fState(kNoInfo),
1239 fCurrentInfo(nullptr), fLastReadInfo(nullptr), fRefProxy(nullptr),
1240 fSchemaRules(nullptr), fStreamerImpl(&TClass::StreamerDefault)
1241{
1243
1244 if (!gROOT)
1245 ::Fatal("TClass::TClass", "ROOT system not initialized");
1246
1247 fDeclFileLine = -2; // -2 for standalone TClass (checked in dtor)
1248
1250 if (!gInterpreter)
1251 ::Fatal("TClass::TClass", "gInterpreter not initialized");
1252
1253 if (!classInfo || !gInterpreter->ClassInfo_IsValid(classInfo)) {
1254 MakeZombie();
1255 fState = kNoInfo;
1256 } else {
1257 fName = gInterpreter->ClassInfo_FullName(classInfo);
1258
1260 Init(fName, cversion, nullptr, nullptr, dfil, ifil, dl, il, classInfo, silent);
1261 }
1263
1264 fConversionStreamerInfo = nullptr;
1265}
1266
1267
1268////////////////////////////////////////////////////////////////////////////////
1269/// Internal constructor.
1270///
1271/// \note Use `TClass::GetClass("class")` to get access to a TClass object for a certain class!
1272
1273TClass::TClass(const char *name, Version_t cversion,
1274 const char *dfil, const char *ifil, Int_t dl, Int_t il, Bool_t silent) :
1276 fPersistentRef(nullptr),
1277 fStreamerInfo(nullptr), fConversionStreamerInfo(nullptr), fRealData(nullptr),
1278 fBase(nullptr), fData(nullptr), fUsingData(nullptr), fEnums(nullptr), fFuncTemplate(nullptr), fMethod(nullptr), fAllPubData(nullptr),
1279 fAllPubMethod(nullptr), fClassMenuList(nullptr),
1280 fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1281 fInstanceCount(0), fOnHeap(0),
1282 fCheckSum(0), fCollectionProxy(nullptr), fClassVersion(0), fClassInfo(nullptr),
1283 fTypeInfo(nullptr), fShowMembers(nullptr),
1284 fStreamer(nullptr), fIsA(nullptr), fGlobalIsA(nullptr), fIsAMethod(nullptr),
1285 fMerge(nullptr), fResetAfterMerge(nullptr), fNew(nullptr), fNewArray(nullptr), fDelete(nullptr), fDeleteArray(nullptr),
1286 fDestructor(nullptr), fDirAutoAdd(nullptr), fStreamerFunc(nullptr), fConvStreamerFunc(nullptr), fSizeof(-1),
1287 fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1288 fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1289 fState(kNoInfo),
1290 fCurrentInfo(nullptr), fLastReadInfo(nullptr), fRefProxy(nullptr),
1291 fSchemaRules(nullptr), fStreamerImpl(&TClass::StreamerDefault)
1292{
1294 Init(name,cversion, nullptr, nullptr, dfil, ifil, dl, il, nullptr, silent);
1295}
1296
1297////////////////////////////////////////////////////////////////////////////////
1298/// Internal constructor.
1299///
1300/// \note Use `TClass::GetClass("class")` to get access to a TClass object for a certain class!
1301
1302TClass::TClass(const char *name, Version_t cversion,
1303 const std::type_info &info, TVirtualIsAProxy *isa,
1304 const char *dfil, const char *ifil, Int_t dl, Int_t il,
1305 Bool_t silent) :
1307 fPersistentRef(nullptr),
1308 fStreamerInfo(nullptr), fConversionStreamerInfo(nullptr), fRealData(nullptr),
1309 fBase(nullptr), fData(nullptr), fUsingData(nullptr), fEnums(nullptr), fFuncTemplate(nullptr), fMethod(nullptr), fAllPubData(nullptr),
1310 fAllPubMethod(nullptr),
1311 fClassMenuList(nullptr),
1312 fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1313 fInstanceCount(0), fOnHeap(0),
1314 fCheckSum(0), fCollectionProxy(nullptr), fClassVersion(0), fClassInfo(nullptr),
1315 fTypeInfo(nullptr), fShowMembers(nullptr),
1316 fStreamer(nullptr), fIsA(nullptr), fGlobalIsA(nullptr), fIsAMethod(nullptr),
1317 fMerge(nullptr), fResetAfterMerge(nullptr), fNew(nullptr), fNewArray(nullptr), fDelete(nullptr), fDeleteArray(nullptr),
1318 fDestructor(nullptr), fDirAutoAdd(nullptr), fStreamerFunc(nullptr), fConvStreamerFunc(nullptr), fSizeof(-1),
1319 fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1320 fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1321 fState(kHasTClassInit),
1322 fCurrentInfo(nullptr), fLastReadInfo(nullptr), fRefProxy(nullptr),
1323 fSchemaRules(nullptr), fStreamerImpl(&TClass::StreamerDefault)
1324{
1326 // use info
1327 Init(name, cversion, &info, isa, dfil, ifil, dl, il, nullptr, silent);
1328}
1329
1330////////////////////////////////////////////////////////////////////////////////
1331/// we found at least one equivalent.
1332/// let's force a reload
1333
1335{
1336 TClass::RemoveClass(oldcl);
1337
1338 if (oldcl->CanIgnoreTObjectStreamer()) {
1340 }
1341
1343 TIter next(oldcl->GetStreamerInfos());
1344 while ((info = (TVirtualStreamerInfo*)next())) {
1345 info->Clear("build");
1346 info->SetClass(this);
1348 }
1349 oldcl->fStreamerInfo->Clear();
1350
1351 oldcl->ReplaceWith(this);
1352 delete oldcl;
1353}
1354
1355////////////////////////////////////////////////////////////////////////////////
1356/// Initialize a TClass object. This object contains the full dictionary
1357/// of a class. It has list to baseclasses, datamembers and methods.
1358
1359void TClass::Init(const char *name, Version_t cversion,
1360 const std::type_info *typeinfo, TVirtualIsAProxy *isa,
1361 const char *dfil, const char *ifil, Int_t dl, Int_t il,
1362 ClassInfo_t *givenInfo,
1363 Bool_t silent)
1364{
1365 if (!gROOT)
1366 ::Fatal("TClass::TClass", "ROOT system not initialized");
1367 if (!name || !name[0]) {
1368 ::Error("TClass::Init", "The name parameter is invalid (null or empty)");
1369 MakeZombie();
1370 return;
1371 }
1372 // Always strip the default STL template arguments (from any template argument or the class name)
1374 fName = name; // We can assume that the artificial class name is already normalized.
1375 else
1377
1378 fClassVersion = cversion;
1379 fDeclFileName = dfil ? dfil : "";
1380 fImplFileName = ifil ? ifil : "";
1381 fDeclFileLine = dl;
1382 fImplFileLine = il;
1383 fTypeInfo = typeinfo;
1384 fIsA = isa;
1385 if ( fIsA ) fIsA->SetClass(this);
1386 // See also TCling::GenerateTClass() which will update fClassVersion after creation!
1387 fStreamerInfo = new TObjArray(fClassVersion+2+10,-1); // +10 to read new data by old
1388 fProperty = -1;
1389 fClassProperty = 0;
1390
1392
1393 TClass *oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(fName.Data());
1394
1396
1397 if (oldcl && oldcl->TestBit(kLoading)) {
1398 // Do not recreate a class while it is already being created!
1399
1400 // We can no longer reproduce this case, to check whether we are, we use
1401 // this code:
1402 // Fatal("Init","A bad replacement for %s was requested\n",name);
1403 return;
1404 }
1405
1406 TClass **persistentRef = nullptr;
1407 if (oldcl) {
1408
1409 persistentRef = oldcl->fPersistentRef.exchange(nullptr);
1410
1411 // The code from here is also in ForceReload.
1412 TClass::RemoveClass(oldcl);
1413 // move the StreamerInfo immediately so that there are
1414 // properly updated!
1415
1416 if (oldcl->CanIgnoreTObjectStreamer()) {
1418 }
1420
1421 TIter next(oldcl->GetStreamerInfos());
1422 while ((info = (TVirtualStreamerInfo*)next())) {
1423 // We need to force a call to BuildOld
1424 info->Clear("build");
1425 info->SetClass(this);
1427 }
1428 oldcl->fStreamerInfo->Clear();
1429 // The code diverges here from ForceReload.
1430
1431 // Move the Schema Rules too.
1432 fSchemaRules = oldcl->fSchemaRules;
1433 oldcl->fSchemaRules = nullptr;
1434
1435 // Move the TFunctions.
1437 if (fFuncTemplate)
1438 fFuncTemplate->fClass = this;
1439 oldcl->fFuncTemplate = nullptr;
1440 fMethod.store( oldcl->fMethod );
1441 if (fMethod)
1442 (*fMethod).fClass = this;
1443 oldcl->fMethod = nullptr;
1444
1445 }
1446
1448 // Advertise ourself as the loading class for this class name
1449 TClass::AddClass(this);
1450
1452
1453 if (!gInterpreter)
1454 ::Fatal("TClass::Init", "gInterpreter not initialized");
1455
1456 if (givenInfo) {
1457 bool invalid = !gInterpreter->ClassInfo_IsValid(givenInfo);
1458 bool notloaded = !gInterpreter->ClassInfo_IsLoaded(givenInfo);
1459 auto property = gInterpreter->ClassInfo_Property(givenInfo);
1460
1461 if (invalid || (notloaded && (property & kIsNamespace)) ||
1462 !(property & (kIsClass | kIsStruct | kIsNamespace))) {
1464 MakeZombie();
1465 fState = kNoInfo;
1466 TClass::RemoveClass(this);
1467 return;
1468 }
1469 }
1470
1471 if (!invalid) {
1472 fClassInfo = gInterpreter->ClassInfo_Factory(givenInfo);
1473 fCanLoadClassInfo = false; // avoids calls to LoadClassInfo() if info is already loaded
1474 if (fState <= kEmulated)
1476 }
1477 }
1478
1479 // We need to check if the class it is not fwd declared for the cases where we
1480 // created a TClass directly in the kForwardDeclared state. Indeed in those cases
1481 // fClassInfo will always be nullptr.
1483
1484 if (fState == kHasTClassInit) {
1485 // If the TClass is being generated from a ROOT dictionary,
1486 // even though we do not seem to have a CINT dictionary for
1487 // the class, we will will try to load it anyway UNLESS
1488 // the class is an STL container (or string).
1489 // This is because we do not expect the CINT dictionary
1490 // to be present for all STL classes (and we can handle
1491 // the lack of CINT dictionary in that cases).
1492 // However, the cling the dictionary no longer carries
1493 // an instantiation with it, unless we request the loading
1494 // here *or* the user explicitly instantiate the template
1495 // we would not have a ClassInfo for the template
1496 // instantiation.
1498 // Here we check and grab the info from the rootpcm.
1500 if (proto)
1501 proto->FillTClass(this);
1502 }
1503 if (!fHasRootPcmInfo && gInterpreter->CheckClassInfo(fName, /* autoload = */ kTRUE)) {
1504 gInterpreter->SetClassInfo(this); // sets fClassInfo pointer
1505 if (fClassInfo) {
1506 // This should be moved out of GetCheckSum itself however the last time
1507 // we tried this cause problem, in particular in the end-of-process operation.
1508 // fCheckSum = GetCheckSum(kLatestCheckSum);
1509 } else {
1510 if (!fClassInfo) {
1511 if (IsZombie()) {
1512 TClass::RemoveClass(this);
1513 return;
1514 }
1515 }
1516 }
1517 }
1518 }
1519 if (!silent && (!fClassInfo && !fCanLoadClassInfo) && !isStl && !TClassEdit::IsArtificial(fName) &&
1521 if (fState == kHasTClassInit) {
1522 if (fImplFileLine == -1 && fClassVersion == 0) {
1523 // We have a 'transient' class with a ClassDefInline and apparently no interpreter
1524 // information. Since it is transient, it is more than likely that the lack
1525 // will be harmles.
1526 } else {
1527 ::Error("TClass::Init", "no interpreter information for class %s is available even though it has a TClass "
1528 "initialization routine.",
1529 fName.Data());
1530 }
1531 } else {
1532 // In this case we initialised this TClass instance starting from the fwd declared state
1533 // and we know we have no dictionary: no need to warn
1534 ::Warning("TClass::Init", "no dictionary for class %s is available", fName.Data());
1535 }
1536 }
1537
1538 fgClassCount++;
1540
1541 // Make the typedef-expanded -> original hash table entries.
1542 // There may be several entries for any given key.
1543 // We only make entries if the typedef-expanded name
1544 // is different from the original name.
1545 TString resolvedThis;
1546 if (!givenInfo && strchr (name, '<')) {
1547 if ( fName != name) {
1548 if (!fgClassTypedefHash) {
1549 fgClassTypedefHash = new THashTable (100, 5);
1551 }
1552
1553 fgClassTypedefHash->Add (new TNameMapNode (name, fName));
1555
1556 }
1557 resolvedThis = TClassEdit::ResolveTypedef (name, kTRUE);
1558 if (resolvedThis != name) {
1559 if (!fgClassTypedefHash) {
1560 fgClassTypedefHash = new THashTable (100, 5);
1562 }
1563
1564 fgClassTypedefHash->Add (new TNameMapNode (resolvedThis, fName));
1566 }
1567
1568 }
1569
1570 //In case a class with the same name had been created by TVirtualStreamerInfo
1571 //we must delete the old class, importing only the StreamerInfo structure
1572 //from the old dummy class.
1573 if (oldcl) {
1574
1575 oldcl->ReplaceWith(this);
1576 delete oldcl;
1577
1578 } else if (!givenInfo && resolvedThis.Length() > 0 && fgClassTypedefHash) {
1579
1580 // Check for existing equivalent.
1581
1582 if (resolvedThis != fName) {
1583 oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(resolvedThis);
1584 if (oldcl && oldcl != this) {
1585 persistentRef = oldcl->fPersistentRef.exchange(nullptr);
1586 ForceReload (oldcl);
1587 }
1588 }
1589 TIter next( fgClassTypedefHash->GetListForObject(resolvedThis) );
1590 while ( TNameMapNode* htmp = static_cast<TNameMapNode*> (next()) ) {
1591 if (resolvedThis != htmp->String()) continue;
1592 oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(htmp->fOrigName); // gROOT->GetClass (htmp->fOrigName, kFALSE);
1593 if (oldcl && oldcl != this) {
1594 persistentRef = oldcl->fPersistentRef.exchange(nullptr);
1595 ForceReload (oldcl);
1596 }
1597 }
1598 }
1599 if (fClassInfo) {
1601 if ( fDeclFileName == nullptr || fDeclFileName[0] == '\0' ) {
1602 fDeclFileName = kUndeterminedClassInfoName;
1603 // Missing interface:
1604 // fDeclFileLine = gInterpreter->ClassInfo_FileLine( fClassInfo );
1605
1606 // But really do not want to set ImplFileLine as it is currently the
1607 // marker of being 'loaded' or not (reminder loaded == has a TClass bootstrap).
1608 }
1609 }
1610
1611 if (persistentRef) {
1612 fPersistentRef = persistentRef;
1613 } else {
1614 fPersistentRef = new TClass*;
1615 }
1616 *fPersistentRef = this;
1617
1618 if ( isStl || !strncmp(GetName(),"stdext::hash_",13) || !strncmp(GetName(),"__gnu_cxx::hash_",16) ) {
1619 if (fState != kHasTClassInit) {
1620 // If we have a TClass compiled initialization, we can safely assume that
1621 // there will also be a collection proxy.
1623 if (fCollectionProxy) {
1625
1626 // Numeric Collections have implicit conversions:
1628
1629 } else if (!silent) {
1630 Warning("Init","Collection proxy for %s was not properly initialized!",GetName());
1631 }
1632 if (fStreamer==nullptr) {
1634 }
1635 }
1636 } else if (TClassEdit::IsStdPair(GetName())) {
1637 // std::pairs have implicit conversions
1639 }
1640
1642}
1643
1644////////////////////////////////////////////////////////////////////////////////
1645/// TClass dtor. Deletes all list that might have been created.
1646
1648{
1650
1651 // Remove from the typedef hashtables.
1653 TString resolvedThis = TClassEdit::ResolveTypedef (GetName(), kTRUE);
1654 TIter next (fgClassTypedefHash->GetListForObject (resolvedThis));
1655 while ( TNameMapNode* htmp = static_cast<TNameMapNode*> (next()) ) {
1656 if (resolvedThis == htmp->String() && htmp->fOrigName == GetName()) {
1657 fgClassTypedefHash->Remove (htmp);
1658 delete htmp;
1659 break;
1660 }
1661 }
1662 }
1663
1664 // Not owning lists, don't call Delete()
1665 // But this still need to be done first because the TList destructor
1666 // does access the object contained (via GetObject()->TestBit(kCanDelete))
1667 delete fStreamer; fStreamer =nullptr;
1668 delete fAllPubData; fAllPubData =nullptr;
1669 delete fAllPubMethod; fAllPubMethod=nullptr;
1670
1671 delete fPersistentRef.load();
1672
1673 if (fBase.load())
1674 (*fBase).Delete();
1675 delete fBase.load(); fBase = nullptr;
1676
1677 if (fData.load())
1678 (*fData).Delete();
1679 delete fData.load(); fData = nullptr;
1680
1681 if (fUsingData.load())
1682 (*fUsingData).Delete();
1683 delete fUsingData.load(); fUsingData = nullptr;
1684
1685 if (fEnums.load())
1686 (*fEnums).Delete();
1687 delete fEnums.load(); fEnums = nullptr;
1688
1689 if (fFuncTemplate)
1691 delete fFuncTemplate; fFuncTemplate = nullptr;
1692
1693 if (fMethod.load())
1694 (*fMethod).Delete();
1695 delete fMethod.load(); fMethod=nullptr;
1696
1697 if (fRealData)
1698 fRealData->Delete();
1699 delete fRealData; fRealData=nullptr;
1700
1701 if (fStreamerInfo)
1703 delete fStreamerInfo; fStreamerInfo = nullptr;
1704
1705 if (fDeclFileLine >= -1)
1706 TClass::RemoveClass(this);
1707
1709 fClassInfo=nullptr;
1710
1711 if (fClassMenuList)
1713 delete fClassMenuList; fClassMenuList=nullptr;
1714
1716
1717 if ( fIsA ) delete fIsA;
1718
1719 if ( fRefProxy ) fRefProxy->Release();
1720 fRefProxy = nullptr;
1721
1722 delete fStreamer;
1723 delete fCollectionProxy;
1724 delete fIsAMethod.load();
1725 delete fSchemaRules;
1726 if (fConversionStreamerInfo.load()) {
1727 std::map<std::string, TObjArray*>::iterator it;
1728 std::map<std::string, TObjArray*>::iterator end = (*fConversionStreamerInfo).end();
1729 for( it = (*fConversionStreamerInfo).begin(); it != end; ++it ) {
1730 delete it->second;
1731 }
1732 delete fConversionStreamerInfo.load();
1733 }
1734}
1735
1736////////////////////////////////////////////////////////////////////////////////
1737
1738namespace {
1739 Int_t ReadRulesContent(FILE *f)
1740 {
1741 // Read a class.rules file which contains one rule per line with comment
1742 // starting with a #
1743 // Returns the number of rules loaded.
1744 // Returns -1 in case of error.
1745
1746 R__ASSERT(f!=nullptr);
1747 TString rule(1024);
1748 int c, state = 0;
1749 Int_t count = 0;
1750
1751 while ((c = fgetc(f)) != EOF) {
1752 if (c == 13) // ignore CR
1753 continue;
1754 if (c == '\n') {
1755 if (state != 3) {
1756 state = 0;
1757 if (rule.Length() > 0) {
1758 if (TClass::AddRule(rule)) {
1759 ++count;
1760 }
1761 rule.Clear();
1762 }
1763 }
1764 continue;
1765 }
1766 switch (state) {
1767 case 0: // start of line
1768 switch (c) {
1769 case ' ':
1770 case '\t':
1771 break;
1772 case '#':
1773 state = 1;
1774 break;
1775 default:
1776 state = 2;
1777 break;
1778 }
1779 break;
1780
1781 case 1: // comment
1782 break;
1783
1784 case 2: // rule
1785 switch (c) {
1786 case '\\':
1787 state = 3; // Continuation request
1788 default:
1789 break;
1790 }
1791 break;
1792 }
1793 switch (state) {
1794 case 2:
1795 rule.Append(c);
1796 break;
1797 }
1798 }
1799 return count;
1800 }
1801}
1802
1803////////////////////////////////////////////////////////////////////////////////
1804/// Read the class.rules files from the default location:.
1805/// $ROOTSYS/etc/class.rules (or ROOTETCDIR/class.rules)
1806
1808{
1809 static const char *suffix = "class.rules";
1810 TString sname = suffix;
1812
1813 Int_t res = -1;
1814
1815 FILE * f = fopen(sname,"r");
1816 if (f != nullptr) {
1817 res = ReadRulesContent(f);
1818 fclose(f);
1819 } else {
1820 ::Error("TClass::ReadRules()", "Cannot find rules file %s", sname.Data());
1821 }
1822 return res;
1823}
1824
1825////////////////////////////////////////////////////////////////////////////////
1826/// Read a class.rules file which contains one rule per line with comment
1827/// starting with a #
1828/// - Returns the number of rules loaded.
1829/// - Returns -1 in case of error.
1830
1831Int_t TClass::ReadRules( const char *filename )
1832{
1833 if (!filename || !filename[0]) {
1834 ::Error("TClass::ReadRules", "no file name specified");
1835 return -1;
1836 }
1837
1838 FILE * f = fopen(filename,"r");
1839 if (f == nullptr) {
1840 ::Error("TClass::ReadRules","Failed to open %s\n",filename);
1841 return -1;
1842 }
1843 Int_t count = ReadRulesContent(f);
1844
1845 fclose(f);
1846 return count;
1847
1848}
1849
1850////////////////////////////////////////////////////////////////////////////////
1851/// Add a schema evolution customization rule.
1852/// The syntax of the rule can be either the short form:
1853/// ~~~ {.cpp}
1854/// [type=Read] classname membername [attributes=... ] [version=[...] ] [checksum=[...] ] [oldtype=...] [code={...}]
1855/// ~~~
1856/// or the long form
1857/// ~~~ {.cpp}
1858/// [type=Read] sourceClass=classname [targetclass=newClassname] [ source="type membername; [type2 membername2]" ]
1859/// [target="membername3;membername4"] [attributes=... ] [version=...] [checksum=...] [code={...}|functionname]
1860/// ~~~
1861///
1862/// For example to set HepMC::GenVertex::m_event to _not_ owned the object it is pointing to:
1863/// HepMC::GenVertex m_event attributes=NotOwner
1864///
1865/// Semantic of the tags:
1866/// - type : the type of the rule, valid values: Read, ReadRaw, Write, WriteRaw, the default is 'Read'.
1867/// - sourceClass : the name of the class as it is on the rule file
1868/// - targetClass : the name of the class as it is in the current code ; defaults to the value of sourceClass
1869/// - source : the types and names of the data members from the class on file that are needed, the list is separated by semi-colons ';'
1870/// - oldtype: in the short form only, indicates the type on disk of the data member.
1871/// - target : the names of the data members updated by this rule, the list is separated by semi-colons ';'
1872/// - attributes : list of possible qualifiers among: Owner, NotOwner
1873/// - 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]
1874/// - checksum : comma delimited list of the checksums of the class layout that this rule applies to.
1875/// - code={...} : code to be executed for the rule or name of the function implementing it.
1876
1877Bool_t TClass::AddRule( const char *rule )
1878{
1879 ROOT::TSchemaRule *ruleobj = new ROOT::TSchemaRule();
1880 if (! ruleobj->SetFromRule( rule ) ) {
1881 delete ruleobj;
1882 return kFALSE;
1883 }
1884
1886
1887 TClass *cl = TClass::GetClass( ruleobj->GetTargetClass() );
1888 if (!cl) {
1889 // Create an empty emulated class for now.
1890 cl = gInterpreter->GenerateTClass(ruleobj->GetTargetClass(), /* emulation = */ kTRUE, /*silent = */ kTRUE);
1891 }
1893
1894 TString errmsg;
1895 if( !rset->AddRule( ruleobj, ROOT::Detail::TSchemaRuleSet::kCheckConflict, &errmsg ) ) {
1896 ::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).",
1897 ruleobj->GetTargetClass(), ruleobj->GetVersion(), ruleobj->GetTargetString(), errmsg.Data() );
1898 delete ruleobj;
1899 return kFALSE;
1900 }
1901 return kTRUE;
1902}
1903
1904////////////////////////////////////////////////////////////////////////////////
1905/// Adopt a new set of Data Model Evolution rules.
1906
1908{
1910
1911 delete fSchemaRules;
1912 fSchemaRules = rules;
1913 fSchemaRules->SetClass( this );
1914}
1915
1916////////////////////////////////////////////////////////////////////////////////
1917/// Return the set of the schema rules if any.
1918
1920{
1921 return fSchemaRules;
1922}
1923
1924////////////////////////////////////////////////////////////////////////////////
1925/// Return the set of the schema rules if any.
1926/// If create is true, create an empty set
1927
1929{
1930 if (create && fSchemaRules == nullptr) {
1932 fSchemaRules->SetClass( this );
1933 }
1934 return fSchemaRules;
1935}
1936
1937////////////////////////////////////////////////////////////////////////////////
1938
1939void TClass::AddImplFile(const char* filename, int line) {
1940 // Currently reset the implementation file and line.
1941 // In the close future, it will actually add this file and line
1942 // to a "list" of implementation files.
1943
1944 fImplFileName = filename;
1946}
1947
1948////////////////////////////////////////////////////////////////////////////////
1949/// Browse external object inherited from TObject.
1950/// It passes through inheritance tree and calls TBrowser::Add
1951/// in appropriate cases. Static function.
1952
1954{
1955 if (!obj) return 0;
1956
1957 TAutoInspector insp(b);
1958 obj->ShowMembers(insp);
1959 return insp.fCount;
1960}
1961
1962////////////////////////////////////////////////////////////////////////////////
1963/// Browse objects of of the class described by this TClass object.
1964
1965Int_t TClass::Browse(void *obj, TBrowser *b) const
1966{
1967 if (!obj) return 0;
1968
1969 TClass *actual = GetActualClass(obj);
1970 if (IsTObject()) {
1971 // Call TObject::Browse.
1972
1973 if (!fIsOffsetStreamerSet) {
1975 }
1976 TObject* realTObject = (TObject*)((size_t)obj + fOffsetStreamer);
1977 realTObject->Browse(b);
1978 return 1;
1979 } else if (actual != this) {
1980 return actual->Browse(obj, b);
1981 } else if (GetCollectionProxy()) {
1982
1983 // do something useful.
1984
1985 } else {
1986 TAutoInspector insp(b);
1987 CallShowMembers(obj,insp,kFALSE);
1988 return insp.fCount;
1989 }
1990
1991 return 0;
1992}
1993
1994////////////////////////////////////////////////////////////////////////////////
1995/// This method is called by a browser to get the class information.
1996
1998{
1999 if (!HasInterpreterInfo()) return;
2000
2001 if (b) {
2002 if (!fRealData) BuildRealData();
2003
2004 b->Add(GetListOfDataMembers(), "Data Members");
2005 b->Add(GetListOfRealData(), "Real Data Members");
2006 b->Add(GetListOfMethods(), "Methods");
2007 b->Add(GetListOfBases(), "Base Classes");
2008 }
2009}
2010
2011////////////////////////////////////////////////////////////////////////////////
2012/// Build a full list of persistent data members.
2013/// Scans the list of all data members in the class itself and also
2014/// in all base classes. For each persistent data member, inserts a
2015/// TRealData object in the list fRealData.
2016///
2017
2018void TClass::BuildRealData(void* pointer, Bool_t isTransient)
2019{
2020
2022
2023 // Only do this once.
2024 if (fRealData) {
2025 return;
2026 }
2027
2028 if (fClassVersion == 0) {
2029 isTransient = kTRUE;
2030 }
2031
2032 // When called via TMapFile (e.g. Update()) make sure that the dictionary
2033 // gets allocated on the heap and not in the mapped file.
2034 TMmallocDescTemp setreset;
2035
2036 // Handle emulated classes and STL containers specially.
2038 // We are an emulated class or an STL container.
2039 fRealData = new TList;
2040 BuildEmulatedRealData("", 0, this, isTransient);
2041 return;
2042 }
2043
2044 // return early on string
2045 static TClassRef clRefString("std::string");
2046 if (clRefString == this) {
2047 return;
2048 }
2049
2050 // Complain about stl classes ending up here (unique_ptr etc) - except for
2051 // pair where we will build .first, .second just fine
2052 // and those for which the user explicitly requested a dictionary.
2053 if (!isTransient && GetState() != kHasTClassInit
2056 Error("BuildRealData", "Inspection for %s not supported!", GetName());
2057 }
2058
2059 // The following statement will recursively call
2060 // all the subclasses of this class.
2061 fRealData = new TList;
2062 TBuildRealData brd(pointer, this);
2063
2064 // CallShowMember will force a call to InheritsFrom, which indirectly
2065 // calls TClass::GetClass. It forces the loading of new typedefs in
2066 // case some of them were not yet loaded.
2067 if ( ! CallShowMembers(pointer, brd, isTransient) ) {
2068 if ( isTransient ) {
2069 // This is a transient data member, so it is probably fine to not have
2070 // access to its content. However let's no mark it as definitively setup,
2071 // since another class might use this class for a persistent data member and
2072 // in this case we really want the error message.
2073 delete fRealData;
2074 fRealData = nullptr;
2075 } else {
2076 Error("BuildRealData", "Cannot find any ShowMembers function for %s!", GetName());
2077 }
2078 }
2079
2080 // Take this opportunity to build the real data for base classes.
2081 // In case one base class is abstract, it would not be possible later
2082 // to create the list of real data for this abstract class.
2083 TBaseClass* base = nullptr;
2084 TIter next(GetListOfBases());
2085 while ((base = (TBaseClass*) next())) {
2086 if (base->IsSTLContainer()) {
2087 continue;
2088 }
2089 TClass* c = base->GetClassPointer();
2090 if (c) {
2091 c->BuildRealData(nullptr, isTransient);
2092 }
2093 }
2094}
2095
2096////////////////////////////////////////////////////////////////////////////////
2097/// Build the list of real data for an emulated class
2098
2099void TClass::BuildEmulatedRealData(const char *name, Longptr_t offset, TClass *cl, Bool_t isTransient)
2100{
2102
2104 if (Property() & kIsAbstract) {
2106 } else {
2107 info = GetStreamerInfoImpl(fClassVersion, isTransient);
2108 }
2109 if (!info) {
2110 // This class is abstract, but we don't yet have a SteamerInfo for it ...
2111 Error("BuildEmulatedRealData","Missing StreamerInfo for %s",GetName());
2112 // Humm .. no information ... let's bail out
2113 return;
2114 }
2115
2116 TIter next(info->GetElements());
2117 TStreamerElement *element;
2118 while ((element = (TStreamerElement*)next())) {
2119 Int_t etype = element->GetType();
2120 Longptr_t eoffset = element->GetOffset();
2121 TClass *cle = element->GetClassPointer();
2122 if (element->IsBase() || etype == TVirtualStreamerInfo::kBase) {
2123 //base class are skipped in this loop, they will be added at the end.
2124 continue;
2125 } else if (etype == TVirtualStreamerInfo::kTObject ||
2128 etype == TVirtualStreamerInfo::kAny) {
2129 //member class
2130 TString rdname; rdname.Form("%s%s",name,element->GetFullName());
2131 TRealData *rd = new TRealData(rdname,offset+eoffset,nullptr);
2132 if (gDebug > 0) printf(" Class: %s, adding TRealData=%s, offset=%ld\n",cl->GetName(),rd->GetName(),rd->GetThisOffset());
2133 cl->GetListOfRealData()->Add(rd);
2134 // Now we a dot
2135 rdname.Form("%s%s.",name,element->GetFullName());
2136 if (cle) cle->BuildEmulatedRealData(rdname,offset+eoffset,cl, isTransient);
2137 } else {
2138 //others
2139 TString rdname; rdname.Form("%s%s",name,element->GetFullName());
2140 TRealData *rd = new TRealData(rdname,offset+eoffset,nullptr);
2141 if (gDebug > 0) printf(" Class: %s, adding TRealData=%s, offset=%ld\n",cl->GetName(),rd->GetName(),rd->GetThisOffset());
2142 cl->GetListOfRealData()->Add(rd);
2143 }
2144 //if (fClassInfo==0 && element->IsBase()) {
2145 // if (fBase==0) fBase = new TList;
2146 // TClass *base = element->GetClassPointer();
2147 // fBase->Add(new TBaseClass(this, cl, eoffset));
2148 //}
2149 }
2150 // The base classes must added last on the list of real data (to help with ambiguous data member names)
2151 next.Reset();
2152 while ((element = (TStreamerElement*)next())) {
2153 Int_t etype = element->GetType();
2154 if (element->IsBase() || etype == TVirtualStreamerInfo::kBase) {
2155 //base class
2156 Longptr_t eoffset = element->GetOffset();
2157 TClass *cle = element->GetClassPointer();
2158 if (cle) cle->BuildEmulatedRealData(name,offset+eoffset,cl, isTransient);
2159 }
2160 }
2161}
2162
2163
2164////////////////////////////////////////////////////////////////////////////////
2165/// Calculate the offset between an object of this class to
2166/// its base class TObject. The pointer can be adjusted by
2167/// that offset to access any virtual method of TObject like
2168/// Streamer() and ShowMembers().
2169
2171{
2174 // When called via TMapFile (e.g. Update()) make sure that the dictionary
2175 // gets allocated on the heap and not in the mapped file.
2176
2177 TMmallocDescTemp setreset;
2179 if (fStreamerType == kTObject) {
2181 }
2183 }
2184}
2185
2186
2187////////////////////////////////////////////////////////////////////////////////
2188/// Call ShowMembers() on the obj of this class type, passing insp and parent.
2189/// isATObject is -1 if unknown, 0 if it is not a TObject, and 1 if it is a TObject.
2190/// The function returns whether it was able to call ShowMembers().
2191
2192Bool_t TClass::CallShowMembers(const void* obj, TMemberInspector &insp, Bool_t isTransient) const
2193{
2194 if (fShowMembers) {
2195 // This should always works since 'pointer' should be pointing
2196 // to an object of the actual type of this TClass object.
2197 fShowMembers(obj, insp, isTransient);
2198 return kTRUE;
2199 } else {
2200
2202 if (fClassInfo) {
2203
2204 if (strcmp(GetName(), "string") == 0) {
2205 // For std::string we know that we do not have a ShowMembers
2206 // function and that it's okay.
2207 return kTRUE;
2208 }
2209 // Since we do have some dictionary information, let's
2210 // call the interpreter's ShowMember.
2211 // This works with Cling to support interpreted classes.
2212 gInterpreter->InspectMembers(insp, obj, this, isTransient);
2213 return kTRUE;
2214
2215 } else if (TVirtualStreamerInfo* sinfo = GetStreamerInfo()) {
2216 sinfo->CallShowMembers(obj, insp, isTransient);
2217 return kTRUE;
2218 } // isATObject
2219 } // fShowMembers is set
2220
2221 return kFALSE;
2222}
2223
2224////////////////////////////////////////////////////////////////////////////////
2225/// Do a ShowMembers() traversal of all members and base classes' members
2226/// using the reflection information from the interpreter. Works also for
2227/// interpreted objects.
2228
2229void TClass::InterpretedShowMembers(void* obj, TMemberInspector &insp, Bool_t isTransient)
2230{
2231 return gInterpreter->InspectMembers(insp, obj, this, isTransient);
2232}
2233
2235{
2236 if (fCanSplit >= 0) {
2237 return ! ( fCanSplit & 0x2 );
2238 }
2239
2241
2242 if (GetCollectionProxy() != nullptr) {
2243 // A collection can never affect its derived class 'splittability'
2244 return kTRUE;
2245 }
2246
2247 if (this == TRef::Class()) { fCanSplit = 2; return kFALSE; }
2248 if (this == TRefArray::Class()) { fCanSplit = 2; return kFALSE; }
2249 if (this == TArray::Class()) { fCanSplit = 2; return kFALSE; }
2250 if (this == TClonesArray::Class()) { fCanSplit = 1; return kTRUE; }
2251 if (this == TCollection::Class()) { fCanSplit = 2; return kFALSE; }
2252
2253 // TTree is not always available (for example in rootcling), so we need
2254 // to grab it silently.
2255 auto refTreeClass( TClass::GetClass("TTree",kTRUE,kTRUE) );
2256 if (this == refTreeClass) { fCanSplit = 2; return kFALSE; }
2257
2258 if (!HasDataMemberInfo()) {
2259 TVirtualStreamerInfo *sinfo = ((TClass *)this)->GetCurrentStreamerInfo();
2260 if (sinfo==nullptr) sinfo = GetStreamerInfo();
2261 TIter next(sinfo->GetElements());
2262 TStreamerElement *element;
2263 while ((element = (TStreamerElement*)next())) {
2264 if (element->IsA() == TStreamerBase::Class()) {
2265 TClass *clbase = element->GetClassPointer();
2266 if (!clbase) {
2267 // If there is a missing base class, we can't split the immediate
2268 // derived class.
2269 fCanSplit = 0;
2270 return kFALSE;
2271 } else if (!clbase->CanSplitBaseAllow()) {
2272 fCanSplit = 2;
2273 return kFALSE;
2274 }
2275 }
2276 }
2277 }
2278
2279 // If we don't have data member info there is no more information
2280 // we can find out.
2281 if (!HasDataMemberInfo()) return kTRUE;
2282
2283 TObjLink *lnk = GetListOfBases() ? fBase.load()->FirstLink() : nullptr;
2284
2285 // Look at inheritance tree
2286 while (lnk) {
2287 TClass *c;
2288 TBaseClass *base = (TBaseClass*) lnk->GetObject();
2289 c = base->GetClassPointer();
2290 if(!c) {
2291 // If there is a missing base class, we can't split the immediate
2292 // derived class.
2293 fCanSplit = 0;
2294 return kFALSE;
2295 } else if (!c->CanSplitBaseAllow()) {
2296 fCanSplit = 2;
2297 return kFALSE;
2298 }
2299 lnk = lnk->Next();
2300 }
2301 return kTRUE;
2302}
2303
2304////////////////////////////////////////////////////////////////////////////////
2305/// Return true if the data member of this TClass can be saved separately.
2306
2308{
2309 // Note: add the possibility to set it for the class and the derived class.
2310 // save the info in TVirtualStreamerInfo
2311 // deal with the info in MakeProject
2312 if (fCanSplit >= 0) {
2313 // The user explicitly set the value
2314 return (fCanSplit & 0x1) == 1;
2315 }
2316
2318 TClass *This = const_cast<TClass*>(this);
2319
2320 if (this == TObject::Class()) { This->fCanSplit = 1; return kTRUE; }
2321 if (fName == "TClonesArray") { This->fCanSplit = 1; return kTRUE; }
2322 if (fRefProxy) { This->fCanSplit = 0; return kFALSE; }
2323 if (fName.BeginsWith("TVectorT<")) { This->fCanSplit = 0; return kFALSE; }
2324 if (fName.BeginsWith("TMatrixT<")) { This->fCanSplit = 0; return kFALSE; }
2325 if (fName == "string") { This->fCanSplit = 0; return kFALSE; }
2326 if (fName == "std::string") { This->fCanSplit = 0; return kFALSE; }
2327
2328 if (GetCollectionProxy()!=nullptr) {
2329 // For STL collection we need to look inside.
2330
2331 // However we do not split collections of collections
2332 // nor collections of strings
2333 // nor collections of pointers (unless explicit request (see TBranchSTL)).
2334
2335 if (GetCollectionProxy()->HasPointers()) { This->fCanSplit = 0; return kFALSE; }
2336
2337 TClass *valueClass = GetCollectionProxy()->GetValueClass();
2338 if (valueClass == nullptr) { This->fCanSplit = 0; return kFALSE; }
2339 static TClassRef stdStringClass("std::string");
2340 if (valueClass==TString::Class() || valueClass==stdStringClass)
2341 { This->fCanSplit = 0; return kFALSE; }
2342 if (!valueClass->CanSplit()) { This->fCanSplit = 0; return kFALSE; }
2343 if (valueClass->GetCollectionProxy() != nullptr) { This->fCanSplit = 0; return kFALSE; }
2344
2345 This->fCanSplit = 1;
2346 return kTRUE;
2347
2348 }
2349
2350 if (GetStreamer() != nullptr || fStreamerFunc != nullptr) {
2351
2352 // We have an external custom streamer provided by the user, we must not
2353 // split it.
2354 This->fCanSplit = 0;
2355 return kFALSE;
2356
2358
2359 // We have a custom member function streamer or
2360 // an older (not StreamerInfo based) automatic streamer.
2361 This->fCanSplit = 0;
2362 return kFALSE;
2363 }
2364
2365 if (Size()==1) {
2366 // 'Empty' class there is nothing to split!.
2367 This->fCanSplit = 0;
2368 return kFALSE;
2369 }
2370
2371
2372 if ( !This->CanSplitBaseAllow() ) {
2373 return kFALSE;
2374 }
2375
2376 This->fCanSplit = 1;
2377 return kTRUE;
2378}
2379
2380////////////////////////////////////////////////////////////////////////////////
2381/// Return the C++ property of this class, eg. is abstract, has virtual base
2382/// class, see EClassProperty in TDictionary.h
2383
2385{
2386 if (fProperty == -1) Property();
2387 return fClassProperty;
2388}
2389
2390////////////////////////////////////////////////////////////////////////////////
2391/// Create a Clone of this TClass object using a different name but using the same 'dictionary'.
2392/// This effectively creates a hard alias for the class name.
2393
2394TObject *TClass::Clone(const char *new_name) const
2395{
2396 if (new_name == nullptr || new_name[0]=='\0' || fName == new_name) {
2397 Error("Clone","The name of the class must be changed when cloning a TClass object.");
2398 return nullptr;
2399 }
2400
2401 // Need to lock access to TROOT::GetListOfClasses so the cloning happens atomically
2403 // Temporarily remove the original from the list of classes.
2404 TClass::RemoveClass(const_cast<TClass*>(this));
2405
2406 TClass *copy;
2407 if (fTypeInfo) {
2408 copy = new TClass(GetName(),
2410 *fTypeInfo,
2411 new TIsAProxy(*fTypeInfo),
2415 GetImplFileLine());
2416 } else {
2417 copy = new TClass(GetName(),
2422 GetImplFileLine());
2423 }
2424 copy->fShowMembers = fShowMembers;
2425 // Remove the copy before renaming it
2426 TClass::RemoveClass(copy);
2427 copy->fName = new_name;
2428 TClass::AddClass(copy);
2429
2430 copy->SetNew(fNew);
2431 copy->SetNewArray(fNewArray);
2432 copy->SetDelete(fDelete);
2438 if (fStreamer) {
2440 }
2441 // If IsZombie is true, something went wrong and we will not be
2442 // able to properly copy the collection proxy
2443 if (fCollectionProxy && !copy->IsZombie()) {
2445 }
2446 copy->SetClassSize(fSizeof);
2447 if (fRefProxy) {
2449 }
2450 TClass::AddClass(const_cast<TClass*>(this));
2451 return copy;
2452}
2453
2454////////////////////////////////////////////////////////////////////////////////
2455/// Copy the argument.
2456
2458{
2459// // This code was used too quickly test the STL Emulation layer
2460// Int_t k = TClassEdit::IsSTLCont(GetName());
2461// if (k==1||k==-1) return;
2462
2463 delete fCollectionProxy;
2464 fCollectionProxy = orig.Generate();
2465}
2466
2467////////////////////////////////////////////////////////////////////////////////
2468/// Draw detailed class inheritance structure.
2469/// If a class B inherits from a class A, the description of B is drawn
2470/// on the right side of the description of A.
2471/// Member functions overridden by B are shown in class A with a blue line
2472/// erasing the corresponding member function
2473
2475{
2476 if (!HasInterpreterInfo()) return;
2477
2478 TVirtualPad *padsav = gPad;
2479
2480 // Should we create a new canvas?
2481 TString opt=option;
2482 if (!padsav || !opt.Contains("same")) {
2483 TVirtualPad *padclass = (TVirtualPad*)(gROOT->GetListOfCanvases())->FindObject("R__class");
2484 if (!padclass) {
2485 gROOT->ProcessLine("new TCanvas(\"R__class\",\"class\",20,20,1000,750);");
2486 } else {
2487 padclass->cd();
2488 }
2489 }
2490
2491 if (gPad) gPad->DrawClassObject(this,option);
2492
2493 if (padsav) padsav->cd();
2494}
2495
2496////////////////////////////////////////////////////////////////////////////////
2497/// Dump contents of object on stdout.
2498/// Using the information in the object dictionary
2499/// each data member is interpreted.
2500/// If a data member is a pointer, the pointer value is printed
2501/// 'obj' is assume to point to an object of the class describe by this TClass
2502///
2503/// The following output is the Dump of a TArrow object:
2504/// ~~~ {.cpp}
2505/// fAngle 0 Arrow opening angle (degrees)
2506/// fArrowSize 0.2 Arrow Size
2507/// fOption.*fData
2508/// fX1 0.1 X of 1st point
2509/// fY1 0.15 Y of 1st point
2510/// fX2 0.67 X of 2nd point
2511/// fY2 0.83 Y of 2nd point
2512/// fUniqueID 0 object unique identifier
2513/// fBits 50331648 bit field status word
2514/// fLineColor 1 line color
2515/// fLineStyle 1 line style
2516/// fLineWidth 1 line width
2517/// fFillColor 19 fill area color
2518/// fFillStyle 1001 fill area style
2519/// ~~~
2520///
2521/// If noAddr is true, printout of all pointer values is skipped.
2522
2523void TClass::Dump(const void *obj, Bool_t noAddr /*=kFALSE*/) const
2524{
2525
2526 Longptr_t prObj = noAddr ? 0 : (Longptr_t)obj;
2527 if (IsTObject()) {
2528 if (!fIsOffsetStreamerSet) {
2530 }
2531 TObject *tobj = (TObject*)((Longptr_t)obj + fOffsetStreamer);
2532
2533
2534 if (sizeof(this) == 4)
2535 Printf("==> Dumping object at: 0x%08lx, name=%s, class=%s\n",prObj,tobj->GetName(),GetName());
2536 else
2537 Printf("==> Dumping object at: 0x%016lx, name=%s, class=%s\n",prObj,tobj->GetName(),GetName());
2538 } else {
2539
2540 if (sizeof(this) == 4)
2541 Printf("==> Dumping object at: 0x%08lx, class=%s\n",prObj,GetName());
2542 else
2543 Printf("==> Dumping object at: 0x%016lx, class=%s\n",prObj,GetName());
2544 }
2545
2546 TDumpMembers dm(noAddr);
2547 if (!CallShowMembers(obj, dm, kFALSE)) {
2548 Info("Dump", "No ShowMembers function, dumping disabled");
2549 }
2550}
2551
2552////////////////////////////////////////////////////////////////////////////////
2553/// Introduce an escape character (@) in front of a special chars.
2554/// You need to use the result immediately before it is being overwritten.
2555
2556char *TClass::EscapeChars(const char *text) const
2557{
2558 static const UInt_t maxsize = 255;
2559 static char name[maxsize+2]; //One extra if last char needs to be escaped
2560
2561 UInt_t nch = strlen(text);
2562 UInt_t icur = 0;
2563 for (UInt_t i = 0; i < nch && icur < maxsize; ++i, ++icur) {
2564 if (text[i] == '\"' || text[i] == '[' || text[i] == '~' ||
2565 text[i] == ']' || text[i] == '&' || text[i] == '#' ||
2566 text[i] == '!' || text[i] == '^' || text[i] == '<' ||
2567 text[i] == '?' || text[i] == '>') {
2568 name[icur] = '@';
2569 ++icur;
2570 }
2571 name[icur] = text[i];
2572 }
2573 name[icur] = 0;
2574 return name;
2575}
2576
2577////////////////////////////////////////////////////////////////////////////////
2578/// Return a pointer the the real class of the object.
2579/// This is equivalent to object->IsA() when the class has a ClassDef.
2580/// It is REQUIRED that object is coming from a proper pointer to the
2581/// class represented by 'this'.
2582/// Example: Special case:
2583/// ~~~ {.cpp}
2584/// class MyClass : public AnotherClass, public TObject
2585/// ~~~
2586/// then on return, one must do:
2587/// ~~~ {.cpp}
2588/// TObject *obj = (TObject*)((void*)myobject)directory->Get("some object of MyClass");
2589/// MyClass::Class()->GetActualClass(obj); // this would be wrong!!!
2590/// ~~~
2591/// Also if the class represented by 'this' and NONE of its parents classes
2592/// have a virtual ptr table, the result will be 'this' and NOT the actual
2593/// class.
2594
2595TClass *TClass::GetActualClass(const void *object) const
2596{
2597 if (object==nullptr) return (TClass*)this;
2598 if (fIsA) {
2599 return (*fIsA)(object); // ROOT::IsA((ThisClass*)object);
2600 } else if (fGlobalIsA) {
2601 return fGlobalIsA(this,object);
2602 } else {
2603 if (IsTObject()) {
2604
2605 if (!fIsOffsetStreamerSet) {
2607 }
2608 TObject* realTObject = (TObject*)((size_t)object + fOffsetStreamer);
2609
2610 return realTObject->IsA();
2611 }
2612
2613 if (HasInterpreterInfo()) {
2614
2615 TVirtualIsAProxy *isa = nullptr;
2617 isa = (TVirtualIsAProxy*)gROOT->ProcessLineFast(TString::Format("new ::TInstrumentedIsAProxy<%s>(0);",GetName()));
2618 }
2619 else {
2620 isa = (TVirtualIsAProxy*)gROOT->ProcessLineFast(TString::Format("new ::TIsAProxy(typeid(%s));",GetName()));
2621 }
2622 if (isa) {
2624 const_cast<TClass*>(this)->fIsA = isa;
2625 }
2626 if (fIsA) {
2627 return (*fIsA)(object); // ROOT::IsA((ThisClass*)object);
2628 }
2629 }
2631 if (sinfo) {
2632 return sinfo->GetActualClass(object);
2633 }
2634 return (TClass*)this;
2635 }
2636}
2637
2638////////////////////////////////////////////////////////////////////////////////
2639/// Return pointer to the base class "classname". Returns 0 in case
2640/// "classname" is not a base class. Takes care of multiple inheritance.
2641
2642TClass *TClass::GetBaseClass(const char *classname)
2643{
2644 // check if class name itself is equal to classname
2645 if (strcmp(GetName(), classname) == 0) return this;
2646
2647 if (!HasDataMemberInfo()) return nullptr;
2648
2649 // Make sure we deal with possible aliases, we could also have normalized
2650 // the name.
2651 TClass *search = TClass::GetClass(classname,kTRUE,kTRUE);
2652
2653 if (search) return GetBaseClass(search);
2654 else return nullptr;
2655}
2656
2657////////////////////////////////////////////////////////////////////////////////
2658/// Return pointer to the base class "cl". Returns 0 in case "cl"
2659/// is not a base class. Takes care of multiple inheritance.
2660
2662{
2663 // check if class name itself is equal to classname
2664 if (cl == this) return this;
2665
2666 if (!HasDataMemberInfo()) return nullptr;
2667
2668 TObjLink *lnk = GetListOfBases() ? fBase.load()->FirstLink() : nullptr;
2669
2670 // otherwise look at inheritance tree
2671 while (lnk) {
2672 TClass *c, *c1;
2673 TBaseClass *base = (TBaseClass*) lnk->GetObject();
2674 c = base->GetClassPointer();
2675 if (c) {
2676 if (cl == c) return c;
2677 c1 = c->GetBaseClass(cl);
2678 if (c1) return c1;
2679 }
2680 lnk = lnk->Next();
2681 }
2682 return nullptr;
2683}
2684
2685////////////////////////////////////////////////////////////////////////////////
2686/// Return data member offset to the base class "cl".
2687/// - Returns -1 in case "cl" is not a base class.
2688/// - Returns -2 if cl is a base class, but we can't find the offset
2689/// because it's virtual.
2690/// Takes care of multiple inheritance.
2691
2693{
2694 // check if class name itself is equal to classname
2695 if (cl == this) return 0;
2696
2697 if (!fBase.load()) {
2699 // If the information was not provided by the root pcm files and
2700 // if we can not find the ClassInfo, we have to fall back to the
2701 // StreamerInfo
2702 if (!fClassInfo) {
2704 if (!sinfo) return -1;
2705 TStreamerElement *element;
2706 Int_t offset = 0;
2707
2708 TObjArray &elems = *(sinfo->GetElements());
2709 Int_t size = elems.GetLast()+1;
2710 for(Int_t i=0; i<size; i++) {
2711 element = (TStreamerElement*)elems[i];
2712 if (element->IsBase()) {
2713 if (element->IsA() == TStreamerBase::Class()) {
2714 TStreamerBase *base = (TStreamerBase*)element;
2715 TClass *baseclass = base->GetClassPointer();
2716 if (!baseclass) return -1;
2717 Int_t subOffset = baseclass->GetBaseClassOffsetRecurse(cl);
2718 if (subOffset == -2) return -2;
2719 if (subOffset != -1) return offset+subOffset;
2720 offset += baseclass->Size();
2721 } else if (element->IsA() == TStreamerSTL::Class()) {
2722 TStreamerSTL *base = (TStreamerSTL*)element;
2723 TClass *baseclass = base->GetClassPointer();
2724 if (!baseclass) return -1;
2725 Int_t subOffset = baseclass->GetBaseClassOffsetRecurse(cl);
2726 if (subOffset == -2) return -2;
2727 if (subOffset != -1) return offset+subOffset;
2728 offset += baseclass->Size();
2729
2730 } else {
2731 Error("GetBaseClassOffsetRecurse","Unexpected element type for base class: %s\n",element->IsA()->GetName());
2732 }
2733 }
2734 }
2735 return -1;
2736 }
2737 }
2738
2739 TClass *c;
2740 Int_t off;
2741 TBaseClass *inh;
2742 TObjLink *lnk = nullptr;
2743 if (fBase.load() == nullptr)
2744 lnk = GetListOfBases()->FirstLink();
2745 else
2746 lnk = fBase.load()->FirstLink();
2747
2748 // otherwise look at inheritance tree
2749 while (lnk) {
2750 inh = (TBaseClass *)lnk->GetObject();
2751 //use option load=kFALSE to avoid a warning like:
2752 //"Warning in <TClass::TClass>: no dictionary for class TRefCnt is available"
2753 //We can not afford to not have the class if it exist, so we
2754 //use kTRUE.
2755 c = inh->GetClassPointer(kTRUE); // kFALSE);
2756 if (c) {
2757 if (cl == c) {
2758 if ((inh->Property() & kIsVirtualBase) != 0)
2759 return -2;
2760 return inh->GetDelta();
2761 }
2762 off = c->GetBaseClassOffsetRecurse(cl);
2763 if (off == -2) return -2;
2764 if (off != -1) {
2765 return off + inh->GetDelta();
2766 }
2767 }
2768 lnk = lnk->Next();
2769 }
2770 return -1;
2771}
2772
2773////////////////////////////////////////////////////////////////////////////////
2774/// - Return data member offset to the base class "cl".
2775/// - Returns -1 in case "cl" is not a base class.
2776/// Takes care of multiple inheritance.
2777
2778Int_t TClass::GetBaseClassOffset(const TClass *toBase, void *address, bool isDerivedObject)
2779{
2780 // Warning("GetBaseClassOffset","Requires the use of fClassInfo for %s to %s",GetName(),toBase->GetName());
2781
2782 if (this == toBase) return 0;
2783
2784 if ((!address /* || !has_virtual_base */) &&
2786 // At least of the ClassInfo have not been loaded in memory yet and
2787 // since there is no virtual base class (or we don't have enough so it
2788 // would not make a difference) we can use the 'static' information
2789 Int_t offset = GetBaseClassOffsetRecurse (toBase);
2790 if (offset != -2) {
2791 return offset;
2792 }
2793 return offset;
2794 }
2795
2796 ClassInfo_t* derived = GetClassInfo();
2797 ClassInfo_t* base = toBase->GetClassInfo();
2798 if(derived && base) {
2799 // TClingClassInfo::GetBaseOffset takes the lock.
2800 return gCling->ClassInfo_GetBaseOffset(derived, base, address, isDerivedObject);
2801 }
2802 else {
2803 Int_t offset = GetBaseClassOffsetRecurse (toBase);
2804 if (offset != -2) {
2805 return offset;
2806 }
2807 }
2808 return -1;
2809}
2810
2811////////////////////////////////////////////////////////////////////////////////
2812/// Return pointer to (base) class that contains datamember.
2813
2814TClass *TClass::GetBaseDataMember(const char *datamember)
2815{
2816 if (!HasDataMemberInfo()) return nullptr;
2817
2818 // Check if data member exists in class itself
2819 TDataMember *dm = GetDataMember(datamember);
2820 if (dm) return this;
2821
2822 // if datamember not found in class, search in next base classes
2823 TBaseClass *inh;
2824 TIter next(GetListOfBases());
2825 while ((inh = (TBaseClass *) next())) {
2826 TClass *c = inh->GetClassPointer();
2827 if (c) {
2828 TClass *cdm = c->GetBaseDataMember(datamember);
2829 if (cdm) return cdm;
2830 }
2831 }
2832
2833 return nullptr;
2834}
2835
2836namespace {
2837 // A local Helper class used to keep 2 pointer (the collection proxy
2838 // and the class streamer) in the thread local storage.
2839
2840 struct TClassLocalStorage {
2841 TClassLocalStorage() : fCollectionProxy(nullptr), fStreamer(nullptr) {};
2842
2843 TVirtualCollectionProxy *fCollectionProxy;
2844 TClassStreamer *fStreamer;
2845
2846 static TClassLocalStorage *GetStorage(const TClass *cl)
2847 {
2848 // Return the thread storage for the TClass.
2849
2850 void **thread_ptr = (*gThreadTsd)(nullptr,ROOT::kClassThreadSlot);
2851 if (thread_ptr) {
2852 if (*thread_ptr==nullptr) *thread_ptr = new TExMap();
2853 TExMap *lmap = (TExMap*)(*thread_ptr);
2854 ULong_t hash = TString::Hash(&cl, sizeof(void*));
2855 ULongptr_t local = 0;
2856 UInt_t slot;
2857 if ((local = (ULongptr_t)lmap->GetValue(hash, (Longptr_t)cl, slot)) != 0) {
2858 } else {
2859 local = (ULongptr_t) new TClassLocalStorage();
2860 lmap->AddAt(slot, hash, (Longptr_t)cl, local);
2861 }
2862 return (TClassLocalStorage*)local;
2863 }
2864 return nullptr;
2865 }
2866 };
2867}
2868
2869////////////////////////////////////////////////////////////////////////////////
2870/// Return the 'type' of the STL the TClass is representing.
2871/// and return ROOT::kNotSTL if it is not representing an STL collection.
2872
2874{
2875 auto proxy = GetCollectionProxy();
2876 if (proxy) return (ROOT::ESTLType)proxy->GetCollectionType();
2877 return ROOT::kNotSTL;
2878}
2879
2880
2881////////////////////////////////////////////////////////////////////////////////
2882/// Return the proxy describing the collection (if any).
2883
2885{
2886 // Use assert, so that this line (slow because of the TClassEdit) is completely
2887 // removed in optimized code.
2888 //assert(TestBit(kLoading) || !TClassEdit::IsSTLCont(fName) || fCollectionProxy || 0 == "The TClass for the STL collection has no collection proxy!");
2890 TClassLocalStorage *local = TClassLocalStorage::GetStorage(this);
2891 if (local == nullptr) return fCollectionProxy;
2892 if (local->fCollectionProxy==nullptr) local->fCollectionProxy = fCollectionProxy->Generate();
2893 return local->fCollectionProxy;
2894 }
2895 return fCollectionProxy;
2896}
2897
2898////////////////////////////////////////////////////////////////////////////////
2899/// Return the Streamer Class allowing streaming (if any).
2900
2902{
2903 if (gThreadTsd && fStreamer) {
2904 TClassLocalStorage *local = TClassLocalStorage::GetStorage(this);
2905 if (local==nullptr) return fStreamer;
2906 if (local->fStreamer==nullptr) {
2907 local->fStreamer = fStreamer->Generate();
2908 const std::type_info &orig = ( typeid(*fStreamer) );
2909 if (!local->fStreamer) {
2910 Warning("GetStreamer","For %s, the TClassStreamer (%s) passed's call to Generate failed!",GetName(),orig.name());
2911 } else {
2912 const std::type_info &copy = ( typeid(*local->fStreamer) );
2913 if (strcmp(orig.name(),copy.name())!=0) {
2914 Warning("GetStreamer","For %s, the TClassStreamer passed does not properly implement the Generate method (%s vs %s)\n",GetName(),orig.name(),copy.name());
2915 }
2916 }
2917 }
2918 return local->fStreamer;
2919 }
2920 return fStreamer;
2921}
2922
2923////////////////////////////////////////////////////////////////////////////////
2924/// Get a wrapper/accessor function around this class custom streamer (member function).
2925
2927{
2928 return fStreamerFunc;
2929}
2930
2931////////////////////////////////////////////////////////////////////////////////
2932/// Get a wrapper/accessor function around this class custom conversion streamer (member function).
2933
2935{
2936 return fConvStreamerFunc;
2937}
2938
2939////////////////////////////////////////////////////////////////////////////////
2940/// Return the proxy implementing the IsA functionality.
2941
2943{
2944 return fIsA;
2945}
2946
2947////////////////////////////////////////////////////////////////////////////////
2948/// Static method returning pointer to TClass of the specified class name.
2949/// If load is true an attempt is made to obtain the class by loading
2950/// the appropriate shared library (directed by the rootmap file).
2951/// If silent is 'true', do not warn about missing dictionary for the class.
2952/// (typically used for class that are used only for transient members)
2953/// Returns 0 in case class is not found.
2954
2955TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent)
2956{
2957 return TClass::GetClass(name, load, silent, 0, 0);
2958}
2959
2960TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent, size_t hint_pair_offset, size_t hint_pair_size)
2961{
2962 if (!name || !name[0]) return nullptr;
2963
2964 if (strstr(name, "(anonymous)")) return nullptr;
2965 if (strncmp(name,"class ",6)==0) name += 6;
2966 if (strncmp(name,"struct ",7)==0) name += 7;
2967
2968 if (!gROOT->GetListOfClasses()) return nullptr;
2969
2970 // FindObject will take the read lock before actually getting the
2971 // TClass pointer so we will need not get a partially initialized
2972 // object.
2973 TClass *cl = (TClass*)gROOT->GetListOfClasses()->FindObject(name);
2974
2975 // Early return to release the lock without having to execute the
2976 // long-ish normalization.
2977 if (cl && (cl->IsLoaded() || cl->TestBit(kUnloading))) return cl;
2978
2980
2981 // Now that we got the write lock, another thread may have constructed the
2982 // TClass while we were waiting, so we need to do the checks again.
2983
2984 cl = (TClass*)gROOT->GetListOfClasses()->FindObject(name);
2985 if (cl) {
2986 if (cl->IsLoaded() || cl->TestBit(kUnloading)) return cl;
2987
2988 // We could speed-up some of the search by adding (the equivalent of)
2989 //
2990 // if (cl->GetState() == kInterpreter) return cl
2991 //
2992 // In this case, if a ROOT dictionary was available when the TClass
2993 // was first requested it would have been used and if a ROOT dictionary is
2994 // loaded later on TClassTable::Add will take care of updating the TClass.
2995 // So as far as ROOT dictionary are concerned, if the current TClass is
2996 // in interpreted state, we are sure there is nothing to load.
2997 //
2998 // However (see TROOT::LoadClass), the TClass can also be loaded/provided
2999 // by a user provided TClassGenerator. We have no way of knowing whether
3000 // those do (or even can) behave the same way as the ROOT dictionary and
3001 // have the 'dictionary is now available for use' step informs the existing
3002 // TClass that their dictionary is now available.
3003
3004 //we may pass here in case of a dummy class created by TVirtualStreamerInfo
3005 load = kTRUE;
3006 }
3007
3009 // If there is a @ symbol (followed by a version number) then this is a synthetic class name created
3010 // from an already normalized name for the purpose of supporting schema evolution.
3011 // There is no dictionary or interpreter information about this kind of class, the only
3012 // (undesirable) side-effect of doing the search would be a waste of CPU time and potential
3013 // auto-loading or auto-parsing based on the scope of the name.
3014 return cl;
3015 }
3016
3017 // To avoid spurious auto parsing, let's check if the name as-is is
3018 // known in the TClassTable.
3020 if (dict) {
3021 // The name is normalized, so the result of the first search is
3022 // authoritative.
3023 if (!cl && !load) return nullptr;
3024
3025 TClass *loadedcl = (dict)();
3026 if (loadedcl) {
3027 loadedcl->PostLoadCheck();
3028 return loadedcl;
3029 }
3030
3031 // We should really not fall through to here, but if we do, let's just
3032 // continue as before ...
3033 }
3034
3035 std::string normalizedName;
3036 Bool_t checkTable = kFALSE;
3037
3038 if (!cl) {
3039 {
3041 TClassEdit::GetNormalizedName(normalizedName, name);
3042 }
3043 // Try the normalized name.
3044 if (normalizedName != name) {
3045 cl = (TClass*)gROOT->GetListOfClasses()->FindObject(normalizedName.c_str());
3046
3047 if (cl) {
3048 if (cl->IsLoaded() || cl->TestBit(kUnloading)) return cl;
3049
3050 //we may pass here in case of a dummy class created by TVirtualStreamerInfo
3051 load = kTRUE;
3052 }
3053 checkTable = kTRUE;
3054 }
3055 } else {
3056 normalizedName = cl->GetName(); // Use the fact that all TClass names are normalized.
3057 checkTable = load && (normalizedName != name);
3058 }
3059
3060 if (!load) return nullptr;
3061
3062// This assertion currently fails because of
3063// TClass *c1 = TClass::GetClass("basic_iostream<char,char_traits<char> >");
3064// TClass *c2 = TClass::GetClass("std::iostream");
3065// where the TClassEdit normalized name of iostream is basic_iostream<char>
3066// i.e missing the addition of the default parameter. This is because TClingLookupHelper
3067// uses only 'part' of TMetaUtils::GetNormalizedName.
3068
3069// if (!cl) {
3070// TDataType* dataType = (TDataType*)gROOT->GetListOfTypes()->FindObject(name);
3071// TClass *altcl = dataType ? (TClass*)gROOT->GetListOfClasses()->FindObject(dataType->GetFullTypeName()) : 0;
3072// if (altcl && normalizedName != altcl->GetName())
3073// ::Fatal("TClass::GetClass","The existing name (%s) for %s is different from the normalized name: %s\n",
3074// altcl->GetName(), name, normalizedName.c_str());
3075// }
3076
3077 // We want to avoid auto-parsing due to intentionally missing dictionary for std::pair.
3078 // However, we don't need this special treatement in rootcling (there is no auto-parsing)
3079 // and we want to make that the TClass for the pair goes through the regular creation
3080 // mechanism (i.e. in rootcling they should be in kInterpreted state and never in
3081 // kEmulated state) so that they have proper interpreter (ClassInfo) information which
3082 // will be used to create the TProtoClass (if one is requested for the pair).
3083 const bool ispair = TClassEdit::IsStdPair(normalizedName) && !IsFromRootCling();
3084 const bool ispairbase = TClassEdit::IsStdPairBase(normalizedName) && !IsFromRootCling();
3085
3086 TClass *loadedcl = nullptr;
3087 if (checkTable) {
3088 loadedcl = LoadClassDefault(normalizedName.c_str(),silent);
3089 } else {
3090 if (gInterpreter->AutoLoad(normalizedName.c_str(),kTRUE)) {
3091 loadedcl = LoadClassDefault(normalizedName.c_str(),silent);
3092 }
3093 auto e = TEnum::GetEnum(normalizedName.c_str(), TEnum::kNone);
3094 if (e)
3095 return nullptr;
3096 // Maybe this was a typedef: let's try to see if this is the case
3097 if (!loadedcl && !ispair && !ispairbase) {
3098 if (TDataType* theDataType = gROOT->GetType(normalizedName.c_str())){
3099 // We have a typedef: we get the name of the underlying type
3100 auto underlyingTypeName = theDataType->GetTypeName();
3101 // We see if we can bootstrap a class with it
3102 auto underlyingTypeDict = TClassTable::GetDictNorm(underlyingTypeName.Data());
3103 if (underlyingTypeDict){
3104 loadedcl = underlyingTypeDict();
3105 }
3106
3107 }
3108 }
3109 }
3110 if (loadedcl) return loadedcl;
3111
3112 // See if the TClassGenerator can produce the TClass we need.
3113 loadedcl = LoadClassCustom(normalizedName.c_str(),silent);
3114 if (loadedcl) return loadedcl;
3115
3116 // We have not been able to find a loaded TClass, return the Emulated
3117 // TClass if we have one.
3118 if (cl) return cl;
3119
3120 if (ispair && hint_pair_offset && hint_pair_size) {
3121 auto pairinfo = TVirtualStreamerInfo::Factory()->GenerateInfoForPair(normalizedName, silent, hint_pair_offset, hint_pair_size);
3122 //return pairinfo ? pairinfo->GetClass() : nullptr;
3123 if (pairinfo)
3124 return pairinfo->GetClass();
3125 } else if (TClassEdit::IsSTLCont( normalizedName.c_str() )) {
3126
3127 return gInterpreter->GenerateTClass(normalizedName.c_str(), kTRUE, silent);
3128 }
3129
3130 // Check the interpreter only after autoparsing the template if any.
3131 if (!ispairbase) {
3132 std::string::size_type posLess = normalizedName.find('<');
3133 if (posLess != std::string::npos) {
3134 gCling->AutoParse(normalizedName.substr(0, posLess).c_str());
3135 }
3136 }
3137
3138 //last attempt. Look in CINT list of all (compiled+interpreted) classes
3139 if (gDebug>0){
3140 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());
3141 }
3142 if (normalizedName.length()) {
3143 auto cci = gInterpreter->CheckClassInfo(normalizedName.c_str(), kTRUE /* autoload */,
3144 kTRUE /*Only class, structs and ns*/);
3145
3146 // We could have an interpreted class with an inline ClassDef, in this case we do not
3147 // want to create an 'interpreted' TClass but we want the one triggered via the call to
3148 // the Dictionary member. If we go ahead and generate the 'interpreted' version it will
3149 // replace if/when there is a call to IsA on an object of this type.
3150
3152 auto ci = gInterpreter->ClassInfo_Factory(normalizedName.c_str());
3153 auto funcDecl = gInterpreter->GetFunctionWithPrototype(ci, "Dictionary", "", false, ROOT::kExactMatch);
3154 auto method = gInterpreter->MethodInfo_Factory(funcDecl);
3155 typedef void (*tcling_callfunc_Wrapper_t)(void *, int, void **, void *);
3156 auto funcPtr = (tcling_callfunc_Wrapper_t)gInterpreter->MethodInfo_InterfaceMethod(method);
3157
3158 TClass *res = nullptr;
3159 if (funcPtr)
3160 funcPtr(nullptr, 0, nullptr, &res);
3161 // else
3162 // We could fallback to the interpreted case ...
3163 // For now just 'fail' (return nullptr)
3164
3165 gInterpreter->MethodInfo_Delete(method);
3166 gInterpreter->ClassInfo_Delete(ci);
3167
3168 return res;
3169 } else if (cci) {
3170 // Get the normalized name based on the decl (currently the only way
3171 // to get the part to add or drop the default arguments as requested by the user)
3172 std::string alternative;
3173 gInterpreter->GetInterpreterTypeName(normalizedName.c_str(), alternative, kTRUE);
3174 if (alternative.empty())
3175 return nullptr;
3176 const char *altname = alternative.c_str();
3177 if (strncmp(altname, "std::", 5) == 0) {
3178 // For namespace (for example std::__1), GetInterpreterTypeName does
3179 // not strip std::, so we must do it explicitly here.
3180 altname += 5;
3181 }
3182 if (altname != normalizedName && strcmp(altname, name) != 0) {
3183 // altname now contains the full name of the class including a possible
3184 // namespace if there has been a using namespace statement.
3185
3186 // At least in the case C<string [2]> (normalized) vs C<string[2]> (altname)
3187 // the TClassEdit normalization and the TMetaUtils normalization leads to
3188 // two different space layout. To avoid an infinite recursion, we also
3189 // add the test on (altname != name)
3190
3191 return GetClass(altname, load);
3192 }
3193
3194 TClass *ncl = gInterpreter->GenerateTClass(normalizedName.c_str(), /* emulation = */ kFALSE, silent);
3195 if (!ncl->IsZombie()) {
3196 return ncl;
3197 }
3198 delete ncl;
3199 }
3200 }
3201 return nullptr;
3202}
3203
3204////////////////////////////////////////////////////////////////////////////////
3205/// Return pointer to class with name.
3206
3207TClass *TClass::GetClass(const std::type_info& typeinfo, Bool_t load, Bool_t /* silent */, size_t hint_pair_offset, size_t hint_pair_size)
3208{
3209 if (!gROOT->GetListOfClasses())
3210 return nullptr;
3211
3212 //protect access to TROOT::GetIdMap
3214
3215 TClass* cl = GetIdMap()->Find(typeinfo.name());
3216
3217 if (cl && cl->IsLoaded()) return cl;
3218
3220
3221 // Now that we got the write lock, another thread may have constructed the
3222 // TClass while we were waiting, so we need to do the checks again.
3223
3224 cl = GetIdMap()->Find(typeinfo.name());
3225
3226 if (cl) {
3227 if (cl->IsLoaded()) return cl;
3228 //we may pass here in case of a dummy class created by TVirtualStreamerInfo
3229 load = kTRUE;
3230 } else {
3231 // Note we might need support for typedefs and simple types!
3232
3233 // TDataType *objType = GetType(name, load);
3234 //if (objType) {
3235 // const char *typdfName = objType->GetTypeName();
3236 // if (typdfName && strcmp(typdfName, name)) {
3237 // cl = GetClass(typdfName, load);
3238 // return cl;
3239 // }
3240 // }
3241 }
3242
3243 if (!load) return nullptr;
3244
3245 DictFuncPtr_t dict = TClassTable::GetDict(typeinfo);
3246 if (dict) {
3247 cl = (dict)();
3248 if (cl) cl->PostLoadCheck();
3249 return cl;
3250 }
3251 if (cl) return cl;
3252
3253 TIter next(gROOT->GetListOfClassGenerators());
3254 TClassGenerator *gen;
3255 while( (gen = (TClassGenerator*) next()) ) {
3256 cl = gen->GetClass(typeinfo,load);
3257 if (cl) {
3258 cl->PostLoadCheck();
3259 return cl;
3260 }
3261 }
3262
3263 // try AutoLoading the typeinfo
3264 int autoload_old = gCling->SetClassAutoLoading(1);
3265 if (!autoload_old) {
3266 // Re-disable, we just meant to test
3268 }
3269 if (autoload_old && gInterpreter->AutoLoad(typeinfo,kTRUE)) {
3270 // Disable autoload to avoid potential infinite recursion
3272 cl = GetClass(typeinfo, load, hint_pair_offset, hint_pair_size);
3273 if (cl) {
3274 return cl;
3275 }
3276 }
3277
3278 if (hint_pair_offset) {
3279 int err = 0;
3280 char* demangled_name = TClassEdit::DemangleTypeIdName(typeinfo, err);
3281 if (!err) {
3282 cl = TClass::GetClass(demangled_name, load, kTRUE, hint_pair_offset, hint_pair_size);
3283 free(demangled_name);
3284 if (cl)
3285 return cl;
3286 }
3287 }
3288
3289 // last attempt. Look in the interpreter list of all (compiled+interpreted)
3290 // classes
3291 cl = gInterpreter->GetClass(typeinfo, load);
3292
3293 return cl; // Can be zero.
3294}
3295
3296////////////////////////////////////////////////////////////////////////////////
3297/// Static method returning pointer to TClass of the specified ClassInfo.
3298/// If load is true an attempt is made to obtain the class by loading
3299/// the appropriate shared library (directed by the rootmap file).
3300/// If silent is 'true', do not warn about missing dictionary for the class.
3301/// (typically used for class that are used only for transient members)
3302/// Returns 0 in case class is not found.
3303
3304TClass *TClass::GetClass(ClassInfo_t *info, Bool_t load, Bool_t silent)
3305{
3306 if (!info || !gCling->ClassInfo_IsValid(info)) return nullptr;
3307 if (!gROOT->GetListOfClasses()) return nullptr;
3308
3309 // Technically we need the write lock only for the call to ClassInfo_FullName
3310 // and GenerateTClass but FindObject will take the read lock (and LoadClass will
3311 // take the write lock). Since taking/releasing the lock is expensive, let just
3312 // take the write guard and keep it.
3314
3315 // Get the normalized name.
3317
3318 TClass *cl = (TClass*)gROOT->GetListOfClasses()->FindObject(name);
3319
3320 if (cl) {
3321 if (cl->IsLoaded()) return cl;
3322
3323 //we may pass here in case of a dummy class created by TVirtualStreamerInfo
3324 load = kTRUE;
3325
3326 }
3327
3328 if (!load) return nullptr;
3329
3330 TClass *loadedcl = nullptr;
3331 if (cl) loadedcl = gROOT->LoadClass(cl->GetName(),silent);
3332 else loadedcl = gROOT->LoadClass(name,silent);
3333
3334 if (loadedcl) return loadedcl;
3335
3336 if (cl) return cl; // If we found the class but we already have a dummy class use it.
3337
3338 // We did not find a proper TClass but we do know (we have a valid
3339 // ClassInfo) that the class is known to the interpreter.
3340 TClass *ncl = gInterpreter->GenerateTClass(info, silent);
3341 if (!ncl->IsZombie()) {
3342 return ncl;
3343 } else {
3344 delete ncl;
3345 return nullptr;
3346 }
3347}
3348
3349////////////////////////////////////////////////////////////////////////////////
3350
3353}
3354
3355////////////////////////////////////////////////////////////////////////////////
3356
3357Bool_t TClass::GetClass(DeclId_t id, std::vector<TClass*> &classes)
3358{
3359 if (!gROOT->GetListOfClasses()) return 0;
3360
3361 DeclIdMap_t* map = GetDeclIdMap();
3362 // Get all the TClass pointer that have the same DeclId.
3363 DeclIdMap_t::equal_range iter = map->Find(id);
3364 if (iter.first == iter.second) return false;
3365 std::vector<TClass*>::iterator vectIt = classes.begin();
3366 for (DeclIdMap_t::const_iterator it = iter.first; it != iter.second; ++it)
3367 vectIt = classes.insert(vectIt, it->second);
3368 return true;
3369}
3370
3371////////////////////////////////////////////////////////////////////////////////
3372/// Return a pointer to the dictionary loading function generated by
3373/// rootcint
3374
3376{
3377 return TClassTable::GetDict(cname);
3378}
3379
3380////////////////////////////////////////////////////////////////////////////////
3381/// Return a pointer to the dictionary loading function generated by
3382/// rootcint
3383
3384DictFuncPtr_t TClass::GetDict (const std::type_info& info)
3385{
3386 return TClassTable::GetDict(info);
3387}
3388
3389////////////////////////////////////////////////////////////////////////////////
3390/// Return pointer to datamember object with name "datamember".
3391
3392TDataMember *TClass::GetDataMember(const char *datamember) const
3393{
3394 if ((!(fData.load() && (*fData).IsLoaded()) && !HasInterpreterInfo())
3395 || datamember == nullptr) return nullptr;
3396
3397 // Strip off leading *'s and trailing [
3398 const char *start_name = datamember;
3399 while (*start_name == '*') ++start_name;
3400
3401 // Empty name are 'legal', they represent anonymous unions.
3402 // if (*start_name == 0) return 0;
3403
3404 if (const char *s = strchr(start_name, '[')){
3405 UInt_t len = s-start_name;
3406 TString name(start_name,len);
3407 return (TDataMember *)((TClass*)this)->GetListOfDataMembers(kFALSE)->FindObject(name.Data());
3408 } else {
3409 return (TDataMember *)((TClass*)this)->GetListOfDataMembers(kFALSE)->FindObject(start_name);
3410 }
3411}
3412
3413////////////////////////////////////////////////////////////////////////////////
3414/// Return name of the file containing the declaration of this class.
3415
3416const char *TClass::GetDeclFileName() const
3417{
3418 if (fDeclFileName == kUndeterminedClassInfoName)
3419 return gInterpreter->ClassInfo_FileName( fClassInfo );
3420 return fDeclFileName;
3421}
3422
3423////////////////////////////////////////////////////////////////////////////////
3424/// return offset for member name. name can be a data member in
3425/// the class itself, one of its base classes, or one member in
3426/// one of the aggregated classes.
3427///
3428/// In case of an emulated class, the list of emulated TRealData is built
3429
3431{
3432 TRealData *rd = GetRealData(name);
3433 if (rd) return rd->GetThisOffset();
3434 if (strchr(name,'[')==nullptr) {
3435 // If this is a simple name there is a chance to find it in the
3436 // StreamerInfo even if we did not find it in the RealData.
3437 // For example an array name would be fArray[3] in RealData but
3438 // just fArray in the streamerInfo.
3439 TVirtualStreamerInfo *info = const_cast<TClass*>(this)->GetCurrentStreamerInfo();
3440 if (info) {
3441 return info->GetOffset(name);
3442 }
3443 }
3444 return 0;
3445}
3446
3447////////////////////////////////////////////////////////////////////////////////
3448/// Return pointer to TRealData element with name "name".
3449///
3450/// Name can be a data member in the class itself,
3451/// one of its base classes, or a member in
3452/// one of the aggregated classes.
3453///
3454/// In case of an emulated class, the list of emulated TRealData is built.
3455
3457{
3458 if (!fRealData) {
3459 const_cast<TClass*>(this)->BuildRealData();
3460 }
3461
3462 if (!fRealData) {
3463 return nullptr;
3464 }
3465
3466 if (!name) {
3467 return nullptr;
3468 }
3469
3470 // First try just the whole name.
3472 if (rd) {
3473 return rd;
3474 }
3475
3476 std::string givenName(name);
3477
3478 // Try ignoring the array dimensions.
3479 std::string::size_type firstBracket = givenName.find_first_of("[");
3480 if (firstBracket != std::string::npos) {
3481 // -- We are looking for an array data member.
3482 std::string nameNoDim(givenName.substr(0, firstBracket));
3483 TObjLink* lnk = fRealData->FirstLink();
3484 while (lnk) {
3485 TObject* obj = lnk->GetObject();
3486 std::string objName(obj->GetName());
3487 std::string::size_type pos = objName.find_first_of("[");
3488 // Only match arrays to arrays for now.
3489 if (pos != std::string::npos) {
3490 objName.erase(pos);
3491 if (objName == nameNoDim) {
3492 return static_cast<TRealData*>(obj);
3493 }
3494 }
3495 lnk = lnk->Next();
3496 }
3497 }
3498
3499 // Now try it as a pointer.
3500 std::ostringstream ptrname;
3501 ptrname << "*" << givenName;
3502 rd = (TRealData*) fRealData->FindObject(ptrname.str().c_str());
3503 if (rd) {
3504 return rd;
3505 }
3506
3507 // Check for a dot in the name.
3508 std::string::size_type firstDot = givenName.find_first_of(".");
3509 if (firstDot == std::string::npos) {
3510 // -- Not found, a simple name, all done.
3511 return nullptr;
3512 }
3513
3514 //
3515 // At this point the name has a dot in it, so it is the name
3516 // of some contained sub-object.
3517 //
3518
3519 // May be a pointer like in TH1: fXaxis.fLabels (in TRealdata is named fXaxis.*fLabels)
3520 std::string::size_type lastDot = givenName.find_last_of(".");
3521 std::ostringstream starname;
3522 starname << givenName.substr(0, lastDot) << ".*" << givenName.substr(lastDot + 1);
3523 rd = (TRealData*) fRealData->FindObject(starname.str().c_str());
3524 if (rd) {
3525 return rd;
3526 }
3527
3528 // Strip the first component, it may be the name of
3529 // the branch (old TBranchElement code), and try again.
3530 std::string firstDotName(givenName.substr(firstDot + 1));
3531
3532 // New attempt starting after the first "." if any,
3533 // this allows for the case that the first component
3534 // may have been a branch name (for TBranchElement).
3535 rd = (TRealData*) fRealData->FindObject(firstDotName.c_str());
3536 if (rd) {
3537 return rd;
3538 }
3539
3540 // New attempt starting after the first "." if any,
3541 // but this time try ignoring the array dimensions.
3542 // Again, we are allowing for the case that the first
3543 // component may have been a branch name (for TBranchElement).
3544 std::string::size_type firstDotBracket = firstDotName.find_first_of("[");
3545 if (firstDotBracket != std::string::npos) {
3546 // -- We are looking for an array data member.
3547 std::string nameNoDim(firstDotName.substr(0, firstDotBracket));
3548 TObjLink* lnk = fRealData->FirstLink();
3549 while (lnk) {
3550 TObject* obj = lnk->GetObject();
3551 std::string objName(obj->GetName());
3552 std::string::size_type pos = objName.find_first_of("[");
3553 // Only match arrays to arrays for now.
3554 if (pos != std::string::npos) {
3555 objName.erase(pos);
3556 if (objName == nameNoDim) {
3557 return static_cast<TRealData*>(obj);
3558 }
3559 }
3560 lnk = lnk->Next();
3561 }
3562 }
3563
3564 // New attempt starting after the first "." if any,
3565 // but this time check for a pointer type. Again, we
3566 // are allowing for the case that the first component
3567 // may have been a branch name (for TBranchElement).
3568 ptrname.str("");
3569 ptrname << "*" << firstDotName;
3570 rd = (TRealData*) fRealData->FindObject(ptrname.str().c_str());
3571 if (rd) {
3572 return rd;
3573 }
3574
3575 // Last attempt in case a member has been changed from
3576 // a static array to a pointer, for example the member
3577 // was arr[20] and is now *arr.
3578 //
3579 // Note: In principle, one could also take into account
3580 // the opposite situation where a member like *arr has
3581 // been converted to arr[20].
3582 //
3583 // FIXME: What about checking after the first dot as well?
3584 //
3585 std::string::size_type bracket = starname.str().find_first_of("[");
3586 if (bracket == std::string::npos) {
3587 return nullptr;
3588 }
3589 rd = (TRealData*) fRealData->FindObject(starname.str().substr(0, bracket).c_str());
3590 if (rd) {
3591 return rd;
3592 }
3593
3594 // Not found;
3595 return nullptr;
3596}
3597
3598////////////////////////////////////////////////////////////////////////////////
3599
3601{
3602 if (!gInterpreter || !HasInterpreterInfo()) return nullptr;
3603
3604 // The following
3606
3608}
3609
3610////////////////////////////////////////////////////////////////////////////////
3611/// Get the list of shared libraries containing the code for class cls.
3612/// The first library in the list is the one containing the class, the
3613/// others are the libraries the first one depends on. Returns 0
3614/// in case the library is not found.
3615
3617{
3618 if (!gInterpreter) return nullptr;
3619
3620 if (fSharedLibs.IsNull())
3621 fSharedLibs = gInterpreter->GetClassSharedLibs(fName);
3622
3623 return !fSharedLibs.IsNull() ? fSharedLibs.Data() : nullptr;
3624}
3625
3626////////////////////////////////////////////////////////////////////////////////
3627/// Return list containing the TBaseClass(es) of a class.
3628
3630{
3631 if (!fBase.load()) {
3632 if (fCanLoadClassInfo) {
3633 if (fState == kHasTClassInit) {
3634
3636 if (!fHasRootPcmInfo) {
3637 // The bases are in our ProtoClass; we don't need the class info.
3639 if (proto && proto->FillTClass(this))
3640 return fBase;
3641 }
3642 }
3643 // We test again on fCanLoadClassInfo has another thread may have executed it.
3645 LoadClassInfo();
3646 }
3647 }
3648 if (!fClassInfo)
3649 return nullptr;
3650
3651 if (!gInterpreter)
3652 Fatal("GetListOfBases", "gInterpreter not initialized");
3653
3655 if (!fBase.load()) {
3656 gInterpreter->CreateListOfBaseClasses(this);
3657 }
3658 }
3659 return fBase;
3660}
3661
3662////////////////////////////////////////////////////////////////////////////////
3663/// Return a list containing the TEnums of a class.
3664///
3665/// The list returned is safe to use from multiple thread without explicitly
3666/// taking the ROOT global lock.
3667///
3668/// In the case the TClass represents a namespace, the returned list will
3669/// implicit take the ROOT global lock upon any access (see TListOfEnumsWithLock)
3670///
3671/// In the case the TClass represents a class or struct and requestListLoading
3672/// is true, the list is immutable (and thus safe to access from multiple thread
3673/// without taking the global lock at all).
3674///
3675/// In the case the TClass represents a class or struct and requestListLoading
3676/// is false, the list is mutable and thus we return a TListOfEnumsWithLock
3677/// which will implicit take the ROOT global lock upon any access.
3678
3679TList *TClass::GetListOfEnums(Bool_t requestListLoading /* = kTRUE */)
3680{
3681 auto temp = fEnums.load();
3682 if (temp) {
3683 if (requestListLoading) {
3684 if (fProperty == -1) Property();
3685 if (! ((kIsClass | kIsStruct | kIsUnion) & fProperty) ) {
3687 temp->Load();
3688 } else if ( temp->IsA() == TListOfEnumsWithLock::Class() ) {
3689 // We have a class for which the list was not loaded fully at
3690 // first use.
3692 temp->Load();
3693 }
3694 }
3695 return temp;
3696 }
3697
3698 if (!requestListLoading) {
3699 if (fProperty == -1) Property();
3701 if (fEnums.load()) {
3702 return fEnums.load();
3703 }
3704
3705 if (IsFromRootCling()) // rootcling is single thread (this save some space in the rootpcm).
3706 fEnums = new TListOfEnums(this);
3707 else
3708 fEnums = new TListOfEnumsWithLock(this);
3709 return fEnums;
3710 }
3711
3713 if (fEnums.load()) {
3714 (*fEnums).Load();
3715 return fEnums.load();
3716 }
3717 if (fProperty == -1) Property();
3718 if ( (kIsClass | kIsStruct | kIsUnion) & fProperty) {
3719 // For this case, the list will be immutable
3720 temp = new TListOfEnums(this);
3721 } else {
3722 //namespaces can have enums added to them
3723 temp = new TListOfEnumsWithLock(this);
3724 }
3725 temp->Load();
3726 fEnums = temp;
3727 return temp;
3728}
3729
3730////////////////////////////////////////////////////////////////////////////////
3731/// Create the list containing the TDataMembers (of actual data members or members
3732/// pulled in through using declarations) of a class.
3733
3734TList *TClass::CreateListOfDataMembers(std::atomic<TListOfDataMembers*> &data, TDictionary::EMemberSelection selection, bool load)
3735{
3737
3738 if (!data) {
3740 // The members are in our ProtoClass; we don't need the class info.
3742 if (proto && proto->FillTClass(this))
3743 return data;
3744 }
3745
3746 data = new TListOfDataMembers(this, selection);
3747 }
3748 if (IsClassStructOrUnion()) {
3749 // If the we have a class or struct or union, the order
3750 // of data members is the list is essential since it determines their
3751 // order on file. So we must always load. Also, the list is fixed
3752 // since the language does not allow to add members.
3753 if (!(*data).IsLoaded())
3754 (*data).Load();
3755
3756 } else if (load) (*data).Load();
3757 return data;
3758}
3759
3760////////////////////////////////////////////////////////////////////////////////
3761/// Return list containing the TDataMembers of a class.
3762
3764{
3765 // Fast path, no lock? Classes load at creation time.
3766 if (IsClassStructOrUnion()) {
3767 auto data = fData.load();
3768 if (data && data->IsLoaded())
3769 return data;
3770 } else if (!load && fData)
3771 return fData;
3772
3774}
3775
3776////////////////////////////////////////////////////////////////////////////////
3777/// Return list containing the TDataMembers of using declarations of a class.
3778
3780{
3781 // Fast path, no lock? Classes load at creation time.
3782 if ((!load || IsClassStructOrUnion()) && fUsingData)
3783 return fUsingData;
3784
3786}
3787
3788////////////////////////////////////////////////////////////////////////////////
3789/// Return TListOfFunctionTemplates for a class.
3790
3792{
3794
3796 if (load) fFuncTemplate->Load();
3797 return fFuncTemplate;
3798}
3799
3800////////////////////////////////////////////////////////////////////////////////
3801/// Return list containing the TMethods of a class.
3802/// If load is true, the list is populated with all the defined function
3803/// and currently instantiated function template.
3804
3806{
3808
3809 if (!fMethod.load()) GetMethodList();
3810 if (load) {
3811 if (gDebug>0) Info("GetListOfMethods","Header Parsing - Asking for all the methods of class %s: this can involve parsing.",GetName());
3812 (*fMethod).Load();
3813 }
3814 return fMethod;
3815}
3816
3817////////////////////////////////////////////////////////////////////////////////
3818/// Return the collection of functions named "name".
3819
3821{
3822 return const_cast<TClass*>(this)->GetMethodList()->GetListForObject(name);
3823}
3824
3825
3826////////////////////////////////////////////////////////////////////////////////
3827/// Returns a list of all public methods of this class and its base classes.
3828/// Refers to a subset of the methods in GetListOfMethods() so don't do
3829/// GetListOfAllPublicMethods()->Delete().
3830/// Algorithm used to get the list is:
3831/// - put all methods of the class in the list (also protected and private
3832/// ones).
3833/// - loop over all base classes and add only those methods not already in the
3834/// list (also protected and private ones).
3835/// - once finished, loop over resulting list and remove all private and
3836/// protected methods.
3837
3839{
3841
3843 if (load) {
3844 if (gDebug>0) Info("GetListOfAllPublicMethods","Header Parsing - Asking for all the methods of class %s: this can involve parsing.",GetName());
3846 }
3847 return fAllPubMethod;
3848}
3849
3850////////////////////////////////////////////////////////////////////////////////
3851/// Returns a list of all public data members of this class and its base
3852/// classes. Refers to a subset of the data members in GetListOfDatamembers()
3853/// so don't do GetListOfAllPublicDataMembers()->Delete().
3854
3856{
3858
3860 if (load) fAllPubData->Load();
3861 return fAllPubData;
3862}
3863
3864////////////////////////////////////////////////////////////////////////////////
3865/// Returns list of methods accessible by context menu.
3866
3868{
3869 if (!HasInterpreterInfo()) return;
3870
3871 // get the base class
3872 TIter nextBase(GetListOfBases(), kIterBackward);
3873 TBaseClass *baseClass;
3874 while ((baseClass = (TBaseClass *) nextBase())) {
3875 TClass *base = baseClass->GetClassPointer();
3876 if (base) base->GetMenuItems(list);
3877 }
3878
3879 // remove methods redefined in this class with no menu
3880 TMethod *method, *m;
3882 while ((method = (TMethod*)next())) {
3883 m = (TMethod*)list->FindObject(method->GetName());
3884 if (method->IsMenuItem() != kMenuNoMenu) {
3885 if (!m)
3886 list->AddFirst(method);
3887 } else {
3888 if (m && m->GetNargs() == method->GetNargs())
3889 list->Remove(m);
3890 }
3891 }
3892}
3893
3894////////////////////////////////////////////////////////////////////////////////
3895/// Check whether a class has a dictionary or not.
3896/// This is equivalent to ask if a class is coming from a bootstrapping
3897/// procedure initiated during the loading of a library.
3898
3900{
3901 return IsLoaded();
3902}
3903
3904////////////////////////////////////////////////////////////////////////////////
3905/// Check whether a class has a dictionary or ROOT can load one.
3906/// This is equivalent to ask HasDictionary() or whether a library is known
3907/// where it can be loaded from, or whether a Dictionary function is
3908/// available because the class's dictionary library was already loaded.
3909
3911{
3912 if (TClass* cl = (TClass*)gROOT->GetListOfClasses()->FindObject(clname))
3913 return cl->IsLoaded();
3914 return gClassTable->GetDict(clname) || gInterpreter->GetClassSharedLibs(clname);
3915}
3916
3917////////////////////////////////////////////////////////////////////////////////
3918/// Verify the base classes always.
3919
3921{
3922 TList* lb = GetListOfBases();
3923 if (!lb) return;
3924 TIter nextBase(lb);
3925 TBaseClass* base = nullptr;
3926 while ((base = (TBaseClass*)nextBase())) {
3927 TClass* baseCl = base->GetClassPointer();
3928 if (baseCl) {
3929 baseCl->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3930 }
3931 }
3932}
3933
3934////////////////////////////////////////////////////////////////////////////////
3935/// Verify the Data Members.
3936
3938{
3940 if (!ldm) return ;
3941 TIter nextMemb(ldm);
3942 TDataMember * dm = nullptr;
3943 while ((dm = (TDataMember*)nextMemb())) {
3944 // If it is a transient
3945 if(!dm->IsPersistent()) {
3946 continue;
3947 }
3948 if (dm->Property() & kIsStatic) {
3949 continue;
3950 }
3951 // If it is a built-in data type.
3952 TClass* dmTClass = nullptr;
3953 if (dm->GetDataType()) {
3954 // We have a basic datatype.
3955 dmTClass = nullptr;
3956 // Otherwise get the string representing the type.
3957 } else if (dm->GetTypeName()) {
3958 dmTClass = TClass::GetClass(dm->GetTypeName());
3959 }
3960 if (dmTClass) {
3961 dmTClass->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3962 }
3963 }
3964}
3965
3967{
3968 // Pair is a special case and we have to check its elements for missing dictionaries
3969 // Pair is a transparent container so we should always look at its.
3970
3972 for (int i = 0; i < 2; i++) {
3973 TClass* pairElement = ((TStreamerElement*)SI->GetElements()->At(i))->GetClass();
3974 if (pairElement) {
3975 pairElement->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3976 }
3977 }
3978}
3979
3980////////////////////////////////////////////////////////////////////////////////
3981/// From the second level of recursion onwards it is different state check.
3982
3984{
3985 if (result.FindObject(this) || visited.FindObject(this)) return;
3986
3987 static TClassRef sCIString("string");
3988 if (this == sCIString) return;
3989
3990 TClassEdit::TSplitType splitType(fName);
3991 if (splitType.IsTemplate()) {
3992 // We now treat special cases:
3993 // - pair
3994 // - unique_ptr
3995 // - array
3996 // - tuple
3997
3998 // Small helper to get the TClass instance from a classname and recursively
3999 // investigate it
4000 auto checkDicts = [&](const string &clName){
4001 auto cl = TClass::GetClass(clName.c_str());
4002 if (!cl) {
4003 // We try to remove * and const from the type name if any
4004 const auto clNameShortType = TClassEdit::ShortType(clName.c_str(), 1);
4005 cl = TClass::GetClass(clNameShortType.c_str());
4006 }
4007 if (cl && !cl->HasDictionary()) {
4008 cl->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
4009 }
4010 };
4011
4012 const auto &elements = splitType.fElements;
4013 const auto &templName = elements[0];
4014
4015 // Special treatment for pair.
4016 if (templName == "pair") {
4017 GetMissingDictionariesForPairElements(result, visited, recurse);
4018 return;
4019 }
4020
4021 // Special treatment of unique_ptr or array
4022 // They are treated together since they have 1 single template argument
4023 // which is interesting when checking for missing dictionaries.
4024 if (templName == "unique_ptr" || templName == "array") {
4025 checkDicts(elements[1]);
4026 return;
4027 }
4028
4029 // Special treatment of tuple
4030 // This type must be treated separately since it can have N template
4031 // arguments which are interesting, unlike unique_ptr or array.
4032 if (templName == "tuple") {
4033 // -1 because the elements end with a list of the "stars", i.e. number of
4034 // * after the type name
4035 const auto nTemplArgs = elements.size() - 1;
4036 // loop starts at 1 because the first element is the template name
4037 for (auto iTemplArg = 1U; iTemplArg < nTemplArgs; ++iTemplArg) {
4038 checkDicts(elements[iTemplArg]);
4039 }
4040 return;
4041 }
4042 } // this is not a template
4043
4044 if (!HasDictionary()) {
4045 result.Add(this);
4046 }
4047
4048 visited.Add(this);
4049 //Check whether a custom streamer
4051 if (GetCollectionProxy()) {
4052 // We need to look at the collection's content
4053 // The collection has different kind of elements the check would be required.
4054 TClass* t = nullptr;
4055 if ((t = GetCollectionProxy()->GetValueClass())) {
4056 if (!t->HasDictionary()) {
4057 t->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
4058 }
4059 }
4060 } else {
4061 if (recurse) {
4062 GetMissingDictionariesForMembers(result, visited, recurse);
4063 }
4064 GetMissingDictionariesForBaseClasses(result, visited, recurse);
4065 }
4066 }
4067}
4068
4069////////////////////////////////////////////////////////////////////////////////
4070/// Get the classes that have a missing dictionary starting from this one.
4071/// - With recurse = false the classes checked for missing dictionaries are:
4072/// the class itself, all base classes, direct data members,
4073/// and for collection proxies the container's
4074/// elements without iterating over the element's data members;
4075/// - With recurse = true the classes checked for missing dictionaries are:
4076/// the class itself, all base classes, recursing on the data members,
4077/// and for the collection proxies recursion on the elements of the
4078/// collection and iterating over the element's data members.
4079
4081{
4082 // Top level recursion it different from the following levels of recursion.
4083
4084 if (result.FindObject(this)) return;
4085
4086 static TClassRef sCIString("string");
4087 if (this == sCIString) return;
4088
4089 THashTable visited;
4090
4092 GetMissingDictionariesForPairElements(result, visited, recurse);
4093 return;
4094 }
4095
4096 if (strncmp(fName, "unique_ptr<", 11) == 0 || strncmp(fName, "array<", 6) == 0 || strncmp(fName, "tuple<", 6) == 0) {
4097 GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
4098 return;
4099 }
4100
4101 if (!HasDictionary()) {
4102 result.Add(this);
4103 }
4104
4105 visited.Add(this);
4106
4107 //Check whether a custom streamer
4109 if (GetCollectionProxy()) {
4110 // We need to look at the collection's content
4111 // The collection has different kind of elements the check would be required.
4112 TClass* t = nullptr;
4113 if ((t = GetCollectionProxy()->GetValueClass())) {
4114 if (!t->HasDictionary()) {
4115 t->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
4116 }
4117 }
4118 } else {
4119 GetMissingDictionariesForMembers(result, visited, recurse);
4120 GetMissingDictionariesForBaseClasses(result, visited, recurse);
4121 }
4122 }
4123}
4124
4125////////////////////////////////////////////////////////////////////////////////
4126/// Return kTRUE if the class has elements.
4127
4128Bool_t TClass::IsFolder(void *obj) const
4129{
4130 return Browse(obj,(TBrowser*)nullptr);
4131}
4132
4133//______________________________________________________________________________
4134//______________________________________________________________________________
4135void TClass::ReplaceWith(TClass *newcl) const
4136{
4137 // Inform the other objects to replace this object by the new TClass (newcl)
4138
4140 //we must update the class pointers pointing to 'this' in all TStreamerElements
4141 TIter nextClass(gROOT->GetListOfClasses());
4142 TClass *acl;
4144
4145 // Since we are in the process of replacing a TClass by a TClass
4146 // coming from a dictionary, there is no point in loading any
4147 // libraries during this search.
4149 while ((acl = (TClass*)nextClass())) {
4150 if (acl == newcl) continue;
4151
4152 TIter nextInfo(acl->GetStreamerInfos());
4153 while ((info = (TVirtualStreamerInfo*)nextInfo())) {
4154
4155 info->Update(this, newcl);
4156 }
4157 }
4158
4159 gInterpreter->UnRegisterTClassUpdate(this);
4160}
4161
4162////////////////////////////////////////////////////////////////////////////////
4163/// Make sure that the current ClassInfo is up to date.
4164
4166{
4167 Warning("ResetClassInfo(Long_t tagnum)","Call to deprecated interface (does nothing)");
4168}
4169
4170////////////////////////////////////////////////////////////////////////////////
4171/// Make sure that the current ClassInfo is up to date.
4172
4174{
4176
4178
4179 if (fClassInfo) {
4181 gInterpreter->ClassInfo_Delete(fClassInfo);
4182 fClassInfo = nullptr;
4183 }
4184 // We can not check at this point whether after the unload there will
4185 // still be interpreter information about this class (as v5 was doing),
4186 // instead this function must only be called if the definition is (about)
4187 // to be unloaded.
4188
4189 ResetCaches();
4190
4191 // We got here because the definition Decl is about to be unloaded.
4193 if (fStreamerInfo->GetEntries() != 0) {
4195 } else {
4197 }
4198 } else {
4199 // if the ClassInfo was loaded for a class with a TClass Init and it
4200 // gets unloaded, should we guess it can be reloaded?
4202 }
4203}
4204
4205////////////////////////////////////////////////////////////////////////////////
4206/// To clean out all caches.
4207
4209{
4210 R__ASSERT(!TestBit(kLoading) && "Resetting the caches does not make sense during loading!" );
4211
4212 // Not owning lists, don't call Delete(), but unload
4213 if (fData.load())
4214 (*fData).Unload();
4215 if (fUsingData.load())
4216 (*fUsingData).Unload();
4217 if (fEnums.load())
4218 (*fEnums).Unload();
4219 if (fMethod.load())
4220 (*fMethod).Unload();
4221
4222 delete fAllPubData; fAllPubData = nullptr;
4223
4224 if (fBase.load())
4225 (*fBase).Delete();
4226 delete fBase.load(); fBase = nullptr;
4227
4228 if (fRealData)
4229 fRealData->Delete();
4230 delete fRealData; fRealData=nullptr;
4231}
4232
4233////////////////////////////////////////////////////////////////////////////////
4234/// Resets the menu list to it's standard value.
4235
4237{
4238 if (fClassMenuList)
4240 else
4241 fClassMenuList = new TList();
4243}
4244
4245////////////////////////////////////////////////////////////////////////////////
4246/// The ls function lists the contents of a class on stdout. Ls output
4247/// is typically much less verbose then Dump().
4248/// If options contains 'streamerinfo', run ls on the list of streamerInfos
4249/// and the list of conversion streamerInfos.
4250
4251void TClass::ls(Option_t *options) const
4252{
4253 TNamed::ls(options);
4254 if (options==nullptr || options[0]==0) return;
4255
4256 if (strstr(options,"streamerinfo")!=nullptr) {
4257 GetStreamerInfos()->ls(options);
4258
4259 if (fConversionStreamerInfo.load()) {
4260 std::map<std::string, TObjArray*>::iterator it;
4261 std::map<std::string, TObjArray*>::iterator end = (*fConversionStreamerInfo).end();
4262 for( it = (*fConversionStreamerInfo).begin(); it != end; ++it ) {
4263 it->second->ls(options);
4264 }
4265 }
4266 }
4267}
4268
4269////////////////////////////////////////////////////////////////////////////////
4270/// Makes a customizable version of the popup menu list, i.e. makes a list
4271/// of TClassMenuItem objects of methods accessible by context menu.
4272/// The standard (and different) way consists in having just one element
4273/// in this list, corresponding to the whole standard list.
4274/// Once the customizable version is done, one can remove or add elements.
4275
4277{
4279 TClassMenuItem *menuItem;
4280
4281 // Make sure fClassMenuList is initialized and empty.
4282 GetMenuList()->Delete();
4283
4284 TList* methodList = new TList;
4285 GetMenuItems(methodList);
4286
4287 TMethod *method;
4288 TMethodArg *methodArg;
4289 TClass *classPtr = nullptr;
4290 TIter next(methodList);
4291
4292 while ((method = (TMethod*) next())) {
4293 // if go to a mother class method, add separator
4294 if (classPtr != method->GetClass()) {
4295 menuItem = new TClassMenuItem(TClassMenuItem::kPopupSeparator, this);
4296 fClassMenuList->AddLast(menuItem);
4297 classPtr = method->GetClass();
4298 }
4299 // Build the signature of the method
4300 TString sig;
4301 TList* margsList = method->GetListOfMethodArgs();
4302 TIter nextarg(margsList);
4303 while ((methodArg = (TMethodArg*)nextarg())) {
4304 sig = sig+","+methodArg->GetFullTypeName();
4305 }
4306 if (sig.Length()!=0) sig.Remove(0,1); // remove first comma
4308 method->GetName(), method->GetName(),nullptr,
4309 sig.Data(),-1,TClassMenuItem::kIsSelf);
4310 if (method->IsMenuItem() == kMenuToggle) menuItem->SetToggle();
4311 fClassMenuList->Add(menuItem);
4312 }
4313 delete methodList;
4314}
4315
4316////////////////////////////////////////////////////////////////////////////////
4317/// Register the fact that an object was moved from the memory location
4318/// 'arenaFrom' to the memory location 'arenaTo'.
4319
4320void TClass::Move(void *arenaFrom, void *arenaTo) const
4321{
4322 // If/when we have access to a copy constructor (or better to a move
4323 // constructor), this function should also perform the data move.
4324 // For now we just information the repository.
4325
4326 if ((GetState() <= kEmulated) && !fCollectionProxy) {
4327 MoveAddressInRepository("TClass::Move",arenaFrom,arenaTo,this);
4328 }
4329}
4330
4331////////////////////////////////////////////////////////////////////////////////
4332/// Return the list of menu items associated with the class.
4333
4335 if (!fClassMenuList) {
4336 fClassMenuList = new TList();
4338 }
4339 return fClassMenuList;
4340}
4341
4342////////////////////////////////////////////////////////////////////////////////
4343/// Return (create an empty one if needed) the list of functions.
4344/// The major difference with GetListOfMethod is that this returns
4345/// the internal type of fMethod and thus can not be made public.
4346/// It also never 'loads' the content of the list.
4347
4349{
4350 if (!fMethod.load()) {
4351 std::unique_ptr<TListOfFunctions> temp{ new TListOfFunctions(this) };
4352 TListOfFunctions* expected = nullptr;
4353 if(fMethod.compare_exchange_strong(expected, temp.get()) ) {
4354 temp.release();
4355 }
4356 }
4357 return fMethod;
4358}
4359
4360
4361////////////////////////////////////////////////////////////////////////////////
4362/// Return pointer to method without looking at parameters.
4363/// Does not look in (possible) base classes.
4364/// Has the side effect of loading all the TMethod object in the list
4365/// of the class.
4366
4367TMethod *TClass::GetMethodAny(const char *method)
4368{
4369 if (!HasInterpreterInfo()) return nullptr;
4370 return (TMethod*) GetMethodList()->FindObject(method);
4371}
4372
4373////////////////////////////////////////////////////////////////////////////////
4374/// Return pointer to method without looking at parameters.
4375/// Does look in all base classes.
4376
4378{
4379 if (!HasInterpreterInfo()) return nullptr;
4380
4381 TMethod* m = GetMethodAny(method);
4382 if (m) return m;
4383
4384 TBaseClass *base;
4385 TIter nextb(GetListOfBases());
4386 while ((base = (TBaseClass *) nextb())) {
4387 TClass *c = base->GetClassPointer();
4388 if (c) {
4389 m = c->GetMethodAllAny(method);
4390 if (m) return m;
4391 }
4392 }
4393
4394 return nullptr;
4395}
4396
4397////////////////////////////////////////////////////////////////////////////////
4398/// Find the best method (if there is one) matching the parameters.
4399/// The params string must contain argument values, like "3189, \"aap\", 1.3".
4400/// The function invokes GetClassMethod to search for a possible method
4401/// in the class itself or in its base classes. Returns 0 in case method
4402/// is not found.
4403
4404TMethod *TClass::GetMethod(const char *method, const char *params,
4405 Bool_t objectIsConst /* = kFALSE */)
4406{
4408 if (!fClassInfo) return nullptr;
4409
4410 if (!gInterpreter)
4411 Fatal("GetMethod", "gInterpreter not initialized");
4412
4413 TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithValues(fClassInfo,
4414 method, params,
4415 objectIsConst);
4416
4417 if (!decl) return nullptr;
4418
4419 // search recursively in this class or its base classes
4421 if (f) return f;
4422
4423 Error("GetMethod",
4424 "\nDid not find matching TMethod <%s> with \"%s\" %sfor %s",
4425 method,params,objectIsConst ? "const " : "", GetName());
4426 return nullptr;
4427}
4428
4429
4430////////////////////////////////////////////////////////////////////////////////
4431/// Find a method with decl id in this class or its bases.
4432
4434 if (TFunction* method = GetMethodList()->Get(declId))
4435 return static_cast<TMethod *>(method);
4436
4437 for (auto item : *GetListOfBases())
4438 if (auto base = static_cast<TBaseClass *>(item)->GetClassPointer())
4439 if (TFunction* method = base->FindClassOrBaseMethodWithId(declId))
4440 return static_cast<TMethod *>(method);
4441
4442 return nullptr;
4443}
4444
4445////////////////////////////////////////////////////////////////////////////////
4446/// Find the method with a given prototype. The proto string must be of the
4447/// form: "char*,int,double". Returns 0 in case method is not found.
4448
4449TMethod *TClass::GetMethodWithPrototype(const char *method, const char *proto,
4450 Bool_t objectIsConst /* = kFALSE */,
4451 ROOT::EFunctionMatchMode mode /* = ROOT::kConversionMatch */)
4452{
4454 if (!fClassInfo) return nullptr;
4455
4456 if (!gInterpreter)
4457 Fatal("GetMethodWithPrototype", "gInterpreter not initialized");
4458
4459 TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithPrototype(fClassInfo,
4460 method, proto,
4461 objectIsConst, mode);
4462
4463 if (!decl) return nullptr;
4465 if (f) return f;
4466 Error("GetMethodWithPrototype",
4467 "\nDid not find matching TMethod <%s> with \"%s\" %sfor %s",
4468 method,proto,objectIsConst ? "const " : "", GetName());
4469 return nullptr;
4470}
4471
4472////////////////////////////////////////////////////////////////////////////////
4473/// Look for a method in this class that has the interface function
4474/// address faddr.
4475
4477{
4478 if (!HasInterpreterInfo()) return nullptr;
4479
4480 TMethod *m;
4481 TIter next(GetListOfMethods());
4482 while ((m = (TMethod *) next())) {
4483 if (faddr == (Longptr_t)m->InterfaceMethod())
4484 return m;
4485 }
4486 return nullptr;
4487}
4488
4489////////////////////////////////////////////////////////////////////////////////
4490/// Look for a method in this class that has the name and matches the parameters.
4491/// The params string must contain argument values, like "3189, \"aap\", 1.3".
4492/// Returns 0 in case method is not found.
4493/// See TClass::GetMethod to also search the base classes.
4494
4495TMethod *TClass::GetClassMethod(const char *name, const char* params,
4496 Bool_t objectIsConst /* = kFALSE */)
4497{
4499 if (!fClassInfo) return nullptr;
4500
4501 if (!gInterpreter)
4502 Fatal("GetClassMethod", "gInterpreter not initialized");
4503
4504 TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithValues(fClassInfo,
4505 name, params,
4506 objectIsConst);
4507
4508 if (!decl) return nullptr;
4509
4510 TFunction *f = GetMethodList()->Get(decl);
4511
4512 return (TMethod*)f; // Could be zero if the decl is actually in a base class.
4513}
4514
4515////////////////////////////////////////////////////////////////////////////////
4516/// Find the method with a given prototype. The proto string must be of the
4517/// form: "char*,int,double". Returns 0 in case method is not found.
4518/// See TClass::GetMethodWithPrototype to also search the base classes.
4519
4521 Bool_t objectIsConst /* = kFALSE */,
4522 ROOT::EFunctionMatchMode mode /* = ROOT::kConversionMatch */)
4523{
4525 if (!fClassInfo) return nullptr;
4526
4527 if (!gInterpreter)
4528 Fatal("GetClassMethodWithPrototype", "gInterpreter not initialized");
4529
4530 TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithPrototype(fClassInfo,
4531 name, proto,
4532 objectIsConst,
4533 mode);
4534
4535 if (!decl) return nullptr;
4536
4537 TFunction *f = GetMethodList()->Get(decl);
4538
4539 return (TMethod*)f; // Could be zero if the decl is actually in a base class.
4540}
4541
4542////////////////////////////////////////////////////////////////////////////////
4543/// Return the number of data members of this class
4544/// Note that in case the list of data members is not yet created, it will be done
4545/// by GetListOfDataMembers().
4546
4548{
4549 if (!HasDataMemberInfo()) return 0;
4550
4552 if (lm)
4553 return lm->GetSize();
4554 else
4555 return 0;
4556}
4557
4558////////////////////////////////////////////////////////////////////////////////
4559/// Return the number of methods of this class
4560/// Note that in case the list of methods is not yet created, it will be done
4561/// by GetListOfMethods().
4562/// This will also load/populate the list of methods, to get 'just' the
4563/// number of currently loaded methods use:
4564/// cl->GetListOfMethods(false)->GetSize();
4565
4567{
4568 if (!HasInterpreterInfo()) return 0;
4569
4570 TList *lm = GetListOfMethods();
4571 if (lm)
4572 return lm->GetSize();
4573 else
4574 return 0;
4575}
4576
4577////////////////////////////////////////////////////////////////////////////////
4578/// returns a pointer to the TVirtualStreamerInfo object for version
4579/// If the object does not exist, it is created
4580///
4581/// Note: There are two special version numbers:
4582///
4583/// - 0: Use the class version from the currently loaded class library.
4584/// - -1: Assume no class library loaded (emulated class).
4585///
4586/// Warning: If we create a new streamer info, whether or not the build
4587/// optimizes is controlled externally to us by a global variable!
4588/// Don't call us unless you have set that variable properly
4589/// with TStreamer::Optimize()!
4590///
4591
4592TVirtualStreamerInfo* TClass::GetStreamerInfo(Int_t version /* = 0 */, Bool_t isTransient /* = false */) const
4593{
4595
4596 // Version 0 is special, it means the currently loaded version.
4597 // We need to set it at the beginning to be able to guess it correctly.
4598
4599 if (version == 0)
4600 version = fClassVersion;
4601
4602 // If the StreamerInfo is assigned to the fLastReadInfo, we are
4603 // guaranteed it was built and compiled.
4604 if (sinfo && sinfo->GetClassVersion() == version)
4605 return sinfo;
4606
4607 // Note that the access to fClassVersion above is technically not thread-safe with a low probably of problems.
4608 // fClassVersion is not an atomic and is modified TClass::SetClassVersion (called from RootClassVersion via
4609 // ROOT::ResetClassVersion) and is 'somewhat' protected by the atomic fVersionUsed.
4610 // However, direct access to fClassVersion should be replaced by calls to GetClassVersion to set fVersionUsed.
4611 // Even with such a change the code here and in these functions need to be reviewed as a cursory look seem
4612 // to indicates they are not yet properly protection against mutli-thread access.
4613 //
4614 // However, the use of these functions is rare and mostly done at library loading time which should
4615 // in almost all cases preceeds the possibility of GetStreamerInfo being called from multiple thread
4616 // on that same TClass object.
4617 //
4618 // Summary: need careful review but risk of problem is extremely low.
4619
4621
4622 return GetStreamerInfoImpl(version, isTransient);
4623};
4624
4625// Implementation of/for TStreamerInfo::GetStreamerInfo.
4626// This routine assumes the global lock has been taken.
4628{
4629 // Warning: version may be -1 for an emulated class, or -2 if the
4630 // user requested the emulated streamerInfo for an abstract
4631 // base class, even though we have a dictionary for it.
4632
4633 if ((version < -1) || (version >= fStreamerInfo->GetSize())) {
4634 Error("GetStreamerInfo", "class: %s, attempting to access a wrong version: %d", GetName(), version);
4635 // FIXME: Shouldn't we go to -1 here, or better just abort?
4636 version = fClassVersion;
4637 }
4638
4640
4641 if (!sinfo && (version != fClassVersion)) {
4642 // When the requested version does not exist we return
4643 // the TVirtualStreamerInfo for the currently loaded class version.
4644 // FIXME: This arguably makes no sense, we should warn and return nothing instead.
4645 // Note: This is done for STL collections
4646 // Note: fClassVersion could be -1 here (for an emulated class).
4647 // This is also the code path take for unversioned classes.
4649 }
4650
4651 if (!sinfo) {
4652 // We just were not able to find a streamer info, we have to make a new one.
4653 TMmallocDescTemp setreset;
4654 sinfo = TVirtualStreamerInfo::Factory()->NewInfo(const_cast<TClass*>(this));
4656 if (gDebug > 0) {
4657 printf("Creating StreamerInfo for class: %s, version: %d\n", GetName(), fClassVersion);
4658 }
4660 // If we do not have a StreamerInfo for this version and we do not
4661 // have dictionary information nor a proxy, there is nothing to build!
4662 sinfo->Build(silent);
4663 }
4664 } else {
4665 if (!sinfo->IsCompiled()) {
4666 // Streamer info has not been compiled, but exists.
4667 // Therefore it was read in from a file and we have to do schema evolution?
4668 // Or it didn't have a dictionary before, but does now?
4669 sinfo->BuildOld();
4670 }
4671 }
4672
4673 // Cache the current info if we now have it.
4674 if (version == fClassVersion)
4675 fCurrentInfo = sinfo;
4676
4677 // If the compilation succeeded, remember this StreamerInfo.
4678 if (sinfo->IsCompiled())
4679 fLastReadInfo = sinfo;
4680
4681 return sinfo;
4682}
4683
4684////////////////////////////////////////////////////////////////////////////////
4685/// For the case where the requestor class is emulated and this class is abstract,
4686/// returns a pointer to the TVirtualStreamerInfo object for version with an emulated
4687/// representation whether or not the class is loaded.
4688///
4689/// If the object does not exist, it is created
4690///
4691/// Note: There are two special version numbers:
4692///
4693/// - 0: Use the class version from the currently loaded class library.
4694/// - -1: Assume no class library loaded (emulated class).
4695///
4696/// Warning: If we create a new streamer info, whether or not the build
4697/// optimizes is controlled externally to us by a global variable!
4698/// Don't call us unless you have set that variable properly
4699/// with TStreamer::Optimize()!
4700///
4701
4703{
4704 TVirtualStreamerInfo *sinfo = nullptr;
4705
4706 TString newname(GetName());
4707 newname += "@@emulated";
4708
4710
4711 TClass *emulated = TClass::GetClass(newname);
4712
4713 if (emulated)
4714 sinfo = emulated->GetStreamerInfo(version);
4715
4716 if (!sinfo) {
4717 // The emulated version of the streamerInfo is explicitly requested and has
4718 // not been built yet.
4719
4720 sinfo = (TVirtualStreamerInfo*) fStreamerInfo->At(version);
4721
4722 if (!sinfo && (version != fClassVersion)) {
4723 // When the requested version does not exist we return
4724 // the TVirtualStreamerInfo for the currently loaded class version.
4725 // FIXME: This arguably makes no sense, we should warn and return nothing instead.
4727 }
4728
4729 if (!sinfo) {
4730 // Let's take the first available StreamerInfo as a start
4731 Int_t ninfos = fStreamerInfo->GetEntriesFast() - 1;
4732 for (Int_t i = -1; sinfo == nullptr && i < ninfos; ++i)
4734 }
4735
4736 if (sinfo) {
4737 sinfo = dynamic_cast<TVirtualStreamerInfo *>(sinfo->Clone());
4738 if (sinfo) {
4739 sinfo->SetClass(nullptr);
4740 sinfo->SetName(newname);
4741 sinfo->BuildCheck();
4742 sinfo->BuildOld();
4743 sinfo->GetClass()->AddRule(TString::Format("sourceClass=%s targetClass=%s",GetName(),newname.Data()));
4744 } else {
4745 Error("GetStreamerInfoAbstractEmulated", "could not create TVirtualStreamerInfo");
4746 }
4747 }
4748 }
4749 return sinfo;
4750}
4751
4752////////////////////////////////////////////////////////////////////////////////
4753/// For the case where the requestor class is emulated and this class is abstract,
4754/// returns a pointer to the TVirtualStreamerInfo object for version with an emulated
4755/// representation whether or not the class is loaded.
4756///
4757/// If the object does not exist, it is created
4758///
4759/// Warning: If we create a new streamer info, whether or not the build
4760/// optimizes is controlled externally to us by a global variable!
4761/// Don't call us unless you have set that variable properly
4762/// with TStreamer::Optimize()!
4763///
4764
4766{
4767 TVirtualStreamerInfo *sinfo = nullptr;
4768
4769 TString newname(GetName());
4770 newname += "@@emulated";
4771
4773
4774 TClass *emulated = TClass::GetClass(newname);
4775
4776 if (emulated)
4777 sinfo = emulated->FindStreamerInfo(checksum);
4778
4779 if (!sinfo) {
4780 // The emulated version of the streamerInfo is explicitly requested and has
4781 // not been built yet.
4782
4783 sinfo = (TVirtualStreamerInfo*) FindStreamerInfo(checksum);
4784
4785 if (!sinfo && (checksum != fCheckSum)) {
4786 // When the requested version does not exist we return
4787 // the TVirtualStreamerInfo for the currently loaded class version.
4788 // FIXME: This arguably makes no sense, we should warn and return nothing instead.
4790 }
4791
4792 if (!sinfo) {
4793 // Let's take the first available StreamerInfo as a start
4794 Int_t ninfos = fStreamerInfo->GetEntriesFast() - 1;
4795 for (Int_t i = -1; sinfo == nullptr && i < ninfos; ++i)
4797 }
4798
4799 if (sinfo) {
4800 sinfo = dynamic_cast<TVirtualStreamerInfo*>( sinfo->Clone() );
4801 if (sinfo) {
4802 sinfo->SetClass(nullptr);
4803 sinfo->SetName( newname );
4804 sinfo->BuildCheck();
4805 sinfo->BuildOld();
4806 sinfo->GetClass()->AddRule(TString::Format("sourceClass=%s targetClass=%s",GetName(),newname.Data()));
4807 } else {
4808 Error("GetStreamerInfoAbstractEmulated", "could not create TVirtualStreamerInfo");
4809 }
4810 }
4811 }
4812 return sinfo;
4813}
4814
4815////////////////////////////////////////////////////////////////////////////////
4816/// When the class kIgnoreTObjectStreamer bit is set, the automatically
4817/// generated Streamer will not call TObject::Streamer.
4818/// This option saves the TObject space overhead on the file.
4819/// However, the information (fBits, fUniqueID) of TObject is lost.
4820///
4821/// Note that to be effective for objects streamed object-wise this function
4822/// must be called for the class deriving directly from TObject, eg, assuming
4823/// that BigTrack derives from Track and Track derives from TObject, one must do:
4824/// ~~~ {.cpp}
4825/// Track::Class()->IgnoreTObjectStreamer();
4826/// ~~~
4827/// and not:
4828/// ~~~ {.cpp}
4829/// BigTrack::Class()->IgnoreTObjectStreamer();
4830/// ~~~
4831/// To be effective for object streamed member-wise or split in a TTree,
4832/// this function must be called for the most derived class (i.e. BigTrack).
4833
4835{
4836 // We need to tak the lock since we are test and then setting fBits
4837 // and TStreamerInfo::fBits (and the StreamerInfo state in general)
4838 // which can also be modified by another thread.
4840
4841 if ( doIgnore && TestBit(kIgnoreTObjectStreamer)) return;
4842 if (!doIgnore && !TestBit(kIgnoreTObjectStreamer)) return;
4844 if (sinfo) {
4845 if (sinfo->IsCompiled()) {
4846 // -- Warn the user that what they are doing cannot work.
4847 // Note: The reason is that TVirtualStreamerInfo::Build() examines
4848 // the kIgnoreTObjectStreamer bit and sets the TStreamerElement
4849 // type for the TObject base class streamer element it creates
4850 // to -1 as a flag. Later on the TStreamerInfo::Compile()
4851 // member function sees the flag and does not insert the base
4852 // class element into the compiled streamer info. None of this
4853 // machinery works correctly if we are called after the streamer
4854 // info has already been built and compiled.
4855 Error("IgnoreTObjectStreamer","Must be called before the creation of StreamerInfo");
4856 return;
4857 }
4858 }
4859 if (doIgnore) SetBit (kIgnoreTObjectStreamer);
4861}
4862
4863////////////////////////////////////////////////////////////////////////////////
4864/// Return kTRUE if this class inherits from a class with name "classname".
4865/// note that the function returns kTRUE in case classname is the class itself
4866
4867Bool_t TClass::InheritsFrom(const char *classname) const
4868{
4869 if (strcmp(GetName(), classname) == 0) return kTRUE;
4870
4871 return InheritsFrom(TClass::GetClass(classname,kTRUE,kTRUE));
4872}
4873
4874////////////////////////////////////////////////////////////////////////////////
4875/// Return kTRUE if this class inherits from class cl.
4876/// note that the function returns KTRUE in case cl is the class itself
4877
4879{
4880 if (!cl) return kFALSE;
4881 if (cl == this) return kTRUE;
4882
4883 if (!HasDataMemberInfo()) {
4884 TVirtualStreamerInfo *sinfo = ((TClass *)this)->GetCurrentStreamerInfo();
4885 if (sinfo==nullptr) sinfo = GetStreamerInfo();
4886 TIter next(sinfo->GetElements());
4887 TStreamerElement *element;
4888 while ((element = (TStreamerElement*)next())) {
4889 if (element->IsA() == TStreamerBase::Class()) {
4890 TClass *clbase = element->GetClassPointer();
4891 if (!clbase) return kFALSE; //missing class
4892 if (clbase->InheritsFrom(cl)) return kTRUE;
4893 }
4894 }
4895 return kFALSE;
4896 }
4897 // cast const away (only for member fBase which can be set in GetListOfBases())
4898 if (((TClass *)this)->GetBaseClass(cl)) return kTRUE;
4899 return kFALSE;
4900}
4901
4902////////////////////////////////////////////////////////////////////////////////
4903/// Cast obj of this class type up to baseclass cl if up is true.
4904/// Cast obj of this class type down from baseclass cl if up is false.
4905/// If this class is not a baseclass of cl return 0, else the pointer
4906/// to the cl part of this (up) or to this (down).
4907
4908void *TClass::DynamicCast(const TClass *cl, void *obj, Bool_t up)
4909{
4910 if (cl == this) return obj;
4911
4912 if (!HasDataMemberInfo()) return nullptr;
4913
4914 Int_t off;
4915 if ((off = GetBaseClassOffset(cl, obj)) != -1) {
4916 if (up)
4917 return (void*)((Longptr_t)obj+off);
4918 else
4919 return (void*)((Longptr_t)obj-off);
4920 }
4921 return nullptr;
4922}
4923
4924////////////////////////////////////////////////////////////////////////////////
4925/// Cast obj of this class type up to baseclass cl if up is true.
4926/// Cast obj of this class type down from baseclass cl if up is false.
4927/// If this class is not a baseclass of cl return 0, else the pointer
4928/// to the cl part of this (up) or to this (down).
4929
4930const void *TClass::DynamicCast(const TClass *cl, const void *obj, Bool_t up)
4931{
4932 return DynamicCast(cl,const_cast<void*>(obj),up);
4933}
4934
4935////////////////////////////////////////////////////////////////////////////////
4936/// Return a pointer to a newly allocated object of this class.
4937/// The class must have a default constructor. For meaning of
4938/// defConstructor, see TClass::IsCallingNew().
4939///
4940/// If quiet is true, do no issue a message via Error on case
4941/// of problems, just return 0.
4942///
4943/// The constructor actually called here can be customized by
4944/// using the rootcint pragma:
4945/// ~~~ {.cpp}
4946/// #pragma link C++ ioctortype UserClass;
4947/// ~~~
4948/// For example, with this pragma and a class named MyClass,
4949/// this method will called the first of the following 3
4950/// constructors which exists and is public:
4951/// ~~~ {.cpp}
4952/// MyClass(UserClass*);
4953/// MyClass(TRootIOCtor*);
4954/// MyClass(); // Or a constructor with all its arguments defaulted.
4955/// ~~~
4956///
4957/// When more than one pragma ioctortype is used, the first seen as priority
4958/// For example with:
4959/// ~~~ {.cpp}
4960/// #pragma link C++ ioctortype UserClass1;
4961/// #pragma link C++ ioctortype UserClass2;
4962/// ~~~
4963/// We look in the following order:
4964/// ~~~ {.cpp}
4965/// MyClass(UserClass1*);
4966/// MyClass(UserClass2*);
4967/// MyClass(TRootIOCtor*);
4968/// MyClass(); // Or a constructor with all its arguments defaulted.
4969/// ~~~
4970
4971void *TClass::New(ENewType defConstructor, Bool_t quiet) const
4972{
4973 auto obj = NewObject(defConstructor, quiet);
4974 if (obj.GetPtr() && obj.GetAllocator()) {
4975 // Register the object for special handling in the destructor.
4976 RegisterAddressInRepository("TClass::New", obj.GetPtr(), this);
4977 }
4978 return obj.GetPtr();
4979}
4980
4981// See TClass:New
4982// returns a TClass::ObjectPtr which remembers if the object was allocated
4983// via a TStreamerInfo.
4984
4986{
4987 ObjectPtr p;
4988
4989 if (fNew) {
4990 // We have the new operator wrapper function,
4991 // so there is a dictionary and it was generated
4992 // by rootcint, so there should be a default
4993 // constructor we can call through the wrapper.
4994 {
4995 TClass__GetCallingNewRAII callingNew(defConstructor);
4996 p = fNew(nullptr);
4997 }
4998 if (!p && !quiet) {
4999 //Error("New", "cannot create object of class %s version %d", GetName(), fClassVersion);
5000 Error("New", "cannot create object of class %s", GetName());
5001 }
5002 } else if (HasInterpreterInfo()) {
5003 // We have the dictionary but do not have the
5004 // constructor wrapper, so the dictionary was
5005 // not generated by rootcint. Let's try to
5006 // create the object by having the interpreter
5007 // call the new operator, hopefully the class
5008 // library is loaded and there will be a default
5009 // constructor we can call.
5010 // [This is very unlikely to work, but who knows!]
5011 {
5012 TClass__GetCallingNewRAII callingNew(defConstructor);
5014 }
5015 if (!p && !quiet) {
5016 //Error("New", "cannot create object of class %s version %d", GetName(), fClassVersion);
5017 Error("New", "cannot create object of class %s", GetName());
5018 }
5019 } else if (!HasInterpreterInfo() && fCollectionProxy) {
5020 // There is no dictionary at all, so this is an emulated
5021 // class; however we do have the services of a collection proxy,
5022 // so this is an emulated STL class.
5023 {
5024 TClass__GetCallingNewRAII callingNew(defConstructor);
5026 }
5027 if (!p && !quiet) {
5028 //Error("New", "cannot create object of class %s version %d", GetName(), fClassVersion);
5029 Error("New", "cannot create object of class %s", GetName());
5030 }
5031 } else if (!HasInterpreterInfo() && !fCollectionProxy) {
5032 // There is no dictionary at all and we do not have
5033 // the services of a collection proxy available, so
5034 // use the streamer info to approximate calling a
5035 // constructor (basically we just make sure that the
5036 // pointer data members are null, unless they are marked
5037 // as preallocated with the "->" comment, in which case
5038 // we default-construct an object to point at).
5039
5040 // Do not register any TObject's that we create