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