Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
clingwrapper.cxx
Go to the documentation of this file.
1#ifndef WIN32
2#ifndef _CRT_SECURE_NO_WARNINGS
3// silence warnings about getenv, strncpy, etc.
4#define _CRT_SECURE_NO_WARNINGS
5#endif
6#endif
7
8// Bindings
9#include "precommondefs.h"
10#include "cpp_cppyy.h"
11#include "callcontext.h"
12
13// ROOT
14#include "TBaseClass.h"
15#include "TClass.h"
16#include "TClassRef.h"
17#include "TClassTable.h"
18#include "TClassEdit.h"
19#include "TCollection.h"
20#include "TDataMember.h"
21#include "TDataType.h"
22#include "TEnum.h"
23#include "TEnumConstant.h"
24#include "TEnv.h"
25#include "TError.h"
26#include "TException.h"
27#include "TFunction.h"
28#include "TFunctionTemplate.h"
29#include "TGlobal.h"
30#include "THashList.h"
31#include "TInterpreter.h"
32#include "TList.h"
33#include "TListOfDataMembers.h"
34#include "TListOfEnums.h"
35#include "TMethod.h"
36#include "TMethodArg.h"
37#include "TROOT.h"
38#include "TSystem.h"
39#include "TThread.h"
40
41// Standard
42#include <cassert>
43#include <algorithm> // for std::count, std::remove
44#include <climits>
45#include <stdexcept>
46#include <map>
47#include <new>
48#include <set>
49#include <sstream>
50#include <csignal>
51#include <cstdlib> // for getenv
52#include <cstring>
53#include <typeinfo>
54
55#if defined(__arm64__)
56#include <exception>
57#include <setjmp.h>
58#define CLING_CATCH_UNCAUGHT_ \
59ARMUncaughtException guard; \
60if (setjmp(gExcJumBuf) == 0) {
61#define _CLING_CATCH_UNCAUGHT \
62} else { \
63 if (!std::getenv("CPPYY_UNCAUGHT_QUIET")) \
64 std::cerr << "Warning: uncaught exception in JIT is rethrown; resources may leak" \
65 << " (suppress with \"CPPYY_UNCAUGHT_QUIET=1\")" << std::endl;\
66 std::rethrow_exception(std::current_exception()); \
67}
68#else
69#define CLING_CATCH_UNCAUGHT_
70#define _CLING_CATCH_UNCAUGHT
71#endif
72
73#if 0
74// force std::string and allocator instantation, otherwise Clang 13+ fails to JIT
75// symbols that rely on some private helpers (e.g. _M_use_local_data) when used in
76// in conjunction with the PCH; hat tip:
77// https://github.com/sxs-collaboration/spectre/pull/5222/files#diff-093aadf224e5fee0d33ae1810f2f1c23304fb5ca398ba6b96c4e7918e0811729
78#if defined(__GLIBCXX__) && __GLIBCXX__ >= 20220506
79template class std::allocator<char>;
80template class std::basic_string<char>;
81template class std::basic_string<wchar_t>;
82#endif
83
84using namespace CppyyLegacy;
85#endif
86
87// temp
88#include <iostream>
90// --temp
91
92#if 0
93#if defined(__arm64__)
94namespace {
95
96// Trap uncaught exceptions and longjump back to the point of JIT wrapper entry
97jmp_buf gExcJumBuf;
98
99void arm_uncaught_exception() {
100 longjmp(gExcJumBuf, 1);
101}
102
103class ARMUncaughtException {
104 std::terminate_handler m_Handler;
105public:
106 ARMUncaughtException() { m_Handler = std::set_terminate(arm_uncaught_exception); }
107 ~ARMUncaughtException() { std::set_terminate(m_Handler); }
108};
109
110} // unnamed namespace
111#endif // __arm64__
112#endif
113
114// small number that allows use of stack for argument passing
115const int SMALL_ARGS_N = 8;
116
117// convention to pass flag for direct calls (similar to Python's vector calls)
118#define DIRECT_CALL ((size_t)1 << (8 * sizeof(size_t) - 1))
119static inline size_t CALL_NARGS(size_t nargs) {
120 return nargs & ~DIRECT_CALL;
121}
122
123// data for life time management ---------------------------------------------
124typedef std::vector<TClassRef> ClassRefs_t;
126static const ClassRefs_t::size_type GLOBAL_HANDLE = 1;
127static const ClassRefs_t::size_type STD_HANDLE = GLOBAL_HANDLE + 1;
128
129typedef std::map<std::string, ClassRefs_t::size_type> Name2ClassRefIndex_t;
131
132static std::map<std::string, std::string> resolved_enum_types;
133
134namespace {
135
136static inline
137Cppyy::TCppType_t find_memoized_scope(const std::string& name)
138{
139 auto icr = g_name2classrefidx.find(name);
140 if (icr != g_name2classrefidx.end())
141 return (Cppyy::TCppType_t)icr->second;
142 return (Cppyy::TCppType_t)0;
143}
144
145static inline
146std::string find_memoized_resolved_name(const std::string& name)
147{
148// resolved class types
149 Cppyy::TCppType_t klass = find_memoized_scope(name);
150 if (klass) return Cppyy::GetScopedFinalName(klass);
151
152// resolved enum types
153 auto res = resolved_enum_types.find(name);
154 if (res != resolved_enum_types.end())
155 return res->second;
156
157// unknown ...
158 return "";
159}
160
161class CallWrapper {
162public:
163 typedef const void* DeclId_t;
164
165public:
166 CallWrapper(TFunction* f) : fDecl(f->GetDeclId()), fName(f->GetName()), fTF(new TFunction(*f)) {}
167 CallWrapper(DeclId_t fid, const std::string& n) : fDecl(fid), fName(n), fTF(nullptr) {}
168 ~CallWrapper() {
169 delete fTF;
170 }
171
172public:
174 DeclId_t fDecl;
175 std::string fName;
176 TFunction* fTF;
177};
178
179}
180
181static std::vector<CallWrapper*> gWrapperHolder;
182
183static inline
185{
186 CallWrapper* wrap = new CallWrapper(f);
187 gWrapperHolder.push_back(wrap);
188 return wrap;
189}
190
191static inline
192CallWrapper* new_CallWrapper(CallWrapper::DeclId_t fid, const std::string& n)
193{
194 CallWrapper* wrap = new CallWrapper(fid, n);
195 gWrapperHolder.push_back(wrap);
196 return wrap;
197}
198
199typedef std::vector<TGlobal*> GlobalVars_t;
200typedef std::map<TGlobal*, GlobalVars_t::size_type> GlobalVarsIndices_t;
201
204
205static std::set<std::string> gSTLNames;
206
207
208// data ----------------------------------------------------------------------
210
211// builtin types (including a few common STL templates as long as they live in
212// the global namespace b/c of choices upstream)
213static std::set<std::string> g_builtins =
214 {"bool", "char", "signed char", "unsigned char", "wchar_t", "short", "unsigned short",
215 "int", "unsigned int", "long", "unsigned long", "long long", "unsigned long long",
216 "float", "double", "long double", "void",
217 "allocator", "array", "basic_string", "complex", "initializer_list", "less", "list",
218 "map", "pair", "set", "vector"};
219
220// smart pointer types
221static std::set<std::string> gSmartPtrTypes =
222 {"auto_ptr", "std::auto_ptr", "shared_ptr", "std::shared_ptr",
223 "unique_ptr", "std::unique_ptr", "weak_ptr", "std::weak_ptr"};
224
225// to filter out ROOT names
226static std::set<std::string> gInitialNames;
227static std::set<std::string> gRootSOs;
228
229// configuration
230static bool gEnableFastPath = true;
231
232
233// global initialization -----------------------------------------------------
234namespace {
235
236// names copied from TUnixSystem
237#ifdef WIN32
238const int SIGBUS = 0; // simple placeholders for ones that don't exist
239const int SIGSYS = 0;
240const int SIGPIPE = 0;
241const int SIGQUIT = 0;
242const int SIGWINCH = 0;
243const int SIGALRM = 0;
244const int SIGCHLD = 0;
245const int SIGURG = 0;
246const int SIGUSR1 = 0;
247const int SIGUSR2 = 0;
248#endif
249
250static struct Signalmap_t {
251 int fCode;
252 const char *fSigName;
253} gSignalMap[kMAXSIGNALS] = { // the order of the signals should be identical
254 { SIGBUS, "bus error" }, // to the one in TSysEvtHandler.h
255 { SIGSEGV, "segmentation violation" },
256 { SIGSYS, "bad argument to system call" },
257 { SIGPIPE, "write on a pipe with no one to read it" },
258 { SIGILL, "illegal instruction" },
259 { SIGABRT, "abort" },
260 { SIGQUIT, "quit" },
261 { SIGINT, "interrupt" },
262 { SIGWINCH, "window size change" },
263 { SIGALRM, "alarm clock" },
264 { SIGCHLD, "death of a child" },
265 { SIGURG, "urgent data arrived on an I/O channel" },
266 { SIGFPE, "floating point exception" },
267 { SIGTERM, "termination signal" },
268 { SIGUSR1, "user-defined signal 1" },
269 { SIGUSR2, "user-defined signal 2" }
270};
271
272static void inline do_trace(int sig) {
273 std::cerr << " *** Break *** " << (sig < kMAXSIGNALS ? gSignalMap[sig].fSigName : "") << std::endl;
275}
276
277class TExceptionHandlerImp : public TExceptionHandler {
278public:
279 void HandleException(Int_t sig) override {
280 if (TROOT::Initialized()) {
281 if (gException) {
282 gInterpreter->RewindDictionary();
283 gInterpreter->ClearFileBusy();
284 }
285
286 if (!std::getenv("CPPYY_CRASH_QUIET"))
287 do_trace(sig);
288
289 // jump back, if catch point set
290 Throw(sig);
291 }
292
293 do_trace(sig);
294 gSystem->Exit(128 + sig);
295 }
296};
297
298class ApplicationStarter {
299public:
300 ApplicationStarter() {
301 // initialize ROOT early to guarantee proper order of shutdown later on (gROOT is a
302 // macro that resolves to the ::CppyyLegacy::GetROOT() function call)
303 (void)gROOT;
304
305 // setup dummy holders for global and std namespaces
306 assert(g_classrefs.size() == GLOBAL_HANDLE);
308 g_classrefs.push_back(TClassRef(""));
309
310 // aliases for std (setup already in pythonify)
312 g_name2classrefidx["::std"] = g_name2classrefidx["std"];
313 g_classrefs.push_back(TClassRef("std"));
314
315 // add a dummy global to refer to as null at index 0
316 g_globalvars.push_back(nullptr);
317 g_globalidx[nullptr] = 0;
318
319 // fill out the builtins
320 std::set<std::string> bi{g_builtins};
321 for (const auto& name : bi) {
322 for (const char* a : {"*", "&", "*&", "[]", "*[]"})
323 g_builtins.insert(name+a);
324 }
325
326 // disable fast path if requested
327 if (std::getenv("CPPYY_DISABLE_FASTPATH")) gEnableFastPath = false;
328
329 // fill the set of STL names
330 const char* stl_names[] = {"allocator", "auto_ptr", "bad_alloc", "bad_cast",
331 "bad_exception", "bad_typeid", "basic_filebuf", "basic_fstream", "basic_ifstream",
332 "basic_ios", "basic_iostream", "basic_istream", "basic_istringstream",
333 "basic_ofstream", "basic_ostream", "basic_ostringstream", "basic_streambuf",
334 "basic_string", "basic_stringbuf", "basic_stringstream", "binary_function",
335 "binary_negate", "bitset", "byte", "char_traits", "codecvt_byname", "codecvt", "collate",
336 "collate_byname", "compare", "complex", "ctype_byname", "ctype", "default_delete",
337 "deque", "divides", "domain_error", "equal_to", "exception", "forward_list", "fpos",
338 "function", "greater_equal", "greater", "gslice_array", "gslice", "hash", "indirect_array",
339 "integer_sequence", "invalid_argument", "ios_base", "istream_iterator", "istreambuf_iterator",
340 "istrstream", "iterator_traits", "iterator", "length_error", "less_equal", "less",
341 "list", "locale", "localedef utility", "locale utility", "logic_error", "logical_and",
342 "logical_not", "logical_or", "map", "mask_array", "mem_fun", "mem_fun_ref", "messages",
343 "messages_byname", "minus", "modulus", "money_get", "money_put", "moneypunct",
344 "moneypunct_byname", "multimap", "multiplies", "multiset", "negate", "not_equal_to",
345 "num_get", "num_put", "numeric_limits", "numpunct", "numpunct_byname",
346 "ostream_iterator", "ostreambuf_iterator", "ostrstream", "out_of_range",
347 "overflow_error", "pair", "plus", "pointer_to_binary_function",
348 "pointer_to_unary_function", "priority_queue", "queue", "range_error",
349 "raw_storage_iterator", "reverse_iterator", "runtime_error", "set", "shared_ptr",
350 "slice_array", "slice", "stack", "string", "strstream", "strstreambuf",
351 "time_get_byname", "time_get", "time_put_byname", "time_put", "unary_function",
352 "unary_negate", "unique_ptr", "underflow_error", "unordered_map", "unordered_multimap",
353 "unordered_multiset", "unordered_set", "valarray", "vector", "weak_ptr", "wstring",
354 "__hash_not_enabled"};
355 for (auto& name : stl_names)
356 gSTLNames.insert(name);
357
358 // set opt level (default to 2 if not given; Cling itself defaults to 0)
359 int optLevel = 2;
360 if (std::getenv("CPPYY_OPT_LEVEL")) optLevel = atoi(std::getenv("CPPYY_OPT_LEVEL"));
361 if (optLevel != 0) {
362 std::ostringstream s;
363 s << "#pragma cling optimize " << optLevel;
364 gInterpreter->ProcessLine(s.str().c_str());
365 }
366
367 // load frequently used headers
368 const char* code =
369 "#include <iostream>\n"
370 "#include <string>\n"
371 "#include <DllImport.h>\n" // defines R__EXTERN
372 "#include <vector>\n"
373 "#include <utility>";
374 gInterpreter->ProcessLine(code);
375
376 // create helpers for comparing thingies
377 gInterpreter->Declare(
378 "namespace __cppyy_internal { template<class C1, class C2>"
379 " bool is_equal(const C1& c1, const C2& c2) { return (bool)(c1 == c2); } }");
380 gInterpreter->Declare(
381 "namespace __cppyy_internal { template<class C1, class C2>"
382 " bool is_not_equal(const C1& c1, const C2& c2) { return (bool)(c1 != c2); } }");
383
384 // helper for multiple inheritance
385 gInterpreter->Declare("namespace __cppyy_internal { struct Sep; }");
386
387 // retrieve all initial (ROOT) C++ names in the global scope to allow filtering later
388 gROOT->GetListOfGlobals(true); // force initialize
389 gROOT->GetListOfGlobalFunctions(true); // id.
390 std::set<std::string> initial;
392 gInitialNames = initial;
393
394#ifndef WIN32
395 gRootSOs.insert("libCore.so ");
396 gRootSOs.insert("libRIO.so ");
397 gRootSOs.insert("libThread.so ");
398 gRootSOs.insert("libMathCore.so ");
399#else
400 gRootSOs.insert("libCore.dll ");
401 gRootSOs.insert("libRIO.dll ");
402 gRootSOs.insert("libThread.dll ");
403 gRootSOs.insert("libMathCore.dll ");
404#endif
405
406 // start off with a reasonable size placeholder for wrappers
407 gWrapperHolder.reserve(1024);
408
409 // create an exception handler to process signals
410 gExceptionHandler = new TExceptionHandlerImp{};
411 }
412
413 ~ApplicationStarter() {
414 for (auto wrap : gWrapperHolder)
415 delete wrap;
416 delete gExceptionHandler; gExceptionHandler = nullptr;
417 }
418} _applicationStarter;
419
420} // unnamed namespace
421
422
423// local helpers -------------------------------------------------------------
424static inline
426{
427 assert((ClassRefs_t::size_type)scope < g_classrefs.size());
428 return g_classrefs[(ClassRefs_t::size_type)scope];
429}
430
431static inline
433 CallWrapper* wrap = ((CallWrapper*)method);
434 if (!wrap->fTF) {
435 MethodInfo_t* mi = gInterpreter->MethodInfo_Factory(wrap->fDecl);
436 wrap->fTF = new TFunction(mi);
437 }
438 return wrap->fTF;
439}
440
441/*
442static inline
443CallWrapper::DeclId_t m2d(Cppyy::TCppMethod_t method) {
444 CallWrapper* wrap = ((CallWrapper*)method);
445 if (!wrap->fTF || wrap->fTF->GetDeclId() != wrap->fDecl) {
446 MethodInfo_t* mi = gInterpreter->MethodInfo_Factory(wrap->fDecl);
447 wrap->fTF = new TFunction(mi);
448 }
449 return wrap->fDecl;
450}
451*/
452
453static inline
454char* cppstring_to_cstring(const std::string& cppstr)
455{
456 char* cstr = (char*)malloc(cppstr.size()+1);
457 memcpy(cstr, cppstr.c_str(), cppstr.size()+1);
458 return cstr;
459}
460
461static inline
462bool match_name(const std::string& tname, const std::string fname)
463{
464// either match exactly, or match the name as template
465 if (fname.rfind(tname, 0) == 0) {
466 if ((tname.size() == fname.size()) ||
467 (tname.size() < fname.size() && fname[tname.size()] == '<'))
468 return true;
469 }
470 return false;
471}
472
473static inline
474bool is_missclassified_stl(const std::string& name)
475{
476 std::string::size_type pos = name.find('<');
477 if (pos != std::string::npos)
478 return gSTLNames.find(name.substr(0, pos)) != gSTLNames.end();
479 return gSTLNames.find(name) != gSTLNames.end();
480}
481
482
483// direct interpreter access -------------------------------------------------
484bool Cppyy::Compile(const std::string& code, bool /*silent*/)
485{
486 return gInterpreter->Declare(code.c_str());
487}
488
490{
491 if (klass && obj && !IsNamespace((TCppScope_t)klass))
492 return gInterpreter->ToString(GetScopedFinalName(klass).c_str(), (void*)obj);
493 return "";
494}
495
496
497// name to opaque C++ scope representation -----------------------------------
498std::string Cppyy::ResolveName(const std::string& cppitem_name)
499{
500// Fully resolve the given name to the final type name.
501
502// try memoized type cache, in case seen before
503 std::string memoized = find_memoized_resolved_name(cppitem_name);
504 if (!memoized.empty()) return memoized;
505
506// remove global scope '::' if present
507 std::string tclean = cppitem_name.compare(0, 2, "::") == 0 ?
508 cppitem_name.substr(2, std::string::npos) : cppitem_name;
509
510// classes (most common)
511 tclean = TClassEdit::CleanType(tclean.c_str());
512 if (tclean.empty() /* unknown, eg. an operator */) return cppitem_name;
513
514// reduce [N] to []
515 if (tclean[tclean.size()-1] == ']')
516 tclean = tclean.substr(0, tclean.rfind('[')) + "[]";
517
518 if (tclean.rfind("byte", 0) == 0 || tclean.rfind("std::byte", 0) == 0)
519 return tclean;
520
521// remove __restrict and __restrict__
522 auto pos = tclean.rfind("__restrict");
523 if (pos != std::string::npos)
524 tclean = tclean.substr(0, pos);
525
526 if (tclean.compare(0, 9, "std::byte") == 0)
527 return tclean;
528
529// check data types list (accept only builtins as typedefs will
530// otherwise not be resolved)
531 if (IsBuiltin(tclean)) return tclean;
532
533// special case for enums
534 if (IsEnum(cppitem_name))
535 return ResolveEnum(cppitem_name);
536
537// special case for clang's builtin __type_pack_element (which does not resolve)
538 pos = cppitem_name.size() > 20 ? \
539 cppitem_name.rfind("__type_pack_element", 5) : std::string::npos;
540 if (pos != std::string::npos) {
541 // shape is "[std::]__type_pack_element<index,type1,type2,...,typeN>cpd": extract
542 // first the index, and from there the indexed type; finally, restore the
543 // qualifiers
544 const char* str = cppitem_name.c_str();
545 char* endptr = nullptr;
546 unsigned long index = strtoul(str+20+pos, &endptr, 0);
547
548 std::string tmplvars{endptr};
549 auto start = tmplvars.find(',') + 1;
550 auto end = tmplvars.find(',', start);
551 while (index != 0) {
552 start = end+1;
553 end = tmplvars.find(',', start);
554 if (end == std::string::npos) end = tmplvars.rfind('>');
555 --index;
556 }
557
558 std::string resolved = tmplvars.substr(start, end-start);
559 auto cpd = tmplvars.rfind('>');
560 if (cpd != std::string::npos && cpd+1 != tmplvars.size())
561 return resolved + tmplvars.substr(cpd+1, std::string::npos);
562 return resolved;
563 }
564
565// typedefs etc. (and a couple of hacks around TClassEdit-isms, fixing of which
566// in ResolveTypedef itself is a TODO ...)
567 tclean = TClassEdit::ResolveTypedef(tclean.c_str(), true);
568 pos = 0;
569 while ((pos = tclean.find("::::", pos)) != std::string::npos) {
570 tclean.replace(pos, 4, "::");
571 pos += 2;
572 }
573
574 if (tclean.compare(0, 6, "const ") != 0)
575 return TClassEdit::ShortType(tclean.c_str(), 2);
576 return "const " + TClassEdit::ShortType(tclean.c_str(), 2);
577}
578
579#if 0
580//----------------------------------------------------------------------------
581static std::string extract_namespace(const std::string& name)
582{
583// Find the namespace the named class lives in, take care of templates
584// Note: this code also lives in CPyCppyy (TODO: refactor?)
585 if (name.empty())
586 return name;
587
588 int tpl_open = 0;
589 for (std::string::size_type pos = name.size()-1; 0 < pos; --pos) {
590 std::string::value_type c = name[pos];
591
592 // count '<' and '>' to be able to skip template contents
593 if (c == '>')
594 ++tpl_open;
595 else if (c == '<')
596 --tpl_open;
597
598 // collect name up to "::"
599 else if (tpl_open == 0 && c == ':' && name[pos-1] == ':') {
600 // found the extend of the scope ... done
601 return name.substr(0, pos-1);
602 }
603 }
604
605// no namespace; assume outer scope
606 return "";
607}
608#endif
609
610std::string Cppyy::ResolveEnum(const std::string& enum_type)
611{
612// The underlying type of a an enum may be any kind of integer.
613// Resolve that type via a workaround (note: this function assumes
614// that the enum_type name is a valid enum type name)
615 auto res = resolved_enum_types.find(enum_type);
616 if (res != resolved_enum_types.end())
617 return res->second;
618
619// desugar the type before resolving
620 std::string et_short = TClassEdit::ShortType(enum_type.c_str(), 1);
621 if (et_short.find("(unnamed") == std::string::npos) {
622 std::ostringstream decl;
623 // TODO: now presumed fixed with https://sft.its.cern.ch/jira/browse/ROOT-6988
624 for (auto& itype : {"unsigned int"}) {
625 // This is pure type introspection: silence any deprecation warning that
626 // would otherwise be emitted just because the enum being resolved (or its
627 // scope) happens to be marked deprecated.
628 decl << "_Pragma(\"clang diagnostic push\")"
629 "_Pragma(\"clang diagnostic ignored \\\"-Wdeprecated-declarations\\\"\")"
630 << "std::is_same<"
631 << itype
632 << ", std::underlying_type<"
633 << et_short
634 << ">::type>::value;"
635 "_Pragma(\"clang diagnostic pop\")";
636 if (gInterpreter->ProcessLine(decl.str().c_str())) {
637 // TODO: "re-sugaring" like this is brittle, but the top
638 // should be re-translated into AST-based code anyway
639 std::string resugared;
640 if (et_short.size() != enum_type.size()) {
641 auto pos = enum_type.find(et_short);
642 if (pos != std::string::npos) {
643 resugared = enum_type.substr(0, pos) + itype;
644 if (pos+et_short.size() < enum_type.size())
645 resugared += enum_type.substr(pos+et_short.size(), std::string::npos);
646 }
647 }
648 if (resugared.empty()) resugared = itype;
649 resolved_enum_types[enum_type] = resugared;
650 return resugared;
651 }
652 }
653 }
654
655// failed or anonymous ... signal upstream to special case this
656 int ipos = (int)enum_type.size()-1;
657 for (; 0 <= ipos; --ipos) {
658 char c = enum_type[ipos];
659 if (isspace(c)) continue;
660 if (isalnum(c) || c == '_' || c == '>' || c == ')') break;
661 }
662 bool isConst = enum_type.find("const ", 6) != std::string::npos;
663 std::string restype = isConst ? "const " : "";
664 restype += "internal_enum_type_t"+enum_type.substr((std::string::size_type)ipos+1, std::string::npos);
665 resolved_enum_types[enum_type] = restype;
666 return restype; // should default to some int variant
667}
668
669#if 0
670static Cppyy::TCppIndex_t ArgSimilarityScore(void *argqtp, void *reqqtp)
671{
672// This scoring is not based on any particular rules
673 if (gInterpreter->IsSameType(argqtp, reqqtp))
674 return 0; // Best match
675 else if ((gInterpreter->IsSignedIntegerType(argqtp) && gInterpreter->IsSignedIntegerType(reqqtp)) ||
676 (gInterpreter->IsUnsignedIntegerType(argqtp) && gInterpreter->IsUnsignedIntegerType(reqqtp)) ||
677 (gInterpreter->IsFloatingType(argqtp) && gInterpreter->IsFloatingType(reqqtp)))
678 return 1;
679 else if ((gInterpreter->IsSignedIntegerType(argqtp) && gInterpreter->IsUnsignedIntegerType(reqqtp)) ||
680 (gInterpreter->IsFloatingType(argqtp) && gInterpreter->IsUnsignedIntegerType(reqqtp)))
681 return 2;
682 else if ((gInterpreter->IsIntegerType(argqtp) && gInterpreter->IsIntegerType(reqqtp)))
683 return 3;
684 else if ((gInterpreter->IsIntegralType(argqtp) && gInterpreter->IsIntegralType(reqqtp)))
685 return 4;
686 else if ((gInterpreter->IsVoidPointerType(argqtp) && gInterpreter->IsPointerType(reqqtp)))
687 return 5;
688 else
689 return 10; // Penalize heavily for no possible match
690}
691#endif
692
693Cppyy::TCppScope_t Cppyy::GetScope(const std::string& sname)
694{
695// First, try cache
696 TCppType_t result = find_memoized_scope(sname);
697 if (result) return result;
698
699// Second, skip builtins before going through the more expensive steps of resolving
700// typedefs and looking up TClass
701 if (g_builtins.find(sname) != g_builtins.end())
702 return (TCppScope_t)0;
703
704// TODO: scope_name should always be final already?
705// Resolve name fully before lookup to make sure all aliases point to the same scope
706 std::string scope_name = ResolveName(sname);
707 bool bHasAlias1 = sname != scope_name;
708 if (bHasAlias1) {
709 result = find_memoized_scope(scope_name);
710 if (result) {
711 g_name2classrefidx[sname] = result;
712 return result;
713 }
714 }
715
716// both failed, but may be STL name that's missing 'std::' now, but didn't before
717 bool b_scope_name_missclassified = is_missclassified_stl(scope_name);
718 if (b_scope_name_missclassified) {
719 result = find_memoized_scope("std::"+scope_name);
720 if (result) g_name2classrefidx["std::"+scope_name] = (ClassRefs_t::size_type)result;
721 }
722 bool b_sname_missclassified = bHasAlias1 ? is_missclassified_stl(sname) : false;
723 if (b_sname_missclassified) {
724 if (!result) result = find_memoized_scope("std::"+sname);
725 if (result) g_name2classrefidx["std::"+sname] = (ClassRefs_t::size_type)result;
726 }
727
728 if (result) return result;
729
730// use TClass directly, to enable auto-loading; class may be stubbed (eg. for
731// function returns) or forward declared, leading to a non-null TClass that is
732// otherwise invalid/unusable
733 TClassRef cr(TClass::GetClass(scope_name.c_str(), true /* load */, true /* silent */));
734 if (!cr.GetClass())
735 return (TCppScope_t)0;
736
737// memoize found/created TClass
738 bool bHasAlias2 = cr->GetName() != scope_name;
739 if (bHasAlias2) {
740 result = find_memoized_scope(cr->GetName());
741 if (result) {
742 g_name2classrefidx[scope_name] = result;
743 if (bHasAlias1) g_name2classrefidx[sname] = result;
744 return result;
745 }
746 }
747
748 ClassRefs_t::size_type sz = g_classrefs.size();
749 g_name2classrefidx[scope_name] = sz;
750 if (bHasAlias1) g_name2classrefidx[sname] = sz;
751 if (bHasAlias2) g_name2classrefidx[cr->GetName()] = sz;
752// TODO: make ROOT/meta NOT remove std :/
753 if (b_scope_name_missclassified)
754 g_name2classrefidx["std::"+scope_name] = sz;
755 if (b_sname_missclassified)
756 g_name2classrefidx["std::"+sname] = sz;
757
758 g_classrefs.push_back(TClassRef(scope_name.c_str()));
759
760 return (TCppScope_t)sz;
761}
762
763bool Cppyy::IsTemplate(const std::string& template_name)
764{
765 return (bool)gInterpreter->CheckClassTemplate(template_name.c_str());
766}
767
768namespace {
769 class AutoCastRTTI {
770 public:
771 virtual ~AutoCastRTTI() {}
772 };
773}
774
776{
777 TClassRef& cr = type_from_handle(klass);
778 if (!cr.GetClass() || !obj) return klass;
779
780 if (!(cr->ClassProperty() & kClassHasVirtual))
781 return klass; // not polymorphic: no RTTI info available
782
783// TODO: ios class casting (ostream, streambuf, etc.) fails with a crash in GetActualClass()
784// below on Mac ARM (it's likely that the found actual class was replaced, maybe because
785// there are duplicates from pcm/pch?); filter them out for now as it's usually unnecessary
786// anyway to autocast these
787 std::string clName = cr->GetName();
788 if (clName.find("std::", 0, 5) == 0 && clName.find("stream") != std::string::npos)
789 return klass;
790
791#ifdef _WIN64
792// Cling does not provide a consistent ImageBase address for calculating relative addresses
793// as used in Windows 64b RTTI. So, check for our own RTTI extension instead. If that fails,
794// see whether the unmangled raw_name is available (e.g. if this is an MSVC compiled rather
795// than JITed class) and pass on if it is.
796 volatile const char* raw = nullptr; // to prevent too aggressive reordering
797 try {
798 // this will filter those objects that do not have RTTI to begin with (throws)
799 AutoCastRTTI* pcst = (AutoCastRTTI*)obj;
800 raw = typeid(*pcst).raw_name();
801
802 // check the signature id (0 == absolute, 1 == relative, 2 == ours)
803 void* vfptr = *(void**)((intptr_t)obj);
804 void* meta = (void*)((intptr_t)*((void**)((intptr_t)vfptr-sizeof(void*))));
805 if (*(intptr_t*)meta == 2) {
806 // access the extra data item which is an absolute pointer to the RTTI
807 void* ptdescr = (void*)((intptr_t)meta + 4*sizeof(unsigned long)+sizeof(void*));
808 if (ptdescr && *(void**)ptdescr) {
809 auto rtti = *(std::type_info**)ptdescr;
810 raw = rtti->raw_name();
811 if (raw && raw[0] != '\0') // likely unnecessary
812 return (TCppType_t)GetScope(rtti->name());
813 }
814
815 return klass; // do not fall through if no RTTI info available
816 }
817
818 // if the raw name is the empty string (no guarantees that this is so as truly, the
819 // address is corrupt, but it is common to be empty), then there is no accessible RTTI
820 // and getting the unmangled name will crash ...
821 if (!raw)
822 return klass;
823 } catch (std::bad_typeid) {
824 return klass; // can't risk passing to ROOT/meta as it may do RTTI
825 }
826#endif
827
828 TClass* clActual = cr->GetActualClass((void*)obj);
829 // The additional check using TClass::GetClassInfo is to prevent returning classes of which the Interpreter has no info (see https://github.com/root-project/root/pull/16177)
830 if (clActual && clActual != cr.GetClass() && clActual->GetClassInfo()) {
831 auto itt = g_name2classrefidx.find(clActual->GetName());
832 if (itt != g_name2classrefidx.end())
833 return (TCppType_t)itt->second;
834 return (TCppType_t)GetScope(clActual->GetName());
835 }
836
837 return klass;
838}
839
841{
842 TClassRef& cr = type_from_handle(klass);
843 if (cr.GetClass() && cr->GetClassInfo())
844 return (size_t)gInterpreter->ClassInfo_Size(cr->GetClassInfo());
845 return (size_t)0;
846}
847
848size_t Cppyy::SizeOf(const std::string& type_name)
849{
850 TDataType* dt = gROOT->GetType(type_name.c_str());
851 if (dt) return dt->Size();
852 return SizeOf(GetScope(type_name));
853}
854
855bool Cppyy::IsBuiltin(const std::string& type_name)
856{
857 if (g_builtins.find(type_name) != g_builtins.end())
858 return true;
859
860 const std::string& tclean = TClassEdit::CleanType(type_name.c_str(), 1);
861 if (g_builtins.find(tclean) != g_builtins.end())
862 return true;
863
864 if (strstr(tclean.c_str(), "std::complex"))
865 return true;
866
867 return false;
868}
869
870bool Cppyy::IsComplete(const std::string& type_name)
871{
872// verify whether the dictionary of this class is fully available
873 bool b = false;
874
875 int oldEIL = gErrorIgnoreLevel;
876 gErrorIgnoreLevel = 3000;
877 TClass* klass = TClass::GetClass(type_name.c_str());
878 if (klass && klass->GetClassInfo()) // works for normal case w/ dict
879 b = gInterpreter->ClassInfo_IsLoaded(klass->GetClassInfo());
880 else { // special case for forward declared classes
881 ClassInfo_t* ci = gInterpreter->ClassInfo_Factory(type_name.c_str());
882 if (ci) {
883 b = gInterpreter->ClassInfo_IsLoaded(ci);
884 gInterpreter->ClassInfo_Delete(ci); // we own the fresh class info
885 }
886 }
887 gErrorIgnoreLevel = oldEIL;
888 return b;
889}
890
891// memory management ---------------------------------------------------------
893{
895 return (TCppObject_t)::operator new(gInterpreter->ClassInfo_Size(cr->GetClassInfo()));
896}
897
899{
900 ::operator delete(instance);
901}
902
904{
906 if (arena)
907 return (TCppObject_t)cr->New(arena, TClass::kRealNew);
908 return (TCppObject_t)cr->New(TClass::kRealNew);
909}
910
911static std::map<Cppyy::TCppType_t, bool> sHasOperatorDelete;
913{
916 cr->Destructor((void*)instance);
917 else {
918 ROOT::DelFunc_t fdel = cr->GetDelete();
919 if (fdel) fdel((void*)instance);
920 else {
921 auto ib = sHasOperatorDelete.find(type);
922 if (ib == sHasOperatorDelete.end()) {
923 TFunction *f = (TFunction *)cr->GetMethodAllAny("operator delete");
924 sHasOperatorDelete[type] = (bool)(f && (f->Property() & kIsPublic));
925 ib = sHasOperatorDelete.find(type);
926 }
927 ib->second ? cr->Destructor((void*)instance) : ::operator delete((void*)instance);
928 }
929 }
930}
931
932
933// method/function dispatching -----------------------------------------------
935{
936// TODO: method should be a callfunc, so that no mapping would be needed.
937 CallWrapper* wrap = (CallWrapper*)method;
938
939 CallFunc_t* callf = gInterpreter->CallFunc_Factory();
940 MethodInfo_t* meth = gInterpreter->MethodInfo_Factory(wrap->fDecl);
941 gInterpreter->CallFunc_SetFunc(callf, meth);
942 gInterpreter->MethodInfo_Delete(meth);
943
944 if (!(callf && gInterpreter->CallFunc_IsValid(callf))) {
945 // TODO: propagate this error to caller w/o use of Python C-API
946 /*
947 PyErr_Format(PyExc_RuntimeError, "could not resolve %s::%s(%s)",
948 const_cast<TClassRef&>(klass).GetClassName(),
949 wrap.fName, callString.c_str()); */
950 std::cerr << "TODO: report unresolved function error to Python\n";
951 if (callf) gInterpreter->CallFunc_Delete(callf);
953 }
954
955// generate the wrapper and JIT it; ignore wrapper generation errors (will simply
956// result in a nullptr that is reported upstream if necessary; often, however,
957// there is a different overload available that will do)
958 auto oldErrLvl = gErrorIgnoreLevel;
960 wrap->fFaceptr = gInterpreter->CallFunc_IFacePtr(callf);
961 gErrorIgnoreLevel = oldErrLvl;
962
963 gInterpreter->CallFunc_Delete(callf); // does not touch IFacePtr
964 return wrap->fFaceptr;
965}
966
967static inline
968bool copy_args(Parameter* args, size_t nargs, void** vargs)
969{
970 bool runRelease = false;
971 for (size_t i = 0; i < nargs; ++i) {
972 switch (args[i].fTypeCode) {
973 case 'X': /* (void*)type& with free */
974 runRelease = true;
975 case 'V': /* (void*)type& */
976 vargs[i] = args[i].fValue.fVoidp;
977 break;
978 case 'r': /* const type& */
979 vargs[i] = args[i].fRef;
980 break;
981 default: /* all other types in union */
982 vargs[i] = (void*)&args[i].fValue.fVoidp;
983 break;
984 }
985 }
986 return runRelease;
987}
988
989static inline
990void release_args(Parameter* args, size_t nargs)
991{
992 for (size_t i = 0; i < nargs; ++i) {
993 if (args[i].fTypeCode == 'X')
994 free(args[i].fValue.fVoidp);
995 }
996}
997
998static inline bool WrapperCall(Cppyy::TCppMethod_t method, size_t nargs, void* args_, void* self, void* result)
999{
1000 Parameter* args = (Parameter*)args_;
1001 //bool is_direct = nargs & DIRECT_CALL;
1002 nargs = CALL_NARGS(nargs);
1003
1004 CallWrapper* wrap = (CallWrapper*)method;
1005 const TInterpreter::CallFuncIFacePtr_t& faceptr = wrap->fFaceptr.fGeneric ? wrap->fFaceptr : GetCallFunc(method);
1006 if (!faceptr.fGeneric)
1007 return false; // happens with compilation error
1008
1010 bool runRelease = false;
1011 if (nargs <= SMALL_ARGS_N) {
1012 void* smallbuf[SMALL_ARGS_N];
1013 if (nargs) runRelease = copy_args(args, nargs, smallbuf);
1014 faceptr.fGeneric(self, (int)nargs, smallbuf, result);
1015 } else {
1016 std::vector<void*> buf(nargs);
1017 runRelease = copy_args(args, nargs, buf.data());
1018 faceptr.fGeneric(self, (int)nargs, buf.data(), result);
1019 }
1020 if (runRelease) release_args(args, nargs);
1021 return true;
1022 }
1023
1025 bool runRelease = false;
1026 if (nargs <= SMALL_ARGS_N) {
1027 void* smallbuf[SMALL_ARGS_N];
1028 if (nargs) runRelease = copy_args(args, nargs, (void**)smallbuf);
1029 faceptr.fCtor((void**)smallbuf, result, (unsigned long)nargs);
1030 } else {
1031 std::vector<void*> buf(nargs);
1032 runRelease = copy_args(args, nargs, buf.data());
1033 faceptr.fCtor(buf.data(), result, (unsigned long)nargs);
1034 }
1035 if (runRelease) release_args(args, nargs);
1036 return true;
1037 }
1038
1040 std::cerr << " DESTRUCTOR NOT IMPLEMENTED YET! " << std::endl;
1041 return false;
1042 }
1043
1044 return false;
1045}
1046
1047template<typename T>
1048static inline
1049T CallT(Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, size_t nargs, void* args)
1050{
1051 T t{};
1052 if (WrapperCall(method, nargs, args, (void*)self, &t))
1053 return t;
1054 return (T)-1;
1055}
1056
1057#define CPPYY_IMP_CALL(typecode, rtype) \
1058rtype Cppyy::Call##typecode(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args)\
1059{ \
1060 return CallT<rtype>(method, self, nargs, args); \
1061}
1062
1063void Cppyy::CallV(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args)
1064{
1065 if (!WrapperCall(method, nargs, args, (void*)self, nullptr))
1066 return /* TODO ... report error */;
1067}
1068
1069CPPYY_IMP_CALL(B, unsigned char)
1078
1079void* Cppyy::CallR(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args)
1080{
1081 void* r = nullptr;
1082 if (WrapperCall(method, nargs, args, (void*)self, &r))
1083 return r;
1084 return nullptr;
1085}
1086
1088 TCppMethod_t method, TCppObject_t self, size_t nargs, void* args, size_t* length)
1089{
1090 char* cstr = nullptr;
1091 TClassRef cr("std::string");
1092 std::string* cppresult = (std::string*)malloc(sizeof(std::string));
1093 if (WrapperCall(method, nargs, args, self, (void*)cppresult)) {
1094 cstr = cppstring_to_cstring(*cppresult);
1095 *length = cppresult->size();
1096 cppresult->std::string::~basic_string();
1097 } else
1098 *length = 0;
1099 free((void*)cppresult);
1100 return cstr;
1101}
1102
1104 TCppMethod_t method, TCppType_t /* klass */, size_t nargs, void* args)
1105{
1106 void* obj = nullptr;
1107 if (WrapperCall(method, nargs, args, nullptr, &obj))
1108 return (TCppObject_t)obj;
1109 return (TCppObject_t)0;
1110}
1111
1113{
1115 cr->Destructor((void*)self, true);
1116}
1117
1119 TCppObject_t self, size_t nargs, void* args, TCppType_t result_type)
1120{
1121 TClassRef& cr = type_from_handle(result_type);
1122 auto *classInfo = cr->GetClassInfo();
1123 // If the class info is missing, we better return null and let cppyy
1124 // handle the error, before we step into undefined behavior
1125 if(!classInfo)
1126 return (TCppObject_t)0;
1127 auto classSize = gInterpreter->ClassInfo_Size(classInfo);
1128 // ClassInfo_Size returns -1 in case of invalid info, and 0 for
1129 // forward-declared classes, which we can't use.
1130 if (classSize <= 0)
1131 return (TCppObject_t)0;
1132 void* obj = ::operator new(classSize);
1133 if (WrapperCall(method, nargs, args, self, obj))
1134 return (TCppObject_t)obj;
1135 ::operator delete(obj);
1136 return (TCppObject_t)0;
1137}
1138
1140{
1141 if (check_enabled && !gEnableFastPath) return (TCppFuncAddr_t)nullptr;
1142 TFunction* f = m2f(method);
1143
1144 TCppFuncAddr_t pf = (TCppFuncAddr_t)gInterpreter->FindSym(f->GetMangledName());
1145 if (pf) return pf;
1146
1147 int ierr = 0;
1148 const char* fn = TClassEdit::DemangleName(f->GetMangledName(), ierr);
1149 if (ierr || !fn)
1150 return pf;
1151
1152 // TODO: the following attempts are all brittle and leak transactions, but
1153 // each properly exposes the symbol so subsequent lookups will succeed
1154 if (strstr(f->GetName(), "<")) {
1155 // force explicit instantiation and try again
1156 std::ostringstream sig;
1157 sig << "template " << fn << ";";
1158 gInterpreter->ProcessLine(sig.str().c_str());
1159 } else {
1160 std::ostringstream sig;
1161
1162 std::string sfn = fn;
1163 std::string::size_type pos = sfn.find('(');
1164 if (pos != std::string::npos) sfn = sfn.substr(0, pos);
1165
1166 // start cast
1167 sig << '(' << f->GetReturnTypeName() << " (";
1168
1169 // add scope for methods
1170 pos = sfn.rfind(':');
1171 if (pos != std::string::npos) {
1172 std::string scope_name = sfn.substr(0, pos-1);
1173 TCppScope_t scope = GetScope(scope_name);
1174 if (scope && !IsNamespace(scope))
1175 sig << scope_name << "::";
1176 }
1177
1178 // finalize cast
1179 sig << "*)" << GetMethodSignature(method, false)
1180 << ((f->Property() & kIsConstMethod) ? " const" : "")
1181 << ')';
1182
1183 // load address
1184 sig << '&' << sfn;
1185 gInterpreter->Calc(sig.str().c_str());
1186 }
1187
1188 return (TCppFuncAddr_t)gInterpreter->FindSym(f->GetMangledName());
1189}
1190
1191
1192// handling of function argument buffer --------------------------------------
1194{
1195 return new Parameter[nargs];
1196}
1197
1199{
1200 delete [] (Parameter*)args;
1201}
1202
1204{
1205 return sizeof(Parameter);
1206}
1207
1209{
1210 return offsetof(Parameter, fTypeCode);
1211}
1212
1213
1214// scope reflection information ----------------------------------------------
1216{
1217// Test if this scope represents a namespace.
1218 if (scope == GLOBAL_HANDLE)
1219 return true;
1220 TClassRef& cr = type_from_handle(scope);
1221 if (cr.GetClass())
1222 return cr->Property() & kIsNamespace;
1223 return false;
1224}
1225
1227{
1228// Test if this type may not be instantiated.
1229 TClassRef& cr = type_from_handle(klass);
1230 if (cr.GetClass())
1231 return cr->Property() & kIsAbstract;
1232 return false;
1233}
1234
1235bool Cppyy::IsEnum(const std::string& type_name)
1236{
1237 if (type_name.empty()) return false;
1238
1239 if (type_name.rfind("enum ", 0) == 0)
1240 return true; // by definition (C-style)
1241
1242 std::string tn_short = TClassEdit::ShortType(type_name.c_str(), 1);
1243 if (tn_short.empty()) return false;
1244 return gInterpreter->ClassInfo_IsEnum(tn_short.c_str());
1245}
1246
1248{
1249// Test if this type is a "plain old data" type
1251 if (cr.GetClass())
1252 return cr->ClassProperty() & kClassIsAggregate;
1253 return false;
1254}
1255
1256bool Cppyy::IsIntegerType(const std::string &type_name)
1257{
1258 // Test if the named type is an integer type
1259 TypeInfo_t *ti = gInterpreter->TypeInfo_Factory(type_name.c_str());
1260 if (!ti)
1261 return false;
1262 void *qtp = gInterpreter->TypeInfo_QualTypePtr(ti);
1263 bool result = qtp ? gInterpreter->IsIntegerType(qtp) : false;
1264 gInterpreter->TypeInfo_Delete(ti);
1265 return result;
1266}
1267
1269{
1270// Test if this type has a default constructor or is a "plain old data" type
1272 if (cr.GetClass())
1273 return cr->HasDefaultConstructor() || (cr->ClassProperty() & kClassIsAggregate);
1274 return true;
1275}
1276
1277// helpers for stripping scope names
1278static
1279std::string outer_with_template(const std::string& name)
1280{
1281// Cut down to the outer-most scope from <name>, taking proper care of templates.
1282 int tpl_open = 0;
1283 for (std::string::size_type pos = 0; pos < name.size(); ++pos) {
1284 std::string::value_type c = name[pos];
1285
1286 // count '<' and '>' to be able to skip template contents
1287 if (c == '<')
1288 ++tpl_open;
1289 else if (c == '>')
1290 --tpl_open;
1291
1292 // collect name up to "::"
1293 else if (tpl_open == 0 && \
1294 c == ':' && pos+1 < name.size() && name[pos+1] == ':') {
1295 // found the extend of the scope ... done
1296 return name.substr(0, pos);
1297 }
1298 }
1299
1300// whole name is apparently a single scope
1301 return name;
1302}
1303
1304static
1305std::string outer_no_template(const std::string& name)
1306{
1307// Cut down to the outer-most scope from <name>, drop templates
1308 std::string::size_type first_scope = name.find(':');
1309 if (first_scope == std::string::npos)
1310 return name.substr(0, name.find('<'));
1311 std::string::size_type first_templ = name.find('<');
1312 if (first_templ == std::string::npos)
1313 return name.substr(0, first_scope);
1314 return name.substr(0, std::min(first_templ, first_scope));
1315}
1316
1317#define FILL_COLL(type, filter) { \
1318 TIter itr{coll}; \
1319 type* obj = nullptr; \
1320 while ((obj = (type*)itr.Next())) { \
1321 const char* nm = obj->GetName(); \
1322 if (nm && nm[0] != '_' && !(obj->Property() & (filter))) { \
1323 if (gInitialNames.find(nm) == gInitialNames.end()) \
1324 cppnames.insert(nm); \
1325 }}}
1326
1327static inline
1328void cond_add(Cppyy::TCppScope_t scope, const std::string& ns_scope,
1329 std::set<std::string>& cppnames, const char* name, bool nofilter = false)
1330{
1331 if (!name || strstr(name, ".h") != 0)
1332 return;
1333
1334 if (scope == GLOBAL_HANDLE) {
1335 std::string to_add = outer_no_template(name);
1336 if ((nofilter || gInitialNames.find(to_add) == gInitialNames.end()) && !is_missclassified_stl(name))
1337 cppnames.insert(outer_no_template(name));
1338 } else if (scope == STD_HANDLE) {
1339 if (strncmp(name, "std::", 5) == 0) {
1340 name += 5;
1341#ifdef __APPLE__
1342 if (strncmp(name, "__1::", 5) == 0) name += 5;
1343#endif
1344 } else if (!is_missclassified_stl(name))
1345 return;
1346 cppnames.insert(outer_no_template(name));
1347 } else {
1348 if (strncmp(name, ns_scope.c_str(), ns_scope.size()) == 0)
1349 cppnames.insert(outer_with_template(name + ns_scope.size()));
1350 }
1351}
1352
1353void Cppyy::GetAllCppNames(TCppScope_t scope, std::set<std::string>& cppnames)
1354{
1355// Collect all known names of C++ entities under scope. This is useful for IDEs
1356// employing tab-completion, for example. Note that functions names need not be
1357// unique as they can be overloaded.
1358 TClassRef& cr = type_from_handle(scope);
1359 if (scope != GLOBAL_HANDLE && !(cr.GetClass() && cr->Property()))
1360 return;
1361
1362 std::string ns_scope = GetFinalName(scope);
1363 if (scope != GLOBAL_HANDLE) ns_scope += "::";
1364
1365// add existing values from read rootmap files if within this scope
1366 TCollection* coll = gInterpreter->GetMapfile()->GetTable();
1367 {
1368 TIter itr{coll};
1369 TEnvRec* ev = nullptr;
1370 while ((ev = (TEnvRec*)itr.Next())) {
1371 // TEnv contains rootmap entries and user-side rootmap files may be already
1372 // loaded on startup. Thus, filter on file name rather than load time.
1373 if (gRootSOs.find(ev->GetValue()) == gRootSOs.end())
1374 cond_add(scope, ns_scope, cppnames, ev->GetName(), true);
1375 }
1376 }
1377
1378// do we care about the class table or are the rootmap and list of types enough?
1379/*
1380 gClassTable->Init();
1381 const int N = gClassTable->Classes();
1382 for (int i = 0; i < N; ++i)
1383 cond_add(scope, ns_scope, cppnames, gClassTable->Next());
1384*/
1385
1386#if 0
1387// add interpreted classes (no load)
1388 {
1389 ClassInfo_t* ci = gInterpreter->ClassInfo_FactoryWithScope(
1390 false /* all */, scope == GLOBAL_HANDLE ? nullptr : cr->GetName());
1391 while (gInterpreter->ClassInfo_Next(ci)) {
1392 const char* className = gInterpreter->ClassInfo_FullName(ci);
1393 if (strstr(className, "(anonymous)") || strstr(className, "(unnamed)"))
1394 continue;
1395 cond_add(scope, ns_scope, cppnames, className);
1396 }
1397 gInterpreter->ClassInfo_Delete(ci);
1398 }
1399#endif
1400
1401// any other types (e.g. that may have come from parsing headers)
1402 coll = gROOT->GetListOfTypes();
1403 {
1404 TIter itr{coll};
1405 TDataType* dt = nullptr;
1406 while ((dt = (TDataType*)itr.Next())) {
1407 if (!(dt->Property() & kIsFundamental)) {
1408 cond_add(scope, ns_scope, cppnames, dt->GetName());
1409 }
1410 }
1411 }
1412
1413// add functions
1414 coll = (scope == GLOBAL_HANDLE) ?
1415 gROOT->GetListOfGlobalFunctions(true) : cr->GetListOfMethods(true);
1416 {
1417 TIter itr{coll};
1418 TFunction* obj = nullptr;
1419 while ((obj = (TFunction*)itr.Next())) {
1420 const char* nm = obj->GetName();
1421 // skip templated functions, adding only the un-instantiated ones
1422 if (nm && gInitialNames.find(nm) == gInitialNames.end())
1423 cppnames.insert(nm);
1424 }
1425 }
1426
1427// add uninstantiated templates
1428 coll = (scope == GLOBAL_HANDLE) ?
1429 gROOT->GetListOfFunctionTemplates() : cr->GetListOfFunctionTemplates(true);
1431
1432// add (global) data members
1433 if (scope == GLOBAL_HANDLE) {
1434 coll = gROOT->GetListOfGlobals();
1436 } else {
1437 coll = cr->GetListOfDataMembers();
1439 coll = cr->GetListOfUsingDataMembers();
1441 }
1442
1443// add enums values only for user classes/namespaces
1444 if (scope != GLOBAL_HANDLE && scope != STD_HANDLE) {
1445 coll = cr->GetListOfEnums();
1447 }
1448
1449#ifdef __APPLE__
1450// special case for Apple, add version namespace '__1' entries to std
1451 if (scope == STD_HANDLE)
1452 GetAllCppNames(GetScope("std::__1"), cppnames);
1453#endif
1454}
1455
1456
1457// class reflection information ----------------------------------------------
1458std::vector<Cppyy::TCppScope_t> Cppyy::GetUsingNamespaces(TCppScope_t scope)
1459{
1460 std::vector<Cppyy::TCppScope_t> res;
1461 if (!IsNamespace(scope))
1462 return res;
1463
1464#ifdef __APPLE__
1465 if (scope == STD_HANDLE) {
1466 res.push_back(GetScope("__1"));
1467 return res;
1468 }
1469#endif
1470
1471 TClassRef& cr = type_from_handle(scope);
1472 if (!cr.GetClass() || !cr->GetClassInfo())
1473 return res;
1474
1475 const std::vector<std::string>& v = gInterpreter->GetUsingNamespaces(cr->GetClassInfo());
1476 res.reserve(v.size());
1477 for (const auto& uid : v) {
1478 Cppyy::TCppScope_t uscope = GetScope(uid);
1479 if (uscope) res.push_back(uscope);
1480 }
1481
1482 return res;
1483}
1484
1485
1486// class reflection information ----------------------------------------------
1488{
1489 if (klass == GLOBAL_HANDLE)
1490 return "";
1491 TClassRef& cr = type_from_handle(klass);
1492 std::string clName = cr->GetName();
1493// TODO: why is this template splitting needed?
1494 std::string::size_type pos = clName.substr(0, clName.find('<')).rfind("::");
1495 if (pos != std::string::npos)
1496 return clName.substr(pos+2, std::string::npos);
1497 return clName;
1498}
1499
1501{
1502 if (klass == GLOBAL_HANDLE)
1503 return "";
1504 TClassRef& cr = type_from_handle(klass);
1505 if (cr.GetClass()) {
1506 std::string name = cr->GetName();
1508 return std::string("std::")+cr->GetName();
1509 return cr->GetName();
1510 }
1511 return "<unknown>";
1512}
1513
1515{
1516 TClassRef& cr = type_from_handle(klass);
1517 if (!cr.GetClass())
1518 return false;
1519
1520 TFunction* f = cr->GetMethod(("~"+GetFinalName(klass)).c_str(), "");
1521 if (f && (f->Property() & kIsVirtual))
1522 return true;
1523
1524 return false;
1525}
1526
1528{
1529 int is_complex = 1;
1530 size_t nbases = 0;
1531
1532 TClassRef& cr = type_from_handle(klass);
1533 if (cr.GetClass() && cr->GetListOfBases() != 0)
1534 nbases = GetNumBases(klass);
1535
1536 if (1 < nbases)
1537 is_complex = 1;
1538 else if (nbases == 0)
1539 is_complex = 0;
1540 else { // one base class only
1541 TBaseClass* base = (TBaseClass*)cr->GetListOfBases()->At(0);
1542 if (base->Property() & kIsVirtualBase)
1543 is_complex = 1; // TODO: verify; can be complex, need not be.
1544 else
1545 is_complex = HasComplexHierarchy(GetScope(base->GetName()));
1546 }
1547
1548 return is_complex;
1549}
1550
1552{
1553// Get the total number of base classes that this class has.
1554 TClassRef& cr = type_from_handle(klass);
1555 if (cr.GetClass() && cr->GetListOfBases() != 0)
1556 return (TCppIndex_t)cr->GetListOfBases()->GetSize();
1557 return (TCppIndex_t)0;
1558}
1559
1560////////////////////////////////////////////////////////////////////////////////
1561/// \fn Cppyy::TCppIndex_t GetLongestInheritancePath(TClass *klass)
1562/// \brief Retrieve number of base classes in the longest branch of the
1563/// inheritance tree of the input class.
1564/// \param[in] klass The class to start the retrieval process from.
1565///
1566/// This is a helper function for Cppyy::GetNumBasesLongestBranch.
1567/// Given an inheritance tree, the function assigns weight 1 to each class that
1568/// has at least one base. Starting from the input class, the function is
1569/// called recursively on all the bases. For each base the return value is one
1570/// (the weight of the base itself) plus the maximum value retrieved for their
1571/// bases in turn. For example, given the following inheritance tree:
1572///
1573/// ~~~{.cpp}
1574/// class A {}; class B: public A {};
1575/// class X {}; class Y: public X {}; class Z: public Y {};
1576/// class C: public B, Z {};
1577/// ~~~
1578///
1579/// calling this function on an instance of `C` will return 3, the steps
1580/// required to go from C to X.
1582{
1583
1584 auto directbases = klass->GetListOfBases();
1585 if (!directbases) {
1586 // This is a leaf with no bases
1587 return 0;
1588 }
1589 auto ndirectbases = directbases->GetSize();
1590 if (ndirectbases == 0) {
1591 // This is a leaf with no bases
1592 return 0;
1593 } else {
1594 // If there is at least one direct base
1595 std::vector<Cppyy::TCppIndex_t> nbases_branches;
1596 nbases_branches.reserve(ndirectbases);
1597
1598 // Traverse all direct bases of the current class and call the function
1599 // recursively
1600 for (auto baseclass : TRangeDynCast<TBaseClass>(directbases)) {
1601 if (!baseclass)
1602 continue;
1603 if (auto baseclass_tclass = baseclass->GetClassPointer()) {
1605 }
1606 }
1607
1608 // Get longest path among the direct bases of the current class
1609 auto longestbranch = std::max_element(std::begin(nbases_branches), std::end(nbases_branches));
1610
1611 // Add 1 to include the current class in the count
1612 return 1 + *longestbranch;
1613 }
1614}
1615
1616////////////////////////////////////////////////////////////////////////////////
1617/// \fn Cppyy::TCppIndex_t Cppyy::GetNumBasesLongest(TCppType_t klass)
1618/// \brief Retrieve number of base classes in the longest branch of the
1619/// inheritance tree.
1620/// \param[in] klass The class to start the retrieval process from.
1621///
1622/// The function converts the input class to a `TClass *` and calls
1623/// GetLongestInheritancePath.
1625{
1626
1627 const auto &cr = type_from_handle(klass);
1628
1629 if (auto klass_tclass = cr.GetClass()) {
1631 }
1632
1633 // In any other case, return zero
1634 return 0;
1635}
1636
1638{
1640 return ((TBaseClass*)cr->GetListOfBases()->At((int)ibase))->GetName();
1641}
1642
1644{
1645 if (derived == base)
1646 return true;
1649 if (derived_type.GetClass() && base_type.GetClass())
1650 return derived_type->GetBaseClass(base_type) != 0;
1651 return false;
1652}
1653
1655{
1657 const std::string& tn = cr->GetName();
1658 if (gSmartPtrTypes.find(tn.substr(0, tn.find("<"))) != gSmartPtrTypes.end())
1659 return true;
1660 return false;
1661}
1662
1664 const std::string& tname, TCppType_t* raw, TCppMethod_t* deref)
1665{
1666 const std::string& rn = ResolveName(tname);
1667 if (gSmartPtrTypes.find(rn.substr(0, rn.find("<"))) != gSmartPtrTypes.end()) {
1668 if (!raw && !deref) return true;
1669
1671 if (cr.GetClass()) {
1672 TFunction* func = cr->GetMethod("operator->", "");
1673 if (!func)
1674 func = cr->GetMethod("operator->", "");
1675 if (func) {
1676 if (deref) *deref = (TCppMethod_t)new_CallWrapper(func);
1677 if (raw) *raw = GetScope(TClassEdit::ShortType(
1678 func->GetReturnTypeNormalizedName().c_str(), 1));
1679 return (!deref || *deref) && (!raw || *raw);
1680 }
1681 }
1682 }
1683
1684 return false;
1685}
1686
1687void Cppyy::AddSmartPtrType(const std::string& type_name)
1688{
1690}
1691
1692void Cppyy::AddTypeReducer(const std::string& /*reducable*/, const std::string& /*reduced*/)
1693{
1694 // This function is deliberately left empty, because it is not used in
1695 // PyROOT, and synchronizing it with cppyy-backend upstream would require
1696 // patches to ROOT meta.
1697}
1698
1699
1700// type offsets --------------------------------------------------------------
1702 TCppObject_t address, int direction, bool rerror)
1703{
1704// calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0
1705 if (derived == base || !(base && derived))
1706 return (ptrdiff_t)0;
1707
1709 TClassRef& cb = type_from_handle(base);
1710
1711 if (!cd.GetClass() || !cb.GetClass())
1712 return (ptrdiff_t)0;
1713
1714 ptrdiff_t offset = -1;
1715 if (!(cd->GetClassInfo() && cb->GetClassInfo())) { // gInterpreter requirement
1716 // would like to warn, but can't quite determine error from intentional
1717 // hiding by developers, so only cover the case where we really should have
1718 // had a class info, but apparently don't:
1719 if (cd->IsLoaded()) {
1720 // warn to allow diagnostics
1721 std::ostringstream msg;
1722 msg << "failed offset calculation between " << cb->GetName() << " and " << cd->GetName();
1723 // TODO: propagate this warning to caller w/o use of Python C-API
1724 // PyErr_WarnEx(PyExc_RuntimeWarning, const_cast<char*>(msg.str().c_str()), 1);
1725 std::cerr << "Warning: " << msg.str() << '\n';
1726 }
1727
1728 // return -1 to signal caller NOT to apply offset
1729 return rerror ? (ptrdiff_t)offset : 0;
1730 }
1731
1732 offset = gInterpreter->ClassInfo_GetBaseOffset(
1733 cd->GetClassInfo(), cb->GetClassInfo(), (void*)address, direction > 0);
1734 if (offset == -1) // Cling error, treat silently
1735 return rerror ? (ptrdiff_t)offset : 0;
1736
1737 return (ptrdiff_t)(direction < 0 ? -offset : offset);
1738}
1739
1740
1741// method/function reflection information ------------------------------------
1743{
1745 return (TCppIndex_t)0; // enforce lazy
1746
1747 if (scope == GLOBAL_HANDLE)
1748 return gROOT->GetListOfGlobalFunctions(true)->GetSize();
1749
1751 if (cr.GetClass() && cr->GetListOfMethods(true)) {
1752 Cppyy::TCppIndex_t nMethods = (TCppIndex_t)cr->GetListOfMethods(false)->GetSize();
1753 if (nMethods == (TCppIndex_t)0) {
1754 std::string clName = GetScopedFinalName(scope);
1755 if (clName.find('<') != std::string::npos) {
1756 // chicken-and-egg problem: TClass does not know about methods until
1757 // instantiation, so force it
1758 std::ostringstream stmt;
1759 stmt << "template class " << clName << ";";
1760 gInterpreter->Declare(stmt.str().c_str()/*, silent = true*/);
1761
1762 // now reload the methods
1763 return (TCppIndex_t)cr->GetListOfMethods(true)->GetSize();
1764 }
1765 }
1766 return nMethods;
1767 }
1768
1769 return (TCppIndex_t)0; // unknown class?
1770}
1771
1772std::vector<Cppyy::TCppIndex_t> Cppyy::GetMethodIndicesFromName(
1773 TCppScope_t scope, const std::string& name)
1774{
1775 std::vector<TCppIndex_t> indices;
1777 if (cr.GetClass()) {
1778 gInterpreter->UpdateListOfMethods(cr.GetClass());
1779 int imeth = 0;
1780 TFunction* func = nullptr;
1781 TIter next(cr->GetListOfMethods());
1782 while ((func = (TFunction*)next())) {
1783 if (match_name(name, func->GetName())) {
1784 // C++ functions should be public to allow access; C functions have no access
1785 // specifier and should always be accepted
1786 auto prop = func->Property();
1787 if ((prop & kIsPublic) || !(prop & (kIsPrivate | kIsProtected | kIsPublic)))
1788 indices.push_back((TCppIndex_t)imeth);
1789 }
1790 ++imeth;
1791 }
1792 } else if (scope == GLOBAL_HANDLE) {
1793 TCollection* funcs = gROOT->GetListOfGlobalFunctions(true);
1794
1795 // tickle deserialization
1796 if (!funcs->FindObject(name.c_str()))
1797 return indices;
1798
1799 TFunction* func = nullptr;
1800 TIter ifunc(funcs);
1801 while ((func = (TFunction*)ifunc.Next())) {
1802 if (match_name(name, func->GetName()))
1803 indices.push_back((TCppIndex_t)new_CallWrapper(func));
1804 }
1805 }
1806
1807 return indices;
1808}
1809
1811{
1813 if (cr.GetClass()) {
1814 TFunction* f = (TFunction*)cr->GetListOfMethods(false)->At((int)idx);
1815 if (f) return (Cppyy::TCppMethod_t)new_CallWrapper(f);
1816 return (Cppyy::TCppMethod_t)nullptr;
1817 }
1818
1820 return (Cppyy::TCppMethod_t)idx;
1821}
1822
1824{
1825 if (method) {
1826 const std::string& name = ((CallWrapper*)method)->fName;
1827
1828 if (name.compare(0, 8, "operator") != 0)
1829 // strip template instantiation part, if any
1830 return name.substr(0, name.find('<'));
1831 return name;
1832 }
1833 return "<unknown>";
1834}
1835
1837{
1838 if (method) {
1839 std::string name = ((CallWrapper*)method)->fName;
1840 name.erase(std::remove(name.begin(), name.end(), ' '), name.end());
1841 return name;
1842 }
1843 return "<unknown>";
1844}
1845
1847{
1848 if (method)
1849 return m2f(method)->GetMangledName();
1850 return "<unknown>";
1851}
1852
1854{
1855 if (method) {
1856 TFunction* f = m2f(method);
1857 if (f->ExtraProperty() & kIsConstructor)
1858 return "constructor";
1859 std::string restype = f->GetReturnTypeName();
1860 // TODO: this is ugly; GetReturnTypeName() keeps typedefs, but may miss scopes
1861 // for some reason; GetReturnTypeNormalizedName() has been modified to return
1862 // the canonical type to guarantee correct namespaces. Sometimes typedefs look
1863 // better, sometimes not, sometimes it's debatable (e.g. vector<int>::size_type).
1864 // So, for correctness sake, GetReturnTypeNormalizedName() is used, except for a
1865 // special case of uint8_t/int8_t that must propagate as their typedefs.
1866 if (restype.find("int8_t") != std::string::npos)
1867 return restype;
1868 restype = f->GetReturnTypeNormalizedName();
1869 if (restype == "(lambda)") {
1870 std::ostringstream s;
1871 // TODO: what if there are parameters to the lambda?
1872 s << "__cling_internal::FT<decltype("
1873 << GetMethodFullName(method) << "(";
1874 for (Cppyy::TCppIndex_t i = 0; i < Cppyy::GetMethodNumArgs(method); ++i) {
1875 if (i != 0) s << ", ";
1876 s << Cppyy::GetMethodArgType(method, i) << "{}";
1877 }
1878 s << "))>::F";
1879 TClass* cl = TClass::GetClass(s.str().c_str());
1880 if (cl) return cl->GetName();
1881 // TODO: signal some type of error (or should that be upstream?
1882 }
1883 return restype;
1884 }
1885 return "<unknown>";
1886}
1887
1889{
1890 if (method)
1891 return m2f(method)->GetNargs();
1892 return 0;
1893}
1894
1896{
1897 if (method) {
1898 TFunction* f = m2f(method);
1899 return (TCppIndex_t)(f->GetNargs() - f->GetNargsOpt());
1900 }
1901 return (TCppIndex_t)0;
1902}
1903
1905{
1906 if (method) {
1907 TFunction* f = m2f(method);
1908 TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At((int)iarg);
1909 return arg->GetName();
1910 }
1911 return "<unknown>";
1912}
1913
1915{
1916 if (method) {
1917 TFunction* f = m2f(method);
1918 TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At((int)iarg);
1919 std::string ft = arg->GetFullTypeName();
1920 if (ft.rfind("enum ", 0) != std::string::npos) { // special case to preserve 'enum' tag
1921 std::string arg_type = arg->GetTypeNormalizedName();
1922 return arg_type.insert(arg_type.rfind("const ", 0) == std::string::npos ? 0 : 6, "enum ");
1923 } else if (g_builtins.find(ft) != g_builtins.end() || ft.find("int8_t") != std::string::npos)
1924 return ft; // do not resolve int8_t and uint8_t typedefs
1925
1926 return arg->GetTypeNormalizedName();
1927 }
1928 return "<unknown>";
1929}
1930
1932{
1933 if (method) {
1934 TFunction* f = m2f(method);
1935 TMethodArg* arg = (TMethodArg *)f->GetListOfMethodArgs()->At((int)iarg);
1936 void *argqtp = gInterpreter->TypeInfo_QualTypePtr(arg->GetTypeInfo());
1937
1938 TypeInfo_t *reqti = gInterpreter->TypeInfo_Factory(req_type.c_str());
1939 void *reqqtp = gInterpreter->TypeInfo_QualTypePtr(reqti);
1940
1941 // This scoring is not based on any particular rules
1942 if (gInterpreter->IsSameType(argqtp, reqqtp))
1943 return 0; // Best match
1944 else if ((gInterpreter->IsSignedIntegerType(argqtp) && gInterpreter->IsSignedIntegerType(reqqtp)) ||
1945 (gInterpreter->IsUnsignedIntegerType(argqtp) && gInterpreter->IsUnsignedIntegerType(reqqtp)) ||
1946 (gInterpreter->IsFloatingType(argqtp) && gInterpreter->IsFloatingType(reqqtp)))
1947 return 1;
1948 else if ((gInterpreter->IsSignedIntegerType(argqtp) && gInterpreter->IsUnsignedIntegerType(reqqtp)) ||
1949 (gInterpreter->IsFloatingType(argqtp) && gInterpreter->IsUnsignedIntegerType(reqqtp)))
1950 return 2;
1951 else if ((gInterpreter->IsIntegerType(argqtp) && gInterpreter->IsIntegerType(reqqtp)))
1952 return 3;
1953 else if ((gInterpreter->IsVoidPointerType(argqtp) && gInterpreter->IsPointerType(reqqtp)))
1954 return 4;
1955 else
1956 return 10; // Penalize heavily for no possible match
1957 }
1958 return INT_MAX; // Method is not valid
1959}
1960
1962{
1963 if (method) {
1964 TFunction* f = m2f(method);
1965 TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At((int)iarg);
1966 const char* def = arg->GetDefault();
1967 if (def)
1968 return def;
1969 }
1970
1971 return "";
1972}
1973
1975{
1976 TFunction* f = m2f(method);
1977 if (f) {
1978 std::ostringstream sig;
1979 sig << "(";
1980 int nArgs = f->GetNargs();
1981 if (maxargs != (TCppIndex_t)-1) nArgs = std::min(nArgs, (int)maxargs);
1982 for (int iarg = 0; iarg < nArgs; ++iarg) {
1983 TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At(iarg);
1984 sig << arg->GetFullTypeName();
1985 if (show_formalargs) {
1986 const char* argname = arg->GetName();
1987 if (argname && argname[0] != '\0') sig << " " << argname;
1988 const char* defvalue = arg->GetDefault();
1989 if (defvalue && defvalue[0] != '\0') sig << " = " << defvalue;
1990 }
1991 if (iarg != nArgs-1) sig << (show_formalargs ? ", " : ",");
1992 }
1993 sig << ")";
1994 return sig.str();
1995 }
1996 return "<unknown>";
1997}
1998
2000{
2001 std::string scName = GetScopedFinalName(scope);
2002 TFunction* f = m2f(method);
2003 if (f) {
2004 std::ostringstream sig;
2005 sig << f->GetReturnTypeName() << " "
2006 << scName << "::" << f->GetName();
2008 return sig.str();
2009 }
2010 return "<unknown>";
2011}
2012
2014{
2015 if (method) {
2016 TFunction* f = m2f(method);
2017 return f->Property() & kIsConstMethod;
2018 }
2019 return false;
2020}
2021
2023{
2025 return (TCppIndex_t)0; // enforce lazy
2026
2027 if (scope == GLOBAL_HANDLE) {
2028 TCollection* coll = gROOT->GetListOfFunctionTemplates();
2029 if (coll) return (TCppIndex_t)coll->GetSize();
2030 } else {
2032 if (cr.GetClass()) {
2033 TCollection* coll = cr->GetListOfFunctionTemplates(true);
2034 if (coll) return (TCppIndex_t)coll->GetSize();
2035 }
2036 }
2037
2038// failure ...
2039 return (TCppIndex_t)0;
2040}
2041
2043{
2045 return ((THashList*)gROOT->GetListOfFunctionTemplates())->At((int)imeth)->GetName();
2046 else {
2048 if (cr.GetClass())
2049 return cr->GetListOfFunctionTemplates(false)->At((int)imeth)->GetName();
2050 }
2051
2052// failure ...
2053 assert(!"should not be called unless GetNumTemplatedMethods() succeeded");
2054 return "";
2055}
2056
2058{
2060 return false;
2061
2063 if (cr.GetClass()) {
2064 TFunctionTemplate* f = (TFunctionTemplate*)cr->GetListOfFunctionTemplates(false)->At((int)imeth);
2065 return f->ExtraProperty() & kIsConstructor;
2066 }
2067
2068 return false;
2069}
2070
2072{
2074 return (bool)gROOT->GetFunctionTemplate(name.c_str());
2075 else {
2077 if (cr.GetClass())
2078 return (bool)cr->GetFunctionTemplate(name.c_str());
2079 }
2080
2081// failure ...
2082 return false;
2083}
2084
2086{
2087 TFunctionTemplate* tf = nullptr;
2089 tf = gROOT->GetFunctionTemplate(name.c_str());
2090 else {
2092 if (cr.GetClass())
2093 tf = cr->GetFunctionTemplate(name.c_str());
2094 }
2095
2096 if (!tf) return false;
2097
2098 return (bool)(tf->Property() & kIsStatic);
2099}
2100
2102{
2104 if (cr.GetClass()) {
2105 TFunction* f = (TFunction*)cr->GetListOfMethods(false)->At((int)idx);
2106 if (f && strstr(f->GetName(), "<")) return true;
2107 return false;
2108 }
2109
2111 if (((CallWrapper*)idx)->fName.find('<') != std::string::npos) return true;
2112 return false;
2113}
2114
2115// helpers for Cppyy::GetMethodTemplate()
2116static std::map<TDictionary::DeclId_t, CallWrapper*> gMethodTemplates;
2117
2118static inline
2119void remove_space(std::string& n) {
2120 std::string::iterator pos = std::remove_if(n.begin(), n.end(), isspace);
2121 n.erase(pos, n.end());
2122}
2123
2124static inline
2125bool template_compare(std::string n1, std::string n2) {
2126 if (n1.back() == '>') n1 = n1.substr(0, n1.size()-1);
2129 return n2.compare(0, n1.size(), n1) == 0;
2130}
2131
2133 TCppScope_t scope, const std::string& name, const std::string& proto)
2134{
2135// There is currently no clean way of extracting a templated method out of ROOT/meta
2136// for a variety of reasons, none of them fundamental. The game played below is to
2137// first get any pre-existing functions already managed by ROOT/meta, but if that fails,
2138// to do an explicit lookup that ignores the prototype (i.e. the full name should be
2139// enough), and finally to ignore the template arguments part of the name as this fails
2140// in cling if there are default parameters.
2141 TFunction* func = nullptr; ClassInfo_t* cl = nullptr;
2143 func = gROOT->GetGlobalFunctionWithPrototype(name.c_str(), proto.c_str());
2144 if (func && name.back() == '>') {
2145 // make sure that all template parameters match (more are okay, e.g. defaults or
2146 // ones derived from the arguments or variadic templates)
2147 if (!template_compare(name, func->GetName()))
2148 func = nullptr; // happens if implicit conversion matches the overload
2149 }
2150 } else {
2152 if (cr.GetClass()) {
2153 func = cr->GetMethodWithPrototype(name.c_str(), proto.c_str());
2154 if (!func) {
2155 cl = cr->GetClassInfo();
2156 // try base classes to cover a common 'using' case (TODO: this is stupid and misses
2157 // out on base classes; fix that with improved access to Cling)
2159 for (TCppIndex_t i = 0; i < nbases; ++i) {
2161 if (base.GetClass()) {
2162 func = base->GetMethodWithPrototype(name.c_str(), proto.c_str());
2163 if (func) break;
2164 }
2165 }
2166 }
2167 }
2168 }
2169
2170 if (!func && name.back() == '>' && (cl || scope == (TCppScope_t)GLOBAL_HANDLE)) {
2171 // try again, ignoring proto in case full name is complete template
2172 auto declid = gInterpreter->GetFunction(cl, name.c_str());
2173 if (declid) {
2174 auto existing = gMethodTemplates.find(declid);
2175 if (existing == gMethodTemplates.end()) {
2176 auto cw = new_CallWrapper(declid, name);
2177 existing = gMethodTemplates.insert(std::make_pair(declid, cw)).first;
2178 }
2179 return (TCppMethod_t)existing->second;
2180 }
2181 }
2182
2183 if (func) {
2184 // make sure we didn't match a non-templated overload
2185 if (func->ExtraProperty() & kIsTemplateSpec)
2186 return (TCppMethod_t)new_CallWrapper(func);
2187
2188 // disregard this non-templated method as it will be considered when appropriate
2189 return (TCppMethod_t)nullptr;
2190 }
2191
2192// try again with template arguments removed from name, if applicable
2193 if (name.back() == '>') {
2194 auto pos = name.find('<');
2195 if (pos != std::string::npos) {
2197 if (cppmeth) {
2198 // allow if requested template names match up to the result
2199 const std::string& alt = GetMethodFullName(cppmeth);
2200 if (name.size() < alt.size() && alt.find('<') == pos) {
2202 return cppmeth;
2203 }
2204 }
2205 }
2206 }
2207
2208// failure ...
2209 return (TCppMethod_t)nullptr;
2210}
2211
2212static inline
2213std::string type_remap(const std::string& n1, const std::string& n2)
2214{
2215// Operator lookups of (C++ string, Python str) should succeed for the combos of
2216// string/str, wstring/str, string/unicode and wstring/unicode; since C++ does not have a
2217// operator+(std::string, std::wstring), we'll have to look up the same type and rely on
2218// the converters in CPyCppyy/_cppyy.
2219 if (n1 == "str" || n1 == "unicode") {
2220 if (n2 == "std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >")
2221 return n2; // match like for like
2222 return "std::string"; // probably best bet
2223 } else if (n1 == "float") {
2224 return "double"; // debatable, but probably intended
2225 } else if (n1 == "complex") {
2226 return "std::complex<double>";
2227 }
2228 return n1;
2229}
2230
2232 TCppType_t scope, const std::string& lc, const std::string& rc, const std::string& opname)
2233{
2234// Find a global operator function with a matching signature; prefer by-ref, but
2235// fall back on by-value if that fails.
2236 std::string lcname1 = TClassEdit::CleanType(lc.c_str());
2237 const std::string& rcname = rc.empty() ? rc : type_remap(TClassEdit::CleanType(rc.c_str()), lcname1);
2238 const std::string& lcname = type_remap(lcname1, rcname);
2239
2240 std::string proto = lcname + "&" + (rc.empty() ? rc : (", " + rcname + "&"));
2242 TFunction* func = gROOT->GetGlobalFunctionWithPrototype(opname.c_str(), proto.c_str());
2243 if (func) return (TCppIndex_t)new_CallWrapper(func);
2244 proto = lcname + (rc.empty() ? rc : (", " + rcname));
2245 func = gROOT->GetGlobalFunctionWithPrototype(opname.c_str(), proto.c_str());
2246 if (func) return (TCppIndex_t)new_CallWrapper(func);
2247 } else {
2249 if (cr.GetClass()) {
2250 TFunction* func = cr->GetMethodWithPrototype(opname.c_str(), proto.c_str());
2251 if (func) return (TCppIndex_t)cr->GetListOfMethods()->IndexOf(func);
2252 proto = lcname + (rc.empty() ? rc : (", " + rcname));
2253 func = cr->GetMethodWithPrototype(opname.c_str(), proto.c_str());
2254 if (func) return (TCppIndex_t)cr->GetListOfMethods()->IndexOf(func);
2255 }
2256 }
2257
2258// failure ...
2259 return (TCppIndex_t)-1;
2260}
2261
2262// method properties ---------------------------------------------------------
2263
2265{
2266 if (!method)
2267 return false;
2268 TFunction *f = m2f(method);
2269 return f->Property() & prop;
2270}
2271
2273{
2274 if (!method)
2275 return false;
2276 TFunction *f = m2f(method);
2277 return f->ExtraProperty() & prop;
2278}
2279
2284
2289
2294
2299
2304
2309
2310// data member reflection information ----------------------------------------
2312{
2314 return (TCppIndex_t)0; // enforce lazy
2315
2316 if (scope == GLOBAL_HANDLE)
2317 return gROOT->GetListOfGlobals(true)->GetSize();
2318
2320 if (cr.GetClass() && cr->GetListOfDataMembers())
2321 return cr->GetListOfDataMembers()->GetSize();
2322
2323 return (TCppIndex_t)0; // unknown class?
2324}
2325
2327{
2329 if (cr.GetClass()) {
2330 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2331 return m->GetName();
2332 }
2335 return gbl->GetName();
2336}
2337
2338static inline
2339int count_scopes(const std::string& tpname)
2340{
2341 int count = 0;
2342 std::string::size_type pos = tpname.find("::", 0);
2343 while (pos != std::string::npos) {
2344 count++;
2345 pos = tpname.find("::", pos+1);
2346 }
2347 return count;
2348}
2349
2351{
2352 if (scope == GLOBAL_HANDLE) {
2354 std::string fullType = gbl->GetFullTypeName();
2355
2356 if ((int)gbl->GetArrayDim()) {
2357 std::ostringstream s;
2358 for (int i = 0; i < (int)gbl->GetArrayDim(); ++i)
2359 s << '[' << gbl->GetMaxIndex(i) << ']';
2360 fullType.append(s.str());
2361 }
2362 return fullType;
2363 }
2364
2366 if (cr.GetClass()) {
2367 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2368 // TODO: fix this upstream ... Usually, we want m->GetFullTypeName(), because it
2369 // does not resolve typedefs, but it looses scopes for inner classes/structs, it
2370 // doesn't resolve constexpr (leaving unresolved names), leaves spurious "struct"
2371 // or "union" in the name, and can not handle anonymous unions. In that case
2372 // m->GetTrueTypeName() should be used. W/o clear criteria to determine all these
2373 // cases, the general rules are to prefer the true name if the full type does not
2374 // exist as a type for classes, and the most scoped name otherwise.
2375 const char* ft = m->GetFullTypeName(); std::string fullType = ft ? ft : "";
2376 const char* tn = m->GetTrueTypeName(); std::string trueName = tn ? tn : "";
2377 if (!trueName.empty() && fullType != trueName && !IsBuiltin(trueName)) {
2378 if ( (!TClass::GetClass(fullType.c_str()) && TClass::GetClass(trueName.c_str())) || \
2380 bool is_enum_tag = fullType.rfind("enum ", 0) != std::string::npos;
2382 if (is_enum_tag)
2383 fullType.insert(fullType.rfind("const ", 0) == std::string::npos ? 0 : 6, "enum ");
2384 }
2385 }
2386
2387 if ((int)m->GetArrayDim()) {
2388 std::ostringstream s;
2389 for (int i = 0; i < (int)m->GetArrayDim(); ++i)
2390 s << '[' << m->GetMaxIndex(i) << ']';
2391 fullType.append(s.str());
2392 }
2393
2394#if 0
2395 // this is the only place where anonymous structs are uniquely identified, so setup
2396 // a class if needed, such that subsequent GetScope() and GetScopedFinalName() calls
2397 // return the uniquely named class
2398 auto declid = m->GetTagDeclId(); //GetDeclId();
2399 if (declid && (m->Property() & (kIsClass | kIsStruct | kIsUnion)) &&\
2400 (fullType.find("(anonymous)") != std::string::npos || fullType.find("(unnamed)") != std::string::npos)) {
2401
2402 // use the (fixed) decl id address to guarantee a unique name, even when there
2403 // are multiple anonymous structs in the parent scope
2404 std::ostringstream fulls;
2405 fulls << fullType << "@" << (void*)declid;
2406 fullType = fulls.str();
2407
2409 ClassInfo_t* ci = gInterpreter->ClassInfo_Factory(declid);
2410 TClass* cl = gInterpreter->GenerateTClass(ci, kTRUE /* silent */);
2411 gInterpreter->ClassInfo_Delete(ci);
2412 if (cl) cl->SetName(fullType.c_str());
2414 g_classrefs.emplace_back(cl);
2415 }
2416 }
2417#endif
2418 return fullType;
2419 }
2420
2421 return "<unknown>";
2422}
2423
2425{
2426 if (scope == GLOBAL_HANDLE) {
2428 if (!gbl->GetAddress() || gbl->GetAddress() == (void*)-1) {
2429 // CLING WORKAROUND: make sure variable is loaded
2430 intptr_t addr = (intptr_t)gInterpreter->ProcessLine((std::string("&")+gbl->GetName()+";").c_str());
2431 if (gbl->GetAddress() && gbl->GetAddress() != (void*)-1)
2432 return (intptr_t)gbl->GetAddress(); // now loaded!
2433 return addr; // last resort ...
2434 }
2435 return (intptr_t)gbl->GetAddress();
2436 }
2437
2439 if (cr.GetClass()) {
2440 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2441 // CLING WORKAROUND: the following causes templates to be instantiated first within the proper
2442 // scope, making the lookup succeed and preventing spurious duplicate instantiations later. Also,
2443 // if the variable is not yet loaded, pull it in through gInterpreter.
2444 intptr_t offset = (intptr_t)-1;
2445 if (m->Property() & kIsStatic) {
2446 if (strchr(cr->GetName(), '<'))
2447 gInterpreter->ProcessLine(((std::string)cr->GetName()+"::"+m->GetName()+";").c_str());
2448 offset = (intptr_t)m->GetOffsetCint(); // yes, Cling (GetOffset() is both wrong
2449 // and caches that wrong result!
2450 if (offset == (intptr_t)-1)
2451 return (intptr_t)gInterpreter->ProcessLine((std::string("&")+cr->GetName()+"::"+m->GetName()+";").c_str());
2452 } else
2453 offset = (intptr_t)m->GetOffsetCint(); // yes, Cling, see above
2454 return offset;
2455 }
2456
2457 return (intptr_t)-1;
2458}
2459
2460static inline
2462{
2463 if (!gb) return (Cppyy::TCppIndex_t)-1;
2464
2465 auto pidx = g_globalidx.find(gb);
2466 if (pidx == g_globalidx.end()) {
2467 auto idx = g_globalvars.size();
2468 g_globalvars.push_back(gb);
2469 g_globalidx[gb] = idx;
2470 return (Cppyy::TCppIndex_t)idx;
2471 }
2472 return (Cppyy::TCppIndex_t)pidx->second;
2473}
2474
2476{
2477 if (scope == GLOBAL_HANDLE) {
2478 TGlobal* gb = (TGlobal*)gROOT->GetListOfGlobals(false /* load */)->FindObject(name.c_str());
2479 if (!gb) gb = (TGlobal*)gROOT->GetListOfGlobals(true /* load */)->FindObject(name.c_str());
2480 if (!gb) {
2481 // some enums are not loaded as they are not considered part of
2482 // the global scope, but of the enum scope; get them w/o checking
2483 TDictionary::DeclId_t did = gInterpreter->GetDataMember(nullptr, name.c_str());
2484 if (did) {
2485 DataMemberInfo_t* t = gInterpreter->DataMemberInfo_Factory(did, nullptr);
2486 ((TListOfDataMembers*)gROOT->GetListOfGlobals())->Get(t, true);
2487 gb = (TGlobal*)gROOT->GetListOfGlobals(false /* load */)->FindObject(name.c_str());
2488 }
2489 }
2490
2491 if (gb && strcmp(gb->GetFullTypeName(), "(lambda)") == 0) {
2492 // lambdas use a compiler internal closure type, so we wrap
2493 // them, then return the wrapper's type
2494 // TODO: this current leaks the std::function; also, if possible,
2495 // should instantiate through TClass rather then ProcessLine
2496 std::ostringstream s;
2497 s << "auto __cppyy_internal_wrap_" << name << " = "
2498 "new __cling_internal::FT<decltype(" << name << ")>::F"
2499 "{" << name << "};";
2500 gInterpreter->ProcessLine(s.str().c_str());
2501 TGlobal* wrap = (TGlobal*)gROOT->GetListOfGlobals(true)->FindObject(
2502 ("__cppyy_internal_wrap_"+name).c_str());
2503 if (wrap && wrap->GetAddress()) gb = wrap;
2504 }
2505
2506 return gb2idx(gb);
2507
2508 } else {
2510 if (cr.GetClass()) {
2511 TDataMember* dm =
2512 (TDataMember*)cr->GetListOfDataMembers()->FindObject(name.c_str());
2513 // TODO: turning this into an index is silly ...
2514 if (dm) return (TCppIndex_t)cr->GetListOfDataMembers()->IndexOf(dm);
2515 }
2516 }
2517
2518 return (TCppIndex_t)-1;
2519}
2520
2522{
2523 if (scope == GLOBAL_HANDLE) {
2524 TGlobal* gb = (TGlobal*)((THashList*)gROOT->GetListOfGlobals(false /* load */))->At((int)idata);
2525 return gb2idx(gb);
2526 }
2527
2528 return idata;
2529}
2530
2531
2532// data member properties ----------------------------------------------------
2534{
2535 if (scope == GLOBAL_HANDLE)
2536 return true;
2538 if (cr->Property() & kIsNamespace)
2539 return true;
2540 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2541 return m->Property() & kIsPublic;
2542}
2543
2545{
2546 if (scope == GLOBAL_HANDLE)
2547 return true;
2549 if (cr->Property() & kIsNamespace)
2550 return true;
2551 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2552 return m->Property() & kIsProtected;
2553}
2554
2556{
2557 if (scope == GLOBAL_HANDLE)
2558 return true;
2560 if (cr->Property() & kIsNamespace)
2561 return true;
2562 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2563 return m->Property() & kIsStatic;
2564}
2565
2567{
2568 Long_t property = 0;
2569 if (scope == GLOBAL_HANDLE) {
2571 property = gbl->Property();
2572 }
2574 if (cr.GetClass()) {
2575 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2576 property = m->Property();
2577 }
2578
2579// if the data type is const, but the data member is a pointer/array, the data member
2580// itself is not const; alternatively it is a pointer that is constant
2582}
2583
2585{
2586// TODO: currently, ROOT/meta does not properly distinguish between variables of enum
2587// type, and values of enums. The latter are supposed to be const. This code relies on
2588// odd features (bugs?) to figure out the difference, but this should really be fixed
2589// upstream and/or deserves a new API.
2590
2591 if (scope == GLOBAL_HANDLE) {
2593
2594 // make use of an oddity: enum global variables do not have their kIsStatic bit
2595 // set, whereas enum global values do
2596 return (gbl->Property() & kIsEnum) && (gbl->Property() & kIsStatic);
2597 }
2598
2600 if (cr.GetClass()) {
2601 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2602 std::string ti = m->GetTypeName();
2603
2604 // can't check anonymous enums by type name, so just accept them as enums
2605 if (ti.rfind("(anonymous)") != std::string::npos || ti.rfind("(unnamed)") != std::string::npos)
2606 return m->Property() & kIsEnum;
2607
2608 // since there seems to be no distinction between data of enum type and enum values,
2609 // check the list of constants for the type to see if there's a match
2610 if (ti.rfind(cr->GetName(), 0) != std::string::npos) {
2611 std::string::size_type s = strlen(cr->GetName())+2;
2612 if (s < ti.size()) {
2613 TEnum* ee = ((TListOfEnums*)cr->GetListOfEnums())->GetObject(ti.substr(s, std::string::npos).c_str());
2614 if (ee) return ee->GetConstant(m->GetName());
2615 }
2616 }
2617 }
2618
2619// this default return only means that the data will be writable, not that it will
2620// be unreadable or otherwise misrepresented
2621 return false;
2622}
2623
2625{
2626 if (scope == GLOBAL_HANDLE) {
2628 return gbl->GetMaxIndex(dimension);
2629 }
2631 if (cr.GetClass()) {
2632 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2633 return m->GetMaxIndex(dimension);
2634 }
2635 return -1;
2636}
2637
2638
2639// enum properties -----------------------------------------------------------
2641{
2642 if (scope == GLOBAL_HANDLE)
2643 return (TCppEnum_t)gROOT->GetListOfEnums(kTRUE)->FindObject(enum_name.c_str());
2644
2646 if (cr.GetClass())
2647 return (TCppEnum_t)cr->GetListOfEnums(kTRUE)->FindObject(enum_name.c_str());
2648
2649 return (TCppEnum_t)0;
2650}
2651
2653{
2654 return (TCppIndex_t)((TEnum*)etype)->GetConstants()->GetSize();
2655}
2656
2658{
2659 return ((TEnumConstant*)((TEnum*)etype)->GetConstants()->At((int)idata))->GetName();
2660}
2661
2663{
2664 TEnumConstant* ecst = (TEnumConstant*)((TEnum*)etype)->GetConstants()->At((int)idata);
2665 return (long long)ecst->GetValue();
2666}
2667
2668
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
static Roo_reg_AGKInteg1D instance
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:68
long double LongDouble_t
Long Double (not portable)
Definition RtypesCore.h:75
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
@ kMAXSIGNALS
Definition Rtypes.h:60
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
EFunctionProperty
@ kIsDestructor
@ kIsTemplateSpec
@ kIsConstructor
@ kClassIsAggregate
@ kClassHasVirtual
@ kClassHasExplicitDtor
@ kClassHasImplicitDtor
EProperty
Definition TDictionary.h:64
@ kIsPublic
Definition TDictionary.h:75
@ kIsPointer
Definition TDictionary.h:78
@ kIsConstant
Definition TDictionary.h:88
@ kIsConstMethod
Definition TDictionary.h:96
@ kIsClass
Definition TDictionary.h:65
@ kIsEnum
Definition TDictionary.h:68
@ kIsPrivate
Definition TDictionary.h:77
@ kIsConstPointer
Definition TDictionary.h:90
@ kIsFundamental
Definition TDictionary.h:70
@ kIsAbstract
Definition TDictionary.h:71
@ kIsArray
Definition TDictionary.h:79
@ kIsStatic
Definition TDictionary.h:80
@ kIsExplicit
Definition TDictionary.h:94
@ kIsStruct
Definition TDictionary.h:66
@ kIsProtected
Definition TDictionary.h:76
@ kIsVirtual
Definition TDictionary.h:72
@ kIsUnion
Definition TDictionary.h:67
@ kIsNamespace
Definition TDictionary.h:95
@ kIsVirtualBase
Definition TDictionary.h:89
constexpr Int_t kFatal
Definition TError.h:50
Int_t gErrorIgnoreLevel
errors with level below this value will be ignored. Default is kUnset.
Definition TError.cxx:33
R__EXTERN TExceptionHandler * gExceptionHandler
Definition TException.h:79
R__EXTERN ExceptionContext_t * gException
Definition TException.h:69
R__EXTERN void Throw(int code)
If an exception context has been set (using the TRY and RETRY macros) jump back to where it was set.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h prop
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h req_type
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void funcs
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t property
char name[80]
Definition TGX11.cxx:148
#define gInterpreter
#define gROOT
Definition TROOT.h:417
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
static struct Signalmap_t gSignalMap[kMAXSIGNALS]
const char * proto
Definition civetweb.c:18822
#define free
Definition civetweb.c:1578
#define malloc
Definition civetweb.c:1575
const_iterator begin() const
const_iterator end() const
Each class (see TClass) has a linked list of its base class(es).
Definition TBaseClass.h:33
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
TClassRef is used to implement a permanent reference to a TClass object.
Definition TClassRef.h:29
TClass * GetClass() const
Definition TClassRef.h:67
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
TList * GetListOfUsingDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of using declarations of a class.
Definition TClass.cxx:3844
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition TClass.cxx:5048
TMethod * GetMethod(const char *method, const char *params, Bool_t objectIsConst=kFALSE)
Find the best method (if there is one) matching the parameters.
Definition TClass.cxx:4469
TMethod * GetMethodWithPrototype(const char *method, const char *proto, Bool_t objectIsConst=kFALSE, ROOT::EFunctionMatchMode mode=ROOT::kConversionMatch)
Find the method with a given prototype.
Definition TClass.cxx:4514
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition TClass.cxx:5470
TList * GetListOfFunctionTemplates(Bool_t load=kTRUE)
Return TListOfFunctionTemplates for a class.
Definition TClass.cxx:3856
TList * GetListOfEnums(Bool_t load=kTRUE)
Return a list containing the TEnums of a class.
Definition TClass.cxx:3744
TList * GetListOfMethods(Bool_t load=kTRUE)
Return list containing the TMethods of a class.
Definition TClass.cxx:3870
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3828
@ kRealNew
Definition TClass.h:110
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3694
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition TClass.cxx:6017
ClassInfo_t * GetClassInfo() const
Definition TClass.h:448
Long_t ClassProperty() const
Return the C++ property of this class, eg.
Definition TClass.cxx:2403
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6191
Bool_t HasDefaultConstructor(Bool_t testio=kFALSE) const
Return true if we have access to a constructor usable for I/O.
Definition TClass.cxx:7550
TMethod * GetMethodAllAny(const char *method)
Return pointer to method without looking at parameters.
Definition TClass.cxx:4442
ROOT::DelFunc_t GetDelete() const
Return the wrapper around delete ThisObject.
Definition TClass.cxx:7628
TClass * GetActualClass(const void *object) const
Return a pointer to the real class of the object.
Definition TClass.cxx:2614
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2994
Collection abstract base class.
Definition TCollection.h:65
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
Basic data type descriptor (datatype information is obtained from CINT).
Definition TDataType.h:44
Int_t GetType() const
Definition TDataType.h:71
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
Int_t Size() const
Get size of basic typedef'ed type.
const void * DeclId_t
The TEnumConstant class implements the constants of the enum type.
The TEnum class implements the enum type.
Definition TEnum.h:33
Definition TEnv.h:41
const char * GetValue() const
Definition TEnv.h:65
const char * GetName() const override
Returns name of object.
Definition TEnv.h:64
Dictionary for function template This class describes one single function template.
Global functions class (global functions are obtained from CINT).
Definition TFunction.h:30
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
Long_t ExtraProperty() const
Get property description word. For meaning of bits see EProperty.
std::string GetReturnTypeNormalizedName() const
Get the normalized name of the return type.
Global variables class (global variables are obtained from CINT).
Definition TGlobal.h:28
THashList implements a hybrid collection class consisting of a hash table and a list to store TObject...
Definition THashList.h:34
A collection of TDataMember objects designed for fast access given a DeclId_t and for keep track of T...
A collection of TEnum objects designed for fast access given a DeclId_t and for keep track of TEnum t...
TObject * At(Int_t idx) const override
Returns the object at position idx. Returns 0 if idx is out of range.
Definition TList.cxx:487
Each ROOT method (see TMethod) has a linked list of its arguments.
Definition TMethodArg.h:36
const char * GetFullTypeName() const
Get full type description of method argument, e.g.: "class TDirectory*".
TypeInfo_t * GetTypeInfo() const
Get the TypeInfo of the method argument.
const char * GetDefault() const
Get default value of method argument.
std::string GetTypeNormalizedName() const
Get the normalized name of the return type.
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:149
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:462
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition TObject.cxx:425
static Bool_t Initialized()
Return kTRUE if the TROOT object has been initialized.
Definition TROOT.cxx:3067
virtual void Exit(int code, Bool_t mode=kTRUE)
Exit the application.
Definition TSystem.cxx:729
virtual void StackTrace()
Print a stack trace.
Definition TSystem.cxx:747
static void cond_add(Cppyy::TCppScope_t scope, const std::string &ns_scope, std::set< std::string > &cppnames, const char *name, bool nofilter=false)
static bool testMethodProperty(Cppyy::TCppMethod_t method, EProperty prop)
static Name2ClassRefIndex_t g_name2classrefidx
#define FILL_COLL(type, filter)
static void remove_space(std::string &n)
const int SMALL_ARGS_N
static std::string outer_with_template(const std::string &name)
static std::string outer_no_template(const std::string &name)
static std::string type_remap(const std::string &n1, const std::string &n2)
static std::map< Cppyy::TCppType_t, bool > sHasOperatorDelete
static std::set< std::string > gRootSOs
static bool template_compare(std::string n1, std::string n2)
static TClassRef & type_from_handle(Cppyy::TCppScope_t scope)
static bool copy_args(Parameter *args, size_t nargs, void **vargs)
static TInterpreter::CallFuncIFacePtr_t GetCallFunc(Cppyy::TCppMethod_t method)
CPyCppyy::Parameter Parameter
static bool is_missclassified_stl(const std::string &name)
std::map< std::string, ClassRefs_t::size_type > Name2ClassRefIndex_t
static const ClassRefs_t::size_type STD_HANDLE
static std::set< std::string > gSmartPtrTypes
static GlobalVars_t g_globalvars
static char * cppstring_to_cstring(const std::string &cppstr)
static void release_args(Parameter *args, size_t nargs)
static std::set< std::string > g_builtins
static std::vector< CallWrapper * > gWrapperHolder
static bool gEnableFastPath
static ClassRefs_t g_classrefs(1)
static bool WrapperCall(Cppyy::TCppMethod_t method, size_t nargs, void *args_, void *self, void *result)
static std::map< std::string, std::string > resolved_enum_types
static Cppyy::TCppIndex_t gb2idx(TGlobal *gb)
static size_t CALL_NARGS(size_t nargs)
static CallWrapper * new_CallWrapper(TFunction *f)
static std::set< std::string > gSTLNames
static const ClassRefs_t::size_type GLOBAL_HANDLE
static GlobalVarsIndices_t g_globalidx
static bool testMethodExtraProperty(Cppyy::TCppMethod_t method, EFunctionProperty prop)
static int count_scopes(const std::string &tpname)
std::vector< TGlobal * > GlobalVars_t
std::map< TGlobal *, GlobalVars_t::size_type > GlobalVarsIndices_t
std::vector< TClassRef > ClassRefs_t
static std::map< TDictionary::DeclId_t, CallWrapper * > gMethodTemplates
static bool match_name(const std::string &tname, const std::string fname)
static TFunction * m2f(Cppyy::TCppMethod_t method)
#define CPPYY_IMP_CALL(typecode, rtype)
static std::set< std::string > gInitialNames
static T CallT(Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, size_t nargs, void *args)
Cppyy::TCppIndex_t GetLongestInheritancePath(TClass *klass)
Retrieve number of base classes in the longest branch of the inheritance tree of the input class.
const Int_t n
Definition legend1.C:16
#define I(x, y, z)
#define H(x, y, z)
size_t TCppIndex_t
Definition cpp_cppyy.h:40
RPY_EXPORTED TCppIndex_t GetNumTemplatedMethods(TCppScope_t scope, bool accept_namespace=false)
RPY_EXPORTED std::string GetMethodMangledName(TCppMethod_t)
RPY_EXPORTED TCppObject_t CallO(TCppMethod_t method, TCppObject_t self, size_t nargs, void *args, TCppType_t result_type)
RPY_EXPORTED TCppIndex_t CompareMethodArgType(TCppMethod_t, TCppIndex_t iarg, const std::string &req_type)
RPY_EXPORTED ptrdiff_t GetBaseOffset(TCppType_t derived, TCppType_t base, TCppObject_t address, int direction, bool rerror=false)
RPY_EXPORTED void DeallocateFunctionArgs(void *args)
RPY_EXPORTED bool IsEnumData(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED bool IsAbstract(TCppType_t type)
RPY_EXPORTED bool IsIntegerType(const std::string &type_name)
RPY_EXPORTED size_t SizeOf(TCppType_t klass)
RPY_EXPORTED TCppObject_t CallConstructor(TCppMethod_t method, TCppType_t type, size_t nargs, void *args)
intptr_t TCppMethod_t
Definition cpp_cppyy.h:38
RPY_EXPORTED void * AllocateFunctionArgs(size_t nargs)
RPY_EXPORTED bool IsDefaultConstructable(TCppType_t type)
RPY_EXPORTED bool IsTemplate(const std::string &template_name)
RPY_EXPORTED TCppIndex_t GetDatamemberIndexEnumerated(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED TCppIndex_t GetMethodReqArgs(TCppMethod_t)
RPY_EXPORTED bool IsEnum(const std::string &type_name)
RPY_EXPORTED std::vector< TCppIndex_t > GetMethodIndicesFromName(TCppScope_t scope, const std::string &name)
RPY_EXPORTED bool ExistsMethodTemplate(TCppScope_t scope, const std::string &name)
RPY_EXPORTED TCppIndex_t GetNumDatamembers(TCppScope_t scope, bool accept_namespace=false)
RPY_EXPORTED std::string ToString(TCppType_t klass, TCppObject_t obj)
RPY_EXPORTED std::string GetMethodName(TCppMethod_t)
RPY_EXPORTED bool IsConstData(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED void AddSmartPtrType(const std::string &)
RPY_EXPORTED bool Compile(const std::string &code, bool silent=false)
RPY_EXPORTED void CallDestructor(TCppType_t type, TCppObject_t self)
RPY_EXPORTED TCppScope_t gGlobalScope
Definition cpp_cppyy.h:69
RPY_EXPORTED bool IsProtectedData(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED std::string GetMethodSignature(TCppMethod_t, bool show_formalargs, TCppIndex_t maxargs=(TCppIndex_t) -1)
RPY_EXPORTED int GetDimensionSize(TCppScope_t scope, TCppIndex_t idata, int dimension)
RPY_EXPORTED bool IsSubtype(TCppType_t derived, TCppType_t base)
RPY_EXPORTED TCppMethod_t GetMethodTemplate(TCppScope_t scope, const std::string &name, const std::string &proto)
void * TCppObject_t
Definition cpp_cppyy.h:37
RPY_EXPORTED bool IsConstructor(TCppMethod_t method)
RPY_EXPORTED TCppIndex_t GetNumMethods(TCppScope_t scope, bool accept_namespace=false)
RPY_EXPORTED TCppObject_t Construct(TCppType_t type, void *arena=nullptr)
RPY_EXPORTED bool GetSmartPtrInfo(const std::string &, TCppType_t *raw, TCppMethod_t *deref)
RPY_EXPORTED std::string GetMethodArgName(TCppMethod_t, TCppIndex_t iarg)
RPY_EXPORTED size_t GetFunctionArgTypeoffset()
RPY_EXPORTED TCppObject_t Allocate(TCppType_t type)
RPY_EXPORTED void Destruct(TCppType_t type, TCppObject_t instance)
RPY_EXPORTED std::string ResolveName(const std::string &cppitem_name)
TCppScope_t TCppType_t
Definition cpp_cppyy.h:35
RPY_EXPORTED void AddTypeReducer(const std::string &reducable, const std::string &reduced)
RPY_EXPORTED std::string ResolveEnum(const std::string &enum_type)
RPY_EXPORTED long long GetEnumDataValue(TCppEnum_t, TCppIndex_t idata)
RPY_EXPORTED bool IsAggregate(TCppType_t type)
RPY_EXPORTED TCppIndex_t GetMethodNumArgs(TCppMethod_t)
RPY_EXPORTED TCppType_t GetActualClass(TCppType_t klass, TCppObject_t obj)
RPY_EXPORTED std::string GetBaseName(TCppType_t type, TCppIndex_t ibase)
RPY_EXPORTED bool IsNamespace(TCppScope_t scope)
void * TCppEnum_t
Definition cpp_cppyy.h:36
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
RPY_EXPORTED void Deallocate(TCppType_t type, TCppObject_t instance)
RPY_EXPORTED bool IsPublicData(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED std::string GetMethodArgType(TCppMethod_t, TCppIndex_t iarg)
RPY_EXPORTED std::string GetEnumDataName(TCppEnum_t, TCppIndex_t idata)
RPY_EXPORTED void GetAllCppNames(TCppScope_t scope, std::set< std::string > &cppnames)
RPY_EXPORTED bool IsComplete(const std::string &type_name)
RPY_EXPORTED bool IsBuiltin(const std::string &type_name)
RPY_EXPORTED bool IsStaticMethod(TCppMethod_t method)
RPY_EXPORTED TCppIndex_t GetDatamemberIndex(TCppScope_t scope, const std::string &name)
RPY_EXPORTED void CallV(TCppMethod_t method, TCppObject_t self, size_t nargs, void *args)
RPY_EXPORTED bool IsStaticData(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED std::string GetDatamemberType(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED bool IsStaticTemplate(TCppScope_t scope, const std::string &name)
RPY_EXPORTED bool IsDestructor(TCppMethod_t method)
RPY_EXPORTED bool IsSmartPtr(TCppType_t type)
RPY_EXPORTED std::string GetTemplatedMethodName(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED size_t GetFunctionArgSizeof()
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
RPY_EXPORTED bool HasVirtualDestructor(TCppType_t type)
RPY_EXPORTED bool IsConstMethod(TCppMethod_t)
RPY_EXPORTED bool HasComplexHierarchy(TCppType_t type)
RPY_EXPORTED std::vector< TCppScope_t > GetUsingNamespaces(TCppScope_t)
size_t TCppScope_t
Definition cpp_cppyy.h:34
RPY_EXPORTED bool IsTemplatedConstructor(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED TCppIndex_t GetGlobalOperator(TCppType_t scope, const std::string &lc, const std::string &rc, const std::string &op)
RPY_EXPORTED TCppFuncAddr_t GetFunctionAddress(TCppMethod_t method, bool check_enabled=true)
RPY_EXPORTED TCppIndex_t GetNumEnumData(TCppEnum_t)
RPY_EXPORTED TCppIndex_t GetNumBases(TCppType_t type)
RPY_EXPORTED TCppIndex_t GetNumBasesLongestBranch(TCppType_t type)
RPY_EXPORTED std::string GetMethodPrototype(TCppScope_t scope, TCppMethod_t, bool show_formalargs)
RPY_EXPORTED std::string GetMethodResultType(TCppMethod_t)
RPY_EXPORTED std::string GetFinalName(TCppType_t type)
RPY_EXPORTED char * CallS(TCppMethod_t method, TCppObject_t self, size_t nargs, void *args, size_t *length)
RPY_EXPORTED bool IsExplicit(TCppMethod_t method)
RPY_EXPORTED std::string GetMethodArgDefault(TCppMethod_t, TCppIndex_t iarg)
RPY_EXPORTED bool IsMethodTemplate(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED std::string GetDatamemberName(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED bool IsPublicMethod(TCppMethod_t method)
RPY_EXPORTED intptr_t GetDatamemberOffset(TCppScope_t scope, TCppIndex_t idata)
void * TCppFuncAddr_t
Definition cpp_cppyy.h:41
RPY_EXPORTED std::string GetMethodFullName(TCppMethod_t)
RPY_EXPORTED bool IsProtectedMethod(TCppMethod_t method)
RPY_EXPORTED TCppEnum_t GetEnum(TCppScope_t scope, const std::string &enum_name)
void(* DelFunc_t)(void *)
Definition Rtypes.h:117
std::string ResolveTypedef(const char *tname, bool resolveAll=false)
std::string CleanType(const char *typeDesc, int mode=0, const char **tail=nullptr)
Cleanup type description, redundant blanks removed and redundant tail ignored return *tail = pointer ...
std::string ShortType(const char *typeDesc, int mode)
Return the absolute type of typeDesc.
char * DemangleName(const char *mangled_name, int &errorCode)
Definition TClassEdit.h:255
union CPyCppyy::Parameter::Value fValue
const char * fSigName
TMarker m
Definition textangle.C:8