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