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