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