Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TClingUtils.cxx
Go to the documentation of this file.
1// @(#)root/metautils:$Id$
2// Author: Paul Russo, 2009-10-06
3
4/*************************************************************************
5 * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12//______________________________________________________________________________
13// //
14// ROOT::TMetaUtils provides utility wrappers around //
15// cling, the LLVM-based interpreter. It's an internal set of tools //
16// used by TCling and rootcling. //
17// //
18//______________________________________________________________________________
19#include <algorithm>
20#include <iostream>
21#include <sstream>
22#include <stdlib.h>
23#include <stdio.h>
24#include <unordered_set>
25
26#include "RConfigure.h"
27#include <ROOT/RConfig.hxx>
29#include "Rtypes.h"
30#include "strlcpy.h"
31
32#include "RStl.h"
33
34#include "clang/AST/ASTContext.h"
35#include "clang/AST/Attr.h"
36#include "clang/AST/CXXInheritance.h"
37#include "clang/AST/Decl.h"
38#include "clang/AST/DeclTemplate.h"
39#include "clang/AST/Mangle.h"
40#include "clang/AST/Type.h"
41#include "clang/AST/TypeVisitor.h"
42#include "clang/Frontend/CompilerInstance.h"
43#include "clang/Lex/HeaderSearch.h"
44#include "clang/Lex/ModuleMap.h"
45#include "clang/Lex/Preprocessor.h"
46#include "clang/Lex/PreprocessorOptions.h"
47
48#include "clang/Sema/Lookup.h"
49#include "clang/Sema/Sema.h"
50#include "clang/Sema/SemaDiagnostic.h"
51
52#include "cling/Interpreter/LookupHelper.h"
53#include "cling/Interpreter/Transaction.h"
54#include "cling/Interpreter/Interpreter.h"
55#include "cling/Utils/AST.h"
56
57#include "llvm/Support/Path.h"
58#include "llvm/Support/FileSystem.h"
59
60#include "TClingUtils.h"
61
62#ifdef _WIN32
63#define strncasecmp _strnicmp
64#include <io.h>
65#else
66#include <unistd.h>
67#endif // _WIN32
68
69namespace ROOT {
70namespace TMetaUtils {
71
72std::string GetRealPath(const std::string &path)
73{
74 llvm::SmallString<256> result_path;
75 llvm::sys::fs::real_path(path, result_path, /*expandTilde*/true);
76 return result_path.str().str();
77}
78
79
80////////////////////////////////////////////////////////////////////////////////
81
83 using DeclsCont_t = TNormalizedCtxt::Config_t::SkipCollection;
87private:
91public:
92 TNormalizedCtxtImpl(const cling::LookupHelper &lh);
93
94 const Config_t &GetConfig() const { return fConfig; }
96 void AddTemplAndNargsToKeep(const clang::ClassTemplateDecl* templ, unsigned int i);
97 int GetNargsToKeep(const clang::ClassTemplateDecl* templ) const;
99 void keepTypedef(const cling::LookupHelper &lh, const char* name,
100 bool replace = false);
101};
102}
103}
104
105namespace {
106
107////////////////////////////////////////////////////////////////////////////////
108/// Add default parameter to the scope if needed.
109
110static clang::NestedNameSpecifier *AddDefaultParametersNNS(const clang::ASTContext& Ctx,
111 clang::NestedNameSpecifier* scope,
112 const cling::Interpreter &interpreter,
113 const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt) {
114 if (!scope) return nullptr;
115
116 const clang::Type* scope_type = scope->getAsType();
117 if (scope_type) {
118 // this is not a namespace, so we might need to desugar
119 clang::NestedNameSpecifier* outer_scope = scope->getPrefix();
120 if (outer_scope) {
121 outer_scope = AddDefaultParametersNNS(Ctx, outer_scope, interpreter, normCtxt);
122 }
123
124 clang::QualType addDefault =
125 ROOT::TMetaUtils::AddDefaultParameters(clang::QualType(scope_type,0), interpreter, normCtxt );
126 // NOTE: Should check whether the type has changed or not.
127 if (addDefault.getTypePtr() != scope_type)
128 return clang::NestedNameSpecifier::Create(Ctx,outer_scope,
129 false /* template keyword wanted */,
130 addDefault.getTypePtr());
131 }
132 return scope;
133}
134
135////////////////////////////////////////////////////////////////////////////////
136
137static bool CheckDefinition(const clang::CXXRecordDecl *cl, const clang::CXXRecordDecl *context)
138{
139 if (!cl->hasDefinition()) {
140 if (context) {
141 ROOT::TMetaUtils::Error("CheckDefinition",
142 "Missing definition for class %s, please #include its header in the header of %s\n",
143 cl->getName().str().c_str(), context->getName().str().c_str());
144 } else {
145 ROOT::TMetaUtils::Error("CheckDefinition",
146 "Missing definition for class %s\n",
147 cl->getName().str().c_str());
148 }
149 return false;
150 }
151 return true;
152}
153
154////////////////////////////////////////////////////////////////////////////////
155/// Check if 'scope' or any of its template parameter was substituted when
156/// instantiating the class template instance and replace it with the
157/// partially sugared types we have from 'instance'.
158
159static clang::NestedNameSpecifier *ReSubstTemplateArgNNS(const clang::ASTContext &Ctxt,
160 clang::NestedNameSpecifier *scope,
161 const clang::Type *instance)
162{
163 if (!scope) return nullptr;
164
165 const clang::Type* scope_type = scope->getAsType();
166 if (scope_type) {
167 clang::NestedNameSpecifier* outer_scope = scope->getPrefix();
168 if (outer_scope) {
169 outer_scope = ReSubstTemplateArgNNS(Ctxt, outer_scope, instance);
170 }
171 clang::QualType substScope =
172 ROOT::TMetaUtils::ReSubstTemplateArg(clang::QualType(scope_type,0), instance);
173 // NOTE: Should check whether the type has changed or not.
174 scope = clang::NestedNameSpecifier::Create(Ctxt,outer_scope,
175 false /* template keyword wanted */,
176 substScope.getTypePtr());
177 }
178 return scope;
179}
180
181////////////////////////////////////////////////////////////////////////////////
182
183static bool IsTypeInt(const clang::Type *type)
184{
185 const clang::BuiltinType * builtin = llvm::dyn_cast<clang::BuiltinType>(type->getCanonicalTypeInternal().getTypePtr());
186 if (builtin) {
187 return builtin->isInteger(); // builtin->getKind() == clang::BuiltinType::Int;
188 } else {
189 return false;
190 }
191}
192
193////////////////////////////////////////////////////////////////////////////////
194
195static bool IsFieldDeclInt(const clang::FieldDecl *field)
196{
197 return IsTypeInt(field->getType().getTypePtr());
198}
199
200////////////////////////////////////////////////////////////////////////////////
201/// Return a data member name 'what' in the class described by 'cl' if any.
202
203static const clang::FieldDecl *GetDataMemberFromAll(const clang::CXXRecordDecl &cl, llvm::StringRef what)
204{
205 clang::ASTContext &C = cl.getASTContext();
206 clang::DeclarationName DName = &C.Idents.get(what);
207 auto R = cl.lookup(DName);
208 for (const clang::NamedDecl *D : R)
209 if (auto FD = llvm::dyn_cast<const clang::FieldDecl>(D))
210 return FD;
211 return nullptr;
212}
213
214////////////////////////////////////////////////////////////////////////////////
215/// Return a data member name 'what' in any of the base classes of the class described by 'cl' if any.
216
217static const clang::FieldDecl *GetDataMemberFromAllParents(clang::Sema &SemaR, const clang::CXXRecordDecl &cl, const char *what)
218{
219 clang::DeclarationName DName = &SemaR.Context.Idents.get(what);
220 clang::LookupResult R(SemaR, DName, clang::SourceLocation(),
221 clang::Sema::LookupOrdinaryName,
222 clang::Sema::ForExternalRedeclaration);
223 SemaR.LookupInSuper(R, &const_cast<clang::CXXRecordDecl&>(cl));
224 if (R.empty())
225 return nullptr;
226 return llvm::dyn_cast<const clang::FieldDecl>(R.getFoundDecl());
227}
228
229static
230cling::LookupHelper::DiagSetting ToLHDS(bool wantDiags) {
231 return wantDiags
232 ? cling::LookupHelper::WithDiagnostics
233 : cling::LookupHelper::NoDiagnostics;
234}
235
236} // end of anonymous namespace
237
238
239namespace ROOT {
240namespace TMetaUtils {
241
242////////////////////////////////////////////////////////////////////////////////
243/// Add to the internal map the pointer of a template as key and the number of
244/// template arguments to keep as value.
245
246void TNormalizedCtxtImpl::AddTemplAndNargsToKeep(const clang::ClassTemplateDecl* templ,
247 unsigned int i){
248 if (!templ){
249 Error("TNormalizedCtxt::AddTemplAndNargsToKeep",
250 "Tring to specify a number of template arguments to keep for a null pointer. Exiting without assigning any value.\n");
251 return;
252 }
253
254 const clang::ClassTemplateDecl* canTempl = templ->getCanonicalDecl();
255
256 if(fTemplatePtrArgsToKeepMap.count(canTempl)==1 &&
257 fTemplatePtrArgsToKeepMap[canTempl]!=(int)i){
258 const std::string templateName (canTempl->getNameAsString());
259 const std::string i_str (std::to_string(i));
260 const std::string previousArgsToKeep(std::to_string(fTemplatePtrArgsToKeepMap[canTempl]));
261 Error("TNormalizedCtxt::AddTemplAndNargsToKeep",
262 "Tring to specify for template %s %s arguments to keep, while before this number was %s\n",
263 canTempl->getNameAsString().c_str(),
264 i_str.c_str(),
265 previousArgsToKeep.c_str());
266 }
267
268 fTemplatePtrArgsToKeepMap[canTempl]=i;
269}
270////////////////////////////////////////////////////////////////////////////////
271/// Get from the map the number of arguments to keep.
272/// It uses the canonical decl of the template as key.
273/// If not present, returns -1.
274
275int TNormalizedCtxtImpl::GetNargsToKeep(const clang::ClassTemplateDecl* templ) const{
276 const clang::ClassTemplateDecl* constTempl = templ->getCanonicalDecl();
277 auto thePairPtr = fTemplatePtrArgsToKeepMap.find(constTempl);
278 int nArgsToKeep = (thePairPtr != fTemplatePtrArgsToKeepMap.end() ) ? thePairPtr->second : -1;
279 return nArgsToKeep;
280}
281
282
283////////////////////////////////////////////////////////////////////////////////
284
285TNormalizedCtxt::TNormalizedCtxt(const cling::LookupHelper &lh):
286 fImpl(new TNormalizedCtxtImpl(lh))
287{}
288
290 fImpl(new TNormalizedCtxtImpl(*other.fImpl))
291{}
292
294 delete fImpl;
295}
297 return fImpl->GetConfig();
298}
301}
302void TNormalizedCtxt::AddTemplAndNargsToKeep(const clang::ClassTemplateDecl* templ, unsigned int i)
303{
304 return fImpl->AddTemplAndNargsToKeep(templ, i);
305}
306int TNormalizedCtxt::GetNargsToKeep(const clang::ClassTemplateDecl* templ) const
307{
308 return fImpl->GetNargsToKeep(templ);
309}
312}
313void TNormalizedCtxt::keepTypedef(const cling::LookupHelper &lh, const char* name,
314 bool replace /*= false*/)
315{
316 return fImpl->keepTypedef(lh, name, replace);
317}
318
319std::string AnnotatedRecordDecl::BuildDemangledTypeInfo(const clang::RecordDecl *rDecl,
320 const std::string &normalizedName)
321{
322 // Types with strong typedefs must not be findable through demangled type names, or else
323 // the demangled name will resolve to both sinblings double / Double32_t.
324 if (normalizedName.find("Double32_t") != std::string::npos
325 || normalizedName.find("Float16_t") != std::string::npos)
326 return {};
327 std::unique_ptr<clang::MangleContext> mangleCtx(rDecl->getASTContext().createMangleContext());
328 std::string mangledName;
329 {
330 llvm::raw_string_ostream sstr(mangledName);
331 if (const clang::TypeDecl* TD = llvm::dyn_cast<clang::TypeDecl>(rDecl)) {
332 mangleCtx->mangleCXXRTTI(clang::QualType(TD->getTypeForDecl(), 0), sstr);
333 }
334 }
335 if (!mangledName.empty()) {
336 int errDemangle = 0;
337#ifdef WIN32
338 if (mangledName[0] == '\01')
339 mangledName.erase(0, 1);
340 char *demangledTIName = TClassEdit::DemangleName(mangledName.c_str(), errDemangle);
341 if (!errDemangle && demangledTIName) {
342 static const char typeinfoNameFor[] = " `RTTI Type Descriptor'";
343 if (strstr(demangledTIName, typeinfoNameFor)) {
344 std::string demangledName = demangledTIName;
345 demangledName.erase(demangledName.end() - strlen(typeinfoNameFor), demangledName.end());
346#else
347 char* demangledTIName = TClassEdit::DemangleName(mangledName.c_str(), errDemangle);
348 if (!errDemangle && demangledTIName) {
349 static const char typeinfoNameFor[] = "typeinfo for ";
350 if (!strncmp(demangledTIName, typeinfoNameFor, strlen(typeinfoNameFor))) {
351 std::string demangledName = demangledTIName + strlen(typeinfoNameFor);
352#endif
353 free(demangledTIName);
354 return demangledName;
355 } else {
356#ifdef WIN32
357 ROOT::TMetaUtils::Error("AnnotatedRecordDecl::BuildDemangledTypeInfo",
358 "Demangled typeinfo name '%s' does not contain `RTTI Type Descriptor'\n",
359 demangledTIName);
360#else
361 ROOT::TMetaUtils::Error("AnnotatedRecordDecl::BuildDemangledTypeInfo",
362 "Demangled typeinfo name '%s' does not start with 'typeinfo for'\n",
363 demangledTIName);
364#endif
365 } // if demangled type_info starts with "typeinfo for "
366 } // if demangling worked
367 free(demangledTIName);
368 } // if mangling worked
369 return {};
370}
371
372
373////////////////////////////////////////////////////////////////////////////////
374/// There is no requested type name.
375/// Still let's normalized the actual name.
376
377// clang-format off
379 const clang::RecordDecl *decl,
380 bool rStreamerInfo,
381 bool rNoStreamer,
382 bool rRequestNoInputOperator,
383 bool rRequestOnlyTClass,
384 int rRequestedVersionNumber,
385 int rRequestedRNTupleSplitMode,
386 const cling::Interpreter &interpreter,
387 const TNormalizedCtxt &normCtxt)
388 : fRuleIndex(index),
389 fDecl(decl),
390 fRequestStreamerInfo(rStreamerInfo),
391 fRequestNoStreamer(rNoStreamer),
392 fRequestNoInputOperator(rRequestNoInputOperator),
393 fRequestOnlyTClass(rRequestOnlyTClass),
394 fRequestedVersionNumber(rRequestedVersionNumber),
395 fRequestedRNTupleSplitMode(rRequestedRNTupleSplitMode)
396// clang-format on
397{
398 TMetaUtils::GetNormalizedName(fNormalizedName, decl->getASTContext().getTypeDeclType(decl), interpreter,normCtxt);
400}
401
402////////////////////////////////////////////////////////////////////////////////
403/// Normalize the requested type name.
404
405// clang-format off
407 const clang::Type *requestedType,
408 const clang::RecordDecl *decl,
409 const char *requestName,
410 unsigned int nTemplateArgsToSkip,
411 bool rStreamerInfo,
412 bool rNoStreamer,
413 bool rRequestNoInputOperator,
414 bool rRequestOnlyTClass,
415 int rRequestVersionNumber,
416 int rRequestedRNTupleSplitMode,
417 const cling::Interpreter &interpreter,
418 const TNormalizedCtxt &normCtxt)
419 : fRuleIndex(index),
420 fDecl(decl),
421 fRequestedName(""),
422 fRequestStreamerInfo(rStreamerInfo),
423 fRequestNoStreamer(rNoStreamer),
424 fRequestNoInputOperator(rRequestNoInputOperator),
425 fRequestOnlyTClass(rRequestOnlyTClass),
426 fRequestedVersionNumber(rRequestVersionNumber),
427 fRequestedRNTupleSplitMode(rRequestedRNTupleSplitMode)
428// clang-format on
429{
430 // For comparison purposes.
432 splitname1.ShortType(fRequestedName, 0);
433
434 TMetaUtils::GetNormalizedName( fNormalizedName, clang::QualType(requestedType,0), interpreter, normCtxt);
435 if ( 0!=TMetaUtils::RemoveTemplateArgsFromName( fNormalizedName, nTemplateArgsToSkip) ){
436 ROOT::TMetaUtils::Warning("AnnotatedRecordDecl",
437 "Could not remove the requested template arguments.\n");
438 }
440}
441
442////////////////////////////////////////////////////////////////////////////////
443/// Normalize the requested type name.
444
445// clang-format off
447 const clang::Type *requestedType,
448 const clang::RecordDecl *decl,
449 const char *requestName,
450 bool rStreamerInfo,
451 bool rNoStreamer,
452 bool rRequestNoInputOperator,
453 bool rRequestOnlyTClass,
454 int rRequestVersionNumber,
455 int rRequestedRNTupleSplitMode,
456 const cling::Interpreter &interpreter,
457 const TNormalizedCtxt &normCtxt)
458 : fRuleIndex(index),
459 fDecl(decl),
460 fRequestedName(""),
461 fRequestStreamerInfo(rStreamerInfo),
462 fRequestNoStreamer(rNoStreamer),
463 fRequestNoInputOperator(rRequestNoInputOperator),
464 fRequestOnlyTClass(rRequestOnlyTClass),
465 fRequestedVersionNumber(rRequestVersionNumber),
466 fRequestedRNTupleSplitMode(rRequestedRNTupleSplitMode)
467// clang-format on
468{
469 // For comparison purposes.
471 splitname1.ShortType(fRequestedName, 0);
472
473 TMetaUtils::GetNormalizedName( fNormalizedName, clang::QualType(requestedType,0), interpreter, normCtxt);
475}
476
477////////////////////////////////////////////////////////////////////////////////
478/// Normalize the requested name.
479
480// clang-format off
482 const clang::RecordDecl *decl,
483 const char *requestName,
484 bool rStreamerInfo,
485 bool rNoStreamer,
486 bool rRequestNoInputOperator,
487 bool rRequestOnlyTClass,
488 int rRequestVersionNumber,
489 int rRequestedRNTupleSplitMode,
490 const cling::Interpreter &interpreter,
491 const TNormalizedCtxt &normCtxt)
492 : fRuleIndex(index),
493 fDecl(decl),
494 fRequestedName(""),
495 fRequestStreamerInfo(rStreamerInfo),
496 fRequestNoStreamer(rNoStreamer),
497 fRequestNoInputOperator(rRequestNoInputOperator),
498 fRequestOnlyTClass(rRequestOnlyTClass),
499 fRequestedVersionNumber(rRequestVersionNumber),
500 fRequestedRNTupleSplitMode(rRequestedRNTupleSplitMode)
501// clang-format on
502{
503 // const clang::ClassTemplateSpecializationDecl *tmplt_specialization = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl> (decl);
504 // if (tmplt_specialization) {
505 // tmplt_specialization->getTemplateArgs ().data()->print(decl->getASTContext().getPrintingPolicy(),llvm::outs());
506 // llvm::outs() << "\n";
507 // }
508 // const char *current = requestName;
509 // Strips spaces and std::
510 if (requestName && requestName[0]) {
513
515 } else {
516 TMetaUtils::GetNormalizedName( fNormalizedName, decl->getASTContext().getTypeDeclType(decl),interpreter,normCtxt);
517 }
519}
520
521////////////////////////////////////////////////////////////////////////////////
522
523TClingLookupHelper::TClingLookupHelper(cling::Interpreter &interpreter,
524 TNormalizedCtxt &normCtxt,
525 ExistingTypeCheck_t existingTypeCheck,
526 AutoParse_t autoParse,
527 bool *shuttingDownPtr,
528 const int* pgDebug /*= 0*/):
529 fInterpreter(&interpreter),fNormalizedCtxt(&normCtxt),
530 fExistingTypeCheck(existingTypeCheck),
531 fAutoParse(autoParse),
532 fInterpreterIsShuttingDownPtr(shuttingDownPtr),
533 fPDebug(pgDebug)
534{
535}
536
537////////////////////////////////////////////////////////////////////////////////
538/// Helper routine to ry hard to avoid looking up in the Cling database as
539/// this could enduce an unwanted autoparsing.
540
541bool TClingLookupHelper::ExistingTypeCheck(const std::string &tname,
542 std::string &result)
543{
544 if (tname.empty()) return false;
545
547 else return false;
548}
549
550////////////////////////////////////////////////////////////////////////////////
551
553{
554 const cling::LookupHelper& lh = fInterpreter->getLookupHelper();
555 clang::QualType t = lh.findType(nameLong, ToLHDS(WantDiags()));
556 if (!t.isNull()) {
557 clang::QualType dest = cling::utils::Transform::GetPartiallyDesugaredType(fInterpreter->getCI()->getASTContext(), t, fNormalizedCtxt->GetConfig(), true /* fully qualify */);
558 if (!dest.isNull() && (dest != t)) {
559 // getAsStringInternal() appends.
560 nameLong.clear();
561 dest.getAsStringInternal(nameLong, fInterpreter->getCI()->getASTContext().getPrintingPolicy());
562 }
563 }
564}
565
566////////////////////////////////////////////////////////////////////////////////
567
569 const std::string &nameLong)
570{
571 const cling::LookupHelper& lh = fInterpreter->getLookupHelper();
572 clang::QualType t = lh.findType(nondef.c_str(), ToLHDS(WantDiags()));
573 if (!t.isNull()) {
574 clang::QualType dest = cling::utils::Transform::GetPartiallyDesugaredType(fInterpreter->getCI()->getASTContext(), t, fNormalizedCtxt->GetConfig(), true /* fully qualify */);
575 if (!dest.isNull() && (dest != t) &&
576 nameLong == t.getAsString(fInterpreter->getCI()->getASTContext().getPrintingPolicy()))
577 return true;
578 }
579 return false;
580}
581
582////////////////////////////////////////////////////////////////////////////////
583
584bool TClingLookupHelper::IsDeclaredScope(const std::string &base, bool &isInlined)
585{
586 const cling::LookupHelper& lh = fInterpreter->getLookupHelper();
587 const clang::Decl *scope = lh.findScope(base.c_str(), ToLHDS(WantDiags()), nullptr);
588
589 if (!scope) {
590 // the nesting namespace is not declared
591 isInlined = false;
592 return false;
593 }
594 const clang::NamespaceDecl *nsdecl = llvm::dyn_cast<clang::NamespaceDecl>(scope);
595 isInlined = nsdecl && nsdecl->isInline();
596 return true;
597}
598
599////////////////////////////////////////////////////////////////////////////////
600/// We assume that we have a simple type:
601/// [const] typename[*&][const]
602
604 std::string &result,
605 bool dropstd /* = true */)
606{
607 if (tname.empty()) return false;
608
609 // Try hard to avoid looking up in the Cling database as this could enduce
610 // an unwanted autoparsing.
611 // Note: this is always done by the callers and thus is redundant.
612 // Maybe replace with
613 assert(! (fExistingTypeCheck && fExistingTypeCheck(tname,result)) );
615 return ! result.empty();
616 }
617
618 if (fAutoParse) fAutoParse(tname.c_str());
619
620 // Since we already check via other means (TClassTable which is populated by
621 // the dictonary loading, and the gROOT list of classes and enums, which are
622 // populated via TProtoClass/Enum), we should be able to disable the autoloading
623 // ... which requires access to libCore or libCling ...
624 const cling::LookupHelper& lh = fInterpreter->getLookupHelper();
625 clang::QualType t = lh.findType(tname.c_str(), ToLHDS(WantDiags()));
626 // Technically we ought to try:
627 // if (t.isNull()) t = lh.findType(TClassEdit::InsertStd(tname), ToLHDS(WantDiags()));
628 // at least until the 'normalized name' contains the std:: prefix.
629
630 if (!t.isNull()) {
632 if (!dest.isNull() && dest != t) {
633 // Since our input is not a template instance name, rather than going through the full
634 // TMetaUtils::GetNormalizedName, we just do the 'strip leading std' and fix
635 // white space.
636 clang::PrintingPolicy policy(fInterpreter->getCI()->getASTContext().getPrintingPolicy());
637 policy.SuppressTagKeyword = true; // Never get the class or struct keyword
638 policy.SuppressScope = true; // Force the scope to be coming from a clang::ElaboratedType.
639 // The scope suppression is required for getting rid of the anonymous part of the name of a class defined in an anonymous namespace.
640 // This gives us more control vs not using the clang::ElaboratedType and relying on the Policy.SuppressUnwrittenScope which would
641 // strip both the anonymous and the inline namespace names (and we probably do not want the later to be suppressed).
642 // getAsStringInternal() appends.
643 result.clear();
644 dest.getAsStringInternal(result, policy);
645 // Strip the std::
646 unsigned long offset = 0;
647 if (strncmp(result.c_str(), "const ", 6) == 0) {
648 offset = 6;
649 }
650 if (dropstd && strncmp(result.c_str()+offset, "std::", 5) == 0) {
651 result.erase(offset,5);
652 }
653 for(unsigned int i = 1; i<result.length(); ++i) {
654 if (result[i]=='s') {
655 if (result[i-1]=='<' || result[i-1]==',' || result[i-1]==' ') {
656 if (dropstd && result.compare(i,5,"std::",5) == 0) {
657 result.erase(i,5);
658 }
659 }
660 }
661 if (result[i]==' ') {
662 if (result[i-1] == ',') {
663 result.erase(i,1);
664 --i;
665 } else if ( (i+1) < result.length() &&
666 (result[i+1]=='*' || result[i+1]=='&' || result[i+1]=='[') ) {
667 result.erase(i,1);
668 --i;
669 }
670 }
671 }
672
673// std::string alt;
674// TMetaUtils::GetNormalizedName(alt, dest, *fInterpreter, *fNormalizedCtxt);
675// if (alt != result) fprintf(stderr,"norm: %s vs result=%s\n",alt.c_str(),result.c_str());
676
677 return true;
678 }
679 }
680 return false;
681}
682
683////////////////////////////////////////////////////////////////////////////////
684// TClassEdit will call this routine as soon as any of its static variable (used
685// for caching) is destroyed.
687{
690}
691
692 } // end namespace ROOT
693} // end namespace TMetaUtils
694
695
696////////////////////////////////////////////////////////////////////////////////
697/// Insert the type with name into the collection of typedefs to keep.
698/// if replace, replace occurrences of the canonical type by name.
699
700void ROOT::TMetaUtils::TNormalizedCtxtImpl::keepTypedef(const cling::LookupHelper &lh,
701 const char* name,
702 bool replace /*=false*/) {
703 clang::QualType toSkip = lh.findType(name, cling::LookupHelper::WithDiagnostics);
704 if (const clang::Type* T = toSkip.getTypePtr()) {
705 const clang::TypedefType *tt = llvm::dyn_cast<clang::TypedefType>(T);
706 if (!tt) return;
707 clang::Decl* D = tt->getDecl();
708 fConfig.m_toSkip.insert(D);
709 if (replace) {
710 clang::QualType canon = toSkip->getCanonicalTypeInternal();
711 fConfig.m_toReplace.insert(std::make_pair(canon.getTypePtr(),T));
712 } else {
713 fTypeWithAlternative.insert(T);
714 }
715 }
716}
717
718////////////////////////////////////////////////////////////////////////////////
719/// Initialize the list of typedef to keep (i.e. make them opaque for normalization)
720/// and the list of typedef whose semantic is different from their underlying type
721/// (Double32_t and Float16_t).
722/// This might be specific to an interpreter.
723
725{
726 keepTypedef(lh, "Double32_t");
727 keepTypedef(lh, "Float16_t");
728 keepTypedef(lh, "Long64_t", true);
729 keepTypedef(lh, "ULong64_t", true);
730
731 clang::QualType toSkip = lh.findType("string", cling::LookupHelper::WithDiagnostics);
732 if (!toSkip.isNull()) {
733 if (const clang::TypedefType* TT
734 = llvm::dyn_cast_or_null<clang::TypedefType>(toSkip.getTypePtr()))
735 fConfig.m_toSkip.insert(TT->getDecl());
736 }
737 toSkip = lh.findType("std::string", cling::LookupHelper::WithDiagnostics);
738 if (!toSkip.isNull()) {
739 if (const clang::TypedefType* TT
740 = llvm::dyn_cast_or_null<clang::TypedefType>(toSkip.getTypePtr()))
741 fConfig.m_toSkip.insert(TT->getDecl());
742
743 clang::QualType canon = toSkip->getCanonicalTypeInternal();
744 fConfig.m_toReplace.insert(std::make_pair(canon.getTypePtr(),toSkip.getTypePtr()));
745 }
746}
747
750
751////////////////////////////////////////////////////////////////////////////////
752
753inline bool IsTemplate(const clang::Decl &cl)
754{
755 return (cl.getKind() == clang::Decl::ClassTemplatePartialSpecialization
756 || cl.getKind() == clang::Decl::ClassTemplateSpecialization);
757}
758
759
760////////////////////////////////////////////////////////////////////////////////
761
762const clang::FunctionDecl* ROOT::TMetaUtils::ClassInfo__HasMethod(const clang::DeclContext *cl, const char* name,
763 const cling::Interpreter& interp)
764{
765 clang::Sema* S = &interp.getSema();
766 const clang::NamedDecl* ND = cling::utils::Lookup::Named(S, name, cl);
767 if (ND == (clang::NamedDecl*)-1)
768 return (clang::FunctionDecl*)-1;
769 return llvm::dyn_cast_or_null<clang::FunctionDecl>(ND);
770}
771
772////////////////////////////////////////////////////////////////////////////////
773/// Return the scope corresponding to 'name' or std::'name'
774
775const clang::CXXRecordDecl *
776ROOT::TMetaUtils::ScopeSearch(const char *name, const cling::Interpreter &interp,
777 bool /*diagnose*/, const clang::Type** resultType)
778{
779 const cling::LookupHelper& lh = interp.getLookupHelper();
780 // We have many bogus diagnostics if we allow diagnostics here. Suppress.
781 // FIXME: silence them in the callers.
782 const clang::CXXRecordDecl *result
783 = llvm::dyn_cast_or_null<clang::CXXRecordDecl>
784 (lh.findScope(name, cling::LookupHelper::NoDiagnostics, resultType));
785 if (!result) {
786 std::string std_name("std::");
787 std_name += name;
788 // We have many bogus diagnostics if we allow diagnostics here. Suppress.
789 // FIXME: silence them in the callers.
790 result = llvm::dyn_cast_or_null<clang::CXXRecordDecl>
791 (lh.findScope(std_name, cling::LookupHelper::NoDiagnostics, resultType));
792 }
793 return result;
794}
795
796
797////////////////////////////////////////////////////////////////////////////////
798
799bool ROOT::TMetaUtils::RequireCompleteType(const cling::Interpreter &interp, const clang::CXXRecordDecl *cl)
800{
801 clang::QualType qType(cl->getTypeForDecl(),0);
802 return RequireCompleteType(interp,cl->getLocation(),qType);
803}
804
805////////////////////////////////////////////////////////////////////////////////
806
807bool ROOT::TMetaUtils::RequireCompleteType(const cling::Interpreter &interp, clang::SourceLocation Loc, clang::QualType Type)
808{
809 clang::Sema& S = interp.getCI()->getSema();
810 // Here we might not have an active transaction to handle
811 // the caused instantiation decl.
812 cling::Interpreter::PushTransactionRAII RAII(const_cast<cling::Interpreter*>(&interp));
813 return S.RequireCompleteType(Loc, Type, clang::diag::err_incomplete_type);
814}
815
816////////////////////////////////////////////////////////////////////////////////
817
818bool ROOT::TMetaUtils::IsBase(const clang::CXXRecordDecl *cl, const clang::CXXRecordDecl *base,
819 const clang::CXXRecordDecl *context, const cling::Interpreter &interp)
820{
821 if (!cl || !base) {
822 return false;
823 }
824
825 if (!cl->getDefinition() || !cl->isCompleteDefinition()) {
826 RequireCompleteType(interp,cl);
827 }
828
829 if (!CheckDefinition(cl, context) || !CheckDefinition(base, context)) {
830 return false;
831 }
832
833 if (!base->hasDefinition()) {
834 ROOT::TMetaUtils::Error("IsBase", "Missing definition for class %s\n", base->getName().str().c_str());
835 return false;
836 }
837 return cl->isDerivedFrom(base);
838}
839
840////////////////////////////////////////////////////////////////////////////////
841
842bool ROOT::TMetaUtils::IsBase(const clang::FieldDecl &m, const char* basename, const cling::Interpreter &interp)
843{
844 const clang::CXXRecordDecl* CRD = llvm::dyn_cast<clang::CXXRecordDecl>(ROOT::TMetaUtils::GetUnderlyingRecordDecl(m.getType()));
845 if (!CRD) {
846 return false;
847 }
848
849 const clang::NamedDecl *base
850 = ScopeSearch(basename, interp, true /*diagnose*/, nullptr);
851
852 if (base) {
853 return IsBase(CRD, llvm::dyn_cast<clang::CXXRecordDecl>( base ),
854 llvm::dyn_cast<clang::CXXRecordDecl>(m.getDeclContext()),interp);
855 }
856 return false;
857}
858
859////////////////////////////////////////////////////////////////////////////////
860
861int ROOT::TMetaUtils::ElementStreamer(std::ostream& finalString,
862 const clang::NamedDecl &forcontext,
863 const clang::QualType &qti,
864 const char *R__t,int rwmode,
865 const cling::Interpreter &interp,
866 const char *tcl)
867{
868 static const clang::CXXRecordDecl *TObject_decl
869 = ROOT::TMetaUtils::ScopeSearch("TObject", interp, true /*diag*/, nullptr);
870 enum {
871 kBIT_ISTOBJECT = 0x10000000,
872 kBIT_HASSTREAMER = 0x20000000,
873 kBIT_ISSTRING = 0x40000000,
874
875 kBIT_ISPOINTER = 0x00001000,
876 kBIT_ISFUNDAMENTAL = 0x00000020,
877 kBIT_ISENUM = 0x00000008
878 };
879
880 const clang::Type &ti( * qti.getTypePtr() );
881 std::string tiName;
882 ROOT::TMetaUtils::GetQualifiedName(tiName, clang::QualType(&ti,0), forcontext);
883
884 std::string objType(ROOT::TMetaUtils::ShortTypeName(tiName.c_str()));
885
886 const clang::Type *rawtype = ROOT::TMetaUtils::GetUnderlyingType(clang::QualType(&ti,0));
887 std::string rawname;
888 ROOT::TMetaUtils::GetQualifiedName(rawname, clang::QualType(rawtype,0), forcontext);
889
890 clang::CXXRecordDecl *cxxtype = rawtype->getAsCXXRecordDecl() ;
891 int isStre = cxxtype && ROOT::TMetaUtils::ClassInfo__HasMethod(cxxtype,"Streamer",interp);
892 int isTObj = cxxtype && (IsBase(cxxtype,TObject_decl,nullptr,interp) || rawname == "TObject");
893
894 long kase = 0;
895
896 if (ti.isPointerType()) kase |= kBIT_ISPOINTER;
897 if (rawtype->isFundamentalType()) kase |= kBIT_ISFUNDAMENTAL;
898 if (rawtype->isEnumeralType()) kase |= kBIT_ISENUM;
899
900
901 if (isTObj) kase |= kBIT_ISTOBJECT;
902 if (isStre) kase |= kBIT_HASSTREAMER;
903 if (tiName == "string") kase |= kBIT_ISSTRING;
904 if (tiName == "string*") kase |= kBIT_ISSTRING;
905
906
907 if (!tcl)
908 tcl = " internal error in rootcling ";
909 // if (strcmp(objType,"string")==0) RStl::Instance().GenerateTClassFor( "string", interp, normCtxt );
910
911 if (rwmode == 0) { //Read mode
912
913 if (R__t) finalString << " " << tiName << " " << R__t << ";" << std::endl;
914 switch (kase) {
915
916 case kBIT_ISFUNDAMENTAL:
917 if (!R__t) return 0;
918 finalString << " R__b >> " << R__t << ";" << std::endl;
919 break;
920
921 case kBIT_ISPOINTER|kBIT_ISTOBJECT|kBIT_HASSTREAMER:
922 if (!R__t) return 1;
923 finalString << " " << R__t << " = (" << tiName << ")R__b.ReadObjectAny(" << tcl << ");" << std::endl;
924 break;
925
926 case kBIT_ISENUM:
927 if (!R__t) return 0;
928 // fprintf(fp, " R__b >> (Int_t&)%s;\n",R__t);
929 // On some platforms enums and not 'Int_t' and casting to a reference to Int_t
930 // induces the silent creation of a temporary which is 'filled' __instead of__
931 // the desired enum. So we need to take it one step at a time.
932 finalString << " Int_t readtemp;" << std::endl
933 << " R__b >> readtemp;" << std::endl
934 << " " << R__t << " = static_cast<" << tiName << ">(readtemp);" << std::endl;
935 break;
936
937 case kBIT_HASSTREAMER:
938 case kBIT_HASSTREAMER|kBIT_ISTOBJECT:
939 if (!R__t) return 0;
940 finalString << " " << R__t << ".Streamer(R__b);" << std::endl;
941 break;
942
943 case kBIT_HASSTREAMER|kBIT_ISPOINTER:
944 if (!R__t) return 1;
945 //fprintf(fp, " fprintf(stderr,\"info is %%p %%d\\n\",R__b.GetInfo(),R__b.GetInfo()?R__b.GetInfo()->GetOldVersion():-1);\n");
946 finalString << " if (R__b.GetInfo() && R__b.GetInfo()->GetOldVersion()<=3) {" << std::endl;
947 if (cxxtype && cxxtype->isAbstract()) {
948 finalString << " R__ASSERT(0);// " << objType << " is abstract. We assume that older file could not be produced using this streaming method." << std::endl;
949 } else {
950 finalString << " " << R__t << " = new " << objType << ";" << std::endl
951 << " " << R__t << "->Streamer(R__b);" << std::endl;
952 }
953 finalString << " } else {" << std::endl
954 << " " << R__t << " = (" << tiName << ")R__b.ReadObjectAny(" << tcl << ");" << std::endl
955 << " }" << std::endl;
956 break;
957
958 case kBIT_ISSTRING:
959 if (!R__t) return 0;
960 finalString << " {TString R__str;" << std::endl
961 << " R__str.Streamer(R__b);" << std::endl
962 << " " << R__t << " = R__str.Data();}" << std::endl;
963 break;
964
965 case kBIT_ISSTRING|kBIT_ISPOINTER:
966 if (!R__t) return 0;
967 finalString << " {TString R__str;" << std::endl
968 << " R__str.Streamer(R__b);" << std::endl
969 << " " << R__t << " = new string(R__str.Data());}" << std::endl;
970 break;
971
972 case kBIT_ISPOINTER:
973 if (!R__t) return 1;
974 finalString << " " << R__t << " = (" << tiName << ")R__b.ReadObjectAny(" << tcl << ");" << std::endl;
975 break;
976
977 default:
978 if (!R__t) return 1;
979 finalString << " R__b.StreamObject(&" << R__t << "," << tcl << ");" << std::endl;
980 break;
981 }
982
983 } else { //Write case
984
985 switch (kase) {
986
987 case kBIT_ISFUNDAMENTAL:
988 case kBIT_ISPOINTER|kBIT_ISTOBJECT|kBIT_HASSTREAMER:
989 if (!R__t) return 0;
990 finalString << " R__b << " << R__t << ";" << std::endl;
991 break;
992
993 case kBIT_ISENUM:
994 if (!R__t) return 0;
995 finalString << " { void *ptr_enum = (void*)&" << R__t << ";\n";
996 finalString << " R__b >> *reinterpret_cast<Int_t*>(ptr_enum); }" << std::endl;
997 break;
998
999 case kBIT_HASSTREAMER:
1000 case kBIT_HASSTREAMER|kBIT_ISTOBJECT:
1001 if (!R__t) return 0;
1002 finalString << " ((" << objType << "&)" << R__t << ").Streamer(R__b);" << std::endl;
1003 break;
1004
1005 case kBIT_HASSTREAMER|kBIT_ISPOINTER:
1006 if (!R__t) return 1;
1007 finalString << " R__b.WriteObjectAny(" << R__t << "," << tcl << ");" << std::endl;
1008 break;
1009
1010 case kBIT_ISSTRING:
1011 if (!R__t) return 0;
1012 finalString << " {TString R__str(" << R__t << ".c_str());" << std::endl
1013 << " R__str.Streamer(R__b);};" << std::endl;
1014 break;
1015
1016 case kBIT_ISSTRING|kBIT_ISPOINTER:
1017 if (!R__t) return 0;
1018 finalString << " {TString R__str(" << R__t << "->c_str());" << std::endl
1019 << " R__str.Streamer(R__b);}" << std::endl;
1020 break;
1021
1022 case kBIT_ISPOINTER:
1023 if (!R__t) return 1;
1024 finalString << " R__b.WriteObjectAny(" << R__t << "," << tcl <<");" << std::endl;
1025 break;
1026
1027 default:
1028 if (!R__t) return 1;
1029 finalString << " R__b.StreamObject((" << objType << "*)&" << R__t << "," << tcl << ");" << std::endl;
1030 break;
1031 }
1032 }
1033 return 0;
1034}
1035
1036////////////////////////////////////////////////////////////////////////////////
1037/// Checks if default constructor exists and accessible
1038
1039bool ROOT::TMetaUtils::CheckDefaultConstructor(const clang::CXXRecordDecl* cl, const cling::Interpreter& interpreter)
1040{
1041 clang::CXXRecordDecl* ncCl = const_cast<clang::CXXRecordDecl*>(cl);
1042
1043 // We may induce template instantiation
1044 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interpreter));
1045
1046 if (auto* Ctor = interpreter.getCI()->getSema().LookupDefaultConstructor(ncCl)) {
1047 if (Ctor->getAccess() == clang::AS_public && !Ctor->isDeleted()) {
1048 return true;
1049 }
1050 }
1051
1052 return false;
1053}
1054
1055
1056////////////////////////////////////////////////////////////////////////////////
1057/// Checks IO constructor - must be public and with specified argument
1058
1060 const char *typeOfArg,
1061 const clang::CXXRecordDecl *expectedArgType,
1062 const cling::Interpreter& interpreter)
1063{
1064 if (typeOfArg && !expectedArgType) {
1065 const cling::LookupHelper& lh = interpreter.getLookupHelper();
1066 // We can not use findScope since the type we are given are usually,
1067 // only forward declared (and findScope explicitly reject them).
1068 clang::QualType instanceType = lh.findType(typeOfArg, cling::LookupHelper::WithDiagnostics);
1069 if (!instanceType.isNull())
1070 expectedArgType = instanceType->getAsCXXRecordDecl();
1071 }
1072
1073 if (!expectedArgType)
1074 return EIOCtorCategory::kAbsent;
1075
1076 // FIXME: We should not iterate here. That costs memory!
1077 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interpreter));
1078 for (auto iter = cl->ctor_begin(), end = cl->ctor_end(); iter != end; ++iter)
1079 {
1080 if ((iter->getAccess() != clang::AS_public) || (iter->getNumParams() != 1))
1081 continue;
1082
1083 // We can reach this constructor.
1084 clang::QualType argType((*iter->param_begin())->getType());
1085 argType = argType.getDesugaredType(cl->getASTContext());
1086 // Deal with pointers and references: ROOT-7723
1087 auto ioCtorCategory = EIOCtorCategory::kAbsent;
1088 if (argType->isPointerType()) {
1089 ioCtorCategory = EIOCtorCategory::kIOPtrType;
1090 argType = argType->getPointeeType();
1091 } else if (argType->isReferenceType()) {
1092 ioCtorCategory = EIOCtorCategory::kIORefType;
1093 argType = argType.getNonReferenceType();
1094 } else
1095 continue;
1096
1097 argType = argType.getDesugaredType(cl->getASTContext());
1098 const clang::CXXRecordDecl *argDecl = argType->getAsCXXRecordDecl();
1099 if (argDecl) {
1100 if (argDecl->getCanonicalDecl() == expectedArgType->getCanonicalDecl()) {
1101 return ioCtorCategory;
1102 }
1103 } else {
1104 std::string realArg = argType.getAsString();
1105 std::string clarg("class ");
1106 clarg += typeOfArg;
1107 if (realArg == clarg)
1108 return ioCtorCategory;
1109 }
1110 } // for each constructor
1111
1112 return EIOCtorCategory::kAbsent;
1113}
1114
1115
1116////////////////////////////////////////////////////////////////////////////////
1117/// Check if class has constructor of provided type - either default or with single argument
1118
1120 const RConstructorType &ioctortype,
1121 const cling::Interpreter& interpreter)
1122{
1123 const char *arg = ioctortype.GetName();
1124
1125 if (!ioctortype.GetType() && (!arg || !arg[0])) {
1126 // We are looking for a constructor with zero non-default arguments.
1127
1128 return CheckDefaultConstructor(cl, interpreter) ? EIOCtorCategory::kDefault : EIOCtorCategory::kAbsent;
1129 }
1130
1131 return CheckIOConstructor(cl, arg, ioctortype.GetType(), interpreter);
1132}
1133
1134
1135////////////////////////////////////////////////////////////////////////////////
1136
1137const clang::CXXMethodDecl *GetMethodWithProto(const clang::Decl* cinfo,
1138 const char *method, const char *proto,
1139 const cling::Interpreter &interp,
1140 bool diagnose)
1141{
1142 const clang::FunctionDecl* funcD
1143 = interp.getLookupHelper().findFunctionProto(cinfo, method, proto,
1144 diagnose ? cling::LookupHelper::WithDiagnostics
1145 : cling::LookupHelper::NoDiagnostics);
1146 if (funcD)
1147 return llvm::dyn_cast<const clang::CXXMethodDecl>(funcD);
1148
1149 return nullptr;
1150}
1151
1152
1153////////////////////////////////////////////////////////////////////////////////
1154
1155namespace ROOT {
1156 namespace TMetaUtils {
1157 RConstructorType::RConstructorType(const char *type_of_arg, const cling::Interpreter &interp) : fArgTypeName(type_of_arg),fArgType(nullptr)
1158 {
1159 const cling::LookupHelper& lh = interp.getLookupHelper();
1160 // We can not use findScope since the type we are given are usually,
1161 // only forward declared (and findScope explicitly reject them).
1162 clang::QualType instanceType = lh.findType(type_of_arg, cling::LookupHelper::WithDiagnostics);
1163 if (!instanceType.isNull())
1164 fArgType = instanceType->getAsCXXRecordDecl();
1165 }
1166 const char *RConstructorType::GetName() const { return fArgTypeName.c_str(); }
1167 const clang::CXXRecordDecl *RConstructorType::GetType() const { return fArgType; }
1168 }
1169}
1170
1171////////////////////////////////////////////////////////////////////////////////
1172/// return true if we can find an constructor calleable without any arguments
1173/// or with one the IOCtor special types.
1174
1175bool ROOT::TMetaUtils::HasIOConstructor(const clang::CXXRecordDecl *cl,
1176 std::string& arg,
1177 const RConstructorTypes& ctorTypes,
1178 const cling::Interpreter &interp)
1179{
1180 if (cl->isAbstract()) return false;
1181
1182 for (auto & ctorType : ctorTypes) {
1183
1184 auto ioCtorCat = ROOT::TMetaUtils::CheckConstructor(cl, ctorType, interp);
1185
1186 if (EIOCtorCategory::kAbsent == ioCtorCat)
1187 continue;
1188
1189 std::string proto( ctorType.GetName() );
1190 bool defaultCtor = proto.empty();
1191 if (defaultCtor) {
1192 arg.clear();
1193 } else {
1194 // I/O constructors can take pointers or references to ctorTypes
1195 proto += " *";
1196 if (EIOCtorCategory::kIOPtrType == ioCtorCat) {
1197 arg = "( ("; //(MyType*)nullptr
1198 } else if (EIOCtorCategory::kIORefType == ioCtorCat) {
1199 arg = "( *("; //*(MyType*)nullptr
1200 }
1201 arg += proto;
1202 arg += ")nullptr )";
1203 }
1204 // Check for private operator new
1205 const clang::CXXMethodDecl *method
1206 = GetMethodWithProto(cl, "operator new", "size_t", interp,
1207 cling::LookupHelper::NoDiagnostics);
1208 if (method && method->getAccess() != clang::AS_public) {
1209 // The non-public op new is not going to improve for other c'tors.
1210 return false;
1211 }
1212
1213 // This one looks good!
1214 return true;
1215 }
1216 return false;
1217}
1218
1219////////////////////////////////////////////////////////////////////////////////
1220
1221bool ROOT::TMetaUtils::NeedDestructor(const clang::CXXRecordDecl *cl,
1222 const cling::Interpreter& interp)
1223{
1224 if (!cl) return false;
1225
1226 if (cl->hasUserDeclaredDestructor()) {
1227
1228 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interp));
1229 clang::CXXDestructorDecl *dest = cl->getDestructor();
1230 if (dest) {
1231 return (dest->getAccess() == clang::AS_public);
1232 } else {
1233 return true; // no destructor, so let's assume it means default?
1234 }
1235 }
1236 return true;
1237}
1238
1239////////////////////////////////////////////////////////////////////////////////
1240/// Return true, if the function (defined by the name and prototype) exists and is public
1241
1242bool ROOT::TMetaUtils::CheckPublicFuncWithProto(const clang::CXXRecordDecl *cl,
1243 const char *methodname,
1244 const char *proto,
1245 const cling::Interpreter &interp,
1246 bool diagnose)
1247{
1248 const clang::CXXMethodDecl *method
1249 = GetMethodWithProto(cl,methodname,proto, interp,
1250 diagnose ? cling::LookupHelper::WithDiagnostics
1251 : cling::LookupHelper::NoDiagnostics);
1252 return (method && method->getAccess() == clang::AS_public);
1253}
1254
1255////////////////////////////////////////////////////////////////////////////////
1256/// Return true if the class has a method DirectoryAutoAdd(TDirectory *)
1257
1258bool ROOT::TMetaUtils::HasDirectoryAutoAdd(const clang::CXXRecordDecl *cl, const cling::Interpreter &interp)
1259{
1260 // Detect if the class has a DirectoryAutoAdd
1261
1262 // Detect if the class or one of its parent has a DirectoryAutoAdd
1263 const char *proto = "TDirectory*";
1264 const char *name = "DirectoryAutoAdd";
1265
1266 return CheckPublicFuncWithProto(cl,name,proto,interp, false /*diags*/);
1267}
1268
1269
1270////////////////////////////////////////////////////////////////////////////////
1271/// Return true if the class has a method Merge(TCollection*,TFileMergeInfo*)
1272
1273bool ROOT::TMetaUtils::HasNewMerge(const clang::CXXRecordDecl *cl, const cling::Interpreter &interp)
1274{
1275 // Detect if the class has a 'new' Merge function.
1276
1277 // Detect if the class or one of its parent has a DirectoryAutoAdd
1278 const char *proto = "TCollection*,TFileMergeInfo*";
1279 const char *name = "Merge";
1280
1281 return CheckPublicFuncWithProto(cl,name,proto,interp, false /*diags*/);
1282}
1283
1284////////////////////////////////////////////////////////////////////////////////
1285/// Return true if the class has a method Merge(TCollection*)
1286
1287bool ROOT::TMetaUtils::HasOldMerge(const clang::CXXRecordDecl *cl, const cling::Interpreter &interp)
1288{
1289 // Detect if the class has an old fashion Merge function.
1290
1291 // Detect if the class or one of its parent has a DirectoryAutoAdd
1292 const char *proto = "TCollection*";
1293 const char *name = "Merge";
1294
1295 return CheckPublicFuncWithProto(cl,name,proto, interp, false /*diags*/);
1296}
1297
1298
1299////////////////////////////////////////////////////////////////////////////////
1300/// Return true if the class has a method ResetAfterMerge(TFileMergeInfo *)
1301
1302bool ROOT::TMetaUtils::HasResetAfterMerge(const clang::CXXRecordDecl *cl, const cling::Interpreter &interp)
1303{
1304 // Detect if the class has a 'new' Merge function.
1305 // bool hasMethod = cl.HasMethod("DirectoryAutoAdd");
1306
1307 // Detect if the class or one of its parent has a DirectoryAutoAdd
1308 const char *proto = "TFileMergeInfo*";
1309 const char *name = "ResetAfterMerge";
1310
1311 return CheckPublicFuncWithProto(cl,name,proto, interp, false /*diags*/);
1312}
1313
1314
1315////////////////////////////////////////////////////////////////////////////////
1316/// Return true if the class has a custom member function streamer.
1317
1319 const clang::CXXRecordDecl* clxx,
1320 const cling::Interpreter &interp,
1321 const TNormalizedCtxt &normCtxt)
1322{
1323 static const char *proto = "TBuffer&";
1324
1325 const clang::CXXMethodDecl *method
1326 = GetMethodWithProto(clxx,"Streamer",proto, interp,
1327 cling::LookupHelper::NoDiagnostics);
1328 const clang::DeclContext *clxx_as_context = llvm::dyn_cast<clang::DeclContext>(clxx);
1329
1330 return (method && method->getDeclContext() == clxx_as_context
1331 && ( cl.RequestNoStreamer() || !cl.RequestStreamerInfo()));
1332}
1333
1334////////////////////////////////////////////////////////////////////////////////
1335/// Return true if the class has a custom member function streamer.
1336
1338 const clang::CXXRecordDecl* clxx,
1339 const cling::Interpreter &interp,
1340 const TNormalizedCtxt &normCtxt)
1341{
1342 static const char *proto = "TBuffer&,TClass*";
1343
1344 const clang::CXXMethodDecl *method
1345 = GetMethodWithProto(clxx,"Streamer",proto, interp,
1346 cling::LookupHelper::NoDiagnostics);
1347 const clang::DeclContext *clxx_as_context = llvm::dyn_cast<clang::DeclContext>(clxx);
1348
1349 return (method && method->getDeclContext() == clxx_as_context
1350 && ( cl.RequestNoStreamer() || !cl.RequestStreamerInfo()));
1351}
1352
1353
1354////////////////////////////////////////////////////////////////////////////////
1355/// Main implementation relying on GetFullyQualifiedTypeName
1356/// All other GetQualifiedName functions leverage this one except the
1357/// one for namespaces.
1358
1359void ROOT::TMetaUtils::GetQualifiedName(std::string &qual_name, const clang::QualType &type, const clang::NamedDecl &forcontext)
1360{
1361 ROOT::TMetaUtils::GetFullyQualifiedTypeName(qual_name, type, forcontext.getASTContext());
1362}
1363
1364//----
1365std::string ROOT::TMetaUtils::GetQualifiedName(const clang::QualType &type, const clang::NamedDecl &forcontext)
1366{
1367 std::string result;
1369 type,
1370 forcontext);
1371 return result;
1372}
1373
1374
1375////////////////////////////////////////////////////////////////////////////////
1376
1377void ROOT::TMetaUtils::GetQualifiedName(std::string& qual_type, const clang::Type &type, const clang::NamedDecl &forcontext)
1378{
1379 clang::QualType qualType(&type,0);
1381 qualType,
1382 forcontext);
1383}
1384
1385//---
1386std::string ROOT::TMetaUtils::GetQualifiedName(const clang::Type &type, const clang::NamedDecl &forcontext)
1387{
1388 std::string result;
1390 type,
1391 forcontext);
1392 return result;
1393}
1394
1395// //______________________________________________________________________________
1396// void ROOT::TMetaUtils::GetQualifiedName(std::string &qual_name, const clang::NamespaceDecl &cl)
1397// {
1398// GetQualifiedName(qual_name,cl);
1399// }
1400//
1401// //----
1402// std::string ROOT::TMetaUtils::GetQualifiedName(const clang::NamespaceDecl &cl){
1403// return GetQualifiedName(cl);
1404// }
1405
1406////////////////////////////////////////////////////////////////////////////////
1407/// This implementation does not rely on GetFullyQualifiedTypeName
1408
1409void ROOT::TMetaUtils::GetQualifiedName(std::string &qual_name, const clang::NamedDecl &cl)
1410{
1411 llvm::raw_string_ostream stream(qual_name);
1412 clang::PrintingPolicy policy( cl.getASTContext().getPrintingPolicy() );
1413 policy.SuppressTagKeyword = true; // Never get the class or struct keyword
1414 policy.SuppressUnwrittenScope = true; // Don't write the inline or anonymous namespace names.
1415
1416 cl.getNameForDiagnostic(stream,policy,true);
1417 stream.flush(); // flush to string.
1418
1419 if ( qual_name == "(anonymous " || qual_name == "(unnamed" ) {
1420 size_t pos = qual_name.find(':');
1421 qual_name.erase(0,pos+2);
1422 }
1423}
1424
1425//----
1426std::string ROOT::TMetaUtils::GetQualifiedName(const clang::NamedDecl &cl){
1427 std::string result;
1429 return result;
1430}
1431
1432
1433////////////////////////////////////////////////////////////////////////////////
1434
1435void ROOT::TMetaUtils::GetQualifiedName(std::string &qual_name, const clang::RecordDecl &recordDecl)
1436{
1437 const clang::Type* declType ( recordDecl.getTypeForDecl() );
1438 clang::QualType qualType(declType,0);
1440 qualType,
1441 recordDecl);
1442}
1443
1444//----
1445std::string ROOT::TMetaUtils::GetQualifiedName(const clang::RecordDecl &recordDecl)
1446{
1447 std::string result;
1449 return result;
1450}
1451
1452////////////////////////////////////////////////////////////////////////////////
1453
1455{
1456 ROOT::TMetaUtils::GetQualifiedName(qual_name, *annotated.GetRecordDecl());
1457}
1458
1459//----
1461{
1462 std::string result;
1464 return result;
1465}
1466
1467////////////////////////////////////////////////////////////////////////////////
1468/// Create the data member name-type map for given class
1469
1470static void CreateNameTypeMap(const clang::CXXRecordDecl &cl, ROOT::MembersTypeMap_t& nameType)
1471{
1472 std::stringstream dims;
1473 std::string typenameStr;
1474
1475 const clang::ASTContext& astContext = cl.getASTContext();
1476
1477 // Loop over the non static data member.
1478 for(clang::RecordDecl::field_iterator field_iter = cl.field_begin(), end = cl.field_end();
1479 field_iter != end;
1480 ++field_iter){
1481 // The CINT based code was filtering away static variables (they are not part of
1482 // the list starting with field_begin in clang), and const enums (which should
1483 // also not be part of this list).
1484 // It was also filtering out the 'G__virtualinfo' artificial member.
1485
1486 typenameStr.clear();
1487 dims.str("");
1488 dims.clear();
1489
1490 clang::QualType fieldType(field_iter->getType());
1491 if (fieldType->isConstantArrayType()) {
1492 const clang::ConstantArrayType *arrayType = llvm::dyn_cast<clang::ConstantArrayType>(fieldType.getTypePtr());
1493 while (arrayType) {
1494 dims << "[" << arrayType->getSize().getLimitedValue() << "]";
1495 fieldType = arrayType->getElementType();
1496 arrayType = llvm::dyn_cast<clang::ConstantArrayType>(arrayType->getArrayElementTypeNoTypeQual());
1497 }
1498 }
1499
1500 ROOT::TMetaUtils::GetFullyQualifiedTypeName(typenameStr, fieldType, astContext);
1501 nameType[field_iter->getName().str()] = ROOT::Internal::TSchemaType(typenameStr.c_str(),dims.str().c_str());
1502 }
1503
1504 // And now the base classes
1505 // We also need to look at the base classes.
1506 for(clang::CXXRecordDecl::base_class_const_iterator iter = cl.bases_begin(), end = cl.bases_end();
1507 iter != end;
1508 ++iter){
1509 std::string basename( iter->getType()->getAsCXXRecordDecl()->getNameAsString() ); // Intentionally using only the unqualified name.
1510 nameType[basename] = ROOT::Internal::TSchemaType(basename.c_str(),"");
1511 }
1512}
1513
1514////////////////////////////////////////////////////////////////////////////////
1515
1516const clang::FunctionDecl *ROOT::TMetaUtils::GetFuncWithProto(const clang::Decl* cinfo,
1517 const char *method,
1518 const char *proto,
1519 const cling::Interpreter &interp,
1520 bool diagnose)
1521{
1522 return interp.getLookupHelper().findFunctionProto(cinfo, method, proto,
1523 diagnose ? cling::LookupHelper::WithDiagnostics
1524 : cling::LookupHelper::NoDiagnostics);
1525}
1526
1527////////////////////////////////////////////////////////////////////////////////
1528/// It looks like the template specialization decl actually contains _less_ information
1529/// on the location of the code than the decl (in case where there is forward declaration,
1530/// that is what the specialization points to.
1531///
1532/// const clang::CXXRecordDecl* clxx = llvm::dyn_cast<clang::CXXRecordDecl>(decl);
1533/// if (clxx) {
1534/// switch(clxx->getTemplateSpecializationKind()) {
1535/// case clang::TSK_Undeclared:
1536/// // We want the default behavior
1537/// break;
1538/// case clang::TSK_ExplicitInstantiationDeclaration:
1539/// case clang::TSK_ExplicitInstantiationDefinition:
1540/// case clang::TSK_ImplicitInstantiation: {
1541/// // We want the location of the template declaration:
1542/// const clang::ClassTemplateSpecializationDecl *tmplt_specialization = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl> (clxx);
1543/// if (tmplt_specialization) {
1544/// return GetLineNumber(const_cast< clang::ClassTemplateSpecializationDecl *>(tmplt_specialization)->getSpecializedTemplate());
1545/// }
1546/// break;
1547/// }
1548/// case clang::TSK_ExplicitSpecialization:
1549/// // We want the default behavior
1550/// break;
1551/// default:
1552/// break;
1553/// }
1554/// }
1555
1556long ROOT::TMetaUtils::GetLineNumber(const clang::Decl *decl)
1557{
1558 clang::SourceLocation sourceLocation = decl->getLocation();
1559 clang::SourceManager& sourceManager = decl->getASTContext().getSourceManager();
1560
1561 if (!sourceLocation.isValid() ) {
1562 return -1;
1563 }
1564
1565 if (!sourceLocation.isFileID()) {
1566 sourceLocation = sourceManager.getExpansionRange(sourceLocation).getEnd();
1567 }
1568
1569 if (sourceLocation.isValid() && sourceLocation.isFileID()) {
1570 return sourceManager.getLineNumber(sourceManager.getFileID(sourceLocation),sourceManager.getFileOffset(sourceLocation));
1571 }
1572 else {
1573 return -1;
1574 }
1575}
1576
1577////////////////////////////////////////////////////////////////////////////////
1578/// Return true if the type is a Double32_t or Float16_t or
1579/// is a instance template that depends on Double32_t or Float16_t.
1580
1581bool ROOT::TMetaUtils::hasOpaqueTypedef(clang::QualType instanceType, const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt)
1582{
1583 while (llvm::isa<clang::PointerType>(instanceType.getTypePtr())
1584 || llvm::isa<clang::ReferenceType>(instanceType.getTypePtr()))
1585 {
1586 instanceType = instanceType->getPointeeType();
1587 }
1588
1589 const clang::ElaboratedType* etype
1590 = llvm::dyn_cast<clang::ElaboratedType>(instanceType.getTypePtr());
1591 if (etype) {
1592 instanceType = clang::QualType(etype->getNamedType().getTypePtr(),0);
1593 }
1594
1595 // There is no typedef to worried about, except for the opaque ones.
1596
1597 // Technically we should probably used our own list with just
1598 // Double32_t and Float16_t
1599 if (normCtxt.GetTypeWithAlternative().count(instanceType.getTypePtr())) {
1600 return true;
1601 }
1602
1603
1604 bool result = false;
1605 const clang::CXXRecordDecl* clxx = instanceType->getAsCXXRecordDecl();
1606 if (clxx && clxx->getTemplateSpecializationKind() != clang::TSK_Undeclared) {
1607 // do the template thing.
1608 const clang::TemplateSpecializationType* TST
1609 = llvm::dyn_cast<const clang::TemplateSpecializationType>(instanceType.getTypePtr());
1610 if (!TST) {
1611 // std::string type_name;
1612 // type_name = GetQualifiedName( instanceType, *clxx );
1613 // fprintf(stderr,"ERROR: Could not findS TST for %s\n",type_name.c_str());
1614 return false;
1615 }
1616 for (const clang::TemplateArgument &TA : TST->template_arguments()) {
1617 if (TA.getKind() == clang::TemplateArgument::Type) {
1618 result |= ROOT::TMetaUtils::hasOpaqueTypedef(TA.getAsType(), normCtxt);
1619 }
1620 }
1621 }
1622 return result;
1623}
1624
1625////////////////////////////////////////////////////////////////////////////////
1626/// Return true if any of the argument is or contains a double32.
1627
1629 const cling::Interpreter &interp,
1630 const TNormalizedCtxt &normCtxt)
1631{
1632 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
1633 if (!clxx || clxx->getTemplateSpecializationKind() == clang::TSK_Undeclared) return false;
1634
1635 clang::QualType instanceType = interp.getLookupHelper().findType(cl.GetNormalizedName(),
1636 cling::LookupHelper::WithDiagnostics);
1637 if (instanceType.isNull()) {
1638 //Error(0,"Could not find the clang::Type for %s\n",cl.GetNormalizedName());
1639 return false;
1640 }
1641
1642 return ROOT::TMetaUtils::hasOpaqueTypedef(instanceType, normCtxt);
1643}
1644
1645////////////////////////////////////////////////////////////////////////////////
1646/// Extract attr string
1647
1648int ROOT::TMetaUtils::extractAttrString(clang::Attr* attribute, std::string& attrString)
1649{
1650 clang::AnnotateAttr* annAttr = clang::dyn_cast<clang::AnnotateAttr>(attribute);
1651 if (!annAttr) {
1652 //TMetaUtils::Error(0,"Could not cast Attribute to AnnotatedAttribute\n");
1653 return 1;
1654 }
1655 attrString = annAttr->getAnnotation().str();
1656 return 0;
1657}
1658
1659////////////////////////////////////////////////////////////////////////////////
1660
1661int ROOT::TMetaUtils::extractPropertyNameValFromString(const std::string attributeStr,std::string& attrName, std::string& attrValue)
1662{
1663 // if separator found, extract name and value
1664 size_t substrFound (attributeStr.find(propNames::separator));
1665 if (substrFound==std::string::npos) {
1666 //TMetaUtils::Error(0,"Could not find property name-value separator (%s)\n",ROOT::TMetaUtils::PropertyNameValSeparator.c_str());
1667 return 1;
1668 }
1669 size_t EndPart1 = attributeStr.find_first_of(propNames::separator) ;
1670 attrName = attributeStr.substr(0, EndPart1);
1671 const int separatorLength(propNames::separator.size());
1672 attrValue = attributeStr.substr(EndPart1 + separatorLength);
1673 return 0;
1674}
1675
1676////////////////////////////////////////////////////////////////////////////////
1677
1678int ROOT::TMetaUtils::extractPropertyNameVal(clang::Attr* attribute, std::string& attrName, std::string& attrValue)
1679{
1680 std::string attrString;
1681 int ret = extractAttrString(attribute, attrString);
1682 if (0!=ret) return ret;
1683 return extractPropertyNameValFromString(attrString, attrName,attrValue);
1684}
1685
1686////////////////////////////////////////////////////////////////////////////////
1687/// This routine counts on the "propName<separator>propValue" format
1688
1690 const std::string& propName,
1691 std::string& propValue)
1692{
1693 for (clang::Decl::attr_iterator attrIt = decl.attr_begin();
1694 attrIt!=decl.attr_end();++attrIt){
1695 clang::AnnotateAttr* annAttr = clang::dyn_cast<clang::AnnotateAttr>(*attrIt);
1696 if (!annAttr) continue;
1697
1698 llvm::StringRef attribute = annAttr->getAnnotation();
1699 std::pair<llvm::StringRef,llvm::StringRef> split = attribute.split(propNames::separator.c_str());
1700 if (split.first != propName.c_str()) continue;
1701 else {
1702 propValue = split.second.str();
1703 return true;
1704 }
1705 }
1706 return false;
1707}
1708
1709////////////////////////////////////////////////////////////////////////////////
1710/// This routine counts on the "propName<separator>propValue" format
1711
1713 const std::string& propName,
1714 int& propValue)
1715{
1716 for (clang::Decl::attr_iterator attrIt = decl.attr_begin();
1717 attrIt!=decl.attr_end();++attrIt){
1718 clang::AnnotateAttr* annAttr = clang::dyn_cast<clang::AnnotateAttr>(*attrIt);
1719 if (!annAttr) continue;
1720
1721 llvm::StringRef attribute = annAttr->getAnnotation();
1722 std::pair<llvm::StringRef,llvm::StringRef> split = attribute.split(propNames::separator.c_str());
1723 if (split.first != propName.c_str()) continue;
1724 else {
1725 return split.second.getAsInteger(10,propValue);
1726 }
1727 }
1728 return false;
1729}
1730
1731////////////////////////////////////////////////////////////////////////////////
1732/// FIXME: a function of 450+ lines!
1733
1734void ROOT::TMetaUtils::WriteClassInit(std::ostream& finalString,
1735 const AnnotatedRecordDecl &cl,
1736 const clang::CXXRecordDecl *decl,
1737 const cling::Interpreter &interp,
1738 const TNormalizedCtxt &normCtxt,
1739 const RConstructorTypes& ctorTypes,
1740 bool& needCollectionProxy)
1741{
1742 std::string classname = TClassEdit::GetLong64_Name(cl.GetNormalizedName());
1743
1744 std::string mappedname;
1745 ROOT::TMetaUtils::GetCppName(mappedname,classname.c_str());
1746 std::string csymbol = classname;
1747 std::string args;
1748
1749 if ( ! TClassEdit::IsStdClass( classname.c_str() ) ) {
1750
1751 // Prefix the full class name with '::' except for the STL
1752 // containers and std::string. This is to request the
1753 // real class instead of the class in the namespace ROOT::Shadow
1754 csymbol.insert(0,"::");
1755 }
1756
1757 int stl = TClassEdit::IsSTLCont(classname);
1758 bool bset = TClassEdit::IsSTLBitset(classname.c_str());
1759
1760 bool isStd = TMetaUtils::IsStdClass(*decl);
1761 const cling::LookupHelper& lh = interp.getLookupHelper();
1762 bool isString = TMetaUtils::IsOfType(*decl,"std::string",lh);
1763
1764 bool isStdNotString = isStd && !isString;
1765
1766 finalString << "namespace ROOT {" << "\n";
1767
1768 if (!ClassInfo__HasMethod(decl,"Dictionary",interp) || IsTemplate(*decl))
1769 {
1770 finalString << " static TClass *" << mappedname.c_str() << "_Dictionary();\n"
1771 << " static void " << mappedname.c_str() << "_TClassManip(TClass*);\n";
1772
1773
1774 }
1775
1776 if (HasIOConstructor(decl, args, ctorTypes, interp)) {
1777 finalString << " static void *new_" << mappedname.c_str() << "(void *p = nullptr);" << "\n";
1778
1779 if (args.size()==0 && NeedDestructor(decl, interp))
1780 {
1781 finalString << " static void *newArray_";
1782 finalString << mappedname.c_str();
1783 finalString << "(Long_t size, void *p);";
1784 finalString << "\n";
1785 }
1786 }
1787
1788 if (NeedDestructor(decl, interp)) {
1789 finalString << " static void delete_" << mappedname.c_str() << "(void *p);" << "\n" << " static void deleteArray_" << mappedname.c_str() << "(void *p);" << "\n" << " static void destruct_" << mappedname.c_str() << "(void *p);" << "\n";
1790 }
1791 if (HasDirectoryAutoAdd(decl, interp)) {
1792 finalString << " static void directoryAutoAdd_" << mappedname.c_str() << "(void *obj, TDirectory *dir);" << "\n";
1793 }
1794 if (HasCustomStreamerMemberFunction(cl, decl, interp, normCtxt)) {
1795 finalString << " static void streamer_" << mappedname.c_str() << "(TBuffer &buf, void *obj);" << "\n";
1796 }
1797 if (HasCustomConvStreamerMemberFunction(cl, decl, interp, normCtxt)) {
1798 finalString << " static void conv_streamer_" << mappedname.c_str() << "(TBuffer &buf, void *obj, const TClass*);" << "\n";
1799 }
1800 if (HasNewMerge(decl, interp) || HasOldMerge(decl, interp)) {
1801 finalString << " static Long64_t merge_" << mappedname.c_str() << "(void *obj, TCollection *coll,TFileMergeInfo *info);" << "\n";
1802 }
1803 if (HasResetAfterMerge(decl, interp)) {
1804 finalString << " static void reset_" << mappedname.c_str() << "(void *obj, TFileMergeInfo *info);" << "\n";
1805 }
1806
1807 //--------------------------------------------------------------------------
1808 // Check if we have any schema evolution rules for this class
1809 /////////////////////////////////////////////////////////////////////////////
1810
1811 ROOT::SchemaRuleClassMap_t::iterator rulesIt1 = ROOT::gReadRules.find( classname.c_str() );
1812 ROOT::SchemaRuleClassMap_t::iterator rulesIt2 = ROOT::gReadRawRules.find( classname.c_str() );
1813
1814 ROOT::MembersTypeMap_t nameTypeMap;
1815 CreateNameTypeMap( *decl, nameTypeMap ); // here types for schema evo are written
1816
1817 //--------------------------------------------------------------------------
1818 // Process the read rules
1819 /////////////////////////////////////////////////////////////////////////////
1820
1821 if( rulesIt1 != ROOT::gReadRules.end() ) {
1822 int i = 0;
1823 finalString << "\n // Schema evolution read functions\n";
1824 std::list<ROOT::SchemaRuleMap_t>::iterator rIt = rulesIt1->second.begin();
1825 while( rIt != rulesIt1->second.end() ) {
1826
1827 //--------------------------------------------------------------------
1828 // Check if the rules refer to valid data members
1829 ///////////////////////////////////////////////////////////////////////
1830
1831 std::string error_string;
1832 if( !HasValidDataMembers( *rIt, nameTypeMap, error_string ) ) {
1833 Warning(nullptr, "%s", error_string.c_str());
1834 rIt = rulesIt1->second.erase(rIt);
1835 continue;
1836 }
1837
1838 //---------------------------------------------------------------------
1839 // Write the conversion function if necessary
1840 ///////////////////////////////////////////////////////////////////////
1841
1842 if( rIt->find( "code" ) != rIt->end() ) {
1843 WriteReadRuleFunc( *rIt, i++, mappedname, nameTypeMap, finalString );
1844 }
1845 ++rIt;
1846 }
1847 }
1848
1849
1850
1851
1852 //--------------------------------------------------------------------------
1853 // Process the read raw rules
1854 /////////////////////////////////////////////////////////////////////////////
1855
1856 if( rulesIt2 != ROOT::gReadRawRules.end() ) {
1857 int i = 0;
1858 finalString << "\n // Schema evolution read raw functions\n";
1859 std::list<ROOT::SchemaRuleMap_t>::iterator rIt = rulesIt2->second.begin();
1860 while( rIt != rulesIt2->second.end() ) {
1861
1862 //--------------------------------------------------------------------
1863 // Check if the rules refer to valid data members
1864 ///////////////////////////////////////////////////////////////////////
1865
1866 std::string error_string;
1867 if( !HasValidDataMembers( *rIt, nameTypeMap, error_string ) ) {
1868 Warning(nullptr, "%s", error_string.c_str());
1869 rIt = rulesIt2->second.erase(rIt);
1870 continue;
1871 }
1872
1873 //---------------------------------------------------------------------
1874 // Write the conversion function
1875 ///////////////////////////////////////////////////////////////////////
1876
1877 if( rIt->find( "code" ) == rIt->end() )
1878 continue;
1879
1880 WriteReadRawRuleFunc( *rIt, i++, mappedname, nameTypeMap, finalString );
1881 ++rIt;
1882 }
1883 }
1884
1885 finalString << "\n" << " // Function generating the singleton type initializer" << "\n";
1886
1887 finalString << " static TGenericClassInfo *GenerateInitInstanceLocal(const " << csymbol << "*)" << "\n" << " {" << "\n";
1888
1889 finalString << " " << csymbol << " *ptr = nullptr;" << "\n";
1890
1891 //fprintf(fp, " static ::ROOT::ClassInfo< %s > \n",classname.c_str());
1892 if (ClassInfo__HasMethod(decl,"IsA",interp) ) {
1893 finalString << " static ::TVirtualIsAProxy* isa_proxy = new ::TInstrumentedIsAProxy< " << csymbol << " >(nullptr);" << "\n";
1894 }
1895 else {
1896 finalString << " static ::TVirtualIsAProxy* isa_proxy = new ::TIsAProxy(typeid(" << csymbol << "));" << "\n";
1897 }
1898 finalString << " static ::ROOT::TGenericClassInfo " << "\n" << " instance(\"" << classname.c_str() << "\", ";
1899
1900 if (ClassInfo__HasMethod(decl,"Class_Version",interp)) {
1901 finalString << csymbol << "::Class_Version(), ";
1902 } else if (bset) {
1903 finalString << "2, "; // bitset 'version number'
1904 } else if (stl) {
1905 finalString << "-2, "; // "::TStreamerInfo::Class_Version(), ";
1906 } else if( cl.HasClassVersion() ) {
1907 finalString << cl.RequestedVersionNumber() << ", ";
1908 } else { // if (cl_input.RequestStreamerInfo()) {
1909
1910 // Need to find out if the operator>> is actually defined for this class.
1911 static const char *versionFunc = "GetClassVersion";
1912 // int ncha = strlen(classname.c_str())+strlen(versionFunc)+5;
1913 // char *funcname= new char[ncha];
1914 // snprintf(funcname,ncha,"%s<%s >",versionFunc,classname.c_str());
1915 std::string proto = classname + "*";
1916 const clang::Decl* ctxt = llvm::dyn_cast<clang::Decl>((*cl).getDeclContext());
1917 const clang::FunctionDecl *methodinfo
1918 = ROOT::TMetaUtils::GetFuncWithProto(ctxt, versionFunc, proto.c_str(),
1919 interp, cling::LookupHelper::NoDiagnostics);
1920 // delete [] funcname;
1921
1922 if (methodinfo &&
1923 ROOT::TMetaUtils::GetFileName(*methodinfo, interp).find("Rtypes.h") == llvm::StringRef::npos) {
1924
1925 // GetClassVersion was defined in the header file.
1926 //fprintf(fp, "GetClassVersion((%s *)0x0), ",classname.c_str());
1927 finalString << "GetClassVersion< ";
1928 finalString << classname.c_str();
1929 finalString << " >(), ";
1930 }
1931 //static char temporary[1024];
1932 //sprintf(temporary,"GetClassVersion<%s>( (%s *) 0x0 )",classname.c_str(),classname.c_str());
1933 //fprintf(stderr,"DEBUG: %s has value %d\n",classname.c_str(),(int)G__int(G__calc(temporary)));
1934 }
1935
1936 std::string filename = ROOT::TMetaUtils::GetFileName(*cl, interp);
1937 if (filename.length() > 0) {
1938 for (unsigned int i=0; i<filename.length(); i++) {
1939 if (filename[i]=='\\') filename[i]='/';
1940 }
1941 }
1942 finalString << "\"" << filename << "\", " << ROOT::TMetaUtils::GetLineNumber(cl)
1943 << "," << "\n" << " typeid(" << csymbol
1944 << "), ::ROOT::Internal::DefineBehavior(ptr, ptr)," << "\n" << " ";
1945
1946 if (ClassInfo__HasMethod(decl,"Dictionary",interp) && !IsTemplate(*decl)) {
1947 finalString << "&" << csymbol << "::Dictionary, ";
1948 } else {
1949 finalString << "&" << mappedname << "_Dictionary, ";
1950 }
1951
1952 enum {
1953 TClassTable__kHasCustomStreamerMember = 0x10 // See TClassTable.h
1954 };
1955
1956 Int_t rootflag = cl.RootFlag();
1957 if (HasCustomStreamerMemberFunction(cl, decl, interp, normCtxt)) {
1958 rootflag = rootflag | TClassTable__kHasCustomStreamerMember;
1959 }
1960 finalString << "isa_proxy, " << rootflag << "," << "\n" << " sizeof(" << csymbol << ") );" << "\n";
1961 if (HasIOConstructor(decl, args, ctorTypes, interp)) {
1962 finalString << " instance.SetNew(&new_" << mappedname.c_str() << ");" << "\n";
1963 if (args.size()==0 && NeedDestructor(decl, interp))
1964 finalString << " instance.SetNewArray(&newArray_" << mappedname.c_str() << ");" << "\n";
1965 }
1966 if (NeedDestructor(decl, interp)) {
1967 finalString << " instance.SetDelete(&delete_" << mappedname.c_str() << ");" << "\n" << " instance.SetDeleteArray(&deleteArray_" << mappedname.c_str() << ");" << "\n" << " instance.SetDestructor(&destruct_" << mappedname.c_str() << ");" << "\n";
1968 }
1969 if (HasDirectoryAutoAdd(decl, interp)) {
1970 finalString << " instance.SetDirectoryAutoAdd(&directoryAutoAdd_" << mappedname.c_str() << ");" << "\n";
1971 }
1972 if (HasCustomStreamerMemberFunction(cl, decl, interp, normCtxt)) {
1973 // We have a custom member function streamer or an older (not StreamerInfo based) automatic streamer.
1974 finalString << " instance.SetStreamerFunc(&streamer_" << mappedname.c_str() << ");" << "\n";
1975 }
1976 if (HasCustomConvStreamerMemberFunction(cl, decl, interp, normCtxt)) {
1977 // We have a custom member function streamer or an older (not StreamerInfo based) automatic streamer.
1978 finalString << " instance.SetConvStreamerFunc(&conv_streamer_" << mappedname.c_str() << ");" << "\n";
1979 }
1980 if (HasNewMerge(decl, interp) || HasOldMerge(decl, interp)) {
1981 finalString << " instance.SetMerge(&merge_" << mappedname.c_str() << ");" << "\n";
1982 }
1983 if (HasResetAfterMerge(decl, interp)) {
1984 finalString << " instance.SetResetAfterMerge(&reset_" << mappedname.c_str() << ");" << "\n";
1985 }
1986 if (bset) {
1987 finalString << " instance.AdoptCollectionProxyInfo(TCollectionProxyInfo::Generate(TCollectionProxyInfo::" << "Pushback" << "<Internal::TStdBitsetHelper< " << classname.c_str() << " > >()));" << "\n";
1988
1989 needCollectionProxy = true;
1990 } else if (stl != 0 &&
1991 ((stl > 0 && stl<ROOT::kSTLend) || (stl < 0 && stl>-ROOT::kSTLend)) && // is an stl container
1992 (stl != ROOT::kSTLbitset && stl !=-ROOT::kSTLbitset) ){ // is no bitset
1993 int idx = classname.find("<");
1994 int stlType = (idx!=(int)std::string::npos) ? TClassEdit::STLKind(classname.substr(0,idx)) : 0;
1995 const char* methodTCP = nullptr;
1996 switch(stlType) {
1997 case ROOT::kSTLvector:
1998 case ROOT::kSTLlist:
1999 case ROOT::kSTLdeque:
2000 case ROOT::kROOTRVec:
2001 methodTCP="Pushback";
2002 break;
2004 methodTCP="Pushfront";
2005 break;
2006 case ROOT::kSTLmap:
2007 case ROOT::kSTLmultimap:
2010 methodTCP="MapInsert";
2011 break;
2012 case ROOT::kSTLset:
2013 case ROOT::kSTLmultiset:
2016 methodTCP="Insert";
2017 break;
2018 }
2019 // FIXME Workaround: for the moment we do not generate coll proxies with unique ptrs since
2020 // they imply copies and therefore do not compile.
2021 auto classNameForIO = TClassEdit::GetNameForIO(classname);
2022 finalString << " instance.AdoptCollectionProxyInfo(TCollectionProxyInfo::Generate(TCollectionProxyInfo::" << methodTCP << "< " << classNameForIO.c_str() << " >()));" << "\n";
2023
2024 needCollectionProxy = true;
2025 }
2026
2027 //---------------------------------------------------------------------------
2028 // Register Alternate spelling of the class name.
2029 /////////////////////////////////////////////////////////////////////////////
2030
2031 if (cl.GetRequestedName()[0] && classname != cl.GetRequestedName()) {
2032 finalString << "\n" << " instance.AdoptAlternate(::ROOT::AddClassAlternate(\""
2033 << classname << "\",\"" << cl.GetRequestedName() << "\"));\n";
2034 }
2035
2036 if (!cl.GetDemangledTypeInfo().empty()
2037 && cl.GetDemangledTypeInfo() != classname
2038 && cl.GetDemangledTypeInfo() != cl.GetRequestedName()) {
2039 finalString << "\n" << " instance.AdoptAlternate(::ROOT::AddClassAlternate(\""
2040 << classname << "\",\"" << cl.GetDemangledTypeInfo() << "\"));\n";
2041
2042 }
2043
2044 //---------------------------------------------------------------------------
2045 // Pass the schema evolution rules to TGenericClassInfo
2046 /////////////////////////////////////////////////////////////////////////////
2047
2048 if( (rulesIt1 != ROOT::gReadRules.end() && rulesIt1->second.size()>0) || (rulesIt2 != ROOT::gReadRawRules.end() && rulesIt2->second.size()>0) ) {
2049 finalString << "\n" << " ::ROOT::Internal::TSchemaHelper* rule;" << "\n";
2050 }
2051
2052 if( rulesIt1 != ROOT::gReadRules.end() ) {
2053 finalString << "\n" << " // the io read rules" << "\n" << " std::vector<::ROOT::Internal::TSchemaHelper> readrules(" << rulesIt1->second.size() << ");" << "\n";
2054 ROOT::WriteSchemaList( rulesIt1->second, "readrules", finalString );
2055 finalString << " instance.SetReadRules( readrules );" << "\n";
2056 }
2057
2058 if( rulesIt2 != ROOT::gReadRawRules.end() ) {
2059 finalString << "\n" << " // the io read raw rules" << "\n" << " std::vector<::ROOT::Internal::TSchemaHelper> readrawrules(" << rulesIt2->second.size() << ");" << "\n";
2060 ROOT::WriteSchemaList( rulesIt2->second, "readrawrules", finalString );
2061 finalString << " instance.SetReadRawRules( readrawrules );" << "\n";
2062 }
2063
2064 finalString << " return &instance;" << "\n" << " }" << "\n";
2065
2066 if (!isStdNotString && !ROOT::TMetaUtils::hasOpaqueTypedef(cl, interp, normCtxt)) {
2067 // The GenerateInitInstance for STL are not unique and should not be externally accessible
2068 finalString << " TGenericClassInfo *GenerateInitInstance(const " << csymbol << "*)" << "\n" << " {\n return GenerateInitInstanceLocal(static_cast<" << csymbol << "*>(nullptr));\n }" << "\n";
2069 }
2070
2071 finalString << " // Static variable to force the class initialization" << "\n";
2072 // must be one long line otherwise UseDummy does not work
2073
2074
2075 finalString << " static ::ROOT::TGenericClassInfo *_R__UNIQUE_DICT_(Init) = GenerateInitInstanceLocal(static_cast<const " << csymbol << "*>(nullptr)); R__UseDummy(_R__UNIQUE_DICT_(Init));" << "\n";
2076
2077 if (!ClassInfo__HasMethod(decl,"Dictionary",interp) || IsTemplate(*decl)) {
2078 finalString << "\n" << " // Dictionary for non-ClassDef classes" << "\n"
2079 << " static TClass *" << mappedname << "_Dictionary() {\n"
2080 << " TClass* theClass ="
2081 << "::ROOT::GenerateInitInstanceLocal(static_cast<const " << csymbol << "*>(nullptr))->GetClass();\n"
2082 << " " << mappedname << "_TClassManip(theClass);\n";
2083 finalString << " return theClass;\n";
2084 finalString << " }\n\n";
2085
2086 // Now manipulate tclass in order to percolate the properties expressed as
2087 // annotations of the decls.
2088 std::string manipString;
2089 std::string attribute_s;
2090 std::string attrName, attrValue;
2091 // Class properties
2092 bool attrMapExtracted = false;
2093 if (decl->hasAttrs()){
2094 // Loop on the attributes
2095 for (clang::Decl::attr_iterator attrIt = decl->attr_begin();
2096 attrIt!=decl->attr_end();++attrIt){
2097 if ( 0!=ROOT::TMetaUtils::extractAttrString(*attrIt,attribute_s)){
2098 continue;
2099 }
2100 if (0!=ROOT::TMetaUtils::extractPropertyNameValFromString(attribute_s, attrName, attrValue)){
2101 continue;
2102 }
2103 if (attrName == "name" ||
2104 attrName == "pattern" ||
2105 attrName == "rootmap") continue;
2106 // A general property
2107 // 1) We need to create the property map (in the gen code)
2108 // 2) we need to take out the map (in the gen code)
2109 // 3) We need to bookkep the fact that the map is created and out (in this source)
2110 // 4) We fill the map (in the gen code)
2111 if (!attrMapExtracted){
2112 manipString+=" theClass->CreateAttributeMap();\n";
2113 manipString+=" TDictAttributeMap* attrMap( theClass->GetAttributeMap() );\n";
2114 attrMapExtracted=true;
2115 }
2116 manipString+=" attrMap->AddProperty(\""+attrName +"\",\""+attrValue+"\");\n";
2117 }
2118 } // end of class has properties
2119
2120 // Member properties
2121 // Loop on declarations inside the class, including data members
2122 for(clang::CXXRecordDecl::decl_iterator internalDeclIt = decl->decls_begin();
2123 internalDeclIt != decl->decls_end(); ++internalDeclIt){
2124 if (!(!(*internalDeclIt)->isImplicit()
2125 && (clang::isa<clang::FieldDecl>(*internalDeclIt) ||
2126 clang::isa<clang::VarDecl>(*internalDeclIt)))) continue; // Check if it's a var or a field
2127
2128 // Now let's check the attributes of the var/field
2129 if (!internalDeclIt->hasAttrs()) continue;
2130
2131 attrMapExtracted = false;
2132 bool memberPtrCreated = false;
2133
2134 for (clang::Decl::attr_iterator attrIt = internalDeclIt->attr_begin();
2135 attrIt!=internalDeclIt->attr_end();++attrIt){
2136
2137 // Get the attribute as string
2138 if ( 0!=ROOT::TMetaUtils::extractAttrString(*attrIt,attribute_s)){
2139 continue;
2140 }
2141
2142 // Check the name of the decl
2143 clang::NamedDecl* namedInternalDecl = clang::dyn_cast<clang::NamedDecl> (*internalDeclIt);
2144 if (!namedInternalDecl) {
2145 TMetaUtils::Error(nullptr, "Cannot convert field declaration to clang::NamedDecl");
2146 continue;
2147 }
2148 const std::string memberName(namedInternalDecl->getName());
2149 const std::string cppMemberName = "theMember_"+memberName;
2150
2151 // Prepare a string to get the data member, it can be used later.
2152 const std::string dataMemberCreation= " TDataMember* "+cppMemberName+" = theClass->GetDataMember(\""+memberName+"\");\n";
2153
2154 // Let's now attack regular properties
2155
2156 if (0 != ROOT::TMetaUtils::extractPropertyNameValFromString(attribute_s, attrName, attrValue)) {
2157 continue;
2158 }
2159
2160 // Skip these
2161 if (attrName == propNames::comment ||
2162 attrName == propNames::iotype ||
2163 attrName == propNames::ioname ) continue;
2164
2165 if (!memberPtrCreated){
2166 manipString+=dataMemberCreation;
2167 memberPtrCreated=true;
2168 }
2169
2170 if (!attrMapExtracted){
2171 manipString+=" "+cppMemberName+"->CreateAttributeMap();\n";
2172 manipString+=" TDictAttributeMap* memberAttrMap_"+memberName+"( theMember_"+memberName+"->GetAttributeMap() );\n";
2173 attrMapExtracted=true;
2174 }
2175
2176 manipString+=" memberAttrMap_"+memberName+"->AddProperty(\""+attrName +"\",\""+attrValue+"\");\n";
2177
2178
2179 } // End loop on attributes
2180 } // End loop on internal declarations
2181
2182
2183 finalString << " static void " << mappedname << "_TClassManip(TClass* " << (manipString.empty() ? "":"theClass") << "){\n"
2184 << manipString
2185 << " }\n\n";
2186 } // End of !ClassInfo__HasMethod(decl,"Dictionary") || IsTemplate(*decl))
2187
2188 finalString << "} // end of namespace ROOT" << "\n" << "\n";
2189}
2190
2191////////////////////////////////////////////////////////////////////////////////
2192/// Return true if one of the class' enclosing scope is a namespace and
2193/// set fullname to the fully qualified name,
2194/// clsname to the name within a namespace
2195/// and nsname to the namespace fully qualified name.
2196
2198 std::string &clsname,
2199 std::string &nsname,
2200 const clang::CXXRecordDecl *cl)
2201{
2202 fullname.clear();
2203 nsname.clear();
2204
2206 clsname = fullname;
2207
2208 // Inline namespace are stripped from the normalized name, we need to
2209 // strip it from the prefix we want to remove.
2210 auto ctxt = cl->getEnclosingNamespaceContext();
2211 while(ctxt && ctxt!=cl && ctxt->isInlineNamespace()) {
2212 ctxt = ctxt->getParent();
2213 }
2214 if (ctxt) {
2215 const clang::NamedDecl *namedCtxt = llvm::dyn_cast<clang::NamedDecl>(ctxt);
2216 if (namedCtxt && namedCtxt!=cl) {
2217 const clang::NamespaceDecl *nsdecl = llvm::dyn_cast<clang::NamespaceDecl>(namedCtxt);
2218 if (nsdecl && !nsdecl->isAnonymousNamespace()) {
2219 ROOT::TMetaUtils::GetQualifiedName(nsname,*nsdecl);
2220 clsname.erase (0, nsname.size() + 2);
2221 return true;
2222 }
2223 }
2224 }
2225 return false;
2226}
2227
2228////////////////////////////////////////////////////////////////////////////////
2229
2230const clang::DeclContext *GetEnclosingSpace(const clang::RecordDecl &cl)
2231{
2232 const clang::DeclContext *ctxt = cl.getDeclContext();
2233 while(ctxt && !ctxt->isNamespace()) {
2234 ctxt = ctxt->getParent();
2235 }
2236 return ctxt;
2237}
2238
2239////////////////////////////////////////////////////////////////////////////////
2240/// Write all the necessary opening part of the namespace and
2241/// return the number of closing brackets needed
2242/// For example for Space1::Space2
2243/// we write: namespace Space1 { namespace Space2 {
2244/// and return 2.
2245
2246int ROOT::TMetaUtils::WriteNamespaceHeader(std::ostream &out, const clang::DeclContext *ctxt)
2247{
2248 int closing_brackets = 0;
2249
2250 //fprintf(stderr,"DEBUG: in WriteNamespaceHeader for %s with %s\n",
2251 // cl.Fullname(),namespace_obj.Fullname());
2252 if (ctxt && ctxt->isNamespace()) {
2253 closing_brackets = WriteNamespaceHeader(out,ctxt->getParent());
2254 const clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(ctxt);
2255 if (ns) {
2256 for (int indent = 0; indent < closing_brackets; ++indent)
2257 out << " ";
2258 if (ns->isInline())
2259 out << "inline ";
2260 out << "namespace " << ns->getNameAsString() << " {" << std::endl;
2261 closing_brackets++;
2262 }
2263 }
2264
2265 return closing_brackets;
2266}
2267
2268////////////////////////////////////////////////////////////////////////////////
2269
2270int ROOT::TMetaUtils::WriteNamespaceHeader(std::ostream &out, const clang::RecordDecl *cl)
2271{
2272 return WriteNamespaceHeader(out, GetEnclosingSpace(*cl));
2273}
2274
2275////////////////////////////////////////////////////////////////////////////////
2276
2277bool ROOT::TMetaUtils::NeedTemplateKeyword(const clang::CXXRecordDecl *cl)
2278{
2279 clang::TemplateSpecializationKind kind = cl->getTemplateSpecializationKind();
2280 if (kind == clang::TSK_Undeclared ) {
2281 // Note a template;
2282 return false;
2283 } else if (kind == clang::TSK_ExplicitSpecialization) {
2284 // This is a specialized templated class
2285 return false;
2286 } else {
2287 // This is an automatically or explicitly instantiated templated class.
2288 return true;
2289 }
2290}
2291
2292////////////////////////////////////////////////////////////////////////////////
2293/// return true if we can find a custom operator new with placement
2294
2295bool ROOT::TMetaUtils::HasCustomOperatorNewPlacement(const char *which, const clang::RecordDecl &cl, const cling::Interpreter &interp)
2296{
2297 const char *name = which;
2298 const char *proto = "size_t";
2299 const char *protoPlacement = "size_t,void*";
2300
2301 // First search in the enclosing namespaces
2302 const clang::FunctionDecl *operatornew
2303 = ROOT::TMetaUtils::GetFuncWithProto(llvm::dyn_cast<clang::Decl>(cl.getDeclContext()),
2304 name, proto, interp,
2305 cling::LookupHelper::NoDiagnostics);
2306 const clang::FunctionDecl *operatornewPlacement
2307 = ROOT::TMetaUtils::GetFuncWithProto(llvm::dyn_cast<clang::Decl>(cl.getDeclContext()),
2308 name, protoPlacement, interp,
2309 cling::LookupHelper::NoDiagnostics);
2310
2311 const clang::DeclContext *ctxtnew = nullptr;
2312 const clang::DeclContext *ctxtnewPlacement = nullptr;
2313
2314 if (operatornew) {
2315 ctxtnew = operatornew->getParent();
2316 }
2317 if (operatornewPlacement) {
2318 ctxtnewPlacement = operatornewPlacement->getParent();
2319 }
2320
2321 // Then in the class and base classes
2322 operatornew = ROOT::TMetaUtils::GetFuncWithProto(&cl, name, proto, interp,
2323 false /*diags*/);
2324 operatornewPlacement
2325 = ROOT::TMetaUtils::GetFuncWithProto(&cl, name, protoPlacement, interp,
2326 false /*diags*/);
2327
2328 if (operatornew) {
2329 ctxtnew = operatornew->getParent();
2330 }
2331 if (operatornewPlacement) {
2332 ctxtnewPlacement = operatornewPlacement->getParent();
2333 }
2334
2335 if (!ctxtnewPlacement) {
2336 return false;
2337 }
2338 if (!ctxtnew) {
2339 // Only a new with placement, no hiding
2340 return true;
2341 }
2342 // Both are non zero
2343 if (ctxtnew == ctxtnewPlacement) {
2344 // Same declaration ctxt, no hiding
2345 return true;
2346 }
2347 const clang::CXXRecordDecl* clnew = llvm::dyn_cast<clang::CXXRecordDecl>(ctxtnew);
2348 const clang::CXXRecordDecl* clnewPlacement = llvm::dyn_cast<clang::CXXRecordDecl>(ctxtnewPlacement);
2349 if (!clnew && !clnewPlacement) {
2350 // They are both in different namespaces, I am not sure of the rules.
2351 // we probably ought to find which one is closest ... for now bail
2352 // (because rootcling was also bailing on that).
2353 return true;
2354 }
2355 if (clnew && !clnewPlacement) {
2356 // operator new is class method hiding the outer scope operator new with placement.
2357 return false;
2358 }
2359 if (!clnew && clnewPlacement) {
2360 // operator new is a not class method and can not hide new with placement which is a method
2361 return true;
2362 }
2363 // Both are class methods
2364 if (clnew->isDerivedFrom(clnewPlacement)) {
2365 // operator new is in a more derived part of the hierarchy, it is hiding operator new with placement.
2366 return false;
2367 }
2368 // operator new with placement is in a more derived part of the hierarchy, it can't be hidden by operator new.
2369 return true;
2370}
2371
2372////////////////////////////////////////////////////////////////////////////////
2373/// return true if we can find a custom operator new with placement
2374
2375bool ROOT::TMetaUtils::HasCustomOperatorNewPlacement(const clang::RecordDecl &cl, const cling::Interpreter &interp)
2376{
2377 return HasCustomOperatorNewPlacement("operator new",cl, interp);
2378}
2379
2380////////////////////////////////////////////////////////////////////////////////
2381/// return true if we can find a custom operator new with placement
2382
2383bool ROOT::TMetaUtils::HasCustomOperatorNewArrayPlacement(const clang::RecordDecl &cl, const cling::Interpreter &interp)
2384{
2385 return HasCustomOperatorNewPlacement("operator new[]",cl, interp);
2386}
2387
2388////////////////////////////////////////////////////////////////////////////////
2389/// std::string NormalizedName;
2390/// GetNormalizedName(NormalizedName, decl->getASTContext().getTypeDeclType(decl), interp, normCtxt);
2391
2392void ROOT::TMetaUtils::WriteAuxFunctions(std::ostream& finalString,
2393 const AnnotatedRecordDecl &cl,
2394 const clang::CXXRecordDecl *decl,
2395 const cling::Interpreter &interp,
2396 const RConstructorTypes& ctorTypes,
2397 const TNormalizedCtxt &normCtxt)
2398{
2399 std::string classname = TClassEdit::GetLong64_Name(cl.GetNormalizedName());
2400
2401 std::string mappedname;
2402 ROOT::TMetaUtils::GetCppName(mappedname,classname.c_str());
2403
2404 // Write the functions that are need for the TGenericClassInfo.
2405 // This includes
2406 // IsA
2407 // operator new
2408 // operator new[]
2409 // operator delete
2410 // operator delete[]
2411
2412 ROOT::TMetaUtils::GetCppName(mappedname,classname.c_str());
2413
2414 if ( ! TClassEdit::IsStdClass( classname.c_str() ) ) {
2415
2416 // Prefix the full class name with '::' except for the STL
2417 // containers and std::string. This is to request the
2418 // real class instead of the class in the namespace ROOT::Shadow
2419 classname.insert(0,"::");
2420 }
2421
2422 finalString << "namespace ROOT {" << "\n";
2423
2424 std::string args;
2425 if (HasIOConstructor(decl, args, ctorTypes, interp)) {
2426 // write the constructor wrapper only for concrete classes
2427 finalString << " // Wrappers around operator new" << "\n";
2428 finalString << " static void *new_" << mappedname.c_str() << "(void *p) {" << "\n" << " return p ? ";
2429 if (HasCustomOperatorNewPlacement(*decl, interp)) {
2430 finalString << "new(p) ";
2431 finalString << classname.c_str();
2432 finalString << args;
2433 finalString << " : ";
2434 } else {
2435 finalString << "::new(static_cast<::ROOT::Internal::TOperatorNewHelper*>(p)) ";
2436 finalString << classname.c_str();
2437 finalString << args;
2438 finalString << " : ";
2439 }
2440 finalString << "new " << classname.c_str() << args << ";" << "\n";
2441 finalString << " }" << "\n";
2442
2443 if (args.size()==0 && NeedDestructor(decl, interp)) {
2444 // Can not can newArray if the destructor is not public.
2445 finalString << " static void *newArray_";
2446 finalString << mappedname.c_str();
2447 finalString << "(Long_t nElements, void *p) {";
2448 finalString << "\n";
2449 finalString << " return p ? ";
2450 if (HasCustomOperatorNewArrayPlacement(*decl, interp)) {
2451 finalString << "new(p) ";
2452 finalString << classname.c_str();
2453 finalString << "[nElements] : ";
2454 } else {
2455 finalString << "::new(static_cast<::ROOT::Internal::TOperatorNewHelper*>(p)) ";
2456 finalString << classname.c_str();
2457 finalString << "[nElements] : ";
2458 }
2459 finalString << "new ";
2460 finalString << classname.c_str();
2461 finalString << "[nElements];";
2462 finalString << "\n";
2463 finalString << " }";
2464 finalString << "\n";
2465 }
2466 }
2467
2468 if (NeedDestructor(decl, interp)) {
2469 finalString << " // Wrapper around operator delete" << "\n" << " static void delete_" << mappedname.c_str() << "(void *p) {" << "\n" << " delete (static_cast<" << classname.c_str() << "*>(p));" << "\n" << " }" << "\n" << " static void deleteArray_" << mappedname.c_str() << "(void *p) {" << "\n" << " delete [] (static_cast<" << classname.c_str() << "*>(p));" << "\n" << " }" << "\n" << " static void destruct_" << mappedname.c_str() << "(void *p) {" << "\n" << " typedef " << classname.c_str() << " current_t;" << "\n" << " (static_cast<current_t*>(p))->~current_t();" << "\n" << " }" << "\n";
2470 }
2471
2472 if (HasDirectoryAutoAdd(decl, interp)) {
2473 finalString << " // Wrapper around the directory auto add." << "\n" << " static void directoryAutoAdd_" << mappedname.c_str() << "(void *p, TDirectory *dir) {" << "\n" << " ((" << classname.c_str() << "*)p)->DirectoryAutoAdd(dir);" << "\n" << " }" << "\n";
2474 }
2475
2476 if (HasCustomStreamerMemberFunction(cl, decl, interp, normCtxt)) {
2477 finalString << " // Wrapper around a custom streamer member function." << "\n" << " static void streamer_" << mappedname.c_str() << "(TBuffer &buf, void *obj) {" << "\n" << " ((" << classname.c_str() << "*)obj)->" << classname.c_str() << "::Streamer(buf);" << "\n" << " }" << "\n";
2478 }
2479
2480 if (HasCustomConvStreamerMemberFunction(cl, decl, interp, normCtxt)) {
2481 finalString << " // Wrapper around a custom streamer member function." << "\n" << " static void conv_streamer_" << mappedname.c_str() << "(TBuffer &buf, void *obj, const TClass *onfile_class) {" << "\n" << " ((" << classname.c_str() << "*)obj)->" << classname.c_str() << "::Streamer(buf,onfile_class);" << "\n" << " }" << "\n";
2482 }
2483
2484 if (HasNewMerge(decl, interp)) {
2485 finalString << " // Wrapper around the merge function." << "\n" << " static Long64_t merge_" << mappedname.c_str() << "(void *obj,TCollection *coll,TFileMergeInfo *info) {" << "\n" << " return ((" << classname.c_str() << "*)obj)->Merge(coll,info);" << "\n" << " }" << "\n";
2486 } else if (HasOldMerge(decl, interp)) {
2487 finalString << " // Wrapper around the merge function." << "\n" << " static Long64_t merge_" << mappedname.c_str() << "(void *obj,TCollection *coll,TFileMergeInfo *) {" << "\n" << " return ((" << classname.c_str() << "*)obj)->Merge(coll);" << "\n" << " }" << "\n";
2488 }
2489
2490 if (HasResetAfterMerge(decl, interp)) {
2491 finalString << " // Wrapper around the Reset function." << "\n" << " static void reset_" << mappedname.c_str() << "(void *obj,TFileMergeInfo *info) {" << "\n" << " ((" << classname.c_str() << "*)obj)->ResetAfterMerge(info);" << "\n" << " }" << "\n";
2492 }
2493 finalString << "} // end of namespace ROOT for class " << classname.c_str() << "\n" << "\n";
2494}
2495
2496////////////////////////////////////////////////////////////////////////////////
2497/// Write interface function for STL members
2498
2500 const cling::Interpreter &interp,
2501 const TNormalizedCtxt &normCtxt)
2502{
2503 std::string a;
2504 std::string clName;
2505 TMetaUtils::GetCppName(clName, ROOT::TMetaUtils::GetFileName(*cl.GetRecordDecl(), interp).c_str());
2506 int version = ROOT::TMetaUtils::GetClassVersion(cl.GetRecordDecl(),interp);
2507 if (version == 0) return;
2508 if (version < 0 && !(cl.RequestStreamerInfo()) ) return;
2509
2510
2511 const clang::CXXRecordDecl *clxx = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
2512 if (!clxx) return;
2513
2514 // We also need to look at the base classes.
2515 for(clang::CXXRecordDecl::base_class_const_iterator iter = clxx->bases_begin(), end = clxx->bases_end();
2516 iter != end;
2517 ++iter)
2518 {
2519 int k = ROOT::TMetaUtils::IsSTLContainer(*iter);
2520 if (k!=0) {
2521 Internal::RStl::Instance().GenerateTClassFor( iter->getType(), interp, normCtxt);
2522 }
2523 }
2524
2525 // Loop over the non static data member.
2526 for(clang::RecordDecl::field_iterator field_iter = clxx->field_begin(), end = clxx->field_end();
2527 field_iter != end;
2528 ++field_iter)
2529 {
2530 std::string mTypename;
2531 ROOT::TMetaUtils::GetQualifiedName(mTypename, field_iter->getType(), *clxx);
2532
2533 //member is a string
2534 {
2535 const char*shortTypeName = ROOT::TMetaUtils::ShortTypeName(mTypename.c_str());
2536 if (!strcmp(shortTypeName, "string")) {
2537 continue;
2538 }
2539 }
2540
2541 if (!ROOT::TMetaUtils::IsStreamableObject(**field_iter, interp)) continue;
2542
2543 int k = ROOT::TMetaUtils::IsSTLContainer( **field_iter );
2544 if (k!=0) {
2545 // fprintf(stderr,"Add %s which is also",m.Type()->Name());
2546 // fprintf(stderr," %s\n",R__TrueName(**field_iter) );
2547 clang::QualType utype(ROOT::TMetaUtils::GetUnderlyingType(field_iter->getType()),0);
2548 Internal::RStl::Instance().GenerateTClassFor(utype, interp, normCtxt);
2549 }
2550 }
2551}
2552
2553////////////////////////////////////////////////////////////////////////////////
2554/// TrueName strips the typedefs and array dimensions.
2555
2556std::string ROOT::TMetaUtils::TrueName(const clang::FieldDecl &m)
2557{
2558 const clang::Type *rawtype = m.getType()->getCanonicalTypeInternal().getTypePtr();
2559 if (rawtype->isArrayType()) {
2560 rawtype = rawtype->getBaseElementTypeUnsafe ();
2561 }
2562
2563 std::string result;
2564 ROOT::TMetaUtils::GetQualifiedName(result, clang::QualType(rawtype,0), m);
2565 return result;
2566}
2567
2568////////////////////////////////////////////////////////////////////////////////
2569/// Return the version number of the class or -1
2570/// if the function Class_Version does not exist.
2571
2572int ROOT::TMetaUtils::GetClassVersion(const clang::RecordDecl *cl, const cling::Interpreter& interp)
2573{
2574 const clang::CXXRecordDecl* CRD = llvm::dyn_cast<clang::CXXRecordDecl>(cl);
2575 if (!CRD) {
2576 // Must be an enum or namespace.
2577 // FIXME: Make it work for a namespace!
2578 return -1;
2579 }
2580 const clang::FunctionDecl* funcCV = ROOT::TMetaUtils::ClassInfo__HasMethod(CRD,"Class_Version",interp);
2581
2582 // if we have no Class_Info() return -1.
2583 if (!funcCV) return -1;
2584
2585 // if we have many Class_Info() (?!) return 1.
2586 if (funcCV == (clang::FunctionDecl*)-1) return 1;
2587
2588 return GetTrivialIntegralReturnValue(funcCV, interp).second;
2589}
2590
2591////////////////////////////////////////////////////////////////////////////////
2592/// If the function contains 'just': return SomeValue;
2593/// this routine will extract this value and return it.
2594/// The first element is set to true we have the body of the function and it
2595/// is indeed a trivial function with just a return of a value.
2596/// The second element contains the value (or -1 is case of failure)
2597
2598std::pair<bool, int>
2599ROOT::TMetaUtils::GetTrivialIntegralReturnValue(const clang::FunctionDecl *funcCV, const cling::Interpreter &interp)
2600{
2601 using res_t = std::pair<bool, int>;
2602
2603 const clang::CompoundStmt* FuncBody
2604 = llvm::dyn_cast_or_null<clang::CompoundStmt>(funcCV->getBody());
2605 if (!FuncBody)
2606 return res_t{false, -1};
2607 if (FuncBody->size() != 1) {
2608 // This is a non-ClassDef(), complex function - it might depend on state
2609 // and thus we'll need the runtime and cannot determine the result
2610 // statically.
2611 return res_t{false, -1};
2612 }
2613 const clang::ReturnStmt* RetStmt
2614 = llvm::dyn_cast<clang::ReturnStmt>(FuncBody->body_back());
2615 if (!RetStmt)
2616 return res_t{false, -1};
2617 const clang::Expr* RetExpr = RetStmt->getRetValue();
2618 // ClassDef controls the content of Class_Version() but not the return
2619 // expression which is CPP expanded from what the user provided as second
2620 // ClassDef argument. It's usually just be an integer literal but it could
2621 // also be an enum or a variable template for all we know.
2622 // Go through ICE to be more general.
2623 if (auto RetRes = RetExpr->getIntegerConstantExpr(funcCV->getASTContext())) {
2624 if (RetRes->isSigned())
2625 return res_t{true, (Version_t)RetRes->getSExtValue()};
2626 return res_t{true, (Version_t)RetRes->getZExtValue()};
2627 }
2628 return res_t{false, -1};
2629}
2630
2631////////////////////////////////////////////////////////////////////////////////
2632/// Is this an STL container.
2633
2635{
2636 return TMetaUtils::IsSTLCont(*annotated.GetRecordDecl());
2637}
2638
2639////////////////////////////////////////////////////////////////////////////////
2640/// Is this an STL container?
2641
2643{
2644 clang::QualType type = m.getType();
2645 clang::RecordDecl *decl = ROOT::TMetaUtils::GetUnderlyingRecordDecl(type);
2646
2647 if (decl) return TMetaUtils::IsSTLCont(*decl);
2648 else return ROOT::kNotSTL;
2649}
2650
2651////////////////////////////////////////////////////////////////////////////////
2652/// Is this an STL container?
2653
2654int ROOT::TMetaUtils::IsSTLContainer(const clang::CXXBaseSpecifier &base)
2655{
2656 clang::QualType type = base.getType();
2657 clang::RecordDecl *decl = ROOT::TMetaUtils::GetUnderlyingRecordDecl(type);
2658
2659 if (decl) return TMetaUtils::IsSTLCont(*decl);
2660 else return ROOT::kNotSTL;
2661}
2662
2663////////////////////////////////////////////////////////////////////////////////
2664/// Calls the given lambda on every header in the given module.
2665/// includeDirectlyUsedModules designates if the foreach should also loop over
2666/// the headers in all modules that are directly used via a `use` declaration
2667/// in the modulemap.
2668void ROOT::TMetaUtils::foreachHeaderInModule(const clang::Module &module,
2669 const std::function<void(const clang::Module::Header &)> &closure,
2670 bool includeDirectlyUsedModules)
2671{
2672 // Iterates over all headers in a module and calls the closure on each.
2673
2674 // FIXME: We currently have to hardcode '4' to do this. Maybe we
2675 // will have a nicer way to do this in the future.
2676 // NOTE: This is on purpose '4', not '5' which is the size of the
2677 // vector. The last element is the list of excluded headers which we
2678 // obviously don't want to check here.
2679 const std::size_t publicHeaderIndex = 4;
2680
2681 // Integrity check in case this array changes its size at some point.
2682 const std::size_t maxArrayLength = ((sizeof module.Headers) / (sizeof *module.Headers));
2683 static_assert(publicHeaderIndex + 1 == maxArrayLength,
2684 "'Headers' has changed it's size, we need to update publicHeaderIndex");
2685
2686 // Make a list of modules and submodules that we can check for headers.
2687 // We use a SetVector to prevent an infinite loop in unlikely case the
2688 // modules somehow are messed up and don't form a tree...
2689 llvm::SetVector<const clang::Module *> modules;
2690 modules.insert(&module);
2691 for (size_t i = 0; i < modules.size(); ++i) {
2692 const clang::Module *M = modules[i];
2693 for (const clang::Module *subModule : M->submodules())
2694 modules.insert(subModule);
2695 }
2696
2697 for (const clang::Module *m : modules) {
2698 if (includeDirectlyUsedModules) {
2699 for (clang::Module *used : m->DirectUses) {
2700 foreachHeaderInModule(*used, closure, true);
2701 }
2702 }
2703
2704 for (std::size_t i = 0; i < publicHeaderIndex; i++) {
2705 auto &headerList = m->Headers[i];
2706 for (const clang::Module::Header &moduleHeader : headerList) {
2707 closure(moduleHeader);
2708 }
2709 }
2710 }
2711}
2712
2713////////////////////////////////////////////////////////////////////////////////
2714/// Return the absolute type of typeDesc.
2715/// E.g.: typeDesc = "class TNamed**", returns "TNamed".
2716/// we remove * and const keywords. (we do not want to remove & ).
2717/// You need to use the result immediately before it is being overwritten.
2718
2719const char *ROOT::TMetaUtils::ShortTypeName(const char *typeDesc)
2720{
2721 static char t[4096];
2722 static const char* constwd = "const ";
2723 static const char* constwdend = "const";
2724
2725 const char *s;
2726 char *p=t;
2727 int lev=0;
2728 for (s=typeDesc;*s;s++) {
2729 if (*s=='<') lev++;
2730 if (*s=='>') lev--;
2731 if (lev==0 && *s=='*') continue;
2732 if (lev==0 && (strncmp(constwd,s,strlen(constwd))==0
2733 ||strcmp(constwdend,s)==0 ) ) {
2734 s+=strlen(constwd)-1; // -1 because the loop adds 1
2735 continue;
2736 }
2737 if (lev==0 && *s==' ' && *(s+1)!='*') { p = t; continue;}
2738 if (p - t > (long)sizeof(t)) {
2739 printf("ERROR (rootcling): type name too long for StortTypeName: %s\n",
2740 typeDesc);
2741 p[0] = 0;
2742 return t;
2743 }
2744 *p++ = *s;
2745 }
2746 p[0]=0;
2747
2748 return t;
2749}
2750
2751bool ROOT::TMetaUtils::IsStreamableObject(const clang::FieldDecl &m,
2752 const cling::Interpreter& interp)
2753{
2754 auto comment = ROOT::TMetaUtils::GetComment( m );
2755
2756 // Transient
2757 if (!comment.empty() && comment[0] == '!')
2758 return false;
2759
2760 clang::QualType type = m.getType();
2761
2762 if (type->isReferenceType()) {
2763 // Reference can not be streamed.
2764 return false;
2765 }
2766
2767 std::string mTypeName = type.getAsString(m.getASTContext().getPrintingPolicy());
2768 if (!strcmp(mTypeName.c_str(), "string") || !strcmp(mTypeName.c_str(), "string*")) {
2769 return true;
2770 }
2771 if (!strcmp(mTypeName.c_str(), "std::string") || !strcmp(mTypeName.c_str(), "std::string*")) {
2772 return true;
2773 }
2774
2776 return true;
2777 }
2778
2779 const clang::Type *rawtype = type.getTypePtr()->getBaseElementTypeUnsafe ();
2780
2781 if (rawtype->isPointerType()) {
2782 //Get to the 'raw' type.
2783 clang::QualType pointee;
2784 while ( (pointee = rawtype->getPointeeType()) , pointee.getTypePtrOrNull() && pointee.getTypePtr() != rawtype)
2785 {
2786 rawtype = pointee.getTypePtr();
2787 }
2788 }
2789
2790 if (rawtype->isFundamentalType() || rawtype->isEnumeralType()) {
2791 // not an ojbect.
2792 return false;
2793 }
2794
2795 const clang::CXXRecordDecl *cxxdecl = rawtype->getAsCXXRecordDecl();
2796 if (cxxdecl && ROOT::TMetaUtils::ClassInfo__HasMethod(cxxdecl,"Streamer", interp)) {
2797 if (!(ROOT::TMetaUtils::ClassInfo__HasMethod(cxxdecl,"Class_Version", interp))) return true;
2798 int version = ROOT::TMetaUtils::GetClassVersion(cxxdecl,interp);
2799 if (version > 0) return true;
2800 }
2801 return false;
2802}
2803
2804////////////////////////////////////////////////////////////////////////////////
2805/// Return the absolute type of typeDesc.
2806/// E.g.: typeDesc = "class TNamed**", returns "TNamed".
2807/// we remove * and const keywords. (we do not want to remove & ).
2808/// You need to use the result immediately before it is being overwritten.
2809
2810std::string ROOT::TMetaUtils::ShortTypeName(const clang::FieldDecl &m)
2811{
2812 const clang::Type *rawtype = m.getType().getTypePtr();
2813
2814 //Get to the 'raw' type.
2815 clang::QualType pointee;
2816 while ( rawtype->isPointerType() && ((pointee = rawtype->getPointeeType()) , pointee.getTypePtrOrNull()) && pointee.getTypePtr() != rawtype)
2817 {
2818 rawtype = pointee.getTypePtr();
2819 }
2820
2821 std::string result;
2822 ROOT::TMetaUtils::GetQualifiedName(result, clang::QualType(rawtype,0), m);
2823 return result;
2824}
2825
2826////////////////////////////////////////////////////////////////////////////////
2827
2828clang::RecordDecl *ROOT::TMetaUtils::GetUnderlyingRecordDecl(clang::QualType type)
2829{
2830 const clang::Type *rawtype = ROOT::TMetaUtils::GetUnderlyingType(type);
2831
2832 if (rawtype->isFundamentalType() || rawtype->isEnumeralType()) {
2833 // not an object.
2834 return nullptr;
2835 }
2836 return rawtype->getAsCXXRecordDecl();
2837}
2838
2839////////////////////////////////////////////////////////////////////////////////
2840/// Generate the code of the class
2841/// If the requestor is genreflex, request the new streamer format
2842
2843void ROOT::TMetaUtils::WriteClassCode(CallWriteStreamer_t WriteStreamerFunc,
2844 const AnnotatedRecordDecl &cl,
2845 const cling::Interpreter &interp,
2846 const TNormalizedCtxt &normCtxt,
2847 std::ostream& dictStream,
2848 const RConstructorTypes& ctorTypes,
2849 bool isGenreflex=false)
2850{
2851 const clang::CXXRecordDecl* decl = llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl());
2852
2853 if (!decl || !decl->isCompleteDefinition()) {
2854 return;
2855 }
2856
2857 std::string fullname;
2859 if (TClassEdit::IsSTLCont(fullname) ) {
2860 Internal::RStl::Instance().GenerateTClassFor(cl.GetNormalizedName(), llvm::dyn_cast<clang::CXXRecordDecl>(cl.GetRecordDecl()), interp, normCtxt);
2861 return;
2862 }
2863
2864 if (ROOT::TMetaUtils::ClassInfo__HasMethod(cl,"Streamer",interp)) {
2865 // The !genreflex is there to prevent genreflex to select collections which are data members
2866 // This is to maintain the behaviour of ROOT5 and ROOT6 up to 6.07 included.
2867 if (cl.RootFlag() && !isGenreflex) ROOT::TMetaUtils::WritePointersSTL(cl, interp, normCtxt); // In particular this detect if the class has a version number.
2868 if (!(cl.RequestNoStreamer())) {
2869 (*WriteStreamerFunc)(cl, interp, normCtxt, dictStream, isGenreflex || cl.RequestStreamerInfo());
2870 } else
2871 ROOT::TMetaUtils::Info(nullptr, "Class %s: Do not generate Streamer() [*** custom streamer ***]\n",fullname.c_str());
2872 } else {
2873 ROOT::TMetaUtils::Info(nullptr, "Class %s: Streamer() not declared\n", fullname.c_str());
2874
2875 // See comment above about the !isGenreflex
2876 if (cl.RequestStreamerInfo() && !isGenreflex) ROOT::TMetaUtils::WritePointersSTL(cl, interp, normCtxt);
2877 }
2878 ROOT::TMetaUtils::WriteAuxFunctions(dictStream, cl, decl, interp, ctorTypes, normCtxt);
2879}
2880
2881////////////////////////////////////////////////////////////////////////////////
2882/// Add any unspecified template parameters to the class template instance,
2883/// mentioned anywhere in the type.
2884///
2885/// Note: this does not strip any typedef but could be merged with cling::utils::Transform::GetPartiallyDesugaredType
2886/// if we can safely replace TClassEdit::IsStd with a test on the declaring scope
2887/// and if we can resolve the fact that the added parameter do not take into account possible use/dependences on Double32_t
2888/// and if we decide that adding the default is the right long term solution or not.
2889/// Whether it is or not depend on the I/O on whether the default template argument might change or not
2890/// and whether they (should) affect the on disk layout (for STL containers, we do know they do not).
2891
2892clang::QualType ROOT::TMetaUtils::AddDefaultParameters(clang::QualType instanceType,
2893 const cling::Interpreter &interpreter,
2894 const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt)
2895{
2896 const clang::ASTContext& Ctx = interpreter.getCI()->getASTContext();
2897
2898 clang::QualType originalType = instanceType;
2899
2900 // In case of name* we need to strip the pointer first, add the default and attach
2901 // the pointer once again.
2902 if (llvm::isa<clang::PointerType>(instanceType.getTypePtr())) {
2903 // Get the qualifiers.
2904 clang::Qualifiers quals = instanceType.getQualifiers();
2905 clang::QualType newPointee = AddDefaultParameters(instanceType->getPointeeType(), interpreter, normCtxt);
2906 if (newPointee != instanceType->getPointeeType()) {
2907 instanceType = Ctx.getPointerType(newPointee);
2908 // Add back the qualifiers.
2909 instanceType = Ctx.getQualifiedType(instanceType, quals);
2910 }
2911 return instanceType;
2912 }
2913
2914 // In case of Int_t& we need to strip the pointer first, desugar and attach
2915 // the pointer once again.
2916 if (llvm::isa<clang::ReferenceType>(instanceType.getTypePtr())) {
2917 // Get the qualifiers.
2918 bool isLValueRefTy = llvm::isa<clang::LValueReferenceType>(instanceType.getTypePtr());
2919 clang::Qualifiers quals = instanceType.getQualifiers();
2920 clang::QualType newPointee = AddDefaultParameters(instanceType->getPointeeType(), interpreter, normCtxt);
2921
2922 if (newPointee != instanceType->getPointeeType()) {
2923 // Add the r- or l- value reference type back to the desugared one
2924 if (isLValueRefTy)
2925 instanceType = Ctx.getLValueReferenceType(newPointee);
2926 else
2927 instanceType = Ctx.getRValueReferenceType(newPointee);
2928 // Add back the qualifiers.
2929 instanceType = Ctx.getQualifiedType(instanceType, quals);
2930 }
2931 return instanceType;
2932 }
2933
2934 // Treat the Scope.
2935 bool prefix_changed = false;
2936 clang::NestedNameSpecifier *prefix = nullptr;
2937 clang::Qualifiers prefix_qualifiers = instanceType.getLocalQualifiers();
2938 const clang::ElaboratedType* etype
2939 = llvm::dyn_cast<clang::ElaboratedType>(instanceType.getTypePtr());
2940 if (etype) {
2941 // We have to also handle the prefix.
2942 prefix = AddDefaultParametersNNS(Ctx, etype->getQualifier(), interpreter, normCtxt);
2943 prefix_changed = prefix != etype->getQualifier();
2944 instanceType = clang::QualType(etype->getNamedType().getTypePtr(),0);
2945 }
2946
2947 // In case of template specializations iterate over the arguments and
2948 // add unspecified default parameter.
2949
2950 const clang::TemplateSpecializationType* TST
2951 = llvm::dyn_cast<const clang::TemplateSpecializationType>(instanceType.getTypePtr());
2952
2953 const clang::ClassTemplateSpecializationDecl* TSTdecl
2954 = llvm::dyn_cast_or_null<const clang::ClassTemplateSpecializationDecl>(instanceType.getTypePtr()->getAsCXXRecordDecl());
2955
2956 // Don't add the default paramater onto std classes.
2957 // We really need this for __shared_ptr which add a enum constant value which
2958 // is spelled in its 'numeral' form and thus the resulting type name is
2959 // incorrect. We also can used this for any of the STL collections where we
2960 // know we don't want the default argument. For the other members of the
2961 // std namespace this is dubious (because TMetaUtils::GetNormalizedName would
2962 // not drop those defaults). [I.e. the real test ought to be is std and
2963 // name is __shared_ptr or vector or list or set or etc.]
2964 bool isStdDropDefault = TSTdecl && IsStdDropDefaultClass(*TSTdecl);
2965
2966 bool mightHaveChanged = false;
2967 if (TST && TSTdecl) {
2968
2969 clang::Sema& S = interpreter.getCI()->getSema();
2970 clang::TemplateDecl *Template = TSTdecl->getSpecializedTemplate()->getMostRecentDecl();
2971 clang::TemplateParameterList *Params = Template->getTemplateParameters();
2972 clang::TemplateParameterList::iterator Param = Params->begin(); // , ParamEnd = Params->end();
2973 //llvm::SmallVectorImpl<TemplateArgument> Converted; // Need to contains the other arguments.
2974 // Converted seems to be the same as our 'desArgs'
2975
2976 unsigned int dropDefault = normCtxt.GetConfig().DropDefaultArg(*Template);
2977
2978 llvm::SmallVector<clang::TemplateArgument, 4> desArgs;
2979 llvm::SmallVector<clang::TemplateArgument, 4> canonArgs;
2980 llvm::ArrayRef<clang::TemplateArgument> template_arguments = TST->template_arguments();
2981 unsigned int Idecl = 0, Edecl = TSTdecl->getTemplateArgs().size();
2982 unsigned int maxAddArg = TSTdecl->getTemplateArgs().size() - dropDefault;
2983 for (const clang::TemplateArgument *I = template_arguments.begin(), *E = template_arguments.end(); Idecl != Edecl;
2984 I != E ? ++I : nullptr, ++Idecl, ++Param) {
2985
2986 if (I != E) {
2987
2988 if (I->getKind() == clang::TemplateArgument::Template) {
2989 clang::TemplateName templateName = I->getAsTemplate();
2990 clang::TemplateDecl* templateDecl = templateName.getAsTemplateDecl();
2991 if (templateDecl) {
2992 clang::DeclContext* declCtxt = templateDecl->getDeclContext();
2993
2994 if (declCtxt && !templateName.getAsQualifiedTemplateName()){
2995 clang::NamespaceDecl* ns = clang::dyn_cast<clang::NamespaceDecl>(declCtxt);
2996 clang::NestedNameSpecifier* nns;
2997 if (ns) {
2998 nns = cling::utils::TypeName::CreateNestedNameSpecifier(Ctx, ns);
2999 } else if (clang::TagDecl* TD = llvm::dyn_cast<clang::TagDecl>(declCtxt)) {
3000 nns = cling::utils::TypeName::CreateNestedNameSpecifier(Ctx,TD, false /*FullyQualified*/);
3001 } else {
3002 // TU scope
3003 desArgs.push_back(*I);
3004 continue;
3005 }
3006 clang::TemplateName UnderlyingTN(templateDecl);
3007 if (clang::UsingShadowDecl *USD = templateName.getAsUsingShadowDecl())
3008 UnderlyingTN = clang::TemplateName(USD);
3009 clang::TemplateName templateNameWithNSS ( Ctx.getQualifiedTemplateName(nns, false, UnderlyingTN) );
3010 desArgs.push_back(clang::TemplateArgument(templateNameWithNSS));
3011 mightHaveChanged = true;
3012 continue;
3013 }
3014 }
3015 }
3016
3017 if (I->getKind() != clang::TemplateArgument::Type) {
3018 desArgs.push_back(*I);
3019 continue;
3020 }
3021
3022 clang::QualType SubTy = I->getAsType();
3023
3024 // Check if the type needs more desugaring and recurse.
3025 // (Originally this was limited to elaborated and templated type,
3026 // but we also need to do it for pointer and reference type
3027 // and who knows what, so do it always)
3028 clang::QualType newSubTy = AddDefaultParameters(SubTy,
3029 interpreter,
3030 normCtxt);
3031 if (SubTy != newSubTy) {
3032 mightHaveChanged = true;
3033 desArgs.push_back(clang::TemplateArgument(newSubTy));
3034 } else {
3035 desArgs.push_back(*I);
3036 }
3037 // Converted.push_back(TemplateArgument(ArgTypeForTemplate));
3038 } else if (!isStdDropDefault && Idecl < maxAddArg) {
3039
3040 mightHaveChanged = true;
3041
3042 const clang::TemplateArgument& templateArg
3043 = TSTdecl->getTemplateArgs().get(Idecl);
3044 if (templateArg.getKind() != clang::TemplateArgument::Type) {
3045 desArgs.push_back(templateArg);
3046 continue;
3047 }
3048 clang::QualType SubTy = templateArg.getAsType();
3049
3050 clang::SourceLocation TemplateLoc = Template->getSourceRange ().getBegin(); //NOTE: not sure that this is the 'right' location.
3051 clang::SourceLocation RAngleLoc = TSTdecl->getSourceRange().getBegin(); // NOTE: most likely wrong, I think this is expecting the location of right angle
3052
3053 clang::TemplateTypeParmDecl *TTP = llvm::dyn_cast<clang::TemplateTypeParmDecl>(*Param);
3054 {
3055 // We may induce template instantiation
3056 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interpreter));
3057 bool HasDefaultArgs;
3058 clang::TemplateArgumentLoc ArgType = S.SubstDefaultTemplateArgumentIfAvailable(
3059 Template,
3060 TemplateLoc,
3061 RAngleLoc,
3062 TTP,
3063 desArgs,
3064 canonArgs,
3065 HasDefaultArgs);
3066 // The substition can fail, in which case there would have been compilation
3067 // error printed on the screen.
3068 if (ArgType.getArgument().isNull()
3069 || ArgType.getArgument().getKind() != clang::TemplateArgument::Type) {
3070 ROOT::TMetaUtils::Error("ROOT::TMetaUtils::AddDefaultParameters",
3071 "Template parameter substitution failed for %s around %s\n",
3072 instanceType.getAsString().c_str(), SubTy.getAsString().c_str());
3073 break;
3074 }
3075 clang::QualType BetterSubTy = ArgType.getArgument().getAsType();
3076 SubTy = cling::utils::Transform::GetPartiallyDesugaredType(Ctx,BetterSubTy,normCtxt.GetConfig(),/*fullyQualified=*/ true);
3077 }
3078 SubTy = AddDefaultParameters(SubTy,interpreter,normCtxt);
3079 desArgs.push_back(clang::TemplateArgument(SubTy));
3080 } else {
3081 // We are past the end of the list of specified arguements and we
3082 // do not want to add the default, no need to continue.
3083 break;
3084 }
3085 }
3086
3087 // If we added default parameter, allocate new type in the AST.
3088 if (mightHaveChanged) {
3089 instanceType = Ctx.getTemplateSpecializationType(TST->getTemplateName(),
3090 desArgs,
3091 TST->getCanonicalTypeInternal());
3092 }
3093 }
3094
3095 if (!prefix_changed && !mightHaveChanged) return originalType;
3096 if (prefix) {
3097 instanceType = Ctx.getElaboratedType(clang::ETK_None,prefix,instanceType);
3098 instanceType = Ctx.getQualifiedType(instanceType,prefix_qualifiers);
3099 }
3100 return instanceType;
3101}
3102
3103////////////////////////////////////////////////////////////////////////////////
3104/// ValidArrayIndex return a static string (so use it or copy it immediatly, do not
3105/// call GrabIndex twice in the same expression) containing the size of the
3106/// array data member.
3107/// In case of error, or if the size is not specified, GrabIndex returns 0.
3108/// If errnum is not null, *errnum updated with the error number:
3109/// Cint::G__DataMemberInfo::G__VALID : valid array index
3110/// Cint::G__DataMemberInfo::G__NOT_INT : array index is not an int
3111/// Cint::G__DataMemberInfo::G__NOT_DEF : index not defined before array
3112/// (this IS an error for streaming to disk)
3113/// Cint::G__DataMemberInfo::G__IS_PRIVATE: index exist in a parent class but is private
3114/// Cint::G__DataMemberInfo::G__UNKNOWN : index is not known
3115/// If errstr is not null, *errstr is updated with the address of a static
3116/// string containing the part of the index with is invalid.
3117
3118llvm::StringRef ROOT::TMetaUtils::DataMemberInfo__ValidArrayIndex(const cling::Interpreter &interp, const clang::DeclaratorDecl &m, int *errnum, llvm::StringRef *errstr)
3119{
3120 llvm::StringRef title;
3121
3122 // Try to get the comment either from the annotation or the header file if present
3123 if (clang::AnnotateAttr *A = m.getAttr<clang::AnnotateAttr>())
3124 title = A->getAnnotation();
3125 else
3126 // Try to get the comment from the header file if present
3128
3129 // Let's see if the user provided us with some information
3130 // with the format: //[dimension] this is the dim of the array
3131 // dimension can be an arithmetical expression containing, literal integer,
3132 // the operator *,+ and - and data member of integral type. In addition the
3133 // data members used for the size of the array need to be defined prior to
3134 // the array.
3135
3136 if (errnum) *errnum = VALID;
3137
3138 if (title.size() == 0 || (title[0] != '[')) return llvm::StringRef();
3139 size_t rightbracket = title.find(']');
3140 if (rightbracket == llvm::StringRef::npos) return llvm::StringRef();
3141
3142 std::string working;
3143 llvm::StringRef indexvar(title.data()+1,rightbracket-1);
3144
3145 // now we should have indexvar=dimension
3146 // Let's see if this is legal.
3147 // which means a combination of data member and digit separated by '*','+','-'
3148 // First we remove white spaces.
3149 unsigned int i;
3150 size_t indexvarlen = indexvar.size();
3151 for ( i=0; i<indexvarlen; i++) {
3152 if (!isspace(indexvar[i])) {
3153 working += indexvar[i];
3154 }
3155 }
3156
3157 // Now we go through all indentifiers
3158 const char *tokenlist = "*+-";
3159 char *current = const_cast<char*>(working.c_str());
3160 current = strtok(current,tokenlist); // this method does not need to be reentrant
3161
3162 while (current) {
3163 // Check the token
3164 if (isdigit(current[0])) {
3165 for(i=0;i<strlen(current);i++) {
3166 if (!isdigit(current[i])) {
3167 // Error we only access integer.
3168 //NOTE: *** Need to print an error;
3169 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not an interger\n",
3170 // member.MemberOf()->Name(), member.Name(), current);
3171 if (errstr) *errstr = current;
3172 if (errnum) *errnum = NOT_INT;
3173 return llvm::StringRef();
3174 }
3175 }
3176 } else { // current token is not a digit
3177 // first let's see if it is a data member:
3178 const clang::CXXRecordDecl *parent_clxx = llvm::dyn_cast<clang::CXXRecordDecl>(m.getDeclContext());
3179 const clang::FieldDecl *index1 = nullptr;
3180 if (parent_clxx)
3181 index1 = GetDataMemberFromAll(*parent_clxx, current );
3182 if ( index1 ) {
3183 if ( IsFieldDeclInt(index1) ) {
3184 // Let's see if it has already been written down in the
3185 // Streamer.
3186 // Let's see if we already wrote it down in the
3187 // streamer.
3188 for(clang::RecordDecl::field_iterator field_iter = parent_clxx->field_begin(), end = parent_clxx->field_end();
3189 field_iter != end;
3190 ++field_iter)
3191 {
3192 if ( field_iter->getNameAsString() == m.getNameAsString() ) {
3193 // we reached the current data member before
3194 // reaching the index so we have not written it yet!
3195 //NOTE: *** Need to print an error;
3196 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) has not been defined before the array \n",
3197 // member.MemberOf()->Name(), member.Name(), current);
3198 if (errstr) *errstr = current;
3199 if (errnum) *errnum = NOT_DEF;
3200 return llvm::StringRef();
3201 }
3202 if ( field_iter->getNameAsString() == index1->getNameAsString() ) {
3203 break;
3204 }
3205 } // end of while (m_local.Next())
3206 } else {
3207 //NOTE: *** Need to print an error;
3208 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not int \n",
3209 // member.MemberOf()->Name(), member.Name(), current);
3210 if (errstr) *errstr = current;
3211 if (errnum) *errnum = NOT_INT;
3212 return llvm::StringRef();
3213 }
3214 } else {
3215 // There is no variable by this name in this class, let see
3216 // the base classes!:
3217 int found = 0;
3218 if (parent_clxx) {
3219 clang::Sema& SemaR = const_cast<cling::Interpreter&>(interp).getSema();
3220 index1 = GetDataMemberFromAllParents(SemaR, *parent_clxx, current);
3221 }
3222 if ( index1 ) {
3223 if ( IsFieldDeclInt(index1) ) {
3224 found = 1;
3225 } else {
3226 // We found a data member but it is the wrong type
3227 //NOTE: *** Need to print an error;
3228 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not int \n",
3229 // member.MemberOf()->Name(), member.Name(), current);
3230 if (errnum) *errnum = NOT_INT;
3231 if (errstr) *errstr = current;
3232 //NOTE: *** Need to print an error;
3233 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not int \n",
3234 // member.MemberOf()->Name(), member.Name(), current);
3235 if (errnum) *errnum = NOT_INT;
3236 if (errstr) *errstr = current;
3237 return llvm::StringRef();
3238 }
3239 if ( found && (index1->getAccess() == clang::AS_private) ) {
3240 //NOTE: *** Need to print an error;
3241 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is a private member of %s \n",
3242 if (errstr) *errstr = current;
3243 if (errnum) *errnum = IS_PRIVATE;
3244 return llvm::StringRef();
3245 }
3246 }
3247 if (!found) {
3248 //NOTE: *** Need to print an error;
3249 //fprintf(stderr,"*** Datamember %s::%s: size of array (%s) is not known \n",
3250 // member.MemberOf()->Name(), member.Name(), indexvar);
3251 if (errstr) *errstr = indexvar;
3252 if (errnum) *errnum = UNKNOWN;
3253 return llvm::StringRef();
3254 } // end of if not found
3255 } // end of if is a data member of the class
3256 } // end of if isdigit
3257
3258 current = strtok(nullptr, tokenlist);
3259 } // end of while loop on tokens
3260
3261 return indexvar;
3262
3263}
3264
3265////////////////////////////////////////////////////////////////////////////////
3266/// Return (in the argument 'output') a valid name of the C++ symbol/type (pass as 'input')
3267/// that can be used in C++ as a variable name.
3268
3269void ROOT::TMetaUtils::GetCppName(std::string &out, const char *in)
3270{
3271 unsigned int i = 0;
3272 char c;
3273 out.clear();
3274 while((c = in[i++])) {
3275 const char *repl = nullptr;
3276 switch(c) {
3277 case '+': repl = "pL"; break;
3278 case '-': repl = "mI"; break;
3279 case '*': repl = "mU"; break;
3280 case '/': repl = "dI"; break;
3281 case '&': repl = "aN"; break;
3282 case '%': repl = "pE"; break;
3283 case '|': repl = "oR"; break;
3284 case '^': repl = "hA"; break;
3285 case '>': repl = "gR"; break;
3286 case '<': repl = "lE"; break;
3287 case '=': repl = "eQ"; break;
3288 case '~': repl = "wA"; break;
3289 case '.': repl = "dO"; break;
3290 case '(': repl = "oP"; break;
3291 case ')': repl = "cP"; break;
3292 case '[': repl = "oB"; break;
3293 case ']': repl = "cB"; break;
3294 case '{': repl = "lB"; break;
3295 case '}': repl = "rB"; break;
3296 case ';': repl = "sC"; break;
3297 case '#': repl = "hS"; break;
3298 case '?': repl = "qM"; break;
3299 case '`': repl = "bT"; break;
3300 case '!': repl = "nO"; break;
3301 case ',': repl = "cO"; break;
3302 case '$': repl = "dA"; break;
3303 case ' ': repl = "sP"; break;
3304 case ':': repl = "cL"; break;
3305 case '"': repl = "dQ"; break;
3306 case '@': repl = "aT"; break;
3307 case '\'': repl = "sQ"; break;
3308 case '\\': repl = "fI"; break;
3309 }
3310 if (repl)
3311 out.append(repl);
3312 else
3313 out.push_back(c);
3314 }
3315
3316 // Remove initial numbers if any
3317 auto firstNonNumber = out.find_first_not_of("0123456789");
3318 if (firstNonNumber != std::string::npos)
3319 out.replace(0,firstNonNumber,"");
3320}
3321
3322static clang::SourceLocation
3323getFinalSpellingLoc(clang::SourceManager& sourceManager,
3324 clang::SourceLocation sourceLoc) {
3325 // Follow macro expansion until we hit a source file.
3326 if (!sourceLoc.isFileID()) {
3327 return sourceManager.getExpansionRange(sourceLoc).getEnd();
3328 }
3329 return sourceLoc;
3330}
3331
3332////////////////////////////////////////////////////////////////////////////////
3333/// Return the header file to be included to declare the Decl.
3334
3335std::string ROOT::TMetaUtils::GetFileName(const clang::Decl& decl,
3336 const cling::Interpreter& interp)
3337{
3338 // It looks like the template specialization decl actually contains _less_ information
3339 // on the location of the code than the decl (in case where there is forward declaration,
3340 // that is what the specialization points to).
3341 //
3342 // const clang::CXXRecordDecl* clxx = llvm::dyn_cast<clang::CXXRecordDecl>(decl);
3343 // if (clxx) {
3344 // switch(clxx->getTemplateSpecializationKind()) {
3345 // case clang::TSK_Undeclared:
3346 // // We want the default behavior
3347 // break;
3348 // case clang::TSK_ExplicitInstantiationDeclaration:
3349 // case clang::TSK_ExplicitInstantiationDefinition:
3350 // case clang::TSK_ImplicitInstantiation: {
3351 // // We want the location of the template declaration:
3352 // const clang::ClassTemplateSpecializationDecl *tmplt_specialization = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl> (clxx);
3353 // if (tmplt_specialization) {
3354 // // return GetFileName(const_cast< clang::ClassTemplateSpecializationDecl *>(tmplt_specialization)->getSpecializedTemplate());
3355 // }
3356 // break;
3357 // }
3358 // case clang::TSK_ExplicitSpecialization:
3359 // // We want the default behavior
3360 // break;
3361 // default:
3362 // break;
3363 // }
3364 // }
3365
3366 using namespace clang;
3367 SourceLocation headerLoc = decl.getLocation();
3368
3369 static const char invalidFilename[] = "";
3370 if (!headerLoc.isValid()) return invalidFilename;
3371
3372 HeaderSearch& HdrSearch = interp.getCI()->getPreprocessor().getHeaderSearchInfo();
3373
3374 SourceManager& sourceManager = decl.getASTContext().getSourceManager();
3375 headerLoc = getFinalSpellingLoc(sourceManager, headerLoc);
3376 FileID headerFID = sourceManager.getFileID(headerLoc);
3377 SourceLocation includeLoc
3378 = getFinalSpellingLoc(sourceManager,
3379 sourceManager.getIncludeLoc(headerFID));
3380
3381 const FileEntry *headerFE = sourceManager.getFileEntryForID(headerFID);
3382 while (includeLoc.isValid() && sourceManager.isInSystemHeader(includeLoc)) {
3383 ConstSearchDirIterator *foundDir = nullptr;
3384 // use HeaderSearch on the basename, to make sure it takes a header from
3385 // the include path (e.g. not from /usr/include/bits/)
3386 assert(headerFE && "Couldn't find FileEntry from FID!");
3387 auto FEhdr
3388 = HdrSearch.LookupFile(llvm::sys::path::filename(headerFE->getName()),
3389 SourceLocation(),
3390 true /*isAngled*/, nullptr/*FromDir*/, foundDir,
3391 ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>>(),
3392 nullptr/*Searchpath*/, nullptr/*RelPath*/,
3393 nullptr/*SuggestedModule*/, nullptr/*RequestingModule*/,
3394 nullptr/*IsMapped*/, nullptr /*IsFrameworkFound*/,
3395 false /*SkipCache*/,
3396 false /*BuildSystemModule*/,
3397 false /*OpenFile*/, true /*CacheFailures*/);
3398 if (FEhdr) break;
3399 headerFID = sourceManager.getFileID(includeLoc);
3400 headerFE = sourceManager.getFileEntryForID(headerFID);
3401 // If we have a system header in a module we can't just trace back the
3402 // original include with the preprocessor. But it should be enough if
3403 // we trace it back to the top-level system header that includes this
3404 // declaration.
3405 if (interp.getCI()->getLangOpts().Modules && !headerFE) {
3406 assert(decl.isFirstDecl() && "Couldn't trace back include from a decl"
3407 " that is not from an AST file");
3408 assert(StringRef(includeLoc.printToString(sourceManager)).startswith("<module-includes>"));
3409 break;
3410 }
3411 includeLoc = getFinalSpellingLoc(sourceManager,
3412 sourceManager.getIncludeLoc(headerFID));
3413 }
3414
3415 if (!headerFE) return invalidFilename;
3416
3417 llvm::SmallString<256> headerFileName(headerFE->getName());
3418 // Remove double ../ from the path so that the search below finds a valid
3419 // longest match and does not result in growing paths.
3420 llvm::sys::path::remove_dots(headerFileName, /*remove_dot_dot=*/true);
3421
3422 // Now headerFID references the last valid system header or the original
3423 // user file.
3424 // Find out how to include it by matching file name to include paths.
3425 // We assume that the file "/A/B/C/D.h" can at some level be included as
3426 // "C/D.h". Be we cannot know whether that happens to be a different file
3427 // with the same name. Thus we first find the longest stem that can be
3428 // reached, say B/C/D.h. Then we find the shortest one, say C/D.h, that
3429 // points to the same file as the long version. If such a short version
3430 // exists it will be returned. If it doesn't the long version is returned.
3431 bool isAbsolute = llvm::sys::path::is_absolute(headerFileName);
3432 clang::OptionalFileEntryRef FELong;
3433 // Find the longest available match.
3434 for (llvm::sys::path::const_iterator
3435 IDir = llvm::sys::path::begin(headerFileName),
3436 EDir = llvm::sys::path::end(headerFileName);
3437 !FELong && IDir != EDir; ++IDir) {
3438 if (isAbsolute) {
3439 // skip "/" part
3440 isAbsolute = false;
3441 continue;
3442 }
3443 size_t lenTrailing = headerFileName.size() - (IDir->data() - headerFileName.data());
3444 llvm::StringRef trailingPart(IDir->data(), lenTrailing);
3445 assert(trailingPart.data() + trailingPart.size()
3446 == headerFileName.data() + headerFileName.size()
3447 && "Mismatched partitioning of file name!");
3448 ConstSearchDirIterator* FoundDir = nullptr;
3449 FELong = HdrSearch.LookupFile(trailingPart, SourceLocation(),
3450 true /*isAngled*/, nullptr/*FromDir*/, FoundDir,
3451 ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>>(),
3452 nullptr/*Searchpath*/, nullptr/*RelPath*/,
3453 nullptr/*SuggestedModule*/, nullptr/*RequestingModule*/,
3454 nullptr/*IsMapped*/, nullptr /*IsFrameworkFound*/);
3455 }
3456
3457 if (!FELong) {
3458 // We did not find any file part in any search path.
3459 return invalidFilename;
3460 }
3461
3462 // Iterates through path *parts* "C"; we need trailing parts "C/D.h"
3463 for (llvm::sys::path::reverse_iterator
3464 IDir = llvm::sys::path::rbegin(headerFileName),
3465 EDir = llvm::sys::path::rend(headerFileName);
3466 IDir != EDir; ++IDir) {
3467 size_t lenTrailing = headerFileName.size() - (IDir->data() - headerFileName.data());
3468 llvm::StringRef trailingPart(IDir->data(), lenTrailing);
3469 assert(trailingPart.data() + trailingPart.size()
3470 == headerFileName.data() + headerFileName.size()
3471 && "Mismatched partitioning of file name!");
3472 ConstSearchDirIterator* FoundDir = nullptr;
3473 // Can we find it, and is it the same file as the long version?
3474 // (or are we back to the previously found spelling, which is fine, too)
3475 if (HdrSearch.LookupFile(trailingPart, SourceLocation(),
3476 true /*isAngled*/, nullptr/*FromDir*/, FoundDir,
3477 ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>>(),
3478 nullptr/*Searchpath*/, nullptr/*RelPath*/,
3479 nullptr/*SuggestedModule*/, nullptr/*RequestingModule*/,
3480 nullptr/*IsMapped*/, nullptr /*IsFrameworkFound*/) == FELong) {
3481 return trailingPart.str();
3482 }
3483 }
3484
3485 return invalidFilename;
3486}
3487
3488////////////////////////////////////////////////////////////////////////////////
3489
3491 const clang::QualType &qtype,
3492 const clang::ASTContext &astContext)
3493{
3494 std::string fqname = cling::utils::TypeName::GetFullyQualifiedName(qtype, astContext);
3495 TClassEdit::TSplitType splitname(fqname.c_str(),
3498}
3499
3500////////////////////////////////////////////////////////////////////////////////
3501
3503 const clang::QualType &qtype,
3504 const cling::Interpreter &interpreter)
3505{
3506 // We need this because GetFullyQualifiedTypeName is triggering deserialization
3507 // This calling the same name function GetFullyQualifiedTypeName, but this should stay here because
3508 // callee doesn't have an interpreter pointer
3509 cling::Interpreter::PushTransactionRAII RAII(const_cast<cling::Interpreter*>(&interpreter));
3510
3511 GetFullyQualifiedTypeName(typenamestr,
3512 qtype,
3513 interpreter.getCI()->getASTContext());
3514}
3515
3516////////////////////////////////////////////////////////////////////////////////
3517/// Get the template specialisation decl and template decl behind the qualtype
3518/// Returns true if successfully found, false otherwise
3519
3520bool ROOT::TMetaUtils::QualType2Template(const clang::QualType& qt,
3521 clang::ClassTemplateDecl*& ctd,
3522 clang::ClassTemplateSpecializationDecl*& ctsd)
3523{
3524 using namespace clang;
3525 const Type* theType = qt.getTypePtr();
3526 if (!theType){
3527 ctd=nullptr;
3528 ctsd=nullptr;
3529 return false;
3530 }
3531
3532 if (theType->isPointerType()) {
3533 return QualType2Template(theType->getPointeeType(), ctd, ctsd);
3534 }
3535
3536 if (const RecordType* rType = llvm::dyn_cast<RecordType>(theType)) {
3537 ctsd = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(rType->getDecl());
3538 if (ctsd) {
3539 ctd = ctsd->getSpecializedTemplate();
3540 return true;
3541 }
3542 }
3543
3544 if (const SubstTemplateTypeParmType* sttpType = llvm::dyn_cast<SubstTemplateTypeParmType>(theType)){
3545 return QualType2Template(sttpType->getReplacementType(), ctd, ctsd);
3546 }
3547
3548
3549 ctsd = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(qt->getAsCXXRecordDecl());
3550 if(ctsd){
3551 ctd = ctsd->getSpecializedTemplate();
3552 return true;
3553 }
3554
3555 ctd=nullptr;
3556 ctsd=nullptr;
3557 return false;
3558}
3559
3560////////////////////////////////////////////////////////////////////////////////
3561/// Extract from a qualtype the class template if this makes sense.
3562/// Retuns the ClassTemplateDecl or nullptr otherwise.
3563
3564clang::ClassTemplateDecl* ROOT::TMetaUtils::QualType2ClassTemplateDecl(const clang::QualType& qt)
3565{
3566 using namespace clang;
3567 ClassTemplateSpecializationDecl* ctsd;
3568 ClassTemplateDecl* ctd;
3569 QualType2Template(qt,ctd,ctsd);
3570 return ctd;
3571}
3572
3573////////////////////////////////////////////////////////////////////////////////
3574/// These manipulations are necessary because a template specialisation type
3575/// does not inherit from a record type (there is an asymmetry between
3576/// the decls and the types in the clang interface).
3577/// We may need therefore to step into the "Decl dimension" to then get back
3578/// to the "type dimension".
3579
3580clang::TemplateName ROOT::TMetaUtils::ExtractTemplateNameFromQualType(const clang::QualType& qt)
3581{
3582 using namespace clang;
3583 TemplateName theTemplateName;
3584
3585 const Type* theType = qt.getTypePtr();
3586
3587 if (const TemplateSpecializationType* tst = llvm::dyn_cast_or_null<const TemplateSpecializationType>(theType)) {
3588 theTemplateName = tst->getTemplateName();
3589 } // We step into the decl dimension
3590 else if (ClassTemplateDecl* ctd = QualType2ClassTemplateDecl(qt)) {
3591 theTemplateName = TemplateName(ctd);
3592 }
3593
3594 return theTemplateName;
3595}
3596
3597////////////////////////////////////////////////////////////////////////////////
3598
3599static bool areEqualTypes(const clang::TemplateArgument& tArg,
3600 llvm::SmallVectorImpl<clang::TemplateArgument>& preceedingTArgs,
3601 const clang::NamedDecl& tPar,
3602 const cling::Interpreter& interp,
3603 const ROOT::TMetaUtils::TNormalizedCtxt& normCtxt)
3604{
3605 using namespace ROOT::TMetaUtils;
3606 using namespace clang;
3607
3608 // Check if this is a type for security
3609 TemplateTypeParmDecl* ttpdPtr = const_cast<TemplateTypeParmDecl*>(llvm::dyn_cast<TemplateTypeParmDecl>(&tPar));
3610 if (!ttpdPtr) return false;
3611 if (!ttpdPtr->hasDefaultArgument()) return false; // we should not be here in this case, but we protect us.
3612
3613 // Try the fast solution
3614 QualType tParQualType = ttpdPtr->getDefaultArgument();
3615 const QualType tArgQualType = tArg.getAsType();
3616
3617 // Now the equality tests for non template specialisations.
3618
3619 // The easy cases:
3620 // template <class T=double> class A; or
3621 // template <class T=A<float>> class B;
3622 if (tParQualType.getTypePtr() == tArgQualType.getTypePtr()) return true;
3623
3624 // Here the difficulty comes. We have to check if the argument is equal to its
3625 // default. We can do that bootstrapping an argument which has the default value
3626 // based on the preceeding arguments.
3627 // Basically we ask sema to give us the value of the argument given the template
3628 // of behind the parameter and the all the arguments.
3629 // So:
3630
3631 // Take the template out of the parameter
3632
3633 const clang::ElaboratedType* etype
3634 = llvm::dyn_cast<clang::ElaboratedType>(tParQualType.getTypePtr());
3635 while (etype) {
3636 tParQualType = clang::QualType(etype->getNamedType().getTypePtr(),0);
3637 etype = llvm::dyn_cast<clang::ElaboratedType>(tParQualType.getTypePtr());
3638 }
3639
3640 const TemplateSpecializationType* tst =
3641 llvm::dyn_cast<TemplateSpecializationType>(tParQualType.getTypePtr());
3642
3643 if(!tst) // nothing more to be tried. They are different indeed.
3644 return false;
3645
3646 ClassTemplateSpecializationDecl* TSTdecl
3647 = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(tArgQualType->getAsCXXRecordDecl());
3648
3649 if(!TSTdecl) // nothing more to be tried. They are different indeed.
3650 return false;
3651
3652 TemplateDecl *Template = tst->getTemplateName().getAsTemplateDecl();
3653
3654 // Take the template location
3655 SourceLocation TemplateLoc = Template->getSourceRange ().getBegin();
3656
3657 // Get the position of the "<" (LA) of the specializaion
3658 SourceLocation LAngleLoc = TSTdecl->getSourceRange().getBegin();
3659
3660
3661 // Enclose in a scope for the RAII
3662 bool isEqual=false;
3663 TemplateArgument newArg = tArg;
3664 {
3665 clang::Sema& S = interp.getCI()->getSema();
3666 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interp));
3667 llvm::SmallVector<clang::TemplateArgument, 4> canonArgs;
3668 bool HasDefaultArgs;
3669 TemplateArgumentLoc defTArgLoc = S.SubstDefaultTemplateArgumentIfAvailable(Template,
3670 TemplateLoc,
3671 LAngleLoc,
3672 ttpdPtr,
3673 preceedingTArgs,
3674 canonArgs,
3675 HasDefaultArgs);
3676 // The substition can fail, in which case there would have been compilation
3677 // error printed on the screen.
3678 newArg = defTArgLoc.getArgument();
3679 if (newArg.isNull() ||
3680 newArg.getKind() != clang::TemplateArgument::Type) {
3681 ROOT::TMetaUtils::Error("areEqualTypes",
3682 "Template parameter substitution failed!");
3683 }
3684
3685 ClassTemplateSpecializationDecl* nTSTdecl
3686 = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(newArg.getAsType()->getAsCXXRecordDecl());
3687// std::cout << "nSTdecl is " << nTSTdecl << std::endl;
3688
3689 isEqual = (nTSTdecl && nTSTdecl->getMostRecentDecl() == TSTdecl->getMostRecentDecl()) ||
3690 (tParQualType.getTypePtr() == newArg.getAsType().getTypePtr());
3691 }
3692
3693
3694 return isEqual;
3695}
3696
3697
3698////////////////////////////////////////////////////////////////////////////////
3699/// std::cout << "Are equal values?\n";
3700
3701static bool areEqualValues(const clang::TemplateArgument& tArg,
3702 const clang::NamedDecl& tPar)
3703{
3704 using namespace clang;
3705 const NonTypeTemplateParmDecl* nttpdPtr = llvm::dyn_cast<NonTypeTemplateParmDecl>(&tPar);
3706 if (!nttpdPtr) return false;
3707 const NonTypeTemplateParmDecl& nttpd = *nttpdPtr;
3708
3709 if (!nttpd.hasDefaultArgument())
3710 return false;
3711
3712 // 64 bits wide and signed (non unsigned, that is why "false")
3713 llvm::APSInt defaultValueAPSInt(64, false);
3714 if (Expr* defArgExpr = nttpd.getDefaultArgument()) {
3715 const ASTContext& astCtxt = nttpdPtr->getASTContext();
3716 if (auto Value = defArgExpr->getIntegerConstantExpr(astCtxt))
3717 defaultValueAPSInt = *Value;
3718 }
3719
3720 const int value = tArg.getAsIntegral().getLimitedValue();
3721
3722 // std::cout << (value == defaultValueAPSInt ? "yes!":"no") << std::endl;
3723 return value == defaultValueAPSInt;
3724}
3725
3726////////////////////////////////////////////////////////////////////////////////
3727/// Check if this NamedDecl is a template parameter with a default argument.
3728/// This is a single interface to treat both integral and type parameters.
3729/// Returns true if this is the case, false otherwise
3730
3731static bool isTypeWithDefault(const clang::NamedDecl* nDecl)
3732{
3733 using namespace clang;
3734 if (!nDecl) return false;
3735 if (const TemplateTypeParmDecl* ttpd = llvm::dyn_cast<TemplateTypeParmDecl>(nDecl))
3736 return ttpd->hasDefaultArgument();
3737 if (const NonTypeTemplateParmDecl* nttpd = llvm::dyn_cast<NonTypeTemplateParmDecl>(nDecl))
3738 return nttpd->hasDefaultArgument();
3739 return false;
3740
3741}
3742
3743static void KeepNParams(clang::QualType& normalizedType,
3744 const clang::QualType& vanillaType,
3745 const cling::Interpreter& interp,
3746 const ROOT::TMetaUtils::TNormalizedCtxt& normCtxt);
3747
3748// Returns true if normTArg might have changed.
3749static bool RecurseKeepNParams(clang::TemplateArgument &normTArg,
3750 const clang::TemplateArgument &tArg,
3751 const cling::Interpreter& interp,
3752 const ROOT::TMetaUtils::TNormalizedCtxt& normCtxt,
3753 const clang::ASTContext& astCtxt)
3754{
3755 using namespace ROOT::TMetaUtils;
3756 using namespace clang;
3757
3758 // Once we know there is no more default parameter, we can run through to the end
3759 // and/or recurse in the template parameter packs.
3760
3761 // If this is a type,
3762 // we need first of all to recurse: this argument may need to be manipulated
3763 if (tArg.getKind() == clang::TemplateArgument::Type) {
3764 QualType thisNormQualType = normTArg.getAsType();
3765 QualType thisArgQualType = tArg.getAsType();
3766 KeepNParams(thisNormQualType,
3767 thisArgQualType,
3768 interp,
3769 normCtxt);
3770 normTArg = TemplateArgument(thisNormQualType);
3771 return (thisNormQualType != thisArgQualType);
3772 } else if (normTArg.getKind() == clang::TemplateArgument::Pack) {
3773 assert( tArg.getKind() == clang::TemplateArgument::Pack );
3774
3775 SmallVector<TemplateArgument, 2> desArgs;
3776 bool mightHaveChanged = true;
3777 for (auto I = normTArg.pack_begin(), E = normTArg.pack_end(),
3778 FI = tArg.pack_begin(), FE = tArg.pack_end();
3779 I != E && FI != FE; ++I, ++FI)
3780 {
3781 TemplateArgument pack_arg(*I);
3782 mightHaveChanged |= RecurseKeepNParams(pack_arg, *FI, interp, normCtxt, astCtxt);
3783 desArgs.push_back(pack_arg);
3784 }
3785 if (mightHaveChanged) {
3786 ASTContext &mutableCtx( const_cast<ASTContext&>(astCtxt) );
3787 normTArg = TemplateArgument::CreatePackCopy(mutableCtx, desArgs);
3788 }
3789 return mightHaveChanged;
3790 }
3791 return false;
3792}
3793
3794
3795////////////////////////////////////////////////////////////////////////////////
3796/// This function allows to manipulate the number of arguments in the type
3797/// of a template specialisation.
3798
3799static void KeepNParams(clang::QualType& normalizedType,
3800 const clang::QualType& vanillaType,
3801 const cling::Interpreter& interp,
3802 const ROOT::TMetaUtils::TNormalizedCtxt& normCtxt)
3803{
3804 using namespace ROOT::TMetaUtils;
3805 using namespace clang;
3806
3807 // If this type has no template specialisation behind, we don't need to do
3808 // anything
3809 ClassTemplateSpecializationDecl* ctsd;
3810 ClassTemplateDecl* ctd;
3811 if (! QualType2Template(vanillaType, ctd, ctsd)) return ;
3812
3813 // Even if this is a template, if we don't keep any argument, return
3814 const int nArgsToKeep = normCtxt.GetNargsToKeep(ctd);
3815
3816 // Important in case of early return: we must restore the original qualtype
3817 QualType originalNormalizedType = normalizedType;
3818
3819 const ASTContext& astCtxt = ctsd->getASTContext();
3820
3821
3822 // In case of name* we need to strip the pointer first, add the default and attach
3823 // the pointer once again.
3824 if (llvm::isa<clang::PointerType>(normalizedType.getTypePtr())) {
3825 // Get the qualifiers.
3826 clang::Qualifiers quals = normalizedType.getQualifiers();
3827 auto valNormalizedType = normalizedType->getPointeeType();
3828 KeepNParams(valNormalizedType,vanillaType, interp, normCtxt);
3829 normalizedType = astCtxt.getPointerType(valNormalizedType);
3830 // Add back the qualifiers.
3831 normalizedType = astCtxt.getQualifiedType(normalizedType, quals);
3832 return;
3833 }
3834
3835 // In case of Int_t& we need to strip the pointer first, desugar and attach
3836 // the pointer once again.
3837 if (llvm::isa<clang::ReferenceType>(normalizedType.getTypePtr())) {
3838 // Get the qualifiers.
3839 bool isLValueRefTy = llvm::isa<clang::LValueReferenceType>(normalizedType.getTypePtr());
3840 clang::Qualifiers quals = normalizedType.getQualifiers();
3841 auto valNormType = normalizedType->getPointeeType();
3842 KeepNParams(valNormType, vanillaType, interp, normCtxt);
3843
3844 // Add the r- or l- value reference type back to the desugared one
3845 if (isLValueRefTy)
3846 normalizedType = astCtxt.getLValueReferenceType(valNormType);
3847 else
3848 normalizedType = astCtxt.getRValueReferenceType(valNormType);
3849 // Add back the qualifiers.
3850 normalizedType = astCtxt.getQualifiedType(normalizedType, quals);
3851 return;
3852 }
3853
3854 // Treat the Scope (factorise the code out to reuse it in AddDefaultParameters)
3855 bool prefix_changed = false;
3856 clang::NestedNameSpecifier* prefix = nullptr;
3857 clang::Qualifiers prefix_qualifiers = normalizedType.getLocalQualifiers();
3858 const clang::ElaboratedType* etype
3859 = llvm::dyn_cast<clang::ElaboratedType>(normalizedType.getTypePtr());
3860 if (etype) {
3861 // We have to also handle the prefix.
3862 // TODO: we ought to be running KeepNParams
3863 prefix = AddDefaultParametersNNS(astCtxt, etype->getQualifier(), interp, normCtxt);
3864 prefix_changed = prefix != etype->getQualifier();
3865 normalizedType = clang::QualType(etype->getNamedType().getTypePtr(),0);
3866 }
3867
3868 // The canonical decl does not necessarily have the template default arguments.
3869 // Need to walk through the redecl chain to find it (we know there will be no
3870 // inconsistencies, at least)
3871 const clang::ClassTemplateDecl* ctdWithDefaultArgs = ctd;
3872 for (const RedeclarableTemplateDecl* rd: ctdWithDefaultArgs->redecls()) {
3873 clang::TemplateParameterList* tpl = rd->getTemplateParameters();
3874 if (tpl->getMinRequiredArguments () < tpl->size()) {
3875 ctdWithDefaultArgs = llvm::dyn_cast<clang::ClassTemplateDecl>(rd);
3876 break;
3877 }
3878 }
3879
3880 if (!ctdWithDefaultArgs) {
3881 Error("KeepNParams", "Not found template default arguments\n");
3882 normalizedType=originalNormalizedType;
3883 return;
3884 }
3885
3886 TemplateParameterList* tParsPtr = ctdWithDefaultArgs->getTemplateParameters();
3887 const TemplateParameterList& tPars = *tParsPtr;
3888 const TemplateArgumentList& tArgs = ctsd->getTemplateArgs();
3889
3890 // We extract the template name from the type
3891 TemplateName theTemplateName = ExtractTemplateNameFromQualType(normalizedType);
3892 if (theTemplateName.isNull()) {
3893 normalizedType=originalNormalizedType;
3894 return;
3895 }
3896
3897 const TemplateSpecializationType* normalizedTst =
3898 llvm::dyn_cast<TemplateSpecializationType>(normalizedType.getTypePtr());
3899 if (!normalizedTst) {
3900 normalizedType=originalNormalizedType;
3901 return;
3902 }
3903
3904 const clang::ClassTemplateSpecializationDecl* TSTdecl
3905 = llvm::dyn_cast_or_null<const clang::ClassTemplateSpecializationDecl>(normalizedType.getTypePtr()->getAsCXXRecordDecl());
3906 bool isStdDropDefault = TSTdecl && IsStdDropDefaultClass(*TSTdecl);
3907
3908 // Loop over the template parameters and arguments recursively.
3909 // We go down the two lanes: the one of template parameters (decls) and the
3910 // one of template arguments (QualTypes) in parallel. The former are a
3911 // property of the template, independent of its instantiations.
3912 // The latter are a property of the instance itself.
3913 llvm::SmallVector<TemplateArgument, 4> argsToKeep;
3914
3915 const int nArgs = tArgs.size();
3916 const auto &normArgs = normalizedTst->template_arguments();
3917 const int nNormArgs = normArgs.size();
3918
3919 bool mightHaveChanged = false;
3920
3921 // becomes true when a parameter has a value equal to its default
3922 for (int formal = 0, inst = 0; formal != nArgs; ++formal, ++inst) {
3923 const NamedDecl* tParPtr = tPars.getParam(formal);
3924 if (!tParPtr) {
3925 Error("KeepNParams", "The parameter number %s is null.\n", formal);
3926 continue;
3927 }
3928
3929 // Stop if the normalized TemplateSpecializationType has less arguments than
3930 // the one index is pointing at.
3931 // We piggy back on the AddDefaultParameters routine basically.
3932 if (formal == nNormArgs || inst == nNormArgs) break;
3933
3934 const TemplateArgument& tArg = tArgs.get(formal);
3935 TemplateArgument normTArg(normArgs[inst]);
3936
3937 bool shouldKeepArg = nArgsToKeep < 0 || inst < nArgsToKeep;
3938 if (isStdDropDefault) shouldKeepArg = false;
3939
3940 // Nothing to do here: either this parameter has no default, or we have to keep it.
3941 // FIXME: Temporary measure to get Atlas started with this.
3942 // We put a hard cut on the number of template arguments to keep, w/o checking if
3943 // they are non default. This makes this feature UNUSABLE for cases like std::vector,
3944 // where 2 different entities would have the same name if an allocator different from
3945 // the default one is by chance used.
3946 if (!isTypeWithDefault(tParPtr) || shouldKeepArg) {
3947 if ( tParPtr->isTemplateParameterPack() ) {
3948 // This is the last template parameter in the template declaration
3949 // but it is signaling that there can be an arbitrary number of arguments
3950 // in the template instance. So to avoid inadvertenly dropping those
3951 // arguments we just process all remaining argument and exit the main loop.
3952 for( ; inst != nNormArgs; ++inst) {
3953 normTArg = normArgs[inst];
3954 mightHaveChanged |= RecurseKeepNParams(normTArg, tArg, interp, normCtxt, astCtxt);
3955 argsToKeep.push_back(normTArg);
3956 }
3957 // Done.
3958 break;
3959 }
3960 mightHaveChanged |= RecurseKeepNParams(normTArg, tArg, interp, normCtxt, astCtxt);
3961 argsToKeep.push_back(normTArg);
3962 continue;
3963 } else {
3964 if (!isStdDropDefault) {
3965 // Here we should not break but rather check if the value is the default one.
3966 mightHaveChanged = true;
3967 break;
3968 }
3969 // For std, we want to check the default args values.
3970 }
3971
3972 // Now, we keep it only if it not is equal to its default, expressed in the arg
3973 // Some gymnastic is needed to decide how to check for equality according to the
3974 // flavour of Type: templateType or Integer
3975 bool equal=false;
3976 auto argKind = tArg.getKind();
3977 if (argKind == clang::TemplateArgument::Type){
3978 // we need all the info
3979 equal = areEqualTypes(tArg, argsToKeep, *tParPtr, interp, normCtxt);
3980 } else if (argKind == clang::TemplateArgument::Integral){
3981 equal = areEqualValues(tArg, *tParPtr);
3982 }
3983 if (!equal) {
3984 mightHaveChanged |= RecurseKeepNParams(normTArg, tArg, interp, normCtxt, astCtxt);
3985 argsToKeep.push_back(normTArg);
3986 } else {
3987 mightHaveChanged = true;
3988 }
3989
3990
3991 } // of loop over parameters and arguments
3992
3993 if (!prefix_changed && !mightHaveChanged) {
3994 normalizedType = originalNormalizedType;
3995 return;
3996 }
3997
3998 // now, let's remanipulate our Qualtype
3999 if (mightHaveChanged) {
4000 Qualifiers qualifiers = normalizedType.getLocalQualifiers();
4001 normalizedType = astCtxt.getTemplateSpecializationType(theTemplateName,
4002 argsToKeep,
4003 normalizedType.getTypePtr()->getCanonicalTypeInternal());
4004 normalizedType = astCtxt.getQualifiedType(normalizedType, qualifiers);
4005 }
4006
4007 // Here we have (prefix_changed==true || mightHaveChanged), in both case
4008 // we need to reconstruct the type.
4009 if (prefix) {
4010 normalizedType = astCtxt.getElaboratedType(clang::ETK_None,prefix,normalizedType);
4011 normalizedType = astCtxt.getQualifiedType(normalizedType,prefix_qualifiers);
4012 }
4013
4014}
4015
4016////////////////////////////////////////////////////////////////////////////////
4017/// Return the type normalized for ROOT,
4018/// keeping only the ROOT opaque typedef (Double32_t, etc.) and
4019/// adding default template argument for all types except those explicitly
4020/// requested to be drop by the user.
4021/// Default template for STL collections are not yet removed by this routine.
4022
4023clang::QualType ROOT::TMetaUtils::GetNormalizedType(const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
4024{
4025 clang::ASTContext &ctxt = interpreter.getCI()->getASTContext();
4026
4027 // Modules can trigger deserialization.
4028 cling::Interpreter::PushTransactionRAII RAII(const_cast<cling::Interpreter*>(&interpreter));
4029 clang::QualType normalizedType = cling::utils::Transform::GetPartiallyDesugaredType(ctxt, type, normCtxt.GetConfig(), true /* fully qualify */);
4030
4031 // Readd missing default template parameters
4032 normalizedType = ROOT::TMetaUtils::AddDefaultParameters(normalizedType, interpreter, normCtxt);
4033
4034 // Get the number of arguments to keep in case they are not default.
4035 KeepNParams(normalizedType,type,interpreter,normCtxt);
4036
4037 return normalizedType;
4038}
4039
4040////////////////////////////////////////////////////////////////////////////////
4041/// Return the type name normalized for ROOT,
4042/// keeping only the ROOT opaque typedef (Double32_t, etc.) and
4043/// adding default template argument for all types except the STL collections
4044/// where we remove the default template argument if any.
4045///
4046/// This routine might actually belong in the interpreter because
4047/// cache the clang::Type might be intepreter specific.
4048
4049void ROOT::TMetaUtils::GetNormalizedName(std::string &norm_name, const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
4050{
4051 if (type.isNull()) {
4052 norm_name = "";
4053 return;
4054 }
4055
4056 clang::QualType normalizedType = GetNormalizedType(type,interpreter,normCtxt);
4057
4058 clang::ASTContext &ctxt = interpreter.getCI()->getASTContext();
4059 clang::PrintingPolicy policy(ctxt.getPrintingPolicy());
4060 policy.SuppressTagKeyword = true; // Never get the class or struct keyword
4061 policy.SuppressScope = true; // Force the scope to be coming from a clang::ElaboratedType.
4062 policy.AnonymousTagLocations = false; // Do not extract file name + line number for anonymous types.
4063 // The scope suppression is required for getting rid of the anonymous part of the name of a class defined in an anonymous namespace.
4064 // This gives us more control vs not using the clang::ElaboratedType and relying on the Policy.SuppressUnwrittenScope which would
4065 // strip both the anonymous and the inline namespace names (and we probably do not want the later to be suppressed).
4066
4067 std::string normalizedNameStep1;
4068
4069 // getAsStringInternal can trigger deserialization
4070 cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interpreter));
4071 normalizedType.getAsStringInternal(normalizedNameStep1,policy);
4072
4073 // Still remove the std:: and default template argument for STL container and
4074 // normalize the location and amount of white spaces.
4077
4078 // The result of this routine is by definition a fully qualified name. There is an implicit starting '::' at the beginning of the name.
4079 // Depending on how the user typed their code, in particular typedef declarations, we may end up with an explicit '::' being
4080 // part of the result string. For consistency, we must remove it.
4081 if (norm_name.length()>2 && norm_name[0]==':' && norm_name[1]==':') {
4082 norm_name.erase(0,2);
4083 }
4084
4085}
4086
4087////////////////////////////////////////////////////////////////////////////////
4088
4089void ROOT::TMetaUtils::GetNormalizedName(std::string &norm_name,
4090 const clang::TypeDecl* typeDecl,
4091 const cling::Interpreter &interpreter)
4092{
4093 ROOT::TMetaUtils::TNormalizedCtxt tNormCtxt(interpreter.getLookupHelper());
4094 const clang::Sema &sema = interpreter.getSema();
4095 clang::ASTContext& astCtxt = sema.getASTContext();
4096 clang::QualType qualType = astCtxt.getTypeDeclType(typeDecl);
4097
4099 qualType,
4100 interpreter,
4101 tNormCtxt);
4102}
4103
4104////////////////////////////////////////////////////////////////////////////////
4105std::pair<std::string,clang::QualType>
4106ROOT::TMetaUtils::GetNameTypeForIO(const clang::QualType& thisType,
4107 const cling::Interpreter &interpreter,
4108 const TNormalizedCtxt &normCtxt,
4110{
4111 std::string thisTypeName;
4112 GetNormalizedName(thisTypeName, thisType, interpreter, normCtxt );
4113 bool hasChanged;
4114 auto thisTypeNameForIO = TClassEdit::GetNameForIO(thisTypeName, mode, &hasChanged);
4115 if (!hasChanged) return std::make_pair(thisTypeName,thisType);
4116
4118 ROOT::TMetaUtils::Info("ROOT::TMetaUtils::GetTypeForIO",
4119 "Name changed from %s to %s\n", thisTypeName.c_str(), thisTypeNameForIO.c_str());
4120 }
4121
4122 auto& lookupHelper = interpreter.getLookupHelper();
4123
4124 const clang::Type* typePtrForIO;
4125 lookupHelper.findScope(thisTypeNameForIO,
4126 cling::LookupHelper::DiagSetting::NoDiagnostics,
4127 &typePtrForIO);
4128
4129 // This should never happen
4130 if (!typePtrForIO) {
4131 ROOT::TMetaUtils::Fatal("ROOT::TMetaUtils::GetTypeForIO",
4132 "Type not found: %s.",thisTypeNameForIO.c_str());
4133 }
4134
4135 clang::QualType typeForIO(typePtrForIO,0);
4136
4137 // Check if this is a class. Indeed it could well be a POD
4138 if (!typeForIO->isRecordType()) {
4139 return std::make_pair(thisTypeNameForIO,typeForIO);
4140 }
4141
4142 auto thisDeclForIO = typeForIO->getAsCXXRecordDecl();
4143 if (!thisDeclForIO) {
4144 ROOT::TMetaUtils::Error("ROOT::TMetaUtils::GetTypeForIO",
4145 "The type for IO corresponding to %s is %s and it could not be found in the AST as class.\n", thisTypeName.c_str(), thisTypeNameForIO.c_str());
4146 return std::make_pair(thisTypeName,thisType);
4147 }
4148
4149 return std::make_pair(thisTypeNameForIO,typeForIO);
4150}
4151
4152////////////////////////////////////////////////////////////////////////////////
4153
4154clang::QualType ROOT::TMetaUtils::GetTypeForIO(const clang::QualType& thisType,
4155 const cling::Interpreter &interpreter,
4156 const TNormalizedCtxt &normCtxt,
4158{
4159 return GetNameTypeForIO(thisType, interpreter, normCtxt, mode).second;
4160}
4161
4162////////////////////////////////////////////////////////////////////////////////
4163/// Return the dictionary file name for a module
4164
4165std::string ROOT::TMetaUtils::GetModuleFileName(const char* moduleName)
4166{
4167 std::string dictFileName(moduleName);
4168 dictFileName += "_rdict.pcm";
4169 return dictFileName;
4170}
4171
4172int dumpDeclForAssert(const clang::Decl& D, const char* commentStart) {
4173 llvm::errs() << llvm::StringRef(commentStart, 80) << '\n';
4174 D.dump();
4175 return 0;
4176}
4177
4178////////////////////////////////////////////////////////////////////////////////
4179/// Returns the comment (// striped away), annotating declaration in a meaningful
4180/// for ROOT IO way.
4181/// Takes optional out parameter clang::SourceLocation returning the source
4182/// location of the comment.
4183///
4184/// CXXMethodDecls, FieldDecls and TagDecls are annotated.
4185/// CXXMethodDecls declarations and FieldDecls are annotated as follows:
4186/// Eg. void f(); // comment1
4187/// int member; // comment2
4188/// Inline definitions of CXXMethodDecls after the closing } \n. Eg:
4189/// void f()
4190/// {...} // comment3
4191/// TagDecls are annotated in the end of the ClassDef macro. Eg.
4192/// class MyClass {
4193/// ...
4194/// ClassDef(MyClass, 1) // comment4
4195///
4196
4197llvm::StringRef ROOT::TMetaUtils::GetComment(const clang::Decl &decl, clang::SourceLocation *loc)
4198{
4199 clang::SourceManager& sourceManager = decl.getASTContext().getSourceManager();
4200 clang::SourceLocation sourceLocation = decl.getEndLoc();
4201
4202 // If the location is a macro get the expansion location.
4203 sourceLocation = sourceManager.getExpansionRange(sourceLocation).getEnd();
4204 // FIXME: We should optimize this routine instead making it do the wrong thing
4205 // returning an empty comment if the decl came from the AST.
4206 // In order to do that we need to: check if the decl has an attribute and
4207 // return the attribute content (including walking the redecl chain) and if
4208 // this is not the case we should try finding it in the header file.
4209 // This will allow us to move the implementation of TCling*Info::Title() in
4210 // TClingDeclInfo.
4211 if (!decl.hasOwningModule() && sourceManager.isLoadedSourceLocation(sourceLocation)) {
4212 // Do not touch disk for nodes coming from the PCH.
4213 return "";
4214 }
4215
4216 bool invalid;
4217 const char *commentStart = sourceManager.getCharacterData(sourceLocation, &invalid);
4218 if (invalid)
4219 return "";
4220
4221 bool skipToSemi = true;
4222 if (const clang::FunctionDecl* FD = clang::dyn_cast<clang::FunctionDecl>(&decl)) {
4223 if (FD->isImplicit()) {
4224 // Compiler generated function.
4225 return "";
4226 }
4227 if (FD->isExplicitlyDefaulted() || FD->isDeletedAsWritten()) {
4228 // ctorOrFunc() = xyz; with commentStart pointing somewhere into
4229 // ctorOrFunc.
4230 // We have to skipToSemi
4231 } else if (FD->doesThisDeclarationHaveABody()) {
4232 // commentStart is at body's '}'
4233 // But we might end up e.g. at the ')' of a CPP macro
4234 assert((decl.getEndLoc() != sourceLocation || *commentStart == '}'
4235 || dumpDeclForAssert(*FD, commentStart))
4236 && "Expected macro or end of body at '}'");
4237 if (*commentStart) ++commentStart;
4238
4239 // We might still have a ';'; skip the spaces and check.
4240 while (*commentStart && isspace(*commentStart)
4241 && *commentStart != '\n' && *commentStart != '\r') {
4242 ++commentStart;
4243 }
4244 if (*commentStart == ';') ++commentStart;
4245
4246 skipToSemi = false;
4247 }
4248 } else if (const clang::EnumConstantDecl* ECD
4249 = clang::dyn_cast<clang::EnumConstantDecl>(&decl)) {
4250 // either "konstant = 12, //COMMENT" or "lastkonstant // COMMENT"
4251 if (ECD->getNextDeclInContext())
4252 while (*commentStart && *commentStart != ',' && *commentStart != '\r' && *commentStart != '\n')
4253 ++commentStart;
4254 // else commentStart already points to the end.
4255
4256 skipToSemi = false;
4257 }
4258
4259 if (skipToSemi) {
4260 while (*commentStart && *commentStart != ';' && *commentStart != '\r' && *commentStart != '\n')
4261 ++commentStart;
4262 if (*commentStart == ';') ++commentStart;
4263 }
4264
4265 // Now skip the spaces until beginning of comments or EOL.
4266 while ( *commentStart && isspace(*commentStart)
4267 && *commentStart != '\n' && *commentStart != '\r') {
4268 ++commentStart;
4269 }
4270
4271 if (commentStart[0] != '/' ||
4272 (commentStart[1] != '/' && commentStart[1] != '*')) {
4273 // not a comment
4274 return "";
4275 }
4276
4277 // Treat by default c++ comments (+2) but also Doxygen comments (+4)
4278 // Int_t fPx; ///< Some doxygen comment for persistent data.
4279 // Int_t fPy; //!< Some doxygen comment for persistent data.
4280 // Int_t fPz; /*!< Some doxygen comment for persistent data. */
4281 // Int_t fPa; /**< Some doxygen comment for persistent data. */
4282 unsigned int skipChars = 2;
4283 if (commentStart[0] == '/' &&
4284 commentStart[1] == '/' &&
4285 (commentStart[2] == '/' || commentStart[2] == '!') &&
4286 commentStart[3] == '<') {
4287 skipChars = 4;
4288 } else if (commentStart[0] == '/' &&
4289 commentStart[1] == '*' &&
4290 (commentStart[2] == '*' || commentStart[2] == '!') &&
4291 commentStart[3] == '<') {
4292 skipChars = 4;
4293 }
4294
4295 commentStart += skipChars;
4296
4297 // Now skip the spaces after comment start until EOL.
4298 while ( *commentStart && isspace(*commentStart)
4299 && *commentStart != '\n' && *commentStart != '\r') {
4300 ++commentStart;
4301 }
4302 const char* commentEnd = commentStart;
4303 // Even for /* comments we only take the first line into account.
4304 while (*commentEnd && *commentEnd != '\n' && *commentEnd != '\r') {
4305 ++commentEnd;
4306 }
4307
4308 // "Skip" (don't include) trailing space.
4309 // *commentEnd points behind comment end thus check commentEnd[-1]
4310 while (commentEnd > commentStart && isspace(commentEnd[-1])) {
4311 --commentEnd;
4312 }
4313
4314 if (loc) {
4315 // Find the true beginning of a comment.
4316 unsigned offset = commentStart - sourceManager.getCharacterData(sourceLocation);
4317 *loc = sourceLocation.getLocWithOffset(offset - 1);
4318 }
4319
4320 return llvm::StringRef(commentStart, commentEnd - commentStart);
4321}
4322
4323////////////////////////////////////////////////////////////////////////////////
4324/// Return true if class has any of class declarations like ClassDef, ClassDefNV, ClassDefOverride
4325
4326bool ROOT::TMetaUtils::HasClassDefMacro(const clang::Decl *decl, const cling::Interpreter &interpreter)
4327{
4328 if (!decl) return false;
4329
4330 auto& sema = interpreter.getCI()->getSema();
4331 auto maybeMacroLoc = decl->getLocation();
4332
4333 if (!maybeMacroLoc.isMacroID()) return false;
4334
4335 static const std::vector<std::string> signatures =
4336 { "ClassDef", "ClassDefOverride", "ClassDefNV", "ClassDefInline", "ClassDefInlineOverride", "ClassDefInlineNV" };
4337
4338 for (auto &name : signatures)
4339 if (sema.findMacroSpelling(maybeMacroLoc, name))
4340 return true;
4341
4342 return false;
4343}
4344
4345////////////////////////////////////////////////////////////////////////////////
4346/// Return the class comment after the ClassDef:
4347/// class MyClass {
4348/// ...
4349/// ClassDef(MyClass, 1) // class comment
4350///
4351
4352llvm::StringRef ROOT::TMetaUtils::GetClassComment(const clang::CXXRecordDecl &decl,
4353 clang::SourceLocation *loc,
4354 const cling::Interpreter &interpreter)
4355{
4356 using namespace clang;
4357
4358 const Decl* DeclFileLineDecl
4359 = interpreter.getLookupHelper().findFunctionProto(&decl, "DeclFileLine", "",
4360 cling::LookupHelper::NoDiagnostics);
4361
4362 // For now we allow only a special macro (ClassDef) to have meaningful comments
4363 if (HasClassDefMacro(DeclFileLineDecl, interpreter)) {
4364 SourceLocation commentSLoc;
4365 llvm::StringRef comment = ROOT::TMetaUtils::GetComment(*DeclFileLineDecl, &commentSLoc);
4366 if (comment.size()) {
4367 if (loc) {
4368 *loc = commentSLoc;
4369 }
4370 return comment;
4371 }
4372 }
4373 return llvm::StringRef();
4374}
4375
4376////////////////////////////////////////////////////////////////////////////////
4377/// Return the base/underlying type of a chain of array or pointers type.
4378/// Does not yet support the array and pointer part being intermixed.
4379
4380const clang::Type *ROOT::TMetaUtils::GetUnderlyingType(clang::QualType type)
4381{
4382 const clang::Type *rawtype = type.getTypePtr();
4383
4384 // NOTE: We probably meant isa<clang::ElaboratedType>
4385 if (rawtype->isElaboratedTypeSpecifier() ) {
4386 rawtype = rawtype->getCanonicalTypeInternal().getTypePtr();
4387 }
4388 if (rawtype->isArrayType()) {
4389 rawtype = type.getTypePtr()->getBaseElementTypeUnsafe ();
4390 }
4391 if (rawtype->isPointerType() || rawtype->isReferenceType() ) {
4392 //Get to the 'raw' type.
4393 clang::QualType pointee;
4394 while ( (pointee = rawtype->getPointeeType()) , pointee.getTypePtrOrNull() && pointee.getTypePtr() != rawtype)
4395 {
4396 rawtype = pointee.getTypePtr();
4397
4398 if (rawtype->isElaboratedTypeSpecifier() ) {
4399 rawtype = rawtype->getCanonicalTypeInternal().getTypePtr();
4400 }
4401 if (rawtype->isArrayType()) {
4402 rawtype = rawtype->getBaseElementTypeUnsafe ();
4403 }
4404 }
4405 }
4406 if (rawtype->isArrayType()) {
4407 rawtype = rawtype->getBaseElementTypeUnsafe ();
4408 }
4409 return rawtype;
4410}
4411
4412////////////////////////////////////////////////////////////////////////////////
4413/// Return true, if the decl is part of the std namespace.
4414
4415bool ROOT::TMetaUtils::IsStdClass(const clang::RecordDecl &cl)
4416{
4417 return cling::utils::Analyze::IsStdClass(cl);
4418}
4419
4420////////////////////////////////////////////////////////////////////////////////
4421/// Return true, if the decl is part of the std namespace and we want
4422/// its default parameter dropped.
4423
4424bool ROOT::TMetaUtils::IsStdDropDefaultClass(const clang::RecordDecl &cl)
4425{
4426 // Might need to reduce it to shared_ptr and STL collection.s
4427 if (cling::utils::Analyze::IsStdClass(cl)) {
4428 static const char *names[] =
4429 { "shared_ptr", "__shared_ptr",
4430 "vector", "list", "deque", "map", "multimap", "set", "multiset", "bitset"};
4431 llvm::StringRef clname(cl.getName());
4432 for(auto &&name : names) {
4433 if (clname == name) return true;
4434 }
4435 }
4436 return false;
4437}
4438
4439////////////////////////////////////////////////////////////////////////////////
4440/// This is a recursive function
4441
4442bool ROOT::TMetaUtils::MatchWithDeclOrAnyOfPrevious(const clang::CXXRecordDecl &cl,
4443 const clang::CXXRecordDecl &currentCl)
4444{
4445 // We found it: let's return true
4446 if (&cl == &currentCl) return true;
4447
4448 const clang::CXXRecordDecl* previous = currentCl.getPreviousDecl();
4449
4450 // There is no previous decl, so we cannot possibly find it
4451 if (nullptr == previous){
4452 return false;
4453 }
4454
4455 // We try to find it in the previous
4457
4458}
4459
4460//______________________________________________________________________________
4461
4462bool ROOT::TMetaUtils::IsOfType(const clang::CXXRecordDecl &cl, const std::string& typ, const cling::LookupHelper& lh)
4463{
4464 // Return true if the decl is of type.
4465 // A proper hashtable for caching results would be the ideal solution
4466 // 1) Only one lookup per type
4467 // 2) No string comparison
4468 // We may use a map which becomes an unordered map if c++11 is enabled?
4469
4470 const clang::CXXRecordDecl *thisDecl =
4471 llvm::dyn_cast_or_null<clang::CXXRecordDecl>(lh.findScope(typ, cling::LookupHelper::WithDiagnostics));
4472
4473 // this would be probably an assert given that this state is not reachable unless a mistake is somewhere
4474 if (! thisDecl){
4475 Error("IsOfType","Record decl of type %s not found in the AST.", typ.c_str());
4476 return false;
4477 }
4478
4479 // Now loop on all previous decls to seek a match
4480 const clang::CXXRecordDecl *mostRecentDecl = thisDecl->getMostRecentDecl();
4481 bool matchFound = MatchWithDeclOrAnyOfPrevious (cl,*mostRecentDecl);
4482
4483 return matchFound;
4484}
4485
4486////////////////////////////////////////////////////////////////////////////////
4487/// type : type name: vector<list<classA,allocator>,allocator>
4488/// result: 0 : not stl container
4489/// abs(result): code of container 1=vector,2=list,3=deque,4=map
4490/// 5=multimap,6=set,7=multiset
4491
4493{
4494 // This routine could be enhanced to also support:
4495 //
4496 // testAlloc: if true, we test allocator, if it is not default result is negative
4497 // result: 0 : not stl container
4498 // abs(result): code of container 1=vector,2=list,3=deque,4=map
4499 // 5=multimap,6=set,7=multiset
4500 // positive val: we have a vector or list with default allocator to any depth
4501 // like vector<list<vector<int>>>
4502 // negative val: STL container other than vector or list, or non default allocator
4503 // For example: vector<deque<int>> has answer -1
4504
4505 if (!IsStdClass(cl)) {
4506 auto *nsDecl = llvm::dyn_cast<clang::NamespaceDecl>(cl.getDeclContext());
4507 if (cl.getName() != "RVec" || nsDecl == nullptr || nsDecl->getName() != "VecOps")
4508 return ROOT::kNotSTL;
4509
4510 auto *parentNsDecl = llvm::dyn_cast<clang::NamespaceDecl>(cl.getDeclContext()->getParent());
4511 if (parentNsDecl == nullptr || parentNsDecl->getName() != "ROOT")
4512 return ROOT::kNotSTL;
4513 }
4514
4515 return STLKind(cl.getName());
4516}
4517
4518static bool hasSomeTypedefSomewhere(const clang::Type* T) {
4519 using namespace clang;
4520 struct SearchTypedef: public TypeVisitor<SearchTypedef, bool> {
4521 bool VisitTypedefType(const TypedefType* TD) {
4522 return true;
4523 }
4524 bool VisitArrayType(const ArrayType* AT) {
4525 return Visit(AT->getElementType().getTypePtr());
4526 }
4527 bool VisitDecltypeType(const DecltypeType* DT) {
4528 return Visit(DT->getUnderlyingType().getTypePtr());
4529 }
4530 bool VisitPointerType(const PointerType* PT) {
4531 return Visit(PT->getPointeeType().getTypePtr());
4532 }
4533 bool VisitReferenceType(const ReferenceType* RT) {
4534 return Visit(RT->getPointeeType().getTypePtr());
4535 }
4536 bool VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType* STST) {
4537 return Visit(STST->getReplacementType().getTypePtr());
4538 }
4539 bool VisitTemplateSpecializationType(const TemplateSpecializationType* TST) {
4540 for (const TemplateArgument &TA : TST->template_arguments()) {
4541 if (TA.getKind() == TemplateArgument::Type && Visit(TA.getAsType().getTypePtr()))
4542 return true;
4543 }
4544 return false;
4545 }
4546 bool VisitTemplateTypeParmType(const TemplateTypeParmType* TTPT) {
4547 return false; // shrug...
4548 }
4549 bool VisitTypeOfType(const TypeOfType* TOT) {
4550 return TOT->getUnmodifiedType().getTypePtr();
4551 }
4552 bool VisitElaboratedType(const ElaboratedType* ET) {
4553 NestedNameSpecifier* NNS = ET->getQualifier();
4554 while (NNS) {
4555 if (NNS->getKind() == NestedNameSpecifier::TypeSpec) {
4556 if (Visit(NNS->getAsType()))
4557 return true;
4558 }
4559 NNS = NNS->getPrefix();
4560 }
4561 return Visit(ET->getNamedType().getTypePtr());
4562 }
4563 };
4564
4565 SearchTypedef ST;
4566 return ST.Visit(T);
4567}
4568
4569////////////////////////////////////////////////////////////////////////////////
4570/// Check if 'input' or any of its template parameter was substituted when
4571/// instantiating the class template instance and replace it with the
4572/// partially sugared types we have from 'instance'.
4573
4574clang::QualType ROOT::TMetaUtils::ReSubstTemplateArg(clang::QualType input, const clang::Type *instance)
4575{
4576 if (!instance) return input;
4577 // if there is no typedef in instance then there is nothing guiding any
4578 // template parameter typedef replacement.
4580 return input;
4581
4582 using namespace llvm;
4583 using namespace clang;
4584 const clang::ASTContext &Ctxt = instance->getAsCXXRecordDecl()->getASTContext();
4585
4586 // Treat scope (clang::ElaboratedType) if any.
4587 const clang::ElaboratedType* etype
4588 = llvm::dyn_cast<clang::ElaboratedType>(input.getTypePtr());
4589 if (etype) {
4590 // We have to also handle the prefix.
4591
4592 clang::Qualifiers scope_qualifiers = input.getLocalQualifiers();
4593 assert(instance->getAsCXXRecordDecl() != nullptr && "ReSubstTemplateArg only makes sense with a type representing a class.");
4594
4595 clang::NestedNameSpecifier *scope = ReSubstTemplateArgNNS(Ctxt,etype->getQualifier(),instance);
4596 clang::QualType subTy = ReSubstTemplateArg(clang::QualType(etype->getNamedType().getTypePtr(),0),instance);
4597
4598 if (scope) subTy = Ctxt.getElaboratedType(clang::ETK_None,scope,subTy);
4599 subTy = Ctxt.getQualifiedType(subTy,scope_qualifiers);
4600 return subTy;
4601 }
4602
4603 QualType QT = input;
4604
4605 // In case of Int_t* we need to strip the pointer first, ReSubst and attach
4606 // the pointer once again.
4607 if (isa<clang::PointerType>(QT.getTypePtr())) {
4608 // Get the qualifiers.
4609 Qualifiers quals = QT.getQualifiers();
4610 QualType nQT;
4611 nQT = ReSubstTemplateArg(QT->getPointeeType(),instance);
4612 if (nQT == QT->getPointeeType()) return QT;
4613
4614 QT = Ctxt.getPointerType(nQT);
4615 // Add back the qualifiers.
4616 QT = Ctxt.getQualifiedType(QT, quals);
4617 return QT;
4618 }
4619
4620 // In case of Int_t& we need to strip the pointer first, ReSubst and attach
4621 // the reference once again.
4622 if (isa<ReferenceType>(QT.getTypePtr())) {
4623 // Get the qualifiers.
4624 bool isLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
4625 Qualifiers quals = QT.getQualifiers();
4626 QualType nQT;
4627 nQT = ReSubstTemplateArg(QT->getPointeeType(),instance);
4628 if (nQT == QT->getPointeeType()) return QT;
4629
4630 // Add the r- or l-value reference type back to the desugared one.
4631 if (isLValueRefTy)
4632 QT = Ctxt.getLValueReferenceType(nQT);
4633 else
4634 QT = Ctxt.getRValueReferenceType(nQT);
4635 // Add back the qualifiers.
4636 QT = Ctxt.getQualifiedType(QT, quals);
4637 return QT;
4638 }
4639
4640 // In case of Int_t[2] we need to strip the array first, ReSubst and attach
4641 // the array once again.
4642 if (isa<clang::ArrayType>(QT.getTypePtr())) {
4643 // Get the qualifiers.
4644 Qualifiers quals = QT.getQualifiers();
4645
4646 if (const auto arr = dyn_cast<ConstantArrayType>(QT.getTypePtr())) {
4647 QualType newQT= ReSubstTemplateArg(arr->getElementType(),instance);
4648
4649 if (newQT == arr->getElementType()) return QT;
4650 QT = Ctxt.getConstantArrayType(newQT,
4651 arr->getSize(),
4652 arr->getSizeExpr(),
4653 arr->getSizeModifier(),
4654 arr->getIndexTypeCVRQualifiers());
4655
4656 } else if (const auto arr = dyn_cast<DependentSizedArrayType>(QT.getTypePtr())) {
4657 QualType newQT = ReSubstTemplateArg(arr->getElementType(),instance);
4658
4659 if (newQT == QT) return QT;
4660 QT = Ctxt.getDependentSizedArrayType (newQT,
4661 arr->getSizeExpr(),
4662 arr->getSizeModifier(),
4663 arr->getIndexTypeCVRQualifiers(),
4664 arr->getBracketsRange());
4665
4666 } else if (const auto arr = dyn_cast<IncompleteArrayType>(QT.getTypePtr())) {
4667 QualType newQT = ReSubstTemplateArg(arr->getElementType(),instance);
4668
4669 if (newQT == arr->getElementType()) return QT;
4670 QT = Ctxt.getIncompleteArrayType (newQT,
4671 arr->getSizeModifier(),
4672 arr->getIndexTypeCVRQualifiers());
4673
4674 } else if (const auto arr = dyn_cast<VariableArrayType>(QT.getTypePtr())) {
4675 QualType newQT = ReSubstTemplateArg(arr->getElementType(),instance);
4676
4677 if (newQT == arr->getElementType()) return QT;
4678 QT = Ctxt.getVariableArrayType (newQT,
4679 arr->getSizeExpr(),
4680 arr->getSizeModifier(),
4681 arr->getIndexTypeCVRQualifiers(),
4682 arr->getBracketsRange());
4683 }
4684
4685 // Add back the qualifiers.
4686 QT = Ctxt.getQualifiedType(QT, quals);
4687 return QT;
4688 }
4689
4690 // If the instance is also an elaborated type, we need to skip
4691 etype = llvm::dyn_cast<clang::ElaboratedType>(instance);
4692 if (etype) {
4693 instance = etype->getNamedType().getTypePtr();
4694 if (!instance) return input;
4695 }
4696
4697 const clang::TemplateSpecializationType* TST
4698 = llvm::dyn_cast<const clang::TemplateSpecializationType>(instance);
4699
4700 if (!TST) return input;
4701
4702 const clang::ClassTemplateSpecializationDecl* TSTdecl
4703 = llvm::dyn_cast_or_null<const clang::ClassTemplateSpecializationDecl>(instance->getAsCXXRecordDecl());
4704
4705 if (!TSTdecl) return input;
4706
4707 const clang::SubstTemplateTypeParmType *substType
4708 = llvm::dyn_cast<clang::SubstTemplateTypeParmType>(input.getTypePtr());
4709
4710 if (substType) {
4711 // Make sure it got replaced from this template
4712 const clang::ClassTemplateDecl *replacedCtxt = nullptr;
4713
4714 const clang::DeclContext *replacedDeclCtxt = substType->getReplacedParameter()->getDeclContext();
4715 const clang::CXXRecordDecl *decl = llvm::dyn_cast<clang::CXXRecordDecl>(replacedDeclCtxt);
4716 unsigned int index = substType->getReplacedParameter()->getIndex();
4717 if (decl) {
4718
4719 if (decl->getKind() == clang::Decl::ClassTemplatePartialSpecialization) {
4720 const clang::ClassTemplatePartialSpecializationDecl *spec = llvm::dyn_cast<clang::ClassTemplatePartialSpecializationDecl>(decl);
4721
4722 unsigned int depth = substType->getReplacedParameter()->getDepth();
4723
4724 const TemplateArgument *instanceArgs = spec->getTemplateArgs().data();
4725 unsigned int instanceNArgs = spec->getTemplateArgs().size();
4726
4727 // Search for the 'right' replacement.
4728
4729 for(unsigned int A = 0; A < instanceNArgs; ++A) {
4730 if (instanceArgs[A].getKind() == clang::TemplateArgument::Type) {
4731 clang::QualType argQualType = instanceArgs[A].getAsType();
4732
4733 const clang::TemplateTypeParmType *replacementType;
4734
4735 replacementType = llvm::dyn_cast<clang::TemplateTypeParmType>(argQualType);
4736
4737 if (!replacementType) {
4738 const clang::SubstTemplateTypeParmType *argType
4739 = llvm::dyn_cast<clang::SubstTemplateTypeParmType>(argQualType);
4740 if (argType) {
4741 clang::QualType replacementQT = argType->getReplacementType();
4742 replacementType = llvm::dyn_cast<clang::TemplateTypeParmType>(replacementQT);
4743 }
4744 }
4745 if (replacementType &&
4746 depth == replacementType->getDepth() &&
4747 index == replacementType->getIndex() )
4748 {
4749 index = A;
4750 break;
4751 }
4752 }
4753 }
4754 replacedCtxt = spec->getSpecializedTemplate();
4755 } else {
4756 replacedCtxt = decl->getDescribedClassTemplate();
4757 }
4758 } else if (auto const declguide = llvm::dyn_cast<clang::CXXDeductionGuideDecl>(replacedDeclCtxt)) {
4759 replacedCtxt = llvm::dyn_cast<clang::ClassTemplateDecl>(declguide->getDeducedTemplate());
4760 } else if (auto const ctdecl = llvm::dyn_cast<clang::ClassTemplateDecl>(replacedDeclCtxt)) {
4761 replacedCtxt = ctdecl;
4762 } else {
4763 std::string astDump;
4764 llvm::raw_string_ostream ostream(astDump);
4765 instance->dump(ostream, Ctxt);
4766 ostream.flush();
4767 ROOT::TMetaUtils::Warning("ReSubstTemplateArg","Unexpected type of declaration context for template parameter: %s.\n\tThe responsible class is:\n\t%s\n",
4768 replacedDeclCtxt->getDeclKindName(), astDump.c_str());
4769 replacedCtxt = nullptr;
4770 }
4771
4772 if ((replacedCtxt && replacedCtxt->getCanonicalDecl() == TSTdecl->getSpecializedTemplate()->getCanonicalDecl())
4773 || /* the following is likely just redundant */
4774 substType->getReplacedParameter()
4775 == TSTdecl->getSpecializedTemplate ()->getTemplateParameters()->getParam(index))
4776 {
4777 const auto &TAs = TST->template_arguments();
4778 if (index >= TAs.size()) {
4779 // The argument replaced was a default template argument that is
4780 // being listed as part of the instance ...
4781 // so we probably don't really know how to spell it ... we would need to recreate it
4782 // (See AddDefaultParameters).
4783 return input;
4784 } else if (TAs[index].getKind() == clang::TemplateArgument::Type) {
4785 return TAs[index].getAsType();
4786 } else {
4787 // The argument is (likely) a value or expression and there is nothing for us
4788 // to change
4789 return input;
4790 }
4791 }
4792 }
4793 // Maybe a class template instance, recurse and rebuild
4794 const clang::TemplateSpecializationType* inputTST
4795 = llvm::dyn_cast<const clang::TemplateSpecializationType>(input.getTypePtr());
4796 const clang::ASTContext& astCtxt = TSTdecl->getASTContext();
4797
4798 if (inputTST) {
4799 bool mightHaveChanged = false;
4800 llvm::SmallVector<clang::TemplateArgument, 4> desArgs;
4801 for (const clang::TemplateArgument &TA : inputTST->template_arguments()) {
4802 if (TA.getKind() != clang::TemplateArgument::Type) {
4803 desArgs.push_back(TA);
4804 continue;
4805 }
4806
4807 clang::QualType SubTy = TA.getAsType();
4808 // Check if the type needs more desugaring and recurse.
4809 if (llvm::isa<clang::ElaboratedType>(SubTy)
4810 || llvm::isa<clang::SubstTemplateTypeParmType>(SubTy)
4811 || llvm::isa<clang::TemplateSpecializationType>(SubTy)) {
4812 clang::QualType newSubTy = ReSubstTemplateArg(SubTy,instance);
4813 mightHaveChanged = SubTy != newSubTy;
4814 if (!newSubTy.isNull()) {
4815 desArgs.push_back(clang::TemplateArgument(newSubTy));
4816 }
4817 } else
4818 desArgs.push_back(TA);
4819 }
4820
4821 // If desugaring happened allocate new type in the AST.
4822 if (mightHaveChanged) {
4823 clang::Qualifiers qualifiers = input.getLocalQualifiers();
4824 input = astCtxt.getTemplateSpecializationType(inputTST->getTemplateName(),
4825 desArgs,
4826 inputTST->getCanonicalTypeInternal());
4827 input = astCtxt.getQualifiedType(input, qualifiers);
4828 }
4829 }
4830
4831 return input;
4832}
4833
4834////////////////////////////////////////////////////////////////////////////////
4835/// Remove the last n template arguments from the name
4836
4837int ROOT::TMetaUtils::RemoveTemplateArgsFromName(std::string& name, unsigned int nArgsToRemove)
4838{
4839 if ( nArgsToRemove == 0 || name == "")
4840 return 0;
4841
4842 // We proceed from the right to the left, counting commas which are not
4843 // enclosed by < >.
4844 const unsigned int length = name.length();
4845 unsigned int cur=0; // let's start beyond the first > from the right
4846 unsigned int nArgsRemoved=0;
4847 unsigned int nBraces=0;
4848 char c='@';
4849 while (nArgsRemoved!=nArgsToRemove && cur<length){
4850 c = name[cur];
4851 if (c == '<') nBraces++;
4852 if (c == '>') nBraces--;
4853 if (c == ',' && nBraces==1 /*So we are not in a sub-template*/) nArgsRemoved++;
4854 cur++;
4855 }
4856 cur--;
4857 name = name.substr(0,cur)+">";
4858 return 0;
4859
4860}
4861
4862////////////////////////////////////////////////////////////////////////////////
4863/// Converts STL container name to number. vector -> 1, etc..
4864
4866{
4867 static const char *stls[] = //container names
4868 {"any","vector","list", "deque","map","multimap","set","multiset","bitset",
4869 "forward_list","unordered_set","unordered_multiset","unordered_map","unordered_multimap", "RVec", nullptr};
4870 static const ROOT::ESTLType values[] =
4881 };
4882 // kind of stl container
4883 for(int k=1;stls[k];k++) {if (type.equals(stls[k])) return values[k];}
4884 return ROOT::kNotSTL;
4885}
4886
4887////////////////////////////////////////////////////////////////////////////////
4888
4889const clang::TypedefNameDecl *ROOT::TMetaUtils::GetAnnotatedRedeclarable(const clang::TypedefNameDecl *TND)
4890{
4891 if (!TND)
4892 return nullptr;
4893
4894 TND = TND->getMostRecentDecl();
4895 while (TND && !(TND->hasAttrs()))
4896 TND = TND->getPreviousDecl();
4897
4898 return TND;
4899}
4900
4901////////////////////////////////////////////////////////////////////////////////
4902
4903const clang::TagDecl *ROOT::TMetaUtils::GetAnnotatedRedeclarable(const clang::TagDecl *TD)
4904{
4905 if (!TD)
4906 return nullptr;
4907
4908 TD = TD->getMostRecentDecl();
4909 while (TD && !(TD->hasAttrs() && TD->isThisDeclarationADefinition()))
4910 TD = TD->getPreviousDecl();
4911
4912 return TD;
4913}
4914
4915////////////////////////////////////////////////////////////////////////////////
4916/// Extract the immediately outer namespace and then launch the recursion
4917
4919 std::list<std::pair<std::string,bool> >& enclosingNamespaces)
4920{
4921 const clang::DeclContext* enclosingNamespaceDeclCtxt = decl.getDeclContext();
4922 if (!enclosingNamespaceDeclCtxt) return;
4923
4924 const clang::NamespaceDecl* enclosingNamespace =
4925 clang::dyn_cast<clang::NamespaceDecl>(enclosingNamespaceDeclCtxt);
4926 if (!enclosingNamespace) return;
4927
4928 enclosingNamespaces.push_back(std::make_pair(enclosingNamespace->getNameAsString(),
4929 enclosingNamespace->isInline()));
4930
4931 ExtractCtxtEnclosingNameSpaces(*enclosingNamespace, enclosingNamespaces);
4932
4933}
4934
4935////////////////////////////////////////////////////////////////////////////////
4936/// Extract enclosing namespaces recursively
4937
4938void ROOT::TMetaUtils::ExtractCtxtEnclosingNameSpaces(const clang::DeclContext& ctxt,
4939 std::list<std::pair<std::string,bool> >& enclosingNamespaces)
4940{
4941 const clang::DeclContext* enclosingNamespaceDeclCtxt = ctxt.getParent ();
4942
4943 // If no parent is found, nothing more to be done
4944 if (!enclosingNamespaceDeclCtxt) {
4945 return;
4946 }
4947
4948 // Check if the parent is a namespace (it could be a class for example)
4949 // if not, nothing to be done here
4950 const clang::NamespaceDecl* enclosingNamespace = clang::dyn_cast<clang::NamespaceDecl>(enclosingNamespaceDeclCtxt);
4951 if (!enclosingNamespace) return;
4952
4953 // Add to the list of parent namespaces
4954 enclosingNamespaces.push_back(std::make_pair(enclosingNamespace->getNameAsString(),
4955 enclosingNamespace->isInline()));
4956
4957 // here the recursion
4958 ExtractEnclosingNameSpaces(*enclosingNamespace, enclosingNamespaces);
4959}
4960
4961////////////////////////////////////////////////////////////////////////////////
4962/// Extract the names and types of containing scopes.
4963/// Stop if a class is met and return its pointer.
4964
4965const clang::RecordDecl *ROOT::TMetaUtils::ExtractEnclosingScopes(const clang::Decl& decl,
4966 std::list<std::pair<std::string,unsigned int> >& enclosingSc)
4967{
4968 const clang::DeclContext* enclosingDeclCtxt = decl.getDeclContext();
4969 if (!enclosingDeclCtxt) return nullptr;
4970
4971 unsigned int scopeType;
4972
4973 if (auto enclosingNamespacePtr =
4974 clang::dyn_cast<clang::NamespaceDecl>(enclosingDeclCtxt)){
4975 scopeType= enclosingNamespacePtr->isInline() ? 1 : 0; // inline or simple namespace
4976 enclosingSc.push_back(std::make_pair(enclosingNamespacePtr->getNameAsString(),scopeType));
4977 return ExtractEnclosingScopes(*enclosingNamespacePtr, enclosingSc);
4978 }
4979
4980 if (auto enclosingClassPtr =
4981 clang::dyn_cast<clang::RecordDecl>(enclosingDeclCtxt)){
4982 return enclosingClassPtr;
4983 }
4984
4985 return nullptr;
4986}
4987
4988////////////////////////////////////////////////////////////////////////////////
4989/// Reimplementation of TSystem::ExpandPathName() that cannot be
4990/// used from TMetaUtils.
4991
4992static void replaceEnvVars(const char* varname, std::string& txt)
4993{
4994 std::string::size_type beginVar = 0;
4995 std::string::size_type endVar = 0;
4996 while ((beginVar = txt.find('$', beginVar)) != std::string::npos
4997 && beginVar + 1 < txt.length()) {
4998 std::string::size_type beginVarName = beginVar + 1;
4999 std::string::size_type endVarName = std::string::npos;
5000 if (txt[beginVarName] == '(') {
5001 // "$(VARNAME)" style.
5002 endVarName = txt.find(')', beginVarName);
5003 ++beginVarName;
5004 if (endVarName == std::string::npos) {
5005 ROOT::TMetaUtils::Error(nullptr, "Missing ')' for '$(' in $%s at %s\n",
5006 varname, txt.c_str() + beginVar);
5007 return;
5008 }
5009 endVar = endVarName + 1;
5010 } else {
5011 // "$VARNAME/..." style.
5012 beginVarName = beginVar + 1;
5013 endVarName = beginVarName;
5014 while (isalnum(txt[endVarName]) || txt[endVarName] == '_')
5015 ++endVarName;
5016 endVar = endVarName;
5017 }
5018
5019 const char* val = getenv(txt.substr(beginVarName,
5020 endVarName - beginVarName).c_str());
5021 if (!val) val = "";
5022
5023 txt.replace(beginVar, endVar - beginVar, val);
5024 int lenval = strlen(val);
5025 int delta = lenval - (endVar - beginVar); // these many extra chars,
5026 endVar += delta; // advance the end marker accordingly.
5027
5028 // Look for the next one
5029 beginVar = endVar + 1;
5030 }
5031}
5032
5033////////////////////////////////////////////////////////////////////////////////
5034/// Organise the parameters for cling in order to guarantee relocatability
5035/// It treats the gcc toolchain and the root include path
5036/// FIXME: enables relocatability for experiments' framework headers until PCMs
5037/// are available.
5038
5039void ROOT::TMetaUtils::SetPathsForRelocatability(std::vector<std::string>& clingArgs )
5040{
5041 const char* envInclPath = getenv("ROOT_INCLUDE_PATH");
5042
5043 if (!envInclPath)
5044 return;
5045 std::istringstream envInclPathsStream(envInclPath);
5046 std::string inclPath;
5047 while (std::getline(envInclPathsStream, inclPath, ':')) {
5048 // Can't use TSystem in here; re-implement TSystem::ExpandPathName().
5049 replaceEnvVars("ROOT_INCLUDE_PATH", inclPath);
5050 if (!inclPath.empty()) {
5051 clingArgs.push_back("-I");
5052 clingArgs.push_back(inclPath);
5053 }
5054 }
5055}
5056
5057////////////////////////////////////////////////////////////////////////////////
5058
5059void ROOT::TMetaUtils::ReplaceAll(std::string& str, const std::string& from, const std::string& to,bool recurse)
5060{
5061 if(from.empty())
5062 return;
5063 size_t start_pos = 0;
5064 bool changed=true;
5065 while (changed){
5066 changed=false;
5067 start_pos = 0;
5068 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
5069 str.replace(start_pos, from.length(), to);
5070 start_pos += to.length();
5071 if (recurse) changed = true;
5072 }
5073 }
5074}
5075
5076////////////////////////////////////////////////////////////////////////////////
5077/// Return the separator suitable for this platform.
5079{
5081}
5082
5083////////////////////////////////////////////////////////////////////////////////
5084
5085bool ROOT::TMetaUtils::EndsWith(const std::string &theString, const std::string &theSubstring)
5086{
5087 if (theString.size() < theSubstring.size()) return false;
5088 const unsigned int theSubstringSize = theSubstring.size();
5089 return 0 == theString.compare(theString.size() - theSubstringSize,
5090 theSubstringSize,
5091 theSubstring);
5092}
5093
5094////////////////////////////////////////////////////////////////////////////////
5095
5096bool ROOT::TMetaUtils::BeginsWith(const std::string &theString, const std::string &theSubstring)
5097{
5098 if (theString.size() < theSubstring.size()) return false;
5099 const unsigned int theSubstringSize = theSubstring.size();
5100 return 0 == theString.compare(0,
5101 theSubstringSize,
5102 theSubstring);
5103}
5104
5105
5106
5107////////////////////////////////////////////////////////////////////////////////
5108
5110{
5111 // Note, should change this into take llvm::StringRef.
5112
5113 if ((strstr(filename, "LinkDef") || strstr(filename, "Linkdef") ||
5114 strstr(filename, "linkdef")) && strstr(filename, ".h")) {
5115 return true;
5116 }
5117 size_t len = strlen(filename);
5118 size_t linkdeflen = 9; /* strlen("linkdef.h") */
5119 if (len >= 9) {
5120 if (0 == strncasecmp(filename + (len - linkdeflen), "linkdef", linkdeflen - 2)
5121 && 0 == strcmp(filename + (len - 2), ".h")
5122 ) {
5123 return true;
5124 } else {
5125 return false;
5126 }
5127 } else {
5128 return false;
5129 }
5130}
5131
5132////////////////////////////////////////////////////////////////////////////////
5133
5135{
5136 return llvm::sys::path::extension(filename) == ".h" ||
5137 llvm::sys::path::extension(filename) == ".hh" ||
5138 llvm::sys::path::extension(filename) == ".hpp" ||
5139 llvm::sys::path::extension(filename) == ".H" ||
5140 llvm::sys::path::extension(filename) == ".h++" ||
5141 llvm::sys::path::extension(filename) == "hxx" ||
5142 llvm::sys::path::extension(filename) == "Hxx" ||
5143 llvm::sys::path::extension(filename) == "HXX";
5144}
5145
5146////////////////////////////////////////////////////////////////////////////////
5147
5148const std::string ROOT::TMetaUtils::AST2SourceTools::Decls2FwdDecls(const std::vector<const clang::Decl *> &decls,
5149 cling::Interpreter::IgnoreFilesFunc_t ignoreFiles,
5150 const cling::Interpreter &interp,
5151 std::string *logs)
5152{
5153 clang::Sema &sema = interp.getSema();
5154 cling::Transaction theTransaction(sema);
5155 std::set<clang::Decl *> addedDecls;
5156 for (auto decl : decls) {
5157 // again waiting for cling
5158 clang::Decl *ncDecl = const_cast<clang::Decl *>(decl);
5159 theTransaction.append(ncDecl);
5160 }
5161 std::string newFwdDecl;
5162 llvm::raw_string_ostream llvmOstr(newFwdDecl);
5163
5164 std::string locallogs;
5165 llvm::raw_string_ostream llvmLogStr(locallogs);
5166 interp.forwardDeclare(theTransaction, sema.getPreprocessor(), sema.getASTContext(), llvmOstr, true,
5167 logs ? &llvmLogStr : nullptr, ignoreFiles);
5168 llvmOstr.flush();
5169 llvmLogStr.flush();
5170 if (logs)
5171 logs->swap(locallogs);
5172 return newFwdDecl;
5173}
5174
5175////////////////////////////////////////////////////////////////////////////////
5176/// Take the namespaces which enclose the decl and put them around the
5177/// definition string.
5178/// For example, if the definition string is "myClass" which is enclosed by
5179/// the namespaces ns1 and ns2, one would get:
5180/// namespace ns2{ namespace ns1 { class myClass; } }
5181
5183 std::string& defString)
5184{
5185 auto rcd = EncloseInScopes(decl, defString);
5186 return rcd ? 1:0;
5187}
5188
5189////////////////////////////////////////////////////////////////////////////////
5190/// Take the scopes which enclose the decl and put them around the
5191/// definition string.
5192/// If a class is encountered, bail out.
5193
5194const clang::RecordDecl* ROOT::TMetaUtils::AST2SourceTools::EncloseInScopes(const clang::Decl& decl,
5195 std::string& defString)
5196{
5197 std::list<std::pair<std::string,unsigned int> > enclosingNamespaces;
5198 auto rcdPtr = ROOT::TMetaUtils::ExtractEnclosingScopes(decl,enclosingNamespaces);
5199
5200 if (rcdPtr) return rcdPtr;
5201
5202 // Check if we have enclosing namespaces
5203 static const std::string scopeType [] = {"namespace ", "inline namespace ", "class "};
5204
5205 std::string scopeName;
5206 std::string scopeContent;
5207 unsigned int scopeIndex;
5208 for (auto const & encScope : enclosingNamespaces){
5209 scopeIndex = encScope.second;
5210 scopeName = encScope.first;
5211 scopeContent = " { " + defString + " }";
5212 defString = scopeType[scopeIndex] +
5213 scopeName +
5214 scopeContent;
5215 }
5216 return nullptr;
5217}
5218
5219////////////////////////////////////////////////////////////////////////////////
5220/// Loop over the template parameters and build a string for template arguments
5221/// using the fully qualified name
5222/// There are different cases:
5223/// Case 1: a simple template parameter
5224/// E.g. `template<typename T> class A;`
5225/// Case 2: a non-type: either an integer or an enum
5226/// E.g. `template<int I, Foo > class A;` where `Foo` is `enum Foo {red, blue};`
5227/// 2 sub cases here:
5228/// SubCase 2.a: the parameter is an enum: bail out, cannot be treated.
5229/// SubCase 2.b: use the fully qualified name
5230/// Case 3: a TemplateTemplate argument
5231/// E.g. `template <template <typename> class T> class container { };`
5232
5234 const clang::TemplateParameterList& tmplParamList,
5235 const cling::Interpreter& interpreter)
5236{
5237 templateArgs="<";
5238 for (auto prmIt = tmplParamList.begin();
5239 prmIt != tmplParamList.end(); prmIt++){
5240
5241 if (prmIt != tmplParamList.begin())
5242 templateArgs += ", ";
5243
5244 auto nDecl = *prmIt;
5245 std::string typeName;
5246
5247 // Case 1
5248 if (llvm::isa<clang::TemplateTypeParmDecl>(nDecl)){
5249 typeName = "typename ";
5250 if (nDecl->isParameterPack())
5251 typeName += "... ";
5252 typeName += (*prmIt)->getNameAsString();
5253 }
5254 // Case 2
5255 else if (auto nttpd = llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(nDecl)){
5256 auto theType = nttpd->getType();
5257 // If this is an enum, use int as it is impossible to fwd declare and
5258 // this makes sense since it is not a type...
5259 if (theType.getAsString().find("enum") != std::string::npos){
5260 std::string astDump;
5261 llvm::raw_string_ostream ostream(astDump);
5262 nttpd->dump(ostream);
5263 ostream.flush();
5264 ROOT::TMetaUtils::Warning(nullptr,"Forward declarations of templates with enums as template parameters. The responsible class is: %s\n", astDump.c_str());
5265 return 1;
5266 } else {
5268 theType,
5269 interpreter);
5270 }
5271 }
5272 // Case 3: TemplateTemplate argument
5273 else if (auto ttpd = llvm::dyn_cast<clang::TemplateTemplateParmDecl>(nDecl)){
5274 int retCode = FwdDeclFromTmplDecl(*ttpd,interpreter,typeName);
5275 if (retCode!=0){
5276 std::string astDump;
5277 llvm::raw_string_ostream ostream(astDump);
5278 ttpd->dump(ostream);
5279 ostream.flush();
5280 ROOT::TMetaUtils::Error(nullptr,"Cannot reconstruct template template parameter forward declaration for %s\n", astDump.c_str());
5281 return 1;
5282 }
5283 }
5284
5285 templateArgs += typeName;
5286 }
5287
5288 templateArgs+=">";
5289 return 0;
5290}
5291
5292////////////////////////////////////////////////////////////////////////////////
5293/// Convert a tmplt decl to its fwd decl
5294
5295int ROOT::TMetaUtils::AST2SourceTools::FwdDeclFromTmplDecl(const clang::TemplateDecl& templDecl,
5296 const cling::Interpreter& interpreter,
5297 std::string& defString)
5298{
5299 std::string templatePrefixString;
5300 auto tmplParamList= templDecl.getTemplateParameters();
5301 if (!tmplParamList){ // Should never happen
5302 Error(nullptr,
5303 "Cannot extract template parameter list for %s",
5304 templDecl.getNameAsString().c_str());
5305 return 1;
5306 }
5307
5308 int retCode = PrepareArgsForFwdDecl(templatePrefixString,*tmplParamList,interpreter);
5309 if (retCode!=0){
5310 Warning(nullptr,
5311 "Problems with arguments for forward declaration of class %s\n",
5312 templDecl.getNameAsString().c_str());
5313 return retCode;
5314 }
5315 templatePrefixString = "template " + templatePrefixString + " ";
5316
5317 defString = templatePrefixString + "class ";
5318 if (templDecl.isParameterPack())
5319 defString += "... ";
5320 defString += templDecl.getNameAsString();
5321 if (llvm::isa<clang::TemplateTemplateParmDecl>(&templDecl)) {
5322 // When fwd declaring the template template arg of
5323 // namespace N { template <template <class T> class C> class X; }
5324 // we don't need to put it into any namespace, and we want no trailing
5325 // ';'
5326 return 0;
5327 }
5328 defString += ';';
5329 return EncloseInNamespaces(templDecl, defString);
5330}
5331
5332////////////////////////////////////////////////////////////////////////////////
5333
5334static int TreatSingleTemplateArg(const clang::TemplateArgument& arg,
5335 std::string& argFwdDecl,
5336 const cling::Interpreter& interpreter,
5337 bool acceptStl=false)
5338{
5339 using namespace ROOT::TMetaUtils::AST2SourceTools;
5340
5341 // We do nothing in presence of ints, bools, templates.
5342 // We should probably in presence of templates though...
5343 if (clang::TemplateArgument::Type != arg.getKind()) return 0;
5344
5345 auto argQualType = arg.getAsType();
5346
5347 // Recursively remove all *
5348 while (llvm::isa<clang::PointerType>(argQualType.getTypePtr())) argQualType = argQualType->getPointeeType();
5349
5350 auto argTypePtr = argQualType.getTypePtr();
5351
5352 // Bail out on enums
5353 if (llvm::isa<clang::EnumType>(argTypePtr)){
5354 return 1;
5355 }
5356
5357 // If this is a built-in, just return: fwd decl not necessary.
5358 if (llvm::isa<clang::BuiltinType>(argTypePtr)){
5359 return 0;
5360 }
5361
5362 // Treat typedefs which are arguments
5363 if (auto tdTypePtr = llvm::dyn_cast<clang::TypedefType>(argTypePtr)) {
5364 FwdDeclFromTypeDefNameDecl(*tdTypePtr->getDecl(), interpreter, argFwdDecl);
5365 return 0;
5366 }
5367
5368 if (auto argRecTypePtr = llvm::dyn_cast<clang::RecordType>(argTypePtr)){
5369 // Now we cannot but have a RecordType
5370 if (auto argRecDeclPtr = argRecTypePtr->getDecl()){
5371 FwdDeclFromRcdDecl(*argRecDeclPtr,interpreter,argFwdDecl,acceptStl);
5372 }
5373 return 0;
5374 }
5375
5376 return 1;
5377}
5378
5379////////////////////////////////////////////////////////////////////////////////
5380/// Convert a tmplt decl to its fwd decl
5381
5382int ROOT::TMetaUtils::AST2SourceTools::FwdDeclIfTmplSpec(const clang::RecordDecl& recordDecl,
5383 const cling::Interpreter& interpreter,
5384 std::string& defString,
5385 const std::string &normalizedName)
5386{
5387 // If this is an explicit specialization, inject it into cling, too, such that it can have
5388 // externalLexicalStorage, see TCling.cxx's ExtVisibleStorageAdder::VisitClassTemplateSpecializationDecl.
5389 if (auto tmplSpecDeclPtr = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&recordDecl)) {
5390 if (const auto *specDef = tmplSpecDeclPtr->getDefinition()) {
5391 if (specDef->getTemplateSpecializationKind() != clang::TSK_ExplicitSpecialization)
5392 return 0;
5393 // normalizedName contains scope, no need to enclose in namespace!
5395 std::cout << " Forward declaring template spec " << normalizedName << ":\n";
5396 for (auto arg : tmplSpecDeclPtr->getTemplateArgs().asArray()) {
5397 std::string argFwdDecl;
5398 int retCode = TreatSingleTemplateArg(arg, argFwdDecl, interpreter, /*acceptStl=*/false);
5400 std::cout << " o Template argument ";
5401 if (retCode == 0) {
5402 std::cout << "successfully treated. Arg fwd decl: " << argFwdDecl << std::endl;
5403 } else {
5404 std::cout << "could not be treated. Abort fwd declaration generation.\n";
5405 }
5406 }
5407
5408 if (retCode != 0) { // A sign we must bail out
5409 return retCode;
5410 }
5411 defString += argFwdDecl + '\n';
5412 }
5413 defString += "template <> class " + normalizedName + ';';
5414 return 0;
5415 }
5416 }
5417
5418 return 0;
5419}
5420
5421////////////////////////////////////////////////////////////////////////////////
5422/// Convert a rcd decl to its fwd decl
5423/// If this is a template specialisation, treat in the proper way.
5424/// If it is contained in a class, just fwd declare the class.
5425
5426int ROOT::TMetaUtils::AST2SourceTools::FwdDeclFromRcdDecl(const clang::RecordDecl& recordDecl,
5427 const cling::Interpreter& interpreter,
5428 std::string& defString,
5429 bool acceptStl)
5430{
5431 // Do not fwd declare the templates in the stl.
5432 if (ROOT::TMetaUtils::IsStdClass(recordDecl) && !acceptStl)
5433 return 0;
5434
5435 // Do not fwd declare unnamed decls.
5436 if (!recordDecl.getIdentifier())
5437 return 0;
5438
5439 // We may need to fwd declare the arguments of the template
5440 std::string argsFwdDecl;
5441
5442 if (auto tmplSpecDeclPtr = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&recordDecl)){
5443 std::string argFwdDecl;
5445 std::cout << "Class " << recordDecl.getNameAsString()
5446 << " is a template specialisation. Treating its arguments.\n";
5447 for(auto arg : tmplSpecDeclPtr->getTemplateArgs().asArray()){
5448 int retCode = TreatSingleTemplateArg(arg, argFwdDecl, interpreter, acceptStl);
5450 std::cout << " o Template argument ";
5451 if (retCode==0){
5452 std::cout << "successfully treated. Arg fwd decl: " << argFwdDecl << std::endl;
5453 } else {
5454 std::cout << "could not be treated. Abort fwd declaration generation.\n";
5455 }
5456 }
5457
5458 if (retCode!=0){ // A sign we must bail out
5459 return retCode;
5460 }
5461 argsFwdDecl+=argFwdDecl;
5462 }
5463
5464 if (acceptStl){
5465 defString=argsFwdDecl;
5466 return 0;
5467 }
5468
5469 int retCode=0;
5470 if (auto tmplDeclPtr = tmplSpecDeclPtr->getSpecializedTemplate()){
5471 retCode = FwdDeclFromTmplDecl(*tmplDeclPtr,interpreter,defString);
5472 }
5473 defString = argsFwdDecl + "\n" + defString;
5474 return retCode;
5475
5476 }
5477
5478 defString = "class " + recordDecl.getNameAsString() + ";";
5479 const clang::RecordDecl* rcd = EncloseInScopes(recordDecl, defString);
5480
5481 if (rcd){
5482 FwdDeclFromRcdDecl(*rcd, interpreter,defString);
5483 }
5484 // Add a \n here to avoid long lines which contain duplications, for example (from MathCore):
5485 // namespace ROOT { namespace Math { class IBaseFunctionMultiDim; } }namespace ROOT { namespace Fit { template <typename FunType> class Chi2FCN; } }
5486 // namespace ROOT { namespace Math { class IGradientFunctionMultiDim; } }namespace ROOT { namespace Fit { template <typename FunType> class Chi2FCN; } }
5487 defString = argsFwdDecl + "\n" + defString;
5488
5489 return 0;
5490}
5491
5492////////////////////////////////////////////////////////////////////////////////
5493/// Extract "forward declaration" of a typedef.
5494/// If the typedef is contained in a class, just fwd declare the class.
5495/// If not, fwd declare the typedef and all the dependent typedefs and types if necessary.
5496
5498 const cling::Interpreter& interpreter,
5499 std::string& fwdDeclString,
5500 std::unordered_set<std::string>* fwdDeclSetPtr)
5501{
5502 std::string buffer = tdnDecl.getNameAsString();
5503 std::string underlyingName;
5504 auto underlyingType = tdnDecl.getUnderlyingType().getCanonicalType();
5505 if (const clang::TagType* TT
5506 = llvm::dyn_cast<clang::TagType>(underlyingType.getTypePtr())) {
5507 if (clang::NamedDecl* ND = TT->getDecl()) {
5508 if (!ND->getIdentifier()) {
5509 // No fwd decl for unnamed underlying entities.
5510 return 0;
5511 }
5512 }
5513 }
5514
5515 TNormalizedCtxt nCtxt(interpreter.getLookupHelper());
5517 underlyingType,
5518 interpreter,
5519 nCtxt);
5520
5521 // Heuristic: avoid entities like myclass<myType1, myType2::xyz>
5522 if (underlyingName.find(">::") != std::string::npos)
5523 return 0;
5524
5525 buffer="typedef "+underlyingName+" "+buffer+";";
5526 const clang::RecordDecl* rcd=EncloseInScopes(tdnDecl,buffer);
5527 if (rcd) {
5528 // We do not need the whole series of scopes, just the class.
5529 // It is enough to trigger an uncomplete type autoload/parse callback
5530 // for example: MyClass::blabla::otherNs::myTypedef
5531 return FwdDeclFromRcdDecl(*rcd, interpreter,fwdDeclString,fwdDeclSetPtr);
5532 }
5533
5534 // Start Recursion if the underlying type is a TypedefNameDecl
5535 // Note: the simple cast w/o the getSingleStepDesugaredType call
5536 // does not work in case the typedef is in a namespace.
5537 auto& ctxt = tdnDecl.getASTContext();
5538 auto immediatelyUnderlyingType = underlyingType.getSingleStepDesugaredType(ctxt);
5539
5540 if (auto underlyingTdnTypePtr = llvm::dyn_cast<clang::TypedefType>(immediatelyUnderlyingType.getTypePtr())){
5541 std::string tdnFwdDecl;
5542 auto underlyingTdnDeclPtr = underlyingTdnTypePtr->getDecl();
5543 FwdDeclFromTypeDefNameDecl(*underlyingTdnDeclPtr,
5544 interpreter,
5545 tdnFwdDecl,
5546 fwdDeclSetPtr);
5547 if (!fwdDeclSetPtr || fwdDeclSetPtr->insert(tdnFwdDecl).second)
5548 fwdDeclString+=tdnFwdDecl;
5549 } else if (auto CXXRcdDeclPtr = immediatelyUnderlyingType->getAsCXXRecordDecl()){
5550 std::string classFwdDecl;
5552 std::cout << "Typedef " << tdnDecl.getNameAsString() << " hides a class: "
5553 << CXXRcdDeclPtr->getNameAsString() << std::endl;
5554 int retCode = FwdDeclFromRcdDecl(*CXXRcdDeclPtr,
5555 interpreter,
5556 classFwdDecl,
5557 true /* acceptStl*/);
5558 if (retCode!=0){ // bail out
5559 return 0;
5560 }
5561
5562 if (!fwdDeclSetPtr || fwdDeclSetPtr->insert(classFwdDecl).second)
5563 fwdDeclString+=classFwdDecl;
5564 }
5565
5566 fwdDeclString+=buffer;
5567
5568 return 0;
5569}
5570
5571////////////////////////////////////////////////////////////////////////////////
5572/// Get the default value as string.
5573/// Limited at the moment to:
5574/// - Integers
5575/// - Booleans
5576
5577int ROOT::TMetaUtils::AST2SourceTools::GetDefArg(const clang::ParmVarDecl& par,
5578 std::string& valAsString,
5579 const clang::PrintingPolicy& ppolicy)
5580{
5581 auto defArgExprPtr = par.getDefaultArg();
5582 auto& ctxt = par.getASTContext();
5583 if(!defArgExprPtr->isEvaluatable(ctxt)){
5584 return -1;
5585 }
5586
5587 auto defArgType = par.getType();
5588
5589 // The value is a boolean
5590 if (defArgType->isBooleanType()){
5591 bool result;
5592 defArgExprPtr->EvaluateAsBooleanCondition (result,ctxt);
5593 valAsString=std::to_string(result);
5594 return 0;
5595 }
5596
5597 // The value is an integer
5598 if (defArgType->isIntegerType()){
5599 clang::Expr::EvalResult evalResult;
5600 defArgExprPtr->EvaluateAsInt(evalResult, ctxt);
5601 llvm::APSInt result = evalResult.Val.getInt();
5602 auto uintVal = *result.getRawData();
5603 if (result.isNegative()){
5604 long long int intVal=uintVal*-1;
5605 valAsString=std::to_string(intVal);
5606 } else {
5607 valAsString=std::to_string(uintVal);
5608 }
5609
5610 return 0;
5611 }
5612
5613 // The value is something else. We go for the generalised printer
5614 llvm::raw_string_ostream rso(valAsString);
5615 defArgExprPtr->printPretty(rso,nullptr,ppolicy);
5616 valAsString = rso.str();
5617 // We can be in presence of a string. Let's escape the characters properly.
5618 ROOT::TMetaUtils::ReplaceAll(valAsString,"\\\"","__TEMP__VAL__");
5619 ROOT::TMetaUtils::ReplaceAll(valAsString,"\"","\\\"");
5620 ROOT::TMetaUtils::ReplaceAll(valAsString,"__TEMP__VAL__","\\\"");
5621
5622 return 0;
5623}
5624
The file contains utilities which are foundational and could be used across the core component of ROO...
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define R(a, b, c, d, e, f, g, h, i)
Definition RSha256.hxx:110
static Roo_reg_AGKInteg1D instance
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
short Version_t
Definition RtypesCore.h:65
static void indent(ostringstream &buf, int indent_level)
static bool RecurseKeepNParams(clang::TemplateArgument &normTArg, const clang::TemplateArgument &tArg, const cling::Interpreter &interp, const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt, const clang::ASTContext &astCtxt)
static clang::SourceLocation getFinalSpellingLoc(clang::SourceManager &sourceManager, clang::SourceLocation sourceLoc)
const clang::DeclContext * GetEnclosingSpace(const clang::RecordDecl &cl)
bool IsTemplate(const clang::Decl &cl)
static void KeepNParams(clang::QualType &normalizedType, const clang::QualType &vanillaType, const cling::Interpreter &interp, const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt)
This function allows to manipulate the number of arguments in the type of a template specialisation.
static void CreateNameTypeMap(const clang::CXXRecordDecl &cl, ROOT::MembersTypeMap_t &nameType)
Create the data member name-type map for given class.
const clang::CXXMethodDecl * GetMethodWithProto(const clang::Decl *cinfo, const char *method, const char *proto, const cling::Interpreter &interp, bool diagnose)
int dumpDeclForAssert(const clang::Decl &D, const char *commentStart)
static void replaceEnvVars(const char *varname, std::string &txt)
Reimplementation of TSystem::ExpandPathName() that cannot be used from TMetaUtils.
static bool areEqualValues(const clang::TemplateArgument &tArg, const clang::NamedDecl &tPar)
std::cout << "Are equal values?\n";
static bool isTypeWithDefault(const clang::NamedDecl *nDecl)
Check if this NamedDecl is a template parameter with a default argument.
static int TreatSingleTemplateArg(const clang::TemplateArgument &arg, std::string &argFwdDecl, const cling::Interpreter &interpreter, bool acceptStl=false)
static bool areEqualTypes(const clang::TemplateArgument &tArg, llvm::SmallVectorImpl< clang::TemplateArgument > &preceedingTArgs, const clang::NamedDecl &tPar, const cling::Interpreter &interp, const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt)
static bool hasSomeTypedefSomewhere(const clang::Type *T)
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:185
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:229
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t dest
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 filename
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 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 value
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 UChar_t len
Option_t Option_t TPoint TPoint const char mode
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
char name[80]
Definition TGX11.cxx:110
const char * proto
Definition civetweb.c:17536
#define free
Definition civetweb.c:1539
const clang::RecordDecl * GetRecordDecl() const
const clang::RecordDecl * fDecl
AnnotatedRecordDecl(long index, const clang::RecordDecl *decl, bool rStreamerInfo, bool rNoStreamer, bool rRequestNoInputOperator, bool rRequestOnlyTClass, int rRequestedVersionNumber, int rRequestedRNTupleSplitMode, const cling::Interpreter &interpret, const TNormalizedCtxt &normCtxt)
There is no requested type name.
const char * GetRequestedName() const
static std::string BuildDemangledTypeInfo(const clang::RecordDecl *rDecl, const std::string &normalizedName)
const std::string & GetDemangledTypeInfo() const
const char * GetNormalizedName() const
const clang::CXXRecordDecl * fArgType
const clang::CXXRecordDecl * GetType() const
RConstructorType(const char *type_of_arg, const cling::Interpreter &)
bool IsDeclaredScope(const std::string &base, bool &isInlined) override
bool IsAlreadyPartiallyDesugaredName(const std::string &nondef, const std::string &nameLong) override
ExistingTypeCheck_t fExistingTypeCheck
TClingLookupHelper(cling::Interpreter &interpreter, TNormalizedCtxt &normCtxt, ExistingTypeCheck_t existingTypeCheck, AutoParse_t autoParse, bool *shuttingDownPtr, const int *pgDebug=nullptr)
bool GetPartiallyDesugaredNameWithScopeHandling(const std::string &tname, std::string &result, bool dropstd=true) override
We assume that we have a simple type: [const] typename[*&][const].
void GetPartiallyDesugaredName(std::string &nameLong) override
bool ExistingTypeCheck(const std::string &tname, std::string &result) override
Helper routine to ry hard to avoid looking up in the Cling database as this could enduce an unwanted ...
const Config_t & GetConfig() const
TNormalizedCtxt::Config_t::SkipCollection DeclsCont_t
TNormalizedCtxt::TemplPtrIntMap_t TemplPtrIntMap_t
int GetNargsToKeep(const clang::ClassTemplateDecl *templ) const
Get from the map the number of arguments to keep.
TNormalizedCtxt::Config_t Config_t
TNormalizedCtxtImpl(const cling::LookupHelper &lh)
Initialize the list of typedef to keep (i.e.
TNormalizedCtxt::TypesCont_t TypesCont_t
void AddTemplAndNargsToKeep(const clang::ClassTemplateDecl *templ, unsigned int i)
Add to the internal map the pointer of a template as key and the number of template arguments to keep...
void keepTypedef(const cling::LookupHelper &lh, const char *name, bool replace=false)
Insert the type with name into the collection of typedefs to keep.
const TypesCont_t & GetTypeWithAlternative() const
const TemplPtrIntMap_t GetTemplNargsToKeepMap() const
static TemplPtrIntMap_t fTemplatePtrArgsToKeepMap
void AddTemplAndNargsToKeep(const clang::ClassTemplateDecl *templ, unsigned int i)
void keepTypedef(const cling::LookupHelper &lh, const char *name, bool replace=false)
cling::utils::Transform::Config Config_t
std::map< const clang::ClassTemplateDecl *, int > TemplPtrIntMap_t
TNormalizedCtxt(const cling::LookupHelper &lh)
TNormalizedCtxtImpl * fImpl
const TypesCont_t & GetTypeWithAlternative() const
std::set< const clang::Type * > TypesCont_t
int GetNargsToKeep(const clang::ClassTemplateDecl *templ) const
const Config_t & GetConfig() const
const TemplPtrIntMap_t GetTemplNargsToKeepMap() const
TIterator begin()
#define I(x, y, z)
const std::string & GetPathSeparator()
int EncloseInNamespaces(const clang::Decl &decl, std::string &defString)
Take the namespaces which enclose the decl and put them around the definition string.
int FwdDeclFromTypeDefNameDecl(const clang::TypedefNameDecl &tdnDecl, const cling::Interpreter &interpreter, std::string &fwdDeclString, std::unordered_set< std::string > *fwdDeclSet=nullptr)
Extract "forward declaration" of a typedef.
int PrepareArgsForFwdDecl(std::string &templateArgs, const clang::TemplateParameterList &tmplParamList, const cling::Interpreter &interpreter)
Loop over the template parameters and build a string for template arguments using the fully qualified...
int FwdDeclFromTmplDecl(const clang::TemplateDecl &tmplDecl, const cling::Interpreter &interpreter, std::string &defString)
Convert a tmplt decl to its fwd decl.
const clang::RecordDecl * EncloseInScopes(const clang::Decl &decl, std::string &defString)
Take the scopes which enclose the decl and put them around the definition string.
int FwdDeclFromRcdDecl(const clang::RecordDecl &recordDecl, const cling::Interpreter &interpreter, std::string &defString, bool acceptStl=false)
Convert a rcd decl to its fwd decl If this is a template specialisation, treat in the proper way.
int GetDefArg(const clang::ParmVarDecl &par, std::string &valAsString, const clang::PrintingPolicy &pp)
Get the default value as string.
int FwdDeclIfTmplSpec(const clang::RecordDecl &recordDecl, const cling::Interpreter &interpreter, std::string &defString, const std::string &normalizedName)
Convert a tmplt decl to its fwd decl.
const std::string Decls2FwdDecls(const std::vector< const clang::Decl * > &decls, bool(*ignoreFiles)(const clang::PresumedLoc &), const cling::Interpreter &interp, std::string *logs)
bool HasClassDefMacro(const clang::Decl *decl, const cling::Interpreter &interpreter)
Return true if class has any of class declarations like ClassDef, ClassDefNV, ClassDefOverride.
llvm::StringRef GetClassComment(const clang::CXXRecordDecl &decl, clang::SourceLocation *loc, const cling::Interpreter &interpreter)
Return the class comment after the ClassDef: class MyClass { ... ClassDef(MyClass,...
const T * GetAnnotatedRedeclarable(const T *Redecl)
int extractPropertyNameValFromString(const std::string attributeStr, std::string &attrName, std::string &attrValue)
bool hasOpaqueTypedef(clang::QualType instanceType, const TNormalizedCtxt &normCtxt)
Return true if the type is a Double32_t or Float16_t or is a instance template that depends on Double...
EIOCtorCategory CheckConstructor(const clang::CXXRecordDecl *, const RConstructorType &, const cling::Interpreter &interp)
Check if class has constructor of provided type - either default or with single argument.
clang::RecordDecl * GetUnderlyingRecordDecl(clang::QualType type)
bool BeginsWith(const std::string &theString, const std::string &theSubstring)
const clang::FunctionDecl * ClassInfo__HasMethod(const clang::DeclContext *cl, char const *, const cling::Interpreter &interp)
bool GetNameWithinNamespace(std::string &, std::string &, std::string &, clang::CXXRecordDecl const *)
Return true if one of the class' enclosing scope is a namespace and set fullname to the fully qualifi...
const clang::RecordDecl * ExtractEnclosingScopes(const clang::Decl &decl, std::list< std::pair< std::string, unsigned int > > &enclosingSc)
Extract the names and types of containing scopes.
bool HasCustomOperatorNewArrayPlacement(clang::RecordDecl const &, const cling::Interpreter &interp)
return true if we can find a custom operator new with placement
void Error(const char *location, const char *fmt,...)
void WriteClassInit(std::ostream &finalString, const AnnotatedRecordDecl &cl, const clang::CXXRecordDecl *decl, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt, const RConstructorTypes &ctorTypes, bool &needCollectionProxy)
FIXME: a function of 450+ lines!
void Info(const char *location, const char *fmt,...)
int WriteNamespaceHeader(std::ostream &, const clang::RecordDecl *)
int GetClassVersion(const clang::RecordDecl *cl, const cling::Interpreter &interp)
Return the version number of the class or -1 if the function Class_Version does not exist.
clang::QualType GetTypeForIO(const clang::QualType &templateInstanceType, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt, TClassEdit::EModType mode=TClassEdit::kNone)
int extractAttrString(clang::Attr *attribute, std::string &attrString)
Extract attr string.
void GetNormalizedName(std::string &norm_name, const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
Return the type name normalized for ROOT, keeping only the ROOT opaque typedef (Double32_t,...
void WritePointersSTL(const AnnotatedRecordDecl &cl, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt)
Write interface function for STL members.
bool HasNewMerge(clang::CXXRecordDecl const *, const cling::Interpreter &)
Return true if the class has a method Merge(TCollection*,TFileMergeInfo*)
bool CheckPublicFuncWithProto(clang::CXXRecordDecl const *, char const *, char const *, const cling::Interpreter &, bool diagnose)
Return true, if the function (defined by the name and prototype) exists and is public.
std::string GetFileName(const clang::Decl &decl, const cling::Interpreter &interp)
Return the header file to be included to declare the Decl.
clang::ClassTemplateDecl * QualType2ClassTemplateDecl(const clang::QualType &qt)
Extract from a qualtype the class template if this makes sense.
int IsSTLContainer(const AnnotatedRecordDecl &annotated)
Is this an STL container.
void Fatal(const char *location, const char *fmt,...)
std::list< RConstructorType > RConstructorTypes
int extractPropertyNameVal(clang::Attr *attribute, std::string &attrName, std::string &attrValue)
std::string GetModuleFileName(const char *moduleName)
Return the dictionary file name for a module.
clang::QualType ReSubstTemplateArg(clang::QualType input, const clang::Type *instance)
Check if 'input' or any of its template parameter was substituted when instantiating the class templa...
bool NeedDestructor(clang::CXXRecordDecl const *, const cling::Interpreter &)
bool EndsWith(const std::string &theString, const std::string &theSubstring)
void GetFullyQualifiedTypeName(std::string &name, const clang::QualType &type, const cling::Interpreter &interpreter)
bool NeedTemplateKeyword(clang::CXXRecordDecl const *)
bool HasCustomConvStreamerMemberFunction(const AnnotatedRecordDecl &cl, const clang::CXXRecordDecl *clxx, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt)
Return true if the class has a custom member function streamer.
bool HasDirectoryAutoAdd(clang::CXXRecordDecl const *, const cling::Interpreter &)
Return true if the class has a method DirectoryAutoAdd(TDirectory *)
const clang::FunctionDecl * GetFuncWithProto(const clang::Decl *cinfo, const char *method, const char *proto, const cling::Interpreter &gInterp, bool diagnose)
int ElementStreamer(std::ostream &finalString, const clang::NamedDecl &forcontext, const clang::QualType &qti, const char *t, int rwmode, const cling::Interpreter &interp, const char *tcl=nullptr)
bool MatchWithDeclOrAnyOfPrevious(const clang::CXXRecordDecl &cl, const clang::CXXRecordDecl &currentCl)
This is a recursive function.
clang::QualType GetNormalizedType(const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
Return the type normalized for ROOT, keeping only the ROOT opaque typedef (Double32_t,...
const char * ShortTypeName(const char *typeDesc)
Return the absolute type of typeDesc.
void GetCppName(std::string &output, const char *input)
Return (in the argument 'output') a valid name of the C++ symbol/type (pass as 'input') that can be u...
bool HasCustomOperatorNewPlacement(char const *, clang::RecordDecl const &, const cling::Interpreter &)
return true if we can find a custom operator new with placement
bool IsStdClass(const clang::RecordDecl &cl)
Return true, if the decl is part of the std namespace.
bool HasResetAfterMerge(clang::CXXRecordDecl const *, const cling::Interpreter &)
Return true if the class has a method ResetAfterMerge(TFileMergeInfo *)
ROOT::ESTLType STLKind(const llvm::StringRef type)
Converts STL container name to number. vector -> 1, etc..
void WriteClassCode(CallWriteStreamer_t WriteStreamerFunc, const AnnotatedRecordDecl &cl, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt, std::ostream &finalString, const RConstructorTypes &ctorTypes, bool isGenreflex)
Generate the code of the class If the requestor is genreflex, request the new streamer format.
bool HasOldMerge(clang::CXXRecordDecl const *, const cling::Interpreter &)
Return true if the class has a method Merge(TCollection*)
clang::TemplateName ExtractTemplateNameFromQualType(const clang::QualType &qt)
These manipulations are necessary because a template specialisation type does not inherit from a reco...
int RemoveTemplateArgsFromName(std::string &name, unsigned int)
Remove the last n template arguments from the name.
long GetLineNumber(clang::Decl const *)
It looks like the template specialization decl actually contains less information on the location of ...
void WriteAuxFunctions(std::ostream &finalString, const AnnotatedRecordDecl &cl, const clang::CXXRecordDecl *decl, const cling::Interpreter &interp, const RConstructorTypes &ctorTypes, const TNormalizedCtxt &normCtxt)
std::string NormalizedName; GetNormalizedName(NormalizedName, decl->getASTContext()....
void foreachHeaderInModule(const clang::Module &module, const std::function< void(const clang::Module::Header &)> &closure, bool includeDirectlyUsedModules=true)
Calls the given lambda on every header in the given module.
bool IsBase(const clang::CXXRecordDecl *cl, const clang::CXXRecordDecl *base, const clang::CXXRecordDecl *context, const cling::Interpreter &interp)
void ExtractCtxtEnclosingNameSpaces(const clang::DeclContext &, std::list< std::pair< std::string, bool > > &)
Extract enclosing namespaces recursively.
std::pair< bool, int > GetTrivialIntegralReturnValue(const clang::FunctionDecl *funcCV, const cling::Interpreter &interp)
If the function contains 'just': return SomeValue; this routine will extract this value and return it...
bool HasCustomStreamerMemberFunction(const AnnotatedRecordDecl &cl, const clang::CXXRecordDecl *clxx, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt)
Return true if the class has a custom member function streamer.
std::string GetRealPath(const std::string &path)
clang::QualType AddDefaultParameters(clang::QualType instanceType, const cling::Interpreter &interpret, const TNormalizedCtxt &normCtxt)
Add any unspecified template parameters to the class template instance, mentioned anywhere in the typ...
std::pair< std::string, clang::QualType > GetNameTypeForIO(const clang::QualType &templateInstanceType, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt, TClassEdit::EModType mode=TClassEdit::kNone)
void GetQualifiedName(std::string &qual_name, const clang::QualType &type, const clang::NamedDecl &forcontext)
Main implementation relying on GetFullyQualifiedTypeName All other GetQualifiedName functions leverag...
bool ExtractAttrIntPropertyFromName(const clang::Decl &decl, const std::string &propName, int &propValue)
This routine counts on the "propName<separator>propValue" format.
bool IsLinkdefFile(const char *filename)
llvm::StringRef GetComment(const clang::Decl &decl, clang::SourceLocation *loc=nullptr)
Returns the comment (// striped away), annotating declaration in a meaningful for ROOT IO way.
void SetPathsForRelocatability(std::vector< std::string > &clingArgs)
Organise the parameters for cling in order to guarantee relocatability It treats the gcc toolchain an...
bool IsStreamableObject(const clang::FieldDecl &m, const cling::Interpreter &interp)
void ReplaceAll(std::string &str, const std::string &from, const std::string &to, bool recurse=false)
bool QualType2Template(const clang::QualType &qt, clang::ClassTemplateDecl *&ctd, clang::ClassTemplateSpecializationDecl *&ctsd)
Get the template specialisation decl and template decl behind the qualtype Returns true if successful...
std::string TrueName(const clang::FieldDecl &m)
TrueName strips the typedefs and array dimensions.
const clang::Type * GetUnderlyingType(clang::QualType type)
Return the base/underlying type of a chain of array or pointers type.
ROOT::ESTLType IsSTLCont(const clang::RecordDecl &cl)
type : type name: vector<list<classA,allocator>,allocator> result: 0 : not stl container abs(result):...
bool IsStdDropDefaultClass(const clang::RecordDecl &cl)
Return true, if the decl is part of the std namespace and we want its default parameter dropped.
bool RequireCompleteType(const cling::Interpreter &interp, const clang::CXXRecordDecl *cl)
bool IsHeaderName(const std::string &filename)
void Warning(const char *location, const char *fmt,...)
bool IsOfType(const clang::CXXRecordDecl &cl, const std::string &type, const cling::LookupHelper &lh)
const std::string & GetPathSeparator()
Return the separator suitable for this platform.
bool CheckDefaultConstructor(const clang::CXXRecordDecl *, const cling::Interpreter &interp)
Checks if default constructor exists and accessible.
EIOCtorCategory CheckIOConstructor(const clang::CXXRecordDecl *, const char *, const clang::CXXRecordDecl *, const cling::Interpreter &interp)
Checks IO constructor - must be public and with specified argument.
bool ExtractAttrPropertyFromName(const clang::Decl &decl, const std::string &propName, std::string &propValue)
This routine counts on the "propName<separator>propValue" format.
const clang::CXXRecordDecl * ScopeSearch(const char *name, const cling::Interpreter &gInterp, bool diagnose, const clang::Type **resultType)
Return the scope corresponding to 'name' or std::'name'.
int & GetErrorIgnoreLevel()
void ExtractEnclosingNameSpaces(const clang::Decl &, std::list< std::pair< std::string, bool > > &)
Extract the immediately outer namespace and then launch the recursion.
bool HasIOConstructor(clang::CXXRecordDecl const *, std::string &, const RConstructorTypes &, const cling::Interpreter &)
return true if we can find an constructor calleable without any arguments or with one the IOCtor spec...
llvm::StringRef DataMemberInfo__ValidArrayIndex(const cling::Interpreter &interp, const clang::DeclaratorDecl &m, int *errnum=nullptr, llvm::StringRef *errstr=nullptr)
ValidArrayIndex return a static string (so use it or copy it immediatly, do not call GrabIndex twice ...
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
void WriteSchemaList(std::list< SchemaRuleMap_t > &rules, const std::string &listName, std::ostream &output)
Write schema rules.
std::map< std::string, ROOT::Internal::TSchemaType > MembersTypeMap_t
ESTLType
Definition ESTLType.h:28
@ kSTLbitset
Definition ESTLType.h:37
@ kSTLmap
Definition ESTLType.h:33
@ kSTLunorderedmultiset
Definition ESTLType.h:43
@ kROOTRVec
Definition ESTLType.h:46
@ kSTLend
Definition ESTLType.h:47
@ kSTLset
Definition ESTLType.h:35
@ kSTLmultiset
Definition ESTLType.h:36
@ kSTLdeque
Definition ESTLType.h:32
@ kSTLvector
Definition ESTLType.h:30
@ kSTLunorderedmultimap
Definition ESTLType.h:45
@ kSTLunorderedset
Definition ESTLType.h:42
@ kSTLlist
Definition ESTLType.h:31
@ kSTLforwardlist
Definition ESTLType.h:41
@ kSTLunorderedmap
Definition ESTLType.h:44
@ kNotSTL
Definition ESTLType.h:29
@ kSTLmultimap
Definition ESTLType.h:34
void WriteReadRuleFunc(SchemaRuleMap_t &rule, int index, std::string &mappedName, MembersTypeMap_t &members, std::ostream &output)
Write the conversion function for Read rule, the function name is being written to rule["funcname"].
R__EXTERN SchemaRuleClassMap_t gReadRules
bool HasValidDataMembers(SchemaRuleMap_t &rule, MembersTypeMap_t &members, std::string &error_string)
Check if given rule contains references to valid data members.
void WriteReadRawRuleFunc(SchemaRuleMap_t &rule, int index, std::string &mappedName, MembersTypeMap_t &members, std::ostream &output)
Write the conversion function for ReadRaw rule, the function name is being written to rule["funcname"...
R__EXTERN SchemaRuleClassMap_t gReadRawRules
ROOT::ESTLType STLKind(std::string_view type)
Converts STL container name to number.
bool IsStdClass(const char *type)
return true if the class belongs to the std namespace
std::string GetLong64_Name(const char *original)
Replace 'long long' and 'unsigned long long' by 'Long64_t' and 'ULong64_t'.
ROOT::ESTLType IsSTLCont(std::string_view type)
type : type name: vector<list<classA,allocator>,allocator> result: 0 : not stl container code of cont...
char * DemangleName(const char *mangled_name, int &errorCode)
Definition TClassEdit.h:208
std::string GetNameForIO(const std::string &templateInstanceName, TClassEdit::EModType mode=TClassEdit::kNone, bool *hasChanged=nullptr)
@ kKeepOuterConst
Definition TClassEdit.h:87
@ kDropStlDefault
Definition TClassEdit.h:82
bool IsSTLBitset(const char *type)
Return true is the name is std::bitset<number> or bitset<number>
constexpr Double_t C()
Velocity of light in .
Definition TMath.h:114
static const char * what
Definition stlLoader.cc:5
void ShortType(std::string &answer, int mode)
Return the absolute type of typeDesc into the string answ.
TMarker m
Definition textangle.C:8
auto * tt
Definition textangle.C:16