Logo ROOT  
Reference Guide
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>
28 #include <ROOT/FoundationUtils.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 
70 namespace ROOT {
71 namespace TMetaUtils {
72 
73 std::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 
83 class 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;
88 private:
89  Config_t fConfig;
90  TypesCont_t fTypeWithAlternative;
91  static TemplPtrIntMap_t fTemplatePtrArgsToKeepMap;
92 public:
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 
106 namespace {
107 
108 ////////////////////////////////////////////////////////////////////////////////
109 /// Add default parameter to the scope if needed.
110 
111 static 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 
138 static 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 
160 static 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 
184 static 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 
196 static 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 
204 static 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 
219 static 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 
260 static 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 
277 static
278 cling::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 
287 namespace ROOT {
288 namespace 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 
294 void 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 
323 int 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 
333 TNormalizedCtxt::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 }
350 void TNormalizedCtxt::AddTemplAndNargsToKeep(const clang::ClassTemplateDecl* templ, unsigned int i)
351 {
352  return fImpl->AddTemplAndNargsToKeep(templ, i);
353 }
354 int TNormalizedCtxt::GetNargsToKeep(const clang::ClassTemplateDecl* templ) const
355 {
356  return fImpl->GetNargsToKeep(templ);
357 }
359  return fImpl->GetTemplNargsToKeepMap();
360 }
361 void TNormalizedCtxt::keepTypedef(const cling::LookupHelper &lh, const char* name,
362  bool replace /*= false*/)
363 {
364  return fImpl->keepTypedef(lh, name, replace);
365 }
366 
367 std::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 
531 TClingLookupHelper::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 
549 bool 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 
592 bool 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 
708 void 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 
732 ROOT::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 
756 using TNCtxtFullQual = ROOT::TMetaUtils::TNormalizedCtxtImpl;
757 TNCtxtFullQual::TemplPtrIntMap_t TNCtxtFullQual::fTemplatePtrArgsToKeepMap=TNCtxtFullQual::TemplPtrIntMap_t{};
758 
759 ////////////////////////////////////////////////////////////////////////////////
760 
761 inline 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 
770 const 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 
783 const clang::CXXRecordDecl *
784 ROOT::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 
807 bool 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 
815 bool 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 
826 bool 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 
850 bool 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 
869 int 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 
1048 bool 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 
1146 const 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 
1164 namespace 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 
1184 bool 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 
1230 bool 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 
1251 bool 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 
1267 bool 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 
1282 bool 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 
1296 bool 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 
1311 bool 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 
1368 void 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 //----
1374 std::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 
1386 void 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 //---
1395 std::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 
1418 void 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 //----
1435 std::string ROOT::TMetaUtils::GetQualifiedName(const clang::NamedDecl &cl){
1436  std::string result;
1438  return result;
1439 }
1440 
1441 
1442 ////////////////////////////////////////////////////////////////////////////////
1443 
1444 void 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 //----
1454 std::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 
1479 void 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 
1525 const 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 
1565 long 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).second;
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 
1590 bool 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 
1663 int 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 
1676 int 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 
1693 int 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 ~300 lines!
1748 
1749 void 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;
2017  case ROOT::kSTLforwardlist:
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 sincelast
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 Altenate 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 
2211 bool ROOT::TMetaUtils::GetNameWithinNamespace(std::string &fullname,
2212  std::string &clsname,
2213  std::string &nsname,
2214  const clang::CXXRecordDecl *cl)
2215 {
2216  fullname.clear();
2217  nsname.clear();
2218 
2219  ROOT::TMetaUtils::GetQualifiedName(fullname,*cl);
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 
2244 const 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 
2260 int 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 
2283 int ROOT::TMetaUtils::WriteNamespaceHeader(std::ostream &out, const clang::RecordDecl *cl)
2284 {
2285  return WriteNamespaceHeader(out, GetEnclosingSpace(*cl));
2286 }
2287 
2288 ////////////////////////////////////////////////////////////////////////////////
2289 
2290 bool 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 
2308 bool 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 
2388 bool 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 
2396 bool 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 
2405 void 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 
2569 std::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 
2585 int 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 
2611 std::pair<bool, int>
2612 ROOT::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 
2669 int 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.
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 
2734 const 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 
2766 bool 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 
2824 std::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 
2842 clang::RecordDecl *ROOT::TMetaUtils::GetUnderlyingRecordDecl(clang::QualType type)
2843 {
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 
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 
2906 clang::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 
3129 llvm::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
3138  title = ROOT::TMetaUtils::GetComment( m );
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 
3278 void 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 
3326 static clang::SourceLocation
3327 getFinalSpellingLoc(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).second;
3332  }
3333  return sourceLoc;
3334 }
3335 
3336 ////////////////////////////////////////////////////////////////////////////////
3337 /// Return the header file to be included to declare the Decl.
3338 
3339 llvm::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/*IsMapped*/, 0/*RequestingModule*/, 0/*SuggestedModule*/,
3398  false /*SkipCache*/,
3399  false /*BuildSystemModule*/,
3400  false /*OpenFile*/, true /*CacheFailures*/);
3401  if (FEhdr) break;
3402  headerFID = sourceManager.getFileID(includeLoc);
3403  headerFE = sourceManager.getFileEntryForID(headerFID);
3404  // If we have a system header in a module we can't just trace back the
3405  // original include with the preprocessor. But it should be enough if
3406  // we trace it back to the top-level system header that includes this
3407  // declaration.
3408  if (interp.getCI()->getLangOpts().Modules && !headerFE) {
3409  assert(decl.isFirstDecl() && "Couldn't trace back include from a decl"
3410  " that is not from an AST file");
3411  assert(StringRef(includeLoc.printToString(sourceManager)).startswith("<module-includes>"));
3412  break;
3413  }
3414  includeLoc = getFinalSpellingLoc(sourceManager,
3415  sourceManager.getIncludeLoc(headerFID));
3416  }
3417 
3418  if (!headerFE) return invalidFilename;
3419  llvm::StringRef headerFileName = headerFE->getName();
3420 
3421  // Now headerFID references the last valid system header or the original
3422  // user file.
3423  // Find out how to include it by matching file name to include paths.
3424  // We assume that the file "/A/B/C/D.h" can at some level be included as
3425  // "C/D.h". Be we cannot know whether that happens to be a different file
3426  // with the same name. Thus we first find the longest stem that can be
3427  // reached, say B/C/D.h. Then we find the shortest one, say C/D.h, that
3428  // points to the same file as the long version. If such a short version
3429  // exists it will be returned. If it doesn't the long version is returned.
3430  bool isAbsolute = llvm::sys::path::is_absolute(headerFileName);
3431  const FileEntry* FELong = 0;
3432  // Find the longest available match.
3433  for (llvm::sys::path::const_iterator
3434  IDir = llvm::sys::path::begin(headerFileName),
3435  EDir = llvm::sys::path::end(headerFileName);
3436  !FELong && IDir != EDir; ++IDir) {
3437  if (isAbsolute) {
3438  // skip "/" part
3439  isAbsolute = false;
3440  continue;
3441  }
3442  size_t lenTrailing = headerFileName.size() - (IDir->data() - headerFileName.data());
3443  llvm::StringRef trailingPart(IDir->data(), lenTrailing);
3444  assert(trailingPart.data() + trailingPart.size()
3445  == headerFileName.data() + headerFileName.size()
3446  && "Mismatched partitioning of file name!");
3447  const DirectoryLookup* FoundDir = 0;
3448  FELong = HdrSearch.LookupFile(trailingPart, SourceLocation(),
3449  true /*isAngled*/, 0/*FromDir*/, FoundDir,
3450  ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>>(),
3451  0/*IsMapped*/, 0/*Searchpath*/, 0/*RelPath*/,
3452  0/*RequestingModule*/, 0/*SuggestedModule*/);
3453  }
3454 
3455  if (!FELong) {
3456  // We did not find any file part in any search path.
3457  return invalidFilename;
3458  }
3459 
3460  // Iterates through path *parts* "C"; we need trailing parts "C/D.h"
3461  for (llvm::sys::path::reverse_iterator
3462  IDir = llvm::sys::path::rbegin(headerFileName),
3463  EDir = llvm::sys::path::rend(headerFileName);
3464  IDir != EDir; ++IDir) {
3465  size_t lenTrailing = headerFileName.size() - (IDir->data() - headerFileName.data());
3466  llvm::StringRef trailingPart(IDir->data(), lenTrailing);
3467  assert(trailingPart.data() + trailingPart.size()
3468  == headerFileName.data() + headerFileName.size()
3469  && "Mismatched partitioning of file name!");
3470  const DirectoryLookup* FoundDir = 0;
3471  // Can we find it, and is it the same file as the long version?
3472  // (or are we back to the previously found spelling, which is fine, too)
3473  if (HdrSearch.LookupFile(trailingPart, SourceLocation(),
3474  true /*isAngled*/, 0/*FromDir*/, FoundDir,
3475  ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>>(),
3476  0/*IsMapped*/,
3477  0/*Searchpath*/,
3478  0/*RelPath*/,
3479  0/*RequestingModule*/, 0 /*SuggestedModule*/) == FELong) {
3480  return trailingPart;
3481  }
3482  }
3483 
3484  return invalidFilename;
3485 }
3486 
3487 ////////////////////////////////////////////////////////////////////////////////
3488 
3489 void ROOT::TMetaUtils::GetFullyQualifiedTypeName(std::string &typenamestr,
3490  const clang::QualType &qtype,
3491  const clang::ASTContext &astContext)
3492 {
3493  std::string fqname = cling::utils::TypeName::GetFullyQualifiedName(qtype, astContext);
3494  TClassEdit::TSplitType splitname(fqname.c_str(),
3497 }
3498 
3499 ////////////////////////////////////////////////////////////////////////////////
3500 
3501 void ROOT::TMetaUtils::GetFullyQualifiedTypeName(std::string &typenamestr,
3502  const clang::QualType &qtype,
3503  const cling::Interpreter &interpreter)
3504 {
3505  // We need this because GetFullyQualifiedTypeName is triggering deserialization
3506  // This calling the same name function GetFullyQualifiedTypeName, but this should stay here because
3507  // callee doesn't have an interpreter pointer
3508  cling::Interpreter::PushTransactionRAII RAII(const_cast<cling::Interpreter*>(&interpreter));
3509 
3510  GetFullyQualifiedTypeName(typenamestr,
3511  qtype,
3512  interpreter.getCI()->getASTContext());
3513 }
3514 
3515 ////////////////////////////////////////////////////////////////////////////////
3516 /// Get the template specialisation decl and template decl behind the qualtype
3517 /// Returns true if successfully found, false otherwise
3518 
3519 bool ROOT::TMetaUtils::QualType2Template(const clang::QualType& qt,
3520  clang::ClassTemplateDecl*& ctd,
3521  clang::ClassTemplateSpecializationDecl*& ctsd)
3522 {
3523  using namespace clang;
3524  const Type* theType = qt.getTypePtr();
3525  if (!theType){
3526  ctd=nullptr;
3527  ctsd=nullptr;
3528  return false;
3529  }
3530 
3531  if (theType->isPointerType()) {
3532  return QualType2Template(theType->getPointeeType(), ctd, ctsd);
3533  }
3534 
3535  if (const RecordType* rType = llvm::dyn_cast<RecordType>(theType)) {
3536  ctsd = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(rType->getDecl());
3537  if (ctsd) {
3538  ctd = ctsd->getSpecializedTemplate();
3539  return true;
3540  }
3541  }
3542 
3543  if (const SubstTemplateTypeParmType* sttpType = llvm::dyn_cast<SubstTemplateTypeParmType>(theType)){
3544  return QualType2Template(sttpType->getReplacementType(), ctd, ctsd);
3545  }
3546 
3547 
3548  ctsd = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(qt->getAsCXXRecordDecl());
3549  if(ctsd){
3550  ctd = ctsd->getSpecializedTemplate();
3551  return true;
3552  }
3553 
3554  ctd=nullptr;
3555  ctsd=nullptr;
3556  return false;
3557 }
3558 
3559 ////////////////////////////////////////////////////////////////////////////////
3560 /// Extract from a qualtype the class template if this makes sense.
3561 /// Retuns the ClassTemplateDecl or nullptr otherwise.
3562 
3563 clang::ClassTemplateDecl* ROOT::TMetaUtils::QualType2ClassTemplateDecl(const clang::QualType& qt)
3564 {
3565  using namespace clang;
3566  ClassTemplateSpecializationDecl* ctsd;
3567  ClassTemplateDecl* ctd;
3568  QualType2Template(qt,ctd,ctsd);
3569  return ctd;
3570 }
3571 
3572 ////////////////////////////////////////////////////////////////////////////////
3573 /// These manipulations are necessary because a template specialisation type
3574 /// does not inherit from a record type (there is an asymmetry between
3575 /// the decls and the types in the clang interface).
3576 /// We may need therefore to step into the "Decl dimension" to then get back
3577 /// to the "type dimension".
3578 
3579 clang::TemplateName ROOT::TMetaUtils::ExtractTemplateNameFromQualType(const clang::QualType& qt)
3580 {
3581  using namespace clang;
3582  TemplateName theTemplateName;
3583 
3584  const Type* theType = qt.getTypePtr();
3585 
3586  if (const TemplateSpecializationType* tst = llvm::dyn_cast_or_null<const TemplateSpecializationType>(theType)) {
3587  theTemplateName = tst->getTemplateName();
3588  } // We step into the decl dimension
3589  else if (ClassTemplateDecl* ctd = QualType2ClassTemplateDecl(qt)) {
3590  theTemplateName = TemplateName(ctd);
3591  }
3592 
3593  return theTemplateName;
3594 }
3595 
3596 ////////////////////////////////////////////////////////////////////////////////
3597 
3598 static bool areEqualTypes(const clang::TemplateArgument& tArg,
3599  llvm::SmallVectorImpl<clang::TemplateArgument>& preceedingTArgs,
3600  const clang::NamedDecl& tPar,
3601  const cling::Interpreter& interp,
3602  const ROOT::TMetaUtils::TNormalizedCtxt& normCtxt)
3603 {
3604  using namespace ROOT::TMetaUtils;
3605  using namespace clang;
3606 
3607  // Check if this is a type for security
3608  TemplateTypeParmDecl* ttpdPtr = const_cast<TemplateTypeParmDecl*>(llvm::dyn_cast<TemplateTypeParmDecl>(&tPar));
3609  if (!ttpdPtr) return false;
3610  if (!ttpdPtr->hasDefaultArgument()) return false; // we should not be here in this case, but we protect us.
3611 
3612  // Try the fast solution
3613  QualType tParQualType = ttpdPtr->getDefaultArgument();
3614  const QualType tArgQualType = tArg.getAsType();
3615 
3616  // Now the equality tests for non template specialisations.
3617 
3618  // The easy cases:
3619  // template <class T=double> class A; or
3620  // template <class T=A<float>> class B;
3621  if (tParQualType.getTypePtr() == tArgQualType.getTypePtr()) return true;
3622 
3623  // Here the difficulty comes. We have to check if the argument is equal to its
3624  // default. We can do that bootstrapping an argument which has the default value
3625  // based on the preceeding arguments.
3626  // Basically we ask sema to give us the value of the argument given the template
3627  // of behind the parameter and the all the arguments.
3628  // So:
3629 
3630  // Take the template out of the parameter
3631 
3632  const clang::ElaboratedType* etype
3633  = llvm::dyn_cast<clang::ElaboratedType>(tParQualType.getTypePtr());
3634  while (etype) {
3635  tParQualType = clang::QualType(etype->getNamedType().getTypePtr(),0);
3636  etype = llvm::dyn_cast<clang::ElaboratedType>(tParQualType.getTypePtr());
3637  }
3638 
3639  const TemplateSpecializationType* tst =
3640  llvm::dyn_cast<TemplateSpecializationType>(tParQualType.getTypePtr());
3641 
3642  if(!tst) // nothing more to be tried. They are different indeed.
3643  return false;
3644 
3645  ClassTemplateSpecializationDecl* TSTdecl
3646  = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(tArgQualType->getAsCXXRecordDecl());
3647 
3648  if(!TSTdecl) // nothing more to be tried. They are different indeed.
3649  return false;
3650 
3651  TemplateDecl *Template = tst->getTemplateName().getAsTemplateDecl();
3652 
3653  // Take the template location
3654  SourceLocation TemplateLoc = Template->getSourceRange ().getBegin();
3655 
3656  // Get the position of the "<" (LA) of the specializaion
3657  SourceLocation LAngleLoc = TSTdecl->getSourceRange().getBegin();
3658 
3659 
3660  // Enclose in a scope for the RAII
3661  bool isEqual=false;
3662  TemplateArgument newArg = tArg;
3663  {
3664  clang::Sema& S = interp.getCI()->getSema();
3665  cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interp));
3666  clang::sema::HackForDefaultTemplateArg raii; // Hic sunt leones
3667  bool HasDefaultArgs;
3668  TemplateArgumentLoc defTArgLoc = S.SubstDefaultTemplateArgumentIfAvailable(Template,
3669  TemplateLoc,
3670  LAngleLoc,
3671  ttpdPtr,
3672  preceedingTArgs,
3673  HasDefaultArgs);
3674  // The substition can fail, in which case there would have been compilation
3675  // error printed on the screen.
3676  newArg = defTArgLoc.getArgument();
3677  if (newArg.isNull() ||
3678  newArg.getKind() != clang::TemplateArgument::Type) {
3679  ROOT::TMetaUtils::Error("areEqualTypes",
3680  "Template parameter substitution failed!");
3681  }
3682 
3683  ClassTemplateSpecializationDecl* nTSTdecl
3684  = llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(newArg.getAsType()->getAsCXXRecordDecl());
3685 // std::cout << "nSTdecl is " << nTSTdecl << std::endl;
3686 
3687  isEqual = nTSTdecl->getMostRecentDecl() == TSTdecl->getMostRecentDecl() ||
3688  tParQualType.getTypePtr() == newArg.getAsType().getTypePtr();
3689  }
3690 
3691 
3692  return isEqual;
3693 }
3694 
3695 
3696 ////////////////////////////////////////////////////////////////////////////////
3697 /// std::cout << "Are equal values?\n";
3698 
3699 static bool areEqualValues(const clang::TemplateArgument& tArg,
3700  const clang::NamedDecl& tPar)
3701 {
3702  using namespace clang;
3703  const NonTypeTemplateParmDecl* nttpdPtr = llvm::dyn_cast<NonTypeTemplateParmDecl>(&tPar);
3704  if (!nttpdPtr) return false;
3705  const NonTypeTemplateParmDecl& nttpd = *nttpdPtr;
3706 
3707  if (!nttpd.hasDefaultArgument())
3708  return false;
3709 
3710  // 64 bits wide and signed (non unsigned, that is why "false")
3711  llvm::APSInt defaultValueAPSInt(64, false);
3712  if (Expr* defArgExpr = nttpd.getDefaultArgument()) {
3713  const ASTContext& astCtxt = nttpdPtr->getASTContext();
3714  defArgExpr->isIntegerConstantExpr(defaultValueAPSInt, astCtxt);
3715  }
3716 
3717  const int value = tArg.getAsIntegral().getLimitedValue();
3718 
3719  // std::cout << (value == defaultValueAPSInt ? "yes!":"no") << std::endl;
3720  return value == defaultValueAPSInt;
3721 }
3722 
3723 ////////////////////////////////////////////////////////////////////////////////
3724 /// Check if this NamedDecl is a template parameter with a default argument.
3725 /// This is a single interface to treat both integral and type parameters.
3726 /// Returns true if this is the case, false otherwise
3727 
3728 static bool isTypeWithDefault(const clang::NamedDecl* nDecl)
3729 {
3730  using namespace clang;
3731  if (!nDecl) return false;
3732  if (const TemplateTypeParmDecl* ttpd = llvm::dyn_cast<TemplateTypeParmDecl>(nDecl))
3733  return ttpd->hasDefaultArgument();
3734  if (const NonTypeTemplateParmDecl* nttpd = llvm::dyn_cast<NonTypeTemplateParmDecl>(nDecl))
3735  return nttpd->hasDefaultArgument();
3736  return false;
3737 
3738 }
3739 
3740 static void KeepNParams(clang::QualType& normalizedType,
3741  const clang::QualType& vanillaType,
3742  const cling::Interpreter& interp,
3743  const ROOT::TMetaUtils::TNormalizedCtxt& normCtxt);
3744 
3745 // Returns true if normTArg might have changed.
3746 static bool RecurseKeepNParams(clang::TemplateArgument &normTArg,
3747  const clang::TemplateArgument &tArg,
3748  const cling::Interpreter& interp,
3749  const ROOT::TMetaUtils::TNormalizedCtxt& normCtxt,
3750  const clang::ASTContext& astCtxt)
3751 {
3752  using namespace ROOT::TMetaUtils;
3753  using namespace clang;
3754 
3755  // Once we know there is no more default parameter, we can run through to the end
3756  // and/or recurse in the template parameter packs.
3757 
3758  // If this is a type,
3759  // we need first of all to recurse: this argument may need to be manipulated
3760  if (tArg.getKind() == clang::TemplateArgument::Type) {
3761  QualType thisNormQualType = normTArg.getAsType();
3762  QualType thisArgQualType = tArg.getAsType();
3763  KeepNParams(thisNormQualType,
3764  thisArgQualType,
3765  interp,
3766  normCtxt);
3767  normTArg = TemplateArgument(thisNormQualType);
3768  return (thisNormQualType != thisArgQualType);
3769  } else if (normTArg.getKind() == clang::TemplateArgument::Pack) {
3770  assert( tArg.getKind() == clang::TemplateArgument::Pack );
3771 
3772  SmallVector<TemplateArgument, 2> desArgs;
3773  bool mightHaveChanged = true;
3774  for (auto I = normTArg.pack_begin(), E = normTArg.pack_end(),
3775  FI = tArg.pack_begin(), FE = tArg.pack_end();
3776  I != E && FI != FE; ++I, ++FI)
3777  {
3778  TemplateArgument pack_arg(*I);
3779  mightHaveChanged |= RecurseKeepNParams(pack_arg, *FI, interp, normCtxt, astCtxt);
3780  desArgs.push_back(pack_arg);
3781  }
3782  if (mightHaveChanged) {
3783  ASTContext &mutableCtx( const_cast<ASTContext&>(astCtxt) );
3784  normTArg = TemplateArgument::CreatePackCopy(mutableCtx, desArgs);
3785  }
3786  return mightHaveChanged;
3787  }
3788  return false;
3789 }
3790 
3791 
3792 ////////////////////////////////////////////////////////////////////////////////
3793 /// This function allows to manipulate the number of arguments in the type
3794 /// of a template specialisation.
3795 
3796 static void KeepNParams(clang::QualType& normalizedType,
3797  const clang::QualType& vanillaType,
3798  const cling::Interpreter& interp,
3799  const ROOT::TMetaUtils::TNormalizedCtxt& normCtxt)
3800 {
3801  using namespace ROOT::TMetaUtils;
3802  using namespace clang;
3803 
3804  // If this type has no template specialisation behind, we don't need to do
3805  // anything
3806  ClassTemplateSpecializationDecl* ctsd;
3807  ClassTemplateDecl* ctd;
3808  if (! QualType2Template(vanillaType, ctd, ctsd)) return ;
3809 
3810  // Even if this is a template, if we don't keep any argument, return
3811  const int nArgsToKeep = normCtxt.GetNargsToKeep(ctd);
3812 
3813  // Important in case of early return: we must restore the original qualtype
3814  QualType originalNormalizedType = normalizedType;
3815 
3816  const ASTContext& astCtxt = ctsd->getASTContext();
3817 
3818 
3819  // In case of name* we need to strip the pointer first, add the default and attach
3820  // the pointer once again.
3821  if (llvm::isa<clang::PointerType>(normalizedType.getTypePtr())) {
3822  // Get the qualifiers.
3823  clang::Qualifiers quals = normalizedType.getQualifiers();
3824  auto valNormalizedType = normalizedType->getPointeeType();
3825  KeepNParams(valNormalizedType,vanillaType, interp, normCtxt);
3826  normalizedType = astCtxt.getPointerType(valNormalizedType);
3827  // Add back the qualifiers.
3828  normalizedType = astCtxt.getQualifiedType(normalizedType, quals);
3829  return;
3830  }
3831 
3832  // In case of Int_t& we need to strip the pointer first, desugar and attach
3833  // the pointer once again.
3834  if (llvm::isa<clang::ReferenceType>(normalizedType.getTypePtr())) {
3835  // Get the qualifiers.
3836  bool isLValueRefTy = llvm::isa<clang::LValueReferenceType>(normalizedType.getTypePtr());
3837  clang::Qualifiers quals = normalizedType.getQualifiers();
3838  auto valNormType = normalizedType->getPointeeType();
3839  KeepNParams(valNormType, vanillaType, interp, normCtxt);
3840 
3841  // Add the r- or l- value reference type back to the desugared one
3842  if (isLValueRefTy)
3843  normalizedType = astCtxt.getLValueReferenceType(valNormType);
3844  else
3845  normalizedType = astCtxt.getRValueReferenceType(valNormType);
3846  // Add back the qualifiers.
3847  normalizedType = astCtxt.getQualifiedType(normalizedType, quals);
3848  return;
3849  }
3850 
3851  // Treat the Scope (factorise the code out to reuse it in AddDefaultParameters)
3852  bool prefix_changed = false;
3853  clang::NestedNameSpecifier* prefix = nullptr;
3854  clang::Qualifiers prefix_qualifiers = normalizedType.getLocalQualifiers();
3855  const clang::ElaboratedType* etype
3856  = llvm::dyn_cast<clang::ElaboratedType>(normalizedType.getTypePtr());
3857  if (etype) {
3858  // We have to also handle the prefix.
3859  // TODO: we ought to be running KeepNParams
3860  prefix = AddDefaultParametersNNS(astCtxt, etype->getQualifier(), interp, normCtxt);
3861  prefix_changed = prefix != etype->getQualifier();
3862  normalizedType = clang::QualType(etype->getNamedType().getTypePtr(),0);
3863  }
3864 
3865  // The canonical decl does not necessarily have the template default arguments.
3866  // Need to walk through the redecl chain to find it (we know there will be no
3867  // inconsistencies, at least)
3868  const clang::ClassTemplateDecl* ctdWithDefaultArgs = ctd;
3869  for (const RedeclarableTemplateDecl* rd: ctdWithDefaultArgs->redecls()) {
3870  clang::TemplateParameterList* tpl = rd->getTemplateParameters();
3871  if (tpl->getMinRequiredArguments () < tpl->size())
3872  ctdWithDefaultArgs = llvm::dyn_cast<clang::ClassTemplateDecl>(rd);
3873  }
3874  TemplateParameterList* tParsPtr = ctdWithDefaultArgs->getTemplateParameters();
3875  const TemplateParameterList& tPars = *tParsPtr;
3876  const TemplateArgumentList& tArgs = ctsd->getTemplateArgs();
3877 
3878  // We extract the template name from the type
3879  TemplateName theTemplateName = ExtractTemplateNameFromQualType(normalizedType);
3880  if (theTemplateName.isNull()) {
3881  normalizedType=originalNormalizedType;
3882  return;
3883  }
3884 
3885  const TemplateSpecializationType* normalizedTst =
3886  llvm::dyn_cast<TemplateSpecializationType>(normalizedType.getTypePtr());
3887  if (!normalizedTst) {
3888  normalizedType=originalNormalizedType;
3889  return;
3890  }
3891 
3892  const clang::ClassTemplateSpecializationDecl* TSTdecl
3893  = llvm::dyn_cast_or_null<const clang::ClassTemplateSpecializationDecl>(normalizedType.getTypePtr()->getAsCXXRecordDecl());
3894  bool isStdDropDefault = TSTdecl && IsStdDropDefaultClass(*TSTdecl);
3895 
3896  // Loop over the template parameters and arguments recursively.
3897  // We go down the two lanes: the one of template parameters (decls) and the
3898  // one of template arguments (QualTypes) in parallel. The former are a
3899  // property of the template, independent of its instantiations.
3900  // The latter are a property of the instance itself.
3901  llvm::SmallVector<TemplateArgument, 4> argsToKeep;
3902 
3903  const int nArgs = tArgs.size();
3904  const int nNormArgs = normalizedTst->getNumArgs();
3905 
3906  bool mightHaveChanged = false;
3907 
3908  // becomes true when a parameter has a value equal to its default
3909  for (int formal = 0, inst = 0; formal != nArgs; ++formal, ++inst) {
3910  const NamedDecl* tParPtr = tPars.getParam(formal);
3911  if (!tParPtr) {
3912  Error("KeepNParams", "The parameter number %s is null.\n", formal);
3913  continue;
3914  }
3915 
3916  // Stop if the normalized TemplateSpecializationType has less arguments than
3917  // the one index is pointing at.
3918  // We piggy back on the AddDefaultParameters routine basically.
3919  if (formal == nNormArgs || inst == nNormArgs) break;
3920 
3921  const TemplateArgument& tArg = tArgs.get(formal);
3922  TemplateArgument normTArg(normalizedTst->getArgs()[inst]);
3923 
3924  bool shouldKeepArg = nArgsToKeep < 0 || inst < nArgsToKeep;
3925  if (isStdDropDefault) shouldKeepArg = false;
3926 
3927  // Nothing to do here: either this parameter has no default, or we have to keep it.
3928  // FIXME: Temporary measure to get Atlas started with this.
3929  // We put a hard cut on the number of template arguments to keep, w/o checking if
3930  // they are non default. This makes this feature UNUSABLE for cases like std::vector,
3931  // where 2 different entities would have the same name if an allocator different from
3932  // the default one is by chance used.
3933  if (!isTypeWithDefault(tParPtr) || shouldKeepArg) {
3934  if ( tParPtr->isTemplateParameterPack() ) {
3935  // This is the last template parameter in the template declaration
3936  // but it is signaling that there can be an arbitrary number of arguments
3937  // in the template instance. So to avoid inadvertenly dropping those
3938  // arguments we just process all remaining argument and exit the main loop.
3939  for( ; inst != nNormArgs; ++inst) {
3940  normTArg = normalizedTst->getArgs()[inst];
3941  mightHaveChanged |= RecurseKeepNParams(normTArg, tArg, interp, normCtxt, astCtxt);
3942  argsToKeep.push_back(normTArg);
3943  }
3944  // Done.
3945  break;
3946  }
3947  mightHaveChanged |= RecurseKeepNParams(normTArg, tArg, interp, normCtxt, astCtxt);
3948  argsToKeep.push_back(normTArg);
3949  continue;
3950  } else {
3951  if (!isStdDropDefault) {
3952  // Here we should not break but rather check if the value is the default one.
3953  mightHaveChanged = true;
3954  break;
3955  }
3956  // For std, we want to check the default args values.
3957  }
3958 
3959  // Now, we keep it only if it not is equal to its default, expressed in the arg
3960  // Some gymnastic is needed to decide how to check for equality according to the
3961  // flavour of Type: templateType or Integer
3962  bool equal=false;
3963  auto argKind = tArg.getKind();
3964  if (argKind == clang::TemplateArgument::Type){
3965  // we need all the info
3966  equal = areEqualTypes(tArg, argsToKeep, *tParPtr, interp, normCtxt);
3967  } else if (argKind == clang::TemplateArgument::Integral){
3968  equal = areEqualValues(tArg, *tParPtr);
3969  }
3970  if (!equal) {
3971  mightHaveChanged |= RecurseKeepNParams(normTArg, tArg, interp, normCtxt, astCtxt);
3972  argsToKeep.push_back(normTArg);
3973  } else {
3974  mightHaveChanged = true;
3975  }
3976 
3977 
3978  } // of loop over parameters and arguments
3979 
3980  if (!prefix_changed && !mightHaveChanged) {
3981  normalizedType = originalNormalizedType;
3982  return;
3983  }
3984 
3985  // now, let's remanipulate our Qualtype
3986  if (mightHaveChanged) {
3987  Qualifiers qualifiers = normalizedType.getLocalQualifiers();
3988  normalizedType = astCtxt.getTemplateSpecializationType(theTemplateName,
3989  argsToKeep,
3990  normalizedType.getTypePtr()->getCanonicalTypeInternal());
3991  normalizedType = astCtxt.getQualifiedType(normalizedType, qualifiers);
3992  }
3993 
3994  // Here we have (prefix_changed==true || mightHaveChanged), in both case
3995  // we need to reconstruct the type.
3996  if (prefix) {
3997  normalizedType = astCtxt.getElaboratedType(clang::ETK_None,prefix,normalizedType);
3998  normalizedType = astCtxt.getQualifiedType(normalizedType,prefix_qualifiers);
3999  }
4000 
4001 }
4002 
4003 ////////////////////////////////////////////////////////////////////////////////
4004 /// Return the type normalized for ROOT,
4005 /// keeping only the ROOT opaque typedef (Double32_t, etc.) and
4006 /// adding default template argument for all types except those explicitly
4007 /// requested to be drop by the user.
4008 /// Default template for STL collections are not yet removed by this routine.
4009 
4010 clang::QualType ROOT::TMetaUtils::GetNormalizedType(const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
4011 {
4012  clang::ASTContext &ctxt = interpreter.getCI()->getASTContext();
4013 
4014  // Modules can trigger deserialization.
4015  cling::Interpreter::PushTransactionRAII RAII(const_cast<cling::Interpreter*>(&interpreter));
4016  clang::QualType normalizedType = cling::utils::Transform::GetPartiallyDesugaredType(ctxt, type, normCtxt.GetConfig(), true /* fully qualify */);
4017 
4018  // Readd missing default template parameters
4019  normalizedType = ROOT::TMetaUtils::AddDefaultParameters(normalizedType, interpreter, normCtxt);
4020 
4021  // Get the number of arguments to keep in case they are not default.
4022  KeepNParams(normalizedType,type,interpreter,normCtxt);
4023 
4024  return normalizedType;
4025 }
4026 
4027 ////////////////////////////////////////////////////////////////////////////////
4028 /// Return the type name normalized for ROOT,
4029 /// keeping only the ROOT opaque typedef (Double32_t, etc.) and
4030 /// adding default template argument for all types except the STL collections
4031 /// where we remove the default template argument if any.
4032 ///
4033 /// This routine might actually belong in the interpreter because
4034 /// cache the clang::Type might be intepreter specific.
4035 
4036 void ROOT::TMetaUtils::GetNormalizedName(std::string &norm_name, const clang::QualType &type, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt)
4037 {
4038  if (type.isNull()) {
4039  norm_name = "";
4040  return;
4041  }
4042 
4043  clang::QualType normalizedType = GetNormalizedType(type,interpreter,normCtxt);
4044 
4045  clang::ASTContext &ctxt = interpreter.getCI()->getASTContext();
4046  clang::PrintingPolicy policy(ctxt.getPrintingPolicy());
4047  policy.SuppressTagKeyword = true; // Never get the class or struct keyword
4048  policy.SuppressScope = true; // Force the scope to be coming from a clang::ElaboratedType.
4049  policy.AnonymousTagLocations = false; // Do not extract file name + line number for anonymous types.
4050  // The scope suppression is required for getting rid of the anonymous part of the name of a class defined in an anonymous namespace.
4051  // This gives us more control vs not using the clang::ElaboratedType and relying on the Policy.SuppressUnwrittenScope which would
4052  // strip both the anonymous and the inline namespace names (and we probably do not want the later to be suppressed).
4053 
4054  std::string normalizedNameStep1;
4055 
4056  // getAsStringInternal can trigger deserialization
4057  cling::Interpreter::PushTransactionRAII clingRAII(const_cast<cling::Interpreter*>(&interpreter));
4058  normalizedType.getAsStringInternal(normalizedNameStep1,policy);
4059 
4060  // Still remove the std:: and default template argument for STL container and
4061  // normalize the location and amount of white spaces.
4064 
4065  // The result of this routine is by definition a fully qualified name. There is an implicit starting '::' at the beginning of the name.
4066  // Depending on how the user typed their code, in particular typedef declarations, we may end up with an explicit '::' being
4067  // part of the result string. For consistency, we must remove it.
4068  if (norm_name.length()>2 && norm_name[0]==':' && norm_name[1]==':') {
4069  norm_name.erase(0,2);
4070  }
4071 
4072 }
4073 
4074 ////////////////////////////////////////////////////////////////////////////////
4075 
4076 void ROOT::TMetaUtils::GetNormalizedName(std::string &norm_name,
4077  const clang::TypeDecl* typeDecl,
4078  const cling::Interpreter &interpreter)
4079 {
4080  ROOT::TMetaUtils::TNormalizedCtxt tNormCtxt(interpreter.getLookupHelper());
4081  const clang::Sema &sema = interpreter.getSema();
4082  clang::ASTContext& astCtxt = sema.getASTContext();
4083  clang::QualType qualType = astCtxt.getTypeDeclType(typeDecl);
4084 
4086  qualType,
4087  interpreter,
4088  tNormCtxt);
4089 }
4090 
4091 ////////////////////////////////////////////////////////////////////////////////
4092 std::pair<std::string,clang::QualType>
4093 ROOT::TMetaUtils::GetNameTypeForIO(const clang::QualType& thisType,
4094  const cling::Interpreter &interpreter,
4095  const TNormalizedCtxt &normCtxt,
4096  TClassEdit::EModType mode)
4097 {
4098  std::string thisTypeName;
4099  GetNormalizedName(thisTypeName, thisType, interpreter, normCtxt );
4100  bool hasChanged;
4101  auto thisTypeNameForIO = TClassEdit::GetNameForIO(thisTypeName, mode, &hasChanged);
4102  if (!hasChanged) return std::make_pair(thisTypeName,thisType);
4103 
4105  ROOT::TMetaUtils::Info("ROOT::TMetaUtils::GetTypeForIO",
4106  "Name changed from %s to %s\n", thisTypeName.c_str(), thisTypeNameForIO.c_str());
4107  }
4108 
4109  auto& lookupHelper = interpreter.getLookupHelper();
4110 
4111  const clang::Type* typePtrForIO;
4112  lookupHelper.findScope(thisTypeNameForIO,
4113  cling::LookupHelper::DiagSetting::NoDiagnostics,
4114  &typePtrForIO);
4115 
4116  // This should never happen
4117  if (!typePtrForIO) {
4118  ROOT::TMetaUtils::Fatal("ROOT::TMetaUtils::GetTypeForIO",
4119  "Type not found: %s.",thisTypeNameForIO.c_str());
4120  }
4121 
4122  clang::QualType typeForIO(typePtrForIO,0);
4123 
4124  // Check if this is a class. Indeed it could well be a POD
4125  if (!typeForIO->isRecordType()) {
4126  return std::make_pair(thisTypeNameForIO,typeForIO);
4127  }
4128 
4129  auto thisDeclForIO = typeForIO->getAsCXXRecordDecl();
4130  if (!thisDeclForIO) {
4131  ROOT::TMetaUtils::Error("ROOT::TMetaUtils::GetTypeForIO",
4132  "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());
4133  return std::make_pair(thisTypeName,thisType);
4134  }
4135 
4136  return std::make_pair(thisTypeNameForIO,typeForIO);
4137 }
4138 
4139 ////////////////////////////////////////////////////////////////////////////////
4140 
4141 clang::QualType ROOT::TMetaUtils::GetTypeForIO(const clang::QualType& thisType,
4142  const cling::Interpreter &interpreter,
4143  const TNormalizedCtxt &normCtxt,
4144  TClassEdit::EModType mode)
4145 {
4146  return GetNameTypeForIO(thisType, interpreter, normCtxt, mode).second;
4147 }
4148 
4149 ////////////////////////////////////////////////////////////////////////////////
4150 /// Return the dictionary file name for a module
4151 
4152 std::string ROOT::TMetaUtils::GetModuleFileName(const char* moduleName)
4153 {
4154  std::string dictFileName(moduleName);
4155  dictFileName += "_rdict.pcm";
4156  return dictFileName;
4157 }
4158 
4159 int dumpDeclForAssert(const clang::Decl& D, const char* commentStart) {
4160  llvm::errs() << llvm::StringRef(commentStart, 80) << '\n';
4161  D.dump();
4162  return 0;
4163 }
4164 
4165 ////////////////////////////////////////////////////////////////////////////////
4166 /// Returns the comment (// striped away), annotating declaration in a meaningful
4167 /// for ROOT IO way.
4168 /// Takes optional out parameter clang::SourceLocation returning the source
4169 /// location of the comment.
4170 ///
4171 /// CXXMethodDecls, FieldDecls and TagDecls are annotated.
4172 /// CXXMethodDecls declarations and FieldDecls are annotated as follows:
4173 /// Eg. void f(); // comment1
4174 /// int member; // comment2
4175 /// Inline definitions of CXXMethodDecls after the closing } \n. Eg:
4176 /// void f()
4177 /// {...} // comment3
4178 /// TagDecls are annotated in the end of the ClassDef macro. Eg.
4179 /// class MyClass {
4180 /// ...
4181 /// ClassDef(MyClass, 1) // comment4
4182 ///
4183 
4184 llvm::StringRef ROOT::TMetaUtils::GetComment(const clang::Decl &decl, clang::SourceLocation *loc)
4185 {
4186  clang::SourceManager& sourceManager = decl.getASTContext().getSourceManager();
4187  clang::SourceLocation sourceLocation = decl.getLocEnd();
4188 
4189  // If the location is a macro get the expansion location.
4190  sourceLocation = sourceManager.getExpansionRange(sourceLocation).second;
4191  // FIXME: We should optimize this routine instead making it do the wrong thing
4192  // returning an empty comment if the decl came from the AST.
4193  // In order to do that we need to: check if the decl has an attribute and
4194  // return the attribute content (including walking the redecl chain) and if
4195  // this is not the case we should try finding it in the header file.
4196  // This will allow us to move the implementation of TCling*Info::Title() in
4197  // TClingDeclInfo.
4198  if (!decl.hasOwningModule() && sourceManager.isLoadedSourceLocation(sourceLocation)) {
4199  // Do not touch disk for nodes coming from the PCH.
4200  return "";
4201  }
4202 
4203  bool invalid;
4204  const char *commentStart = sourceManager.getCharacterData(sourceLocation, &invalid);
4205  if (invalid)
4206  return "";
4207 
4208  bool skipToSemi = true;
4209  if (const clang::FunctionDecl* FD = clang::dyn_cast<clang::FunctionDecl>(&decl)) {
4210  if (FD->isImplicit()) {
4211  // Compiler generated function.
4212  return "";
4213  }
4214  if (FD->isExplicitlyDefaulted() || FD->isDeletedAsWritten()) {
4215  // ctorOrFunc() = xyz; with commentStart pointing somewhere into
4216  // ctorOrFunc.
4217  // We have to skipToSemi
4218  } else if (FD->doesThisDeclarationHaveABody()) {
4219  // commentStart is at body's '}'
4220  // But we might end up e.g. at the ')' of a CPP macro
4221  assert((decl.getLocEnd() != sourceLocation || *commentStart == '}'
4222  || dumpDeclForAssert(*FD, commentStart))
4223  && "Expected macro or end of body at '}'");
4224  if (*commentStart) ++commentStart;
4225 
4226  // We might still have a ';'; skip the spaces and check.
4227  while (*commentStart && isspace(*commentStart)
4228  && *commentStart != '\n' && *commentStart != '\r') {
4229  ++commentStart;
4230  }
4231  if (*commentStart == ';') ++commentStart;
4232 
4233  skipToSemi = false;
4234  }
4235  } else if (const clang::EnumConstantDecl* ECD
4236  = clang::dyn_cast<clang::EnumConstantDecl>(&decl)) {
4237  // either "konstant = 12, //COMMENT" or "lastkonstant // COMMENT"
4238  if (ECD->getNextDeclInContext())
4239  while (*commentStart && *commentStart != ',' && *commentStart != '\r' && *commentStart != '\n')
4240  ++commentStart;
4241  // else commentStart already points to the end.
4242 
4243  skipToSemi = false;
4244  }
4245 
4246  if (skipToSemi) {
4247  while (*commentStart && *commentStart != ';' && *commentStart != '\r' && *commentStart != '\n')
4248  ++commentStart;
4249  if (*commentStart == ';') ++commentStart;
4250  }
4251 
4252  // Now skip the spaces until beginning of comments or EOL.
4253  while ( *commentStart && isspace(*commentStart)
4254  && *commentStart != '\n' && *commentStart != '\r') {
4255  ++commentStart;
4256  }
4257 
4258  if (commentStart[0] != '/' ||
4259  (commentStart[1] != '/' && commentStart[1] != '*')) {
4260  // not a comment
4261  return "";
4262  }
4263 
4264  // Treat by default c++ comments (+2) but also Doxygen comments (+4)
4265  // Int_t fPx; ///< Some doxygen comment for persistent data.
4266  // Int_t fPy; //!< Some doxygen comment for persistent data.
4267  // Int_t fPz; /*!< Some doxygen comment for persistent data. */
4268  // Int_t fPa; /**< Some doxygen comment for persistent data. */
4269  unsigned int skipChars = 2;
4270  if (commentStart[0] == '/' &&
4271  commentStart[1] == '/' &&
4272  (commentStart[2] == '/' || commentStart[2] == '!') &&
4273  commentStart[3] == '<') {
4274  skipChars = 4;
4275  } else if (commentStart[0] == '/' &&
4276  commentStart[1] == '*' &&
4277  (commentStart[2] == '*' || commentStart[2] == '!') &&
4278  commentStart[3] == '<') {
4279  skipChars = 4;
4280  }
4281 
4282  commentStart += skipChars;
4283 
4284  // Now skip the spaces after comment start until EOL.
4285  while ( *commentStart && isspace(*commentStart)
4286  && *commentStart != '\n' && *commentStart != '\r') {
4287  ++commentStart;
4288  }
4289  const char* commentEnd = commentStart;
4290  // Even for /* comments we only take the first line into account.
4291  while (*commentEnd && *commentEnd != '\n' && *commentEnd != '\r') {
4292  ++commentEnd;
4293  }
4294 
4295  // "Skip" (don't include) trailing space.
4296  // *commentEnd points behind comment end thus check commentEnd[-1]
4297  while (commentEnd > commentStart && isspace(commentEnd[-1])) {
4298  --commentEnd;
4299  }
4300 
4301  if (loc) {
4302  // Find the true beginning of a comment.
4303  unsigned offset = commentStart - sourceManager.getCharacterData(sourceLocation);
4304  *loc = sourceLocation.getLocWithOffset(offset - 1);
4305  }
4306 
4307  return llvm::StringRef(commentStart, commentEnd - commentStart);
4308 }
4309 
4310 ////////////////////////////////////////////////////////////////////////////////
4311 /// Return the class comment after the ClassDef:
4312 /// class MyClass {
4313 /// ...
4314 /// ClassDef(MyClass, 1) // class comment
4315 ///
4316 
4317 llvm::StringRef ROOT::TMetaUtils::GetClassComment(const clang::CXXRecordDecl &decl,
4318  clang::SourceLocation *loc,
4319  const cling::Interpreter &interpreter)
4320 {
4321  using namespace clang;
4322  SourceLocation commentSLoc;
4323  llvm::StringRef comment;
4324 
4325  Sema& sema = interpreter.getCI()->getSema();
4326 
4327  const Decl* DeclFileLineDecl
4328  = interpreter.getLookupHelper().findFunctionProto(&decl, "DeclFileLine", "",
4329  cling::LookupHelper::NoDiagnostics);
4330  if (!DeclFileLineDecl) return llvm::StringRef();
4331 
4332  // For now we allow only a special macro (ClassDef) to have meaningful comments
4333  SourceLocation maybeMacroLoc = DeclFileLineDecl->getLocation();
4334  bool isClassDefMacro = maybeMacroLoc.isMacroID() && sema.findMacroSpelling(maybeMacroLoc, "ClassDef");
4335  if (isClassDefMacro) {
4336  comment = ROOT::TMetaUtils::GetComment(*DeclFileLineDecl, &commentSLoc);
4337  if (comment.size()) {
4338  if (loc){
4339  *loc = commentSLoc;
4340  }
4341  return comment;
4342  }
4343  }
4344  return llvm::StringRef();
4345 }
4346 
4347 ////////////////////////////////////////////////////////////////////////////////
4348 /// Return the base/underlying type of a chain of array or pointers type.
4349 /// Does not yet support the array and pointer part being intermixed.
4350 
4352 {
4353  const clang::Type *rawtype = type.getTypePtr();
4354 
4355  // NOTE: We probably meant isa<clang::ElaboratedType>
4356  if (rawtype->isElaboratedTypeSpecifier() ) {
4357  rawtype = rawtype->getCanonicalTypeInternal().getTypePtr();
4358  }
4359  if (rawtype->isArrayType()) {
4360  rawtype = type.getTypePtr()->getBaseElementTypeUnsafe ();
4361  }
4362  if (rawtype->isPointerType() || rawtype->isReferenceType() ) {
4363  //Get to the 'raw' type.
4364  clang::QualType pointee;
4365  while ( (pointee = rawtype->getPointeeType()) , pointee.getTypePtrOrNull() && pointee.getTypePtr() != rawtype)
4366  {
4367  rawtype = pointee.getTypePtr();
4368 
4369  if (rawtype->isElaboratedTypeSpecifier() ) {
4370  rawtype = rawtype->getCanonicalTypeInternal().getTypePtr();
4371  }
4372  if (rawtype->isArrayType()) {
4373  rawtype = rawtype->getBaseElementTypeUnsafe ();
4374  }
4375  }
4376  }
4377  if (rawtype->isArrayType()) {
4378  rawtype = rawtype->getBaseElementTypeUnsafe ();
4379  }
4380  return rawtype;
4381 }
4382 
4383 ////////////////////////////////////////////////////////////////////////////////
4384 /// Return true, if the decl is part of the std namespace.
4385 
4386 bool ROOT::TMetaUtils::IsStdClass(const clang::RecordDecl &cl)
4387 {
4389 }
4390 
4391 ////////////////////////////////////////////////////////////////////////////////
4392 /// Return true, if the decl is part of the std namespace and we want
4393 /// its default parameter dropped.
4394 
4395 bool ROOT::TMetaUtils::IsStdDropDefaultClass(const clang::RecordDecl &cl)
4396 {
4397  // Might need to reduce it to shared_ptr and STL collection.s
4399  static const char *names[] =
4400  { "shared_ptr", "__shared_ptr",
4401  "vector", "list", "deque", "map", "multimap", "set", "multiset", "bitset"};
4402  llvm::StringRef clname(cl.getName());
4403  for(auto &&name : names) {
4404  if (clname == name) return true;
4405  }
4406  }
4407  return false;
4408 }
4409 
4410 ////////////////////////////////////////////////////////////////////////////////
4411 /// This is a recursive function
4412 
4413 bool ROOT::TMetaUtils::MatchWithDeclOrAnyOfPrevious(const clang::CXXRecordDecl &cl,
4414  const clang::CXXRecordDecl &currentCl)
4415 {
4416  // We found it: let's return true
4417  if (&cl == &currentCl) return true;
4418 
4419  const clang::CXXRecordDecl* previous = currentCl.getPreviousDecl();
4420 
4421  // There is no previous decl, so we cannot possibly find it
4422  if (NULL == previous){
4423  return false;
4424  }
4425 
4426  // We try to find it in the previous
4427  return ROOT::TMetaUtils::MatchWithDeclOrAnyOfPrevious(cl, *previous);
4428 
4429 }
4430 
4431 //______________________________________________________________________________
4432 
4433 bool ROOT::TMetaUtils::IsOfType(const clang::CXXRecordDecl &cl, const std::string& typ, const cling::LookupHelper& lh)
4434 {
4435  // Return true if the decl is of type.
4436  // A proper hashtable for caching results would be the ideal solution
4437  // 1) Only one lookup per type
4438  // 2) No string comparison
4439  // We may use a map which becomes an unordered map if c++11 is enabled?
4440 
4441  const clang::CXXRecordDecl *thisDecl =
4442  llvm::dyn_cast_or_null<clang::CXXRecordDecl>(lh.findScope(typ, cling::LookupHelper::WithDiagnostics));
4443 
4444  // this would be probably an assert given that this state is not reachable unless a mistake is somewhere
4445  if (! thisDecl){
4446  Error("IsOfType","Record decl of type %s not found in the AST.", typ.c_str());
4447  return false;
4448  }
4449 
4450  // Now loop on all previous decls to seek a match
4451  const clang::CXXRecordDecl *mostRecentDecl = thisDecl->getMostRecentDecl();
4452  bool matchFound = MatchWithDeclOrAnyOfPrevious (cl,*mostRecentDecl);
4453 
4454  return matchFound;
4455 }
4456 
4457 ////////////////////////////////////////////////////////////////////////////////
4458 /// type : type name: vector<list<classA,allocator>,allocator>
4459 /// result: 0 : not stl container
4460 /// abs(result): code of container 1=vector,2=list,3=deque,4=map
4461 /// 5=multimap,6=set,7=multiset
4462 
4463 ROOT::ESTLType ROOT::TMetaUtils::IsSTLCont(const clang::RecordDecl &cl)
4464 {
4465  // This routine could be enhanced to also support:
4466  //
4467  // testAlloc: if true, we test allocator, if it is not default result is negative
4468  // result: 0 : not stl container
4469  // abs(result): code of container 1=vector,2=list,3=deque,4=map
4470  // 5=multimap,6=set,7=multiset
4471  // positive val: we have a vector or list with default allocator to any depth
4472  // like vector<list<vector<int>>>
4473  // negative val: STL container other than vector or list, or non default allocator
4474  // For example: vector<deque<int>> has answer -1
4475 
4476  if (!IsStdClass(cl)) {
4477  return ROOT::kNotSTL;
4478  }
4479 
4480  return STLKind(cl.getName());
4481 }
4482 
4484  using namespace clang;
4485  struct SearchTypedef: public TypeVisitor<SearchTypedef, bool> {
4486  bool VisitTypedefType(const TypedefType* TD) {
4487  return true;
4488  }
4489  bool VisitArrayType(const ArrayType* AT) {
4490  return Visit(AT->getElementType().getTypePtr());
4491  }
4492  bool VisitDecltypeType(const DecltypeType* DT) {
4493  return Visit(DT->getUnderlyingType().getTypePtr());
4494  }
4495  bool VisitPointerType(const PointerType* PT) {
4496  return Visit(PT->getPointeeType().getTypePtr());
4497  }
4498  bool VisitReferenceType(const ReferenceType* RT) {
4499  return Visit(RT->getPointeeType().getTypePtr());
4500  }
4501  bool VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType* STST) {
4502  return Visit(STST->getReplacementType().getTypePtr());
4503  }
4504  bool VisitTemplateSpecializationType(const TemplateSpecializationType* TST) {
4505  for (int I = 0, N = TST->getNumArgs(); I < N; ++I) {
4506  const TemplateArgument& TA = TST->getArg(I);
4507  if (TA.getKind() == TemplateArgument::Type
4508  && Visit(TA.getAsType().getTypePtr()))
4509  return true;
4510  }
4511  return false;
4512  }
4513  bool VisitTemplateTypeParmType(const TemplateTypeParmType* TTPT) {
4514  return false; // shrug...
4515  }
4516  bool VisitTypeOfType(const TypeOfType* TOT) {
4517  return TOT->getUnderlyingType().getTypePtr();
4518  }
4519  bool VisitElaboratedType(const ElaboratedType* ET) {
4520  NestedNameSpecifier* NNS = ET->getQualifier();
4521  while (NNS) {
4522  if (NNS->getKind() == NestedNameSpecifier::TypeSpec) {
4523  if (Visit(NNS->getAsType()))
4524  return true;
4525  }
4526  NNS = NNS->getPrefix();
4527  }
4528  return Visit(ET->getNamedType().getTypePtr());
4529  }
4530  };
4531 
4532  SearchTypedef ST;
4533  return ST.Visit(T);
4534 }
4535 
4536 ////////////////////////////////////////////////////////////////////////////////
4537 /// Check if 'input' or any of its template parameter was substituted when
4538 /// instantiating the class template instance and replace it with the
4539 /// partially sugared types we have from 'instance'.
4540 
4541 clang::QualType ROOT::TMetaUtils::ReSubstTemplateArg(clang::QualType input, const clang::Type *instance)
4542 {
4543  if (!instance) return input;
4544  // if there is no typedef in instance then there is nothing guiding any
4545  // template parameter typedef replacement.
4547  return input;
4548 
4549  using namespace llvm;
4550  using namespace clang;
4551  const clang::ASTContext &Ctxt = instance->getAsCXXRecordDecl()->getASTContext();
4552 
4553  // Treat scope (clang::ElaboratedType) if any.
4554  const clang::ElaboratedType* etype
4555  = llvm::dyn_cast<clang::ElaboratedType>(input.getTypePtr());
4556  if (etype) {
4557  // We have to also handle the prefix.
4558 
4559  clang::Qualifiers scope_qualifiers = input.getLocalQualifiers();
4560  assert(instance->getAsCXXRecordDecl()!=0 && "ReSubstTemplateArg only makes sense with a type representing a class.");
4561 
4562  clang::NestedNameSpecifier *scope = ReSubstTemplateArgNNS(Ctxt,etype->getQualifier(),instance);
4563  clang::QualType subTy = ReSubstTemplateArg(clang::QualType(etype->getNamedType().getTypePtr(),0),instance);
4564 
4565  if (scope) subTy = Ctxt.getElaboratedType(clang::ETK_None,scope,subTy);
4566  subTy = Ctxt.getQualifiedType(subTy,scope_qualifiers);
4567  return subTy;
4568  }
4569 
4570  QualType QT = input;
4571 
4572  // In case of Int_t* we need to strip the pointer first, ReSubst and attach
4573  // the pointer once again.
4574  if (isa<clang::PointerType>(QT.getTypePtr())) {
4575  // Get the qualifiers.
4576  Qualifiers quals = QT.getQualifiers();
4577  QualType nQT;
4578  nQT = ReSubstTemplateArg(QT->getPointeeType(),instance);
4579  if (nQT == QT->getPointeeType()) return QT;
4580 
4581  QT = Ctxt.getPointerType(nQT);
4582  // Add back the qualifiers.
4583  QT = Ctxt.getQualifiedType(QT, quals);
4584  return QT;
4585  }
4586 
4587  // In case of Int_t& we need to strip the pointer first, ReSubst and attach
4588  // the reference once again.
4589  if (isa<ReferenceType>(QT.getTypePtr())) {
4590  // Get the qualifiers.
4591  bool isLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
4592  Qualifiers quals = QT.getQualifiers();
4593  QualType nQT;
4594  nQT = ReSubstTemplateArg(QT->getPointeeType(),instance);
4595  if (nQT == QT->getPointeeType()) return QT;
4596 
4597  // Add the r- or l-value reference type back to the desugared one.
4598  if (isLValueRefTy)
4599  QT = Ctxt.getLValueReferenceType(nQT);
4600  else
4601  QT = Ctxt.getRValueReferenceType(nQT);
4602  // Add back the qualifiers.
4603  QT = Ctxt.getQualifiedType(QT, quals);
4604  return QT;
4605  }
4606 
4607  // In case of Int_t[2] we need to strip the array first, ReSubst and attach
4608  // the array once again.
4609  if (isa<clang::ArrayType>(QT.getTypePtr())) {
4610  // Get the qualifiers.
4611  Qualifiers quals = QT.getQualifiers();
4612 
4613  if (const auto arr = dyn_cast<ConstantArrayType>(QT.getTypePtr())) {
4614  QualType newQT= ReSubstTemplateArg(arr->getElementType(),instance);
4615 
4616  if (newQT == arr->getElementType()) return QT;
4617  QT = Ctxt.getConstantArrayType (newQT,
4618  arr->getSize(),
4619  arr->getSizeModifier(),
4620  arr->getIndexTypeCVRQualifiers());
4621 
4622  } else if (const auto arr = dyn_cast<DependentSizedArrayType>(QT.getTypePtr())) {
4623  QualType newQT = ReSubstTemplateArg(arr->getElementType(),instance);
4624 
4625  if (newQT == QT) return QT;
4626  QT = Ctxt.getDependentSizedArrayType (newQT,
4627  arr->getSizeExpr(),
4628  arr->getSizeModifier(),
4629  arr->getIndexTypeCVRQualifiers(),
4630  arr->getBracketsRange());
4631 
4632  } else if (const auto arr = dyn_cast<IncompleteArrayType>(QT.getTypePtr())) {
4633  QualType newQT = ReSubstTemplateArg(arr->getElementType(),instance);
4634 
4635  if (newQT == arr->getElementType()) return QT;
4636  QT = Ctxt.getIncompleteArrayType (newQT,
4637  arr->getSizeModifier(),
4638  arr->getIndexTypeCVRQualifiers());
4639 
4640  } else if (const auto arr = dyn_cast<VariableArrayType>(QT.getTypePtr())) {
4641  QualType newQT = ReSubstTemplateArg(arr->getElementType(),instance);
4642 
4643  if (newQT == arr->getElementType()) return QT;
4644  QT = Ctxt.getVariableArrayType (newQT,
4645  arr->getSizeExpr(),
4646  arr->getSizeModifier(),
4647  arr->getIndexTypeCVRQualifiers(),
4648  arr->getBracketsRange());
4649  }
4650 
4651  // Add back the qualifiers.
4652  QT = Ctxt.getQualifiedType(QT, quals);
4653  return QT;
4654  }
4655 
4656  // If the instance is also an elaborated type, we need to skip
4657  etype = llvm::dyn_cast<clang::ElaboratedType>(instance);
4658  if (etype) {
4659  instance = etype->getNamedType().getTypePtr();
4660  if (!instance) return input;
4661  }
4662 
4663  const clang::TemplateSpecializationType* TST
4664  = llvm::dyn_cast<const clang::TemplateSpecializationType>(instance);
4665 
4666  if (!TST) return input;
4667 
4668  const clang::ClassTemplateSpecializationDecl* TSTdecl
4669  = llvm::dyn_cast_or_null<const clang::ClassTemplateSpecializationDecl>(instance->getAsCXXRecordDecl());
4670 
4671  const clang::SubstTemplateTypeParmType *substType
4672  = llvm::dyn_cast<clang::SubstTemplateTypeParmType>(input.getTypePtr());
4673 
4674  if (substType) {
4675  // Make sure it got replaced from this template
4676  const clang::ClassTemplateDecl *replacedCtxt = 0;
4677 
4678  const clang::DeclContext *replacedDeclCtxt = substType->getReplacedParameter()->getDecl()->getDeclContext();
4679  const clang::CXXRecordDecl *decl = llvm::dyn_cast<clang::CXXRecordDecl>(replacedDeclCtxt);
4680  unsigned int index = substType->getReplacedParameter()->getIndex();
4681  if (decl) {
4682 
4683  if (decl->getKind() == clang::Decl::ClassTemplatePartialSpecialization) {
4684  const clang::ClassTemplatePartialSpecializationDecl *spec = llvm::dyn_cast<clang::ClassTemplatePartialSpecializationDecl>(decl);
4685 
4686  unsigned int depth = substType->getReplacedParameter()->getDepth();
4687 
4688  const TemplateArgument *instanceArgs = spec->getTemplateArgs().data();
4689  unsigned int instanceNArgs = spec->getTemplateArgs().size();
4690 
4691  // Search for the 'right' replacement.
4692 
4693  for(unsigned int A = 0; A < instanceNArgs; ++A) {
4694  if (instanceArgs[A].getKind() == clang::TemplateArgument::Type) {
4695  clang::QualType argQualType = instanceArgs[A].getAsType();
4696 
4697  const clang::TemplateTypeParmType *replacementType;
4698 
4699  replacementType = llvm::dyn_cast<clang::TemplateTypeParmType>(argQualType);
4700 
4701  if (!replacementType) {
4702  const clang::SubstTemplateTypeParmType *argType
4703  = llvm::dyn_cast<clang::SubstTemplateTypeParmType>(argQualType);
4704  if (argType) {
4705  clang::QualType replacementQT = argType->getReplacementType();
4706  replacementType = llvm::dyn_cast<clang::TemplateTypeParmType>(replacementQT);
4707  }
4708  }
4709  if (replacementType &&
4710  depth == replacementType->getDepth() &&
4711  index == replacementType->getIndex() )
4712  {
4713  index = A;
4714  break;
4715  }
4716  }
4717  }
4718  replacedCtxt = spec->getSpecializedTemplate();
4719  } else {
4720  replacedCtxt = decl->getDescribedClassTemplate();
4721  }
4722  } else if (auto const declguide = llvm::dyn_cast<clang::CXXDeductionGuideDecl>(replacedDeclCtxt)) {
4723  replacedCtxt = llvm::dyn_cast<clang::ClassTemplateDecl>(declguide->getDeducedTemplate());
4724  } else if (auto const ctdecl = llvm::dyn_cast<clang::ClassTemplateDecl>(replacedDeclCtxt)) {
4725  replacedCtxt = ctdecl;
4726  } else {
4727  std::string astDump;
4728  llvm::raw_string_ostream ostream(astDump);
4729  instance->dump(ostream);
4730  ostream.flush();
4731  ROOT::TMetaUtils::Warning("ReSubstTemplateArg","Unexpected type of declaration context for template parameter: %s.\n\tThe responsible class is:\n\t%s\n",
4732  replacedDeclCtxt->getDeclKindName(), astDump.c_str());
4733  replacedCtxt = nullptr;
4734  }
4735 
4736  if ((replacedCtxt && replacedCtxt->getCanonicalDecl() == TSTdecl->getSpecializedTemplate()->getCanonicalDecl())
4737  || /* the following is likely just redundant */
4738  substType->getReplacedParameter()->getDecl()
4739  == TSTdecl->getSpecializedTemplate ()->getTemplateParameters()->getParam(index))
4740  {
4741  if ( index >= TST->getNumArgs() ) {
4742  // The argument replaced was a default template argument that is
4743  // being listed as part of the instance ...
4744  // so we probably don't really know how to spell it ... we would need to recreate it
4745  // (See AddDefaultParameters).
4746  return input;
4747  } else {
4748  return TST->getArg(index).getAsType();
4749  }
4750  }
4751  }
4752  // Maybe a class template instance, recurse and rebuild
4753  const clang::TemplateSpecializationType* inputTST
4754  = llvm::dyn_cast<const clang::TemplateSpecializationType>(input.getTypePtr());
4755  const clang::ASTContext& astCtxt = TSTdecl->getASTContext();
4756 
4757  if (inputTST) {
4758  bool mightHaveChanged = false;
4759  llvm::SmallVector<clang::TemplateArgument, 4> desArgs;
4760  for(clang::TemplateSpecializationType::iterator I = inputTST->begin(), E = inputTST->end();
4761  I != E; ++I) {
4762  if (I->getKind() != clang::TemplateArgument::Type) {
4763  desArgs.push_back(*I);
4764  continue;
4765  }
4766 
4767  clang::QualType SubTy = I->getAsType();
4768  // Check if the type needs more desugaring and recurse.
4769  if (llvm::isa<clang::SubstTemplateTypeParmType>(SubTy)
4770  || llvm::isa<clang::TemplateSpecializationType>(SubTy)) {
4771  clang::QualType newSubTy = ReSubstTemplateArg(SubTy,instance);
4772  mightHaveChanged = SubTy != newSubTy;
4773  if (!newSubTy.isNull()) {
4774  desArgs.push_back(clang::TemplateArgument(newSubTy));
4775  }
4776  } else
4777  desArgs.push_back(*I);
4778  }
4779 
4780  // If desugaring happened allocate new type in the AST.
4781  if (mightHaveChanged) {
4782  clang::Qualifiers qualifiers = input.getLocalQualifiers();
4783  input = astCtxt.getTemplateSpecializationType(inputTST->getTemplateName(),
4784  desArgs,
4785  inputTST->getCanonicalTypeInternal());
4786  input = astCtxt.getQualifiedType(input, qualifiers);
4787  }
4788  }
4789 
4790  return input;
4791 }
4792 
4793 ////////////////////////////////////////////////////////////////////////////////
4794 /// Remove the last n template arguments from the name
4795 
4796 int ROOT::TMetaUtils::RemoveTemplateArgsFromName(std::string& name, unsigned int nArgsToRemove)
4797 {
4798  if ( nArgsToRemove == 0 || name == "")
4799  return 0;
4800 
4801  // We proceed from the right to the left, counting commas which are not
4802  // enclosed by < >.
4803  const unsigned int length = name.length();
4804  unsigned int cur=0; // let's start beyond the first > from the right
4805  unsigned int nArgsRemoved=0;
4806  unsigned int nBraces=0;
4807  char c='@';
4808  while (nArgsRemoved!=nArgsToRemove && cur<length){
4809  c = name[cur];
4810  if (c == '<') nBraces++;
4811  if (c == '>') nBraces--;
4812  if (c == ',' && nBraces==1 /*So we are not in a sub-template*/) nArgsRemoved++;
4813  cur++;
4814  }
4815  cur--;
4816  name = name.substr(0,cur)+">";
4817  return 0;
4818 
4819 }
4820 
4821 ////////////////////////////////////////////////////////////////////////////////
4822 /// Converts STL container name to number. vector -> 1, etc..
4823 
4825 {
4826  static const char *stls[] = //container names
4827  {"any","vector","list", "deque","map","multimap","set","multiset","bitset",
4828  "forward_list","unordered_set","unordered_multiset","unordered_map","unordered_multimap",0};
4829  static const ROOT::ESTLType values[] =
4839  };
4840  // kind of stl container
4841  for(int k=1;stls[k];k++) {if (type.equals(stls[k])) return values[k];}
4842  return ROOT::kNotSTL;
4843 }
4844 
4845 ////////////////////////////////////////////////////////////////////////////////
4846 
4847 const clang::TypedefNameDecl* ROOT::TMetaUtils::GetAnnotatedRedeclarable(const clang::TypedefNameDecl* TND)
4848 {
4849  if (!TND)
4850  return 0;
4851 
4852  TND = TND->getMostRecentDecl();
4853  while (TND && !(TND->hasAttrs()))
4854  TND = TND->getPreviousDecl();
4855 
4856  return TND;
4857 }
4858 
4859 ////////////////////////////////////////////////////////////////////////////////
4860 
4861 const clang::TagDecl* ROOT::TMetaUtils::GetAnnotatedRedeclarable(const clang::TagDecl* TD)
4862 {
4863  if (!TD)
4864  return 0;
4865 
4866  TD = TD->getMostRecentDecl();
4867  while (TD && !(TD->hasAttrs() && TD->isThisDeclarationADefinition()))
4868  TD = TD->getPreviousDecl();
4869 
4870  return TD;
4871 }
4872 
4873 ////////////////////////////////////////////////////////////////////////////////
4874 /// Extract the immediately outer namespace and then launch the recursion
4875 
4877  std::list<std::pair<std::string,bool> >& enclosingNamespaces)
4878 {
4879  const clang::DeclContext* enclosingNamespaceDeclCtxt = decl.getDeclContext();
4880  if (!enclosingNamespaceDeclCtxt) return;
4881 
4882  const clang::NamespaceDecl* enclosingNamespace =
4883  clang::dyn_cast<clang::NamespaceDecl>(enclosingNamespaceDeclCtxt);
4884  if (!enclosingNamespace) return;
4885 
4886  enclosingNamespaces.push_back(std::make_pair(enclosingNamespace->getNameAsString(),
4887  enclosingNamespace->isInline()));
4888 
4889  ExtractCtxtEnclosingNameSpaces(*enclosingNamespace, enclosingNamespaces);
4890 
4891 }
4892 
4893 ////////////////////////////////////////////////////////////////////////////////
4894 /// Extract enclosing namespaces recursively
4895 
4896 void ROOT::TMetaUtils::ExtractCtxtEnclosingNameSpaces(const clang::DeclContext& ctxt,
4897  std::list<std::pair<std::string,bool> >& enclosingNamespaces)
4898 {
4899  const clang::DeclContext* enclosingNamespaceDeclCtxt = ctxt.getParent ();
4900 
4901  // If no parent is found, nothing more to be done
4902  if (!enclosingNamespaceDeclCtxt) {
4903  return;
4904  }
4905 
4906  // Check if the parent is a namespace (it could be a class for example)
4907  // if not, nothing to be done here
4908  const clang::NamespaceDecl* enclosingNamespace = clang::dyn_cast<clang::NamespaceDecl>(enclosingNamespaceDeclCtxt);
4909  if (!enclosingNamespace) return;
4910 
4911  // Add to the list of parent namespaces
4912  enclosingNamespaces.push_back(std::make_pair(enclosingNamespace->getNameAsString(),
4913  enclosingNamespace->isInline()));
4914 
4915  // here the recursion
4916  ExtractEnclosingNameSpaces(*enclosingNamespace, enclosingNamespaces);
4917 }
4918 
4919 ////////////////////////////////////////////////////////////////////////////////
4920 /// Extract the names and types of containing scopes.
4921 /// Stop if a class is met and return its pointer.
4922 
4923 const clang::RecordDecl* ROOT::TMetaUtils::ExtractEnclosingScopes(const clang::Decl& decl,
4924  std::list<std::pair<std::string,unsigned int> >& enclosingSc)
4925 {
4926  const clang::DeclContext* enclosingDeclCtxt = decl.getDeclContext();
4927  if (!enclosingDeclCtxt) return 0;
4928 
4929  unsigned int scopeType;
4930 
4931  if (auto enclosingNamespacePtr =
4932  clang::dyn_cast<clang::NamespaceDecl>(enclosingDeclCtxt)){
4933  scopeType= enclosingNamespacePtr->isInline() ? 1 : 0; // inline or simple namespace
4934  enclosingSc.push_back(std::make_pair(enclosingNamespacePtr->getNameAsString(),scopeType));
4935  return ExtractEnclosingScopes(*enclosingNamespacePtr, enclosingSc);
4936  }
4937 
4938  if (auto enclosingClassPtr =
4939  clang::dyn_cast<clang::RecordDecl>(enclosingDeclCtxt)){
4940  return enclosingClassPtr;
4941  }
4942 
4943  return nullptr;
4944 
4945 }
4946 
4947 ////////////////////////////////////////////////////////////////////////////////
4948 /// Reimplementation of TSystem::ExpandPathName() that cannot be
4949 /// used from TMetaUtils.
4950 
4951 static void replaceEnvVars(const char* varname, std::string& txt)
4952 {
4953  std::string::size_type beginVar = 0;
4954  std::string::size_type endVar = 0;
4955  while ((beginVar = txt.find('$', beginVar)) != std::string::npos
4956  && beginVar + 1 < txt.length()) {
4957  std::string::size_type beginVarName = beginVar + 1;
4958  std::string::size_type endVarName = std::string::npos;
4959  if (txt[beginVarName] == '(') {
4960  // "$(VARNAME)" style.
4961  endVarName = txt.find(')', beginVarName);
4962  ++beginVarName;
4963  if (endVarName == std::string::npos) {
4964  ROOT::TMetaUtils::Error(0, "Missing ')' for '$(' in $%s at %s\n",
4965  varname, txt.c_str() + beginVar);
4966  return;
4967  }
4968  endVar = endVarName + 1;
4969  } else {
4970  // "$VARNAME/..." style.
4971  beginVarName = beginVar + 1;
4972  endVarName = beginVarName;
4973  while (isalnum(txt[endVarName]) || txt[endVarName] == '_')
4974  ++endVarName;
4975  endVar = endVarName;
4976  }
4977 
4978  const char* val = getenv(txt.substr(beginVarName,
4979  endVarName - beginVarName).c_str());
4980  if (!val) val = "";
4981 
4982  txt.replace(beginVar, endVar - beginVar, val);
4983  int lenval = strlen(val);
4984  int delta = lenval - (endVar - beginVar); // these many extra chars,
4985  endVar += delta; // advance the end marker accordingly.
4986 
4987  // Look for the next one
4988  beginVar = endVar + 1;
4989  }
4990 }
4991 
4992 ////////////////////////////////////////////////////////////////////////////////
4993 /// Organise the parameters for cling in order to guarantee relocatability
4994 /// It treats the gcc toolchain and the root include path
4995 /// FIXME: enables relocatability for experiments' framework headers until PCMs
4996 /// are available.
4997 
4998 void ROOT::TMetaUtils::SetPathsForRelocatability(std::vector<std::string>& clingArgs )
4999 {
5000  const char* envInclPath = getenv("ROOT_INCLUDE_PATH");
5001 
5002  if (!envInclPath)
5003  return;
5004  std::istringstream envInclPathsStream(envInclPath);
5005  std::string inclPath;
5006  while (std::getline(envInclPathsStream, inclPath, ':')) {
5007  // Can't use TSystem in here; re-implement TSystem::ExpandPathName().
5008  replaceEnvVars("ROOT_INCLUDE_PATH", inclPath);
5009  if (!inclPath.empty()) {
5010  clingArgs.push_back("-I");
5011  clingArgs.push_back(inclPath);
5012  }
5013  }
5014 }
5015 
5016 ////////////////////////////////////////////////////////////////////////////////
5017 
5018 void ROOT::TMetaUtils::ReplaceAll(std::string& str, const std::string& from, const std::string& to,bool recurse)
5019 {
5020  if(from.empty())
5021  return;
5022  size_t start_pos = 0;
5023  bool changed=true;
5024  while (changed){
5025  changed=false;
5026  start_pos = 0;
5027  while((start_pos = str.find(from, start_pos)) != std::string::npos) {
5028  str.replace(start_pos, from.length(), to);
5029  start_pos += to.length();
5030  if (recurse) changed = true;
5031  }
5032  }
5033 }
5034 
5035 ////////////////////////////////////////////////////////////////////////////////
5036 /// Return the separator suitable for this platform.
5038 {
5040 }
5041 
5042 ////////////////////////////////////////////////////////////////////////////////
5043 
5044 bool ROOT::TMetaUtils::EndsWith(const std::string &theString, const std::string &theSubstring)
5045 {
5046  if (theString.size() < theSubstring.size()) return false;
5047  const unsigned int theSubstringSize = theSubstring.size();
5048  return 0 == theString.compare(theString.size() - theSubstringSize,
5049  theSubstringSize,
5050  theSubstring);
5051 }
5052 
5053 ////////////////////////////////////////////////////////////////////////////////
5054 
5055 bool ROOT::TMetaUtils::BeginsWith(const std::string &theString, const std::string &theSubstring)
5056 {
5057  if (theString.size() < theSubstring.size()) return false;
5058  const unsigned int theSubstringSize = theSubstring.size();
5059  return 0 == theString.compare(0,
5060  theSubstringSize,
5061  theSubstring);
5062 }
5063 
5064 
5065 
5066 ////////////////////////////////////////////////////////////////////////////////
5067 
5068 bool ROOT::TMetaUtils::IsLinkdefFile(const char *filename)
5069 {
5070  // Note, should change this into take llvm::StringRef.
5071 
5072  if ((strstr(filename, "LinkDef") || strstr(filename, "Linkdef") ||
5073  strstr(filename, "linkdef")) && strstr(filename, ".h")) {
5074  return true;
5075  }
5076  size_t len = strlen(filename);
5077  size_t linkdeflen = 9; /* strlen("linkdef.h") */
5078  if (len >= 9) {
5079  if (0 == strncasecmp(filename + (len - linkdeflen), "linkdef", linkdeflen - 2)
5080  && 0 == strcmp(filename + (len - 2), ".h")
5081  ) {
5082  return true;
5083  } else {
5084  return false;
5085  }
5086  } else {
5087  return false;
5088  }
5089 }
5090 
5091 ////////////////////////////////////////////////////////////////////////////////
5092 
5093 bool ROOT::TMetaUtils::IsHeaderName(const std::string &filename)
5094 {
5095  return llvm::sys::path::extension(filename) == ".h" ||
5096  llvm::sys::path::extension(filename) == ".hh" ||
5097  llvm::sys::path::extension(filename) == ".hpp" ||
5098  llvm::sys::path::extension(filename) == ".H" ||
5099  llvm::sys::path::extension(filename) == ".h++" ||
5100  llvm::sys::path::extension(filename) == "hxx" ||
5101  llvm::sys::path::extension(filename) == "Hxx" ||
5102  llvm::sys::path::extension(filename) == "HXX";
5103 }
5104 
5105 ////////////////////////////////////////////////////////////////////////////////
5106 
5107 const std::string ROOT::TMetaUtils::AST2SourceTools::Decls2FwdDecls(const std::vector<const clang::Decl *> &decls, cling::Interpreter::IgnoreFilesFunc_t ignoreFiles, const cling::Interpreter &interp)
5108 {
5109  clang::Sema &sema = interp.getSema();
5110  cling::Transaction theTransaction(sema);
5111  std::set<clang::Decl *> addedDecls;
5112  for (auto decl : decls) {
5113  // again waiting for cling
5114  clang::Decl *ncDecl = const_cast<clang::Decl *>(decl);
5115  theTransaction.append(ncDecl);
5116  }
5117  std::string newFwdDecl;
5118  llvm::raw_string_ostream llvmOstr(newFwdDecl);
5119  interp.forwardDeclare(theTransaction, sema.getPreprocessor(), sema.getASTContext(), llvmOstr, true, nullptr, ignoreFiles);
5120  llvmOstr.flush();
5121  return newFwdDecl;
5122 }
5123 
5124 ////////////////////////////////////////////////////////////////////////////////
5125 /// Take the namespaces which enclose the decl and put them around the
5126 /// definition string.
5127 /// For example, if the definition string is "myClass" which is enclosed by
5128 /// the namespaces ns1 and ns2, one would get:
5129 /// namespace ns2{ namespace ns1 { class myClass; } }
5130 
5132  std::string& defString)
5133 {
5134  auto rcd = EncloseInScopes(decl, defString);
5135  return rcd ? 1:0;
5136 }
5137 
5138 ////////////////////////////////////////////////////////////////////////////////
5139 /// Take the scopes which enclose the decl and put them around the
5140 /// definition string.
5141 /// If a class is encountered, bail out.
5142 
5143 const clang::RecordDecl* ROOT::TMetaUtils::AST2SourceTools::EncloseInScopes(const clang::Decl& decl,
5144  std::string& defString)
5145 {
5146  std::list<std::pair<std::string,unsigned int> > enclosingNamespaces;
5147  auto rcdPtr = ROOT::TMetaUtils::ExtractEnclosingScopes(decl,enclosingNamespaces);
5148 
5149  if (rcdPtr) return rcdPtr;
5150 
5151  // Check if we have enclosing namespaces
5152  static const std::string scopeType [] = {"namespace ", "inline namespace ", "class "};
5153 
5154  std::string scopeName;
5155  std::string scopeContent;
5156  unsigned int scopeIndex;
5157  for (auto const & encScope : enclosingNamespaces){
5158  scopeIndex = encScope.second;
5159  scopeName = encScope.first;
5160  scopeContent = " { " + defString + " }";
5161  defString = scopeType[scopeIndex] +
5162  scopeName +
5163  scopeContent;
5164  }
5165  return nullptr;
5166 }
5167 
5168 ////////////////////////////////////////////////////////////////////////////////
5169 /// Loop over the template parameters and build a string for template arguments
5170 /// using the fully qualified name
5171 /// There are different cases:
5172 /// Case 1: a simple template parameter
5173 /// E.g. template<typename T> class A;
5174 /// Case 2: a non-type: either an integer or an enum
5175 /// E.g. template<int I, Foo > class A; where Foo is enum Foo {red, blue};
5176 /// 2 sub cases here:
5177 /// SubCase 2.a: the parameter is an enum: bail out, cannot be treated.
5178 /// SubCase 2.b: use the fully qualified name
5179 /// Case 3: a TemplateTemplate argument
5180 /// E.g. template <template <typename> class T> class container { };
5181 
5183  const clang::TemplateParameterList& tmplParamList,
5184  const cling::Interpreter& interpreter)
5185 {
5186  templateArgs="<";
5187  for (auto prmIt = tmplParamList.begin();
5188  prmIt != tmplParamList.end(); prmIt++){
5189 
5190  if (prmIt != tmplParamList.begin())
5191  templateArgs += ", ";
5192 
5193  auto nDecl = *prmIt;
5194  std::string typeName;
5195 
5196  // Case 1
5197  if (llvm::isa<clang::TemplateTypeParmDecl>(nDecl)){
5198  typeName = "typename ";
5199  if (nDecl->isParameterPack())
5200  typeName += "... ";
5201  typeName += (*prmIt)->getNameAsString();
5202  }
5203  // Case 2
5204  else if (auto nttpd = llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(nDecl)){
5205  auto theType = nttpd->getType();
5206  // If this is an enum, use int as it is impossible to fwd declare and
5207  // this makes sense since it is not a type...
5208  if (theType.getAsString().find("enum") != std::string::npos){
5209  std::string astDump;
5210  llvm::raw_string_ostream ostream(astDump);
5211  nttpd->dump(ostream);
5212  ostream.flush();
5213  ROOT::TMetaUtils::Warning(0,"Forward declarations of templates with enums as template parameters. The responsible class is: %s\n", astDump.c_str());
5214  return 1;
5215  } else {
5217  theType,
5218  interpreter);
5219  }
5220  }
5221  // Case 3: TemplateTemplate argument
5222  else if (auto ttpd = llvm::dyn_cast<clang::TemplateTemplateParmDecl>(nDecl)){
5223  int retCode = FwdDeclFromTmplDecl(*ttpd,interpreter,typeName);
5224  if (retCode!=0){
5225  std::string astDump;
5226  llvm::raw_string_ostream ostream(astDump);
5227  ttpd->dump(ostream);
5228  ostream.flush();
5229  ROOT::TMetaUtils::Error(0,"Cannot reconstruct template template parameter forward declaration for %s\n", astDump.c_str());
5230  return 1;
5231  }
5232  }
5233 
5234  templateArgs += typeName;
5235  }
5236 
5237  templateArgs+=">";
5238  return 0;
5239 }
5240 
5241 ////////////////////////////////////////////////////////////////////////////////
5242 /// Convert a tmplt decl to its fwd decl
5243 
5244 int ROOT::TMetaUtils::AST2SourceTools::FwdDeclFromTmplDecl(const clang::TemplateDecl& templDecl,
5245  const cling::Interpreter& interpreter,
5246  std::string& defString)
5247 {
5248  std::string templatePrefixString;
5249  auto tmplParamList= templDecl.getTemplateParameters();
5250  if (!tmplParamList){ // Should never happen
5251  Error(0,
5252  "Cannot extract template parameter list for %s",
5253  templDecl.getNameAsString().c_str());
5254  return 1;
5255  }
5256 
5257  int retCode = PrepareArgsForFwdDecl(templatePrefixString,*tmplParamList,interpreter);
5258  if (retCode!=0){
5259  Warning(0,
5260  "Problems with arguments for forward declaration of class %s\n",
5261  templDecl.getNameAsString().c_str());
5262  return retCode;
5263  }
5264  templatePrefixString = "template " + templatePrefixString + " ";
5265 
5266  defString = templatePrefixString + "class ";
5267  if (templDecl.isParameterPack())
5268  defString += "... ";
5269  defString += templDecl.getNameAsString();
5270  if (llvm::isa<clang::TemplateTemplateParmDecl>(&templDecl)) {
5271  // When fwd declaring the template template arg of
5272  // namespace N { template <template <class T> class C> class X; }
5273  // we don't need to put it into any namespace, and we want no trailing
5274  // ';'
5275  return 0;
5276  }
5277  defString += ';';
5278  return EncloseInNamespaces(templDecl, defString);
5279 }
5280 
5281 ////////////////////////////////////////////////////////////////////////////////
5282 
5283 static int TreatSingleTemplateArg(const clang::TemplateArgument& arg,
5284  std::string& argFwdDecl,
5285  const cling::Interpreter& interpreter,
5286  bool acceptStl=false)
5287 {
5288  using namespace ROOT::TMetaUtils::AST2SourceTools;
5289 
5290  // We do nothing in presence of ints, bools, templates.
5291  // We should probably in presence of templates though...
5292  if (clang::TemplateArgument::Type != arg.getKind()) return 0;
5293 
5294  auto argQualType = arg.getAsType();
5295 
5296  // Recursively remove all *
5297  while (llvm::isa<clang::PointerType>(argQualType.getTypePtr())) argQualType = argQualType->getPointeeType();
5298 
5299  auto argTypePtr = argQualType.getTypePtr();
5300 
5301  // Bail out on enums
5302  if (llvm::isa<clang::EnumType>(argTypePtr)){
5303  return 1;
5304  }
5305 
5306  // If this is a built-in, just return: fwd decl not necessary.
5307  if (llvm::isa<clang::BuiltinType>(argTypePtr)){
5308  return 0;
5309  }
5310 
5311  // Treat typedefs which are arguments
5312  if (auto tdTypePtr = llvm::dyn_cast<clang::TypedefType>(argTypePtr)) {
5313  FwdDeclFromTypeDefNameDecl(*tdTypePtr->getDecl(), interpreter, argFwdDecl);
5314  return 0;
5315  }
5316 
5317  if (auto argRecTypePtr = llvm::dyn_cast<clang::RecordType>(argTypePtr)){
5318  // Now we cannot but have a RecordType
5319  if (auto argRecDeclPtr = argRecTypePtr->getDecl()){
5320  FwdDeclFromRcdDecl(*argRecDeclPtr,interpreter,argFwdDecl,acceptStl);
5321  }
5322  return 0;
5323  }
5324 
5325  return 1;
5326 }
5327 
5328 ////////////////////////////////////////////////////////////////////////////////
5329 /// Convert a rcd decl to its fwd decl
5330 /// If this is a template specialisation, treat in the proper way.
5331 /// If it is contained in a class, just fwd declare the class.
5332 
5333 int ROOT::TMetaUtils::AST2SourceTools::FwdDeclFromRcdDecl(const clang::RecordDecl& recordDecl,
5334  const cling::Interpreter& interpreter,
5335  std::string& defString,
5336  bool acceptStl)
5337 {
5338  // Do not fwd declare the templates in the stl.
5339  if (ROOT::TMetaUtils::IsStdClass(recordDecl) && !acceptStl)
5340  return 0;
5341 
5342  // Do not fwd declare unnamed decls.
5343  if (!recordDecl.getIdentifier())
5344  return 0;
5345 
5346  // We may need to fwd declare the arguments of the template
5347  std::string argsFwdDecl;
5348 
5349  if (auto tmplSpecDeclPtr = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&recordDecl)){
5350  std::string argFwdDecl;
5352  std::cout << "Class " << recordDecl.getNameAsString()
5353  << " is a template specialisation. Treating its arguments.\n";
5354  for(auto arg : tmplSpecDeclPtr->getTemplateArgs().asArray()){
5355  int retCode = TreatSingleTemplateArg(arg, argFwdDecl, interpreter, acceptStl);
5357  std::cout << " o Template argument ";
5358  if (retCode==0){
5359  std::cout << "successfully treated. Arg fwd decl: " << argFwdDecl << std::endl;
5360  } else {
5361  std::cout << "could not be treated. Abort fwd declaration generation.\n";
5362  }
5363  }
5364 
5365  if (retCode!=0){ // A sign we must bail out
5366  return retCode;
5367  }
5368  argsFwdDecl+=argFwdDecl;
5369  }
5370 
5371  if (acceptStl){
5372  defString=argsFwdDecl;
5373  return 0;
5374  }
5375 
5376  int retCode=0;
5377  if (auto tmplDeclPtr = tmplSpecDeclPtr->getSpecializedTemplate()){
5378  retCode = FwdDeclFromTmplDecl(*tmplDeclPtr,interpreter,defString);
5379  }
5380  defString = argsFwdDecl + "\n" + defString;
5381  return retCode;
5382 
5383  }
5384 
5385  defString = "class " + recordDecl.getNameAsString() + ";";
5386  const clang::RecordDecl* rcd = EncloseInScopes(recordDecl, defString);
5387 
5388  if (rcd){
5389  FwdDeclFromRcdDecl(*rcd, interpreter,defString);
5390  }
5391  // Add a \n here to avoid long lines which contain duplications, for example (from MathCore):
5392  // namespace ROOT { namespace Math { class IBaseFunctionMultiDim; } }namespace ROOT { namespace Fit { template <typename FunType> class Chi2FCN; } }
5393  // namespace ROOT { namespace Math { class IGradientFunctionMultiDim; } }namespace ROOT { namespace Fit { template <typename FunType> class Chi2FCN; } }
5394  defString = argsFwdDecl + "\n" + defString;
5395 
5396  return 0;
5397 }
5398 
5399 ////////////////////////////////////////////////////////////////////////////////
5400 /// Extract "forward declaration" of a typedef.
5401 /// If the typedef is contained in a class, just fwd declare the class.
5402 /// If not, fwd declare the typedef and all the dependent typedefs and types if necessary.
5403 
5404 int ROOT::TMetaUtils::AST2SourceTools::FwdDeclFromTypeDefNameDecl(const clang::TypedefNameDecl& tdnDecl,
5405  const cling::Interpreter& interpreter,
5406  std::string& fwdDeclString,
5407  std::unordered_set<std::string>* fwdDeclSetPtr)
5408 {
5409  std::string buffer = tdnDecl.getNameAsString();
5410  std::string underlyingName;
5411  auto underlyingType = tdnDecl.getUnderlyingType().getCanonicalType();
5412  if (const clang::TagType* TT
5413  = llvm::dyn_cast<clang::TagType>(underlyingType.getTypePtr())) {
5414  if (clang::NamedDecl* ND = TT->getDecl()) {
5415  if (!ND->getIdentifier()) {
5416  // No fwd decl for unnamed underlying entities.
5417  return 0;
5418  }
5419  }
5420  }
5421 
5422  TNormalizedCtxt nCtxt(interpreter.getLookupHelper());
5423  ROOT::TMetaUtils::GetNormalizedName(underlyingName,
5424  underlyingType,
5425  interpreter,
5426  nCtxt);
5427 
5428  // Heuristic: avoid entities like myclass<myType1, myType2::xyz>
5429  if (underlyingName.find(">::") != std::string::npos)
5430  return 0;
5431 
5432  buffer="typedef "+underlyingName+" "+buffer+";";
5433  const clang::RecordDecl* rcd=EncloseInScopes(tdnDecl,buffer);
5434  if (rcd) {
5435  // We do not need the whole series of scopes, just the class.
5436  // It is enough to trigger an uncomplete type autoload/parse callback
5437  // for example: MyClass::blabla::otherNs::myTypedef
5438  return FwdDeclFromRcdDecl(*rcd, interpreter,fwdDeclString,fwdDeclSetPtr);
5439  }
5440 
5441  // Start Recursion if the underlying type is a TypedefNameDecl
5442  // Note: the simple cast w/o the getSingleStepDesugaredType call
5443  // does not work in case the typedef is in a namespace.
5444  auto& ctxt = tdnDecl.getASTContext();
5445  auto immediatelyUnderlyingType = underlyingType.getSingleStepDesugaredType(ctxt);
5446 
5447  if (auto underlyingTdnTypePtr = llvm::dyn_cast<clang::TypedefType>(immediatelyUnderlyingType.getTypePtr())){
5448  std::string tdnFwdDecl;
5449  auto underlyingTdnDeclPtr = underlyingTdnTypePtr->getDecl();
5450  FwdDeclFromTypeDefNameDecl(*underlyingTdnDeclPtr,
5451  interpreter,
5452  tdnFwdDecl,
5453  fwdDeclSetPtr);
5454  if (!fwdDeclSetPtr || fwdDeclSetPtr->insert(tdnFwdDecl).second)
5455  fwdDeclString+=tdnFwdDecl;
5456  } else if (auto CXXRcdDeclPtr = immediatelyUnderlyingType->getAsCXXRecordDecl()){
5457  std::string classFwdDecl;
5459  std::cout << "Typedef " << tdnDecl.getNameAsString() << " hides a class: "
5460  << CXXRcdDeclPtr->getNameAsString() << std::endl;
5461  int retCode = FwdDeclFromRcdDecl(*CXXRcdDeclPtr,
5462  interpreter,
5463  classFwdDecl,
5464  true /* acceptStl*/);
5465  if (retCode!=0){ // bail out
5466  return 0;
5467  }
5468 
5469  if (!fwdDeclSetPtr || fwdDeclSetPtr->insert(classFwdDecl).second)
5470  fwdDeclString+=classFwdDecl;
5471  }
5472 
5473  fwdDeclString+=buffer;
5474 
5475  return 0;
5476 }
5477 
5478 ////////////////////////////////////////////////////////////////////////////////
5479 /// Get the default value as string.
5480 /// Limited at the moment to:
5481 /// - Integers
5482 /// - Booleans
5483 
5484 int ROOT::TMetaUtils::AST2SourceTools::GetDefArg(const clang::ParmVarDecl& par,
5485  std::string& valAsString,
5486  const clang::PrintingPolicy& ppolicy)
5487 {
5488  auto defArgExprPtr = par.getDefaultArg();
5489  auto& ctxt = par.getASTContext();
5490  if(!defArgExprPtr->isEvaluatable(ctxt)){
5491  return -1;
5492  }
5493 
5494  auto defArgType = par.getType();
5495 
5496  // The value is a boolean
5497  if (defArgType->isBooleanType()){
5498  bool result;
5499  defArgExprPtr->EvaluateAsBooleanCondition (result,ctxt);
5500  valAsString=std::to_string(result);
5501  return 0;
5502  }
5503 
5504  // The value is an integer
5505  if (defArgType->isIntegerType()){
5506  llvm::APSInt result;
5507  defArgExprPtr->EvaluateAsInt(result,ctxt);
5508  auto uintVal = *result.getRawData();
5509  if (result.isNegative()){
5510  long long int intVal=uintVal*-1;
5511  valAsString=std::to_string(intVal);
5512  } else {
5513  valAsString=std::to_string(uintVal);
5514  }
5515 
5516  return 0;
5517  }
5518 
5519  // The value is something else. We go for the generalised printer
5520  llvm::raw_string_ostream rso(valAsString);
5521  defArgExprPtr->printPretty(rso,nullptr,ppolicy);
5522  valAsString = rso.str();
5523  // We can be in presence of a string. Let's escape the characters properly.
5524  ROOT::TMetaUtils::ReplaceAll(valAsString,"\\\"","__TEMP__VAL__");
5525  ROOT::TMetaUtils::ReplaceAll(valAsString,"\"","\\\"");
5526  ROOT::TMetaUtils::ReplaceAll(valAsString,"__TEMP__VAL__","\\\"");
5527 
5528  return 0;
5529 }
5530 
ROOT::TMetaUtils::RConstructorType::GetType
const clang::CXXRecordDecl * GetType() const
Definition: TClingUtils.cxx:1176
c
#define c(i)
Definition: RSha256.hxx:119
ROOT::TMetaUtils::IsSTLContainer
int IsSTLContainer(const AnnotatedRecordDecl &annotated)
Is this an STL container.
Definition: TClingUtils.cxx:2649
ROOT::TMetaUtils::propNames::separator
static const std::string separator("@@@")
m
auto * m
Definition: textangle.C:8
ROOT::TMetaUtils::TClingLookupHelper::IsAlreadyPartiallyDesugaredName
virtual bool IsAlreadyPartiallyDesugaredName(const std::string &nondef, const std::string &nameLong)
Definition: TClingUtils.cxx:576
ROOT::TMetaUtils::AnnotatedRecordDecl::fRequestNoStreamer
bool fRequestNoStreamer
Definition: TClingUtils.h:201
GetMethodWithProto
const clang::CXXMethodDecl * GetMethodWithProto(const clang::Decl *cinfo, const char *method, const char *proto, const cling::Interpreter &interp, bool diagnose)
Definition: TClingUtils.cxx:1146
ROOT::TMetaUtils::GetCppName
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...
Definition: TClingUtils.cxx:3278
ROOT::kSTLdeque
@ kSTLdeque
Definition: ESTLType.h:44
ROOT::TMetaUtils::HasCustomOperatorNewPlacement
bool HasCustomOperatorNewPlacement(char const *, clang::RecordDecl const &, const cling::Interpreter &)
return true if we can find a custom operator new with placement
Definition: TClingUtils.cxx:2308
llvm
Definition: TString.h:850
ROOT::TMetaUtils::propNames::ioname
static const std::string ioname("ioname")
ROOT::TMetaUtils::AnnotatedRecordDecl::fRuleIndex
long fRuleIndex
Definition: TClingUtils.h:195
ROOT::kSTLvector
@ kSTLvector
Definition: ESTLType.h:42
ROOT::TMetaUtils::TNormalizedCtxt::GetNargsToKeep
int GetNargsToKeep(const clang::ClassTemplateDecl *templ) const
Definition: TClingUtils.cxx:354
ROOT::kSTLset
@ kSTLset
Definition: ESTLType.h:47
IsTemplate
bool IsTemplate(const clang::Decl &cl)
Definition: TClingUtils.cxx:761
tt
auto * tt
Definition: textangle.C:16
ROOT::TMetaUtils::AnnotatedRecordDecl::fRequestedName
std::string fRequestedName
Definition: TClingUtils.h:197
ROOT::TMetaUtils::GetUnderlyingType
const clang::Type * GetUnderlyingType(clang::QualType type)
Return the base/underlying type of a chain of array or pointers type.
Definition: TClingUtils.cxx:4351
ROOT::kSTLunorderedmultimap
@ kSTLunorderedmultimap
Definition: ESTLType.h:57
ROOT::kSTLbitset
@ kSTLbitset
Definition: ESTLType.h:49
ROOT::TMetaUtils::IsStreamableObject
bool IsStreamableObject(const clang::FieldDecl &m, const cling::Interpreter &interp)
Definition: TClingUtils.cxx:2766
Version_t
short Version_t
Definition: RtypesCore.h:65
ROOT::TMetaUtils::HasIOConstructor
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...
Definition: TClingUtils.cxx:1184
TClassEdit::GetNameForIO
std::string GetNameForIO(const std::string &templateInstanceName, TClassEdit::EModType mode=TClassEdit::kNone, bool *hasChanged=nullptr)
Definition: TClassEdit.cxx:2047
Warning
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition: TError.cxx:231
ROOT::TMetaUtils::AnnotatedRecordDecl::fNormalizedName
std::string fNormalizedName
Definition: TClingUtils.h:198
ROOT::TMetaUtils::AnnotatedRecordDecl::RequestStreamerInfo
bool RequestStreamerInfo() const
Definition: TClingUtils.h:272
ROOT::TMetaUtils::ReplaceAll
void ReplaceAll(std::string &str, const std::string &from, const std::string &to, bool recurse=false)
Definition: TClingUtils.cxx:5018
dest
#define dest(otri, vertexptr)
Definition: triangle.c:1040
ROOT::TMetaUtils::GetLineNumber
long GetLineNumber(clang::Decl const *)
It looks like the template specialization decl actually contains less information on the location of ...
Definition: TClingUtils.cxx:1565
ROOT::TMetaUtils::AST2SourceTools::PrepareArgsForFwdDecl
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...
Definition: TClingUtils.cxx:5182
ROOT::TMetaUtils::Warning
void Warning(const char *location, const char *va_(fmt),...)
Definition: TClingUtils.h:819
ROOT::TMetaUtils::AST2SourceTools::FwdDeclFromRcdDecl
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.
Definition: TClingUtils.cxx:5333
ROOT::TMetaUtils::TClingLookupHelper::IsDeclaredScope
virtual bool IsDeclaredScope(const std::string &base, bool &isInlined)
Definition: TClingUtils.cxx:592
RStl.h
ROOT::TMetaUtils::AST2SourceTools::EncloseInScopes
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.
Definition: TClingUtils.cxx:5143
ROOT::TMetaUtils::AnnotatedRecordDecl
Definition: TClingUtils.h:191
ROOT::TMetaUtils::GetNormalizedType
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,...
Definition: TClingUtils.cxx:4010
ROOT::TMetaUtils::AST2SourceTools
Definition: TClingUtils.h:853
ROOT::TMetaUtils::QualType2ClassTemplateDecl
clang::ClassTemplateDecl * QualType2ClassTemplateDecl(const clang::QualType &qt)
Extract from a qualtype the class template if this makes sense.
Definition: TClingUtils.cxx:3563
ROOT::TMetaUtils::TClingLookupHelper::fAutoParse
AutoParse_t fAutoParse
Definition: TClingUtils.h:169
ROOT::kSTLunorderedmultiset
@ kSTLunorderedmultiset
Definition: ESTLType.h:55
ROOT::kNotSTL
@ kNotSTL
Definition: ESTLType.h:41
ROOT::TMetaUtils::AnnotatedRecordDecl::fDemangledTypeInfo
std::string fDemangledTypeInfo
Definition: TClingUtils.h:199
ROOT::TMetaUtils::AnnotatedRecordDecl::GetRequestedName
const char * GetRequestedName() const
Definition: TClingUtils.h:268
ROOT::TMetaUtils::HasDirectoryAutoAdd
bool HasDirectoryAutoAdd(clang::CXXRecordDecl const *, const cling::Interpreter &)
Return true if the class has a method DirectoryAutoAdd(TDirectory *)
Definition: TClingUtils.cxx:1267
ROOT::WriteReadRawRuleFunc
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"...
Definition: RConversionRuleParser.cxx:694
TClassEdit::kLong64
@ kLong64
Definition: TClassEdit.h:84
ROOT::TMetaUtils::ShortTypeName
const char * ShortTypeName(const char *typeDesc)
Return the absolute type of typeDesc.
Definition: TClingUtils.cxx:2734
ROOT::kSTLend
@ kSTLend
Definition: ESTLType.h:58
TClassEdit::IsStdClass
bool IsStdClass(const char *type)
return true if the class belongs to the std namespace
Definition: TClassEdit.cxx:1373
ROOT::TMetaUtils::HasCustomOperatorNewArrayPlacement
bool HasCustomOperatorNewArrayPlacement(clang::RecordDecl const &, const cling::Interpreter &interp)
return true if we can find a custom operator new with placement
Definition: TClingUtils.cxx:2396
ROOT::TMetaUtils::NeedDestructor
bool NeedDestructor(clang::CXXRecordDecl const *, const cling::Interpreter &)
Definition: TClingUtils.cxx:1230
ROOT::gReadRawRules
R__EXTERN SchemaRuleClassMap_t gReadRawRules
Definition: RConversionRuleParser.h:25
ROOT::TMetaUtils::ReSubstTemplateArg
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...
Definition: TClingUtils.cxx:4541
ROOT::MembersTypeMap_t
std::map< std::string, ROOT::Internal::TSchemaType > MembersTypeMap_t
Definition: RConversionRuleParser.h:27
TGeant4Unit::s
static constexpr double s
Definition: TGeant4SystemOfUnits.h:168
TClassEdit::GetLong64_Name
std::string GetLong64_Name(const char *original)
Replace 'long long' and 'unsigned long long' by 'Long64_t' and 'ULong64_t'.
Definition: TClassEdit.cxx:873
ROOT::TMetaUtils::AnnotatedRecordDecl::fRequestOnlyTClass
bool fRequestOnlyTClass
Definition: TClingUtils.h:203
ROOT::TMetaUtils::Error
void Error(const char *location, const char *va_(fmt),...)
Definition: TClingUtils.h:789
N
#define N
ROOT::TMetaUtils::GetFullyQualifiedTypeName
void GetFullyQualifiedTypeName(std::string &name, const clang::QualType &type, const cling::Interpreter &interpreter)
Definition: TClingUtils.cxx:3501
ROOT::FoundationUtils::GetPathSeparator
const std::string & GetPathSeparator()
Return the separator suitable for this platform.
Definition: FoundationUtils.hxx:55
ROOT::TMetaUtils::TNormalizedCtxt::GetTemplNargsToKeepMap
const TemplPtrIntMap_t GetTemplNargsToKeepMap() const
Definition: TClingUtils.cxx:358
ROOT::TMetaUtils::ExtractAttrIntPropertyFromName
bool ExtractAttrIntPropertyFromName(const clang::Decl &decl, const std::string &propName, int &propValue)
This routine counts on the "propName<separator>propValue" format.
Definition: TClingUtils.cxx:1727
ROOT::TMetaUtils::propNames::nArgsToKeep
static const std::string nArgsToKeep("nArgsToKeep")
indent
static void indent(ostringstream &buf, int indent_level)
Definition: TClingCallFunc.cxx:87
RooFitShortHand::S
RooArgSet S(const RooAbsArg &v1)
Definition: RooGlobalFunc.cxx:348
ROOT::TMetaUtils::TClingLookupHelper::WantDiags
bool WantDiags() const
Definition: TClingUtils.h:172
ROOT::TMetaUtils::RConstructorType::RConstructorType
RConstructorType(const char *type_of_arg, const cling::Interpreter &)
Definition: TClingUtils.cxx:1166
ROOT::TMetaUtils::TrueName
std::string TrueName(const clang::FieldDecl &m)
TrueName strips the typedefs and array dimensions.
Definition: TClingUtils.cxx:2569
ROOT::TMetaUtils::extractPropertyNameVal
int extractPropertyNameVal(clang::Attr *attribute, std::string &attrName, std::string &attrValue)
Definition: TClingUtils.cxx:1693
RConfig.hxx
ROOT::TMetaUtils::IS_PRIVATE
@ IS_PRIVATE
Definition: TClingUtils.h:118
ROOT::Math::Cephes::A
static double A[]
Definition: SpecFuncCephes.cxx:170
ROOT::TMetaUtils::TClingLookupHelper::fInterpreterIsShuttingDownPtr
bool * fInterpreterIsShuttingDownPtr
Definition: TClingUtils.h:170
TClassEdit::TSplitType
Definition: TClassEdit.h:137
ROOT::TMetaUtils::GetUnderlyingRecordDecl
clang::RecordDecl * GetUnderlyingRecordDecl(clang::QualType type)
Definition: TClingUtils.cxx:2842
RecurseKeepNParams
static bool RecurseKeepNParams(clang::TemplateArgument &normTArg, const clang::TemplateArgument &tArg, const cling::Interpreter &interp, const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt, const clang::ASTContext &astCtxt)
Definition: TClingUtils.cxx:3746
ROOT::TMetaUtils::ExtractEnclosingScopes
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.
Definition: TClingUtils.cxx:4923
ROOT::TMetaUtils::AST2SourceTools::EncloseInNamespaces
int EncloseInNamespaces(const clang::Decl &decl, std::string &defString)
Take the namespaces which enclose the decl and put them around the definition string.
Definition: TClingUtils.cxx:5131
ROOT::kSTLlist
@ kSTLlist
Definition: ESTLType.h:43
ROOT::TMetaUtils::GetModuleFileName
std::string GetModuleFileName(const char *moduleName)
Return the dictionary file name for a module.
Definition: TClingUtils.cxx:4152
TNCtxtFullQual
ROOT::TMetaUtils::TNormalizedCtxtImpl TNCtxtFullQual
Definition: TClingUtils.cxx:756
ROOT::TMetaUtils::AST2SourceTools::GetDefArg
int GetDefArg(const clang::ParmVarDecl &par, std::string &valAsString, const clang::PrintingPolicy &pp)
Get the default value as string.
Definition: TClingUtils.cxx:5484
ROOT::TMetaUtils::CheckPublicFuncWithProto
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.
Definition: TClingUtils.cxx:1251
ROOT::Math::IntegrationOneDim::Type
Type
enumeration specifying the integration types.
Definition: AllIntegrationTypes.h:60
getFinalSpellingLoc
static clang::SourceLocation getFinalSpellingLoc(clang::SourceManager &sourceManager, clang::SourceLocation sourceLoc)
Definition: TClingUtils.cxx:3327
ROOT::TMetaUtils::WritePointersSTL
void WritePointersSTL(const AnnotatedRecordDecl &cl, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt)
Write interface function for STL members.
Definition: TClingUtils.cxx:2512
ROOT::TMetaUtils::GetNormalizedName
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,...
Definition: TClingUtils.cxx:4036
ROOT::TMetaUtils::WriteClassInit
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 ~300 lines!
Definition: TClingUtils.cxx:1749
ROOT::TMetaUtils::extractPropertyNameValFromString
int extractPropertyNameValFromString(const std::string attributeStr, std::string &attrName, std::string &attrValue)
Definition: TClingUtils.cxx:1676
ROOT::TMetaUtils::TNormalizedCtxt::keepTypedef
void keepTypedef(const cling::LookupHelper &lh, const char *name, bool replace=false)
Definition: TClingUtils.cxx:361
ROOT::TMetaUtils::DataMemberInfo__ValidArrayIndex
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 ...
Definition: TClingUtils.cxx:3129
ROOT::kSTLmap
@ kSTLmap
Definition: ESTLType.h:45
ROOT::TMetaUtils::TClingLookupHelper::TClingLookupHelper
TClingLookupHelper(cling::Interpreter &interpreter, TNormalizedCtxt &normCtxt, ExistingTypeCheck_t existingTypeCheck, AutoParse_t autoParse, bool *shuttingDownPtr, const int *pgDebug=0)
Definition: TClingUtils.cxx:531
ROOT::TMetaUtils::CheckDefaultConstructor
bool CheckDefaultConstructor(const clang::CXXRecordDecl *, const cling::Interpreter &interp)
Checks if default constructor exists and accessible.
Definition: TClingUtils.cxx:1048
ROOT::TMetaUtils::Fatal
void Fatal(const char *location, const char *va_(fmt),...)
Definition: TClingUtils.h:829
ROOT::TMetaUtils::AnnotatedRecordDecl::GetNormalizedName
const char * GetNormalizedName() const
Definition: TClingUtils.h:269
ROOT::TMetaUtils::propNames::iotype
static const std::string iotype("iotype")
ROOT::TMetaUtils::TNormalizedCtxt::TemplPtrIntMap_t
std::map< const clang::ClassTemplateDecl *, int > TemplPtrIntMap_t
Definition: TClingUtils.h:144
ROOT::TMetaUtils::TNormalizedCtxt::AddTemplAndNargsToKeep
void AddTemplAndNargsToKeep(const clang::ClassTemplateDecl *templ, unsigned int i)
Definition: TClingUtils.cxx:350
ROOT::TMetaUtils::MatchWithDeclOrAnyOfPrevious
bool MatchWithDeclOrAnyOfPrevious(const clang::CXXRecordDecl &cl, const clang::CXXRecordDecl &currentCl)
This is a recursive function.
Definition: TClingUtils.cxx:4413
ROOT::TMetaUtils::Info
void Info(const char *location, const char *va_(fmt),...)
Definition: TClingUtils.h:809
GetEnclosingSpace
const clang::DeclContext * GetEnclosingSpace(const clang::RecordDecl &cl)
Definition: TClingUtils.cxx:2244
ROOT::TMetaUtils::HasCustomStreamerMemberFunction
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.
Definition: TClingUtils.cxx:1327
ROOT::TMetaUtils::IsStdClass
bool IsStdClass(const clang::RecordDecl &cl)
Return true, if the decl is part of the std namespace.
Definition: TClingUtils.cxx:4386
ROOT::TMetaUtils::GetQualifiedName
void GetQualifiedName(std::string &qual_name, const clang::QualType &type, const clang::NamedDecl &forcontext)
Main implementation relying on GetFullyQualifiedTypeName All other GetQualifiedName functions leverag...
Definition: TClingUtils.cxx:1368
ROOT::TMetaUtils::IsStdDropDefaultClass
bool IsStdDropDefaultClass(const clang::RecordDecl &cl)
Return true, if the decl is part of the std namespace and we want its default parameter dropped.
Definition: TClingUtils.cxx:4395
ROOT::TMetaUtils::RConstructorType::fArgType
const clang::CXXRecordDecl * fArgType
Definition: TClingUtils.h:313
ROOT::TMetaUtils::GetNameWithinNamespace
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...
Definition: TClingUtils.cxx:2211
ROOT::TMetaUtils::AnnotatedRecordDecl::fRequestedVersionNumber
int fRequestedVersionNumber
Definition: TClingUtils.h:204
ROOT::ESTLType
ESTLType
Definition: ESTLType.h:34
ROOT::TMetaUtils::AnnotatedRecordDecl::HasClassVersion
bool HasClassVersion() const
Definition: TClingUtils.h:271
ROOT::TMetaUtils::GetNameTypeForIO
std::pair< std::string, clang::QualType > GetNameTypeForIO(const clang::QualType &templateInstanceType, const cling::Interpreter &interpreter, const TNormalizedCtxt &normCtxt, TClassEdit::EModType mode=TClassEdit::kNone)
Definition: TClingUtils.cxx:4093
ROOT::TMetaUtils::HasCustomConvStreamerMemberFunction
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.
Definition: TClingUtils.cxx:1346
TClassEdit::DemangleName
char * DemangleName(const char *mangled_name, int &errorCode)
Definition: TClassEdit.h:205
ROOT::TMetaUtils::CheckConstructor
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.
Definition: TClingUtils.cxx:1128
replaceEnvVars
static void replaceEnvVars(const char *varname, std::string &txt)
Reimplementation of TSystem::ExpandPathName() that cannot be used from TMetaUtils.
Definition: TClingUtils.cxx:4951
TClassEdit::IsSTLCont
ROOT::ESTLType IsSTLCont(std::string_view type)
type : type name: vector<list<classA,allocator>,allocator> result: 0 : not stl container code of cont...
Definition: TClassEdit.cxx:1333
ROOT::TMetaUtils::GetClassComment
llvm::StringRef GetClassComment(const clang::CXXRecordDecl &decl, clang::SourceLocation *loc, const cling::Interpreter &interpreter)
Return the class comment after the ClassDef: class MyClass { ...
Definition: TClingUtils.cxx:4317
ROOT::kSTLmultiset
@ kSTLmultiset
Definition: ESTLType.h:48
ROOT::TMetaUtils::GetAnnotatedRedeclarable
const T * GetAnnotatedRedeclarable(const T *Redecl)
Definition: TClingUtils.h:641
ROOT::TMetaUtils::GetRealPath
std::string GetRealPath(const std::string &path)
Definition: TClingUtils.cxx:85
ROOT::TMetaUtils::ExtractAttrPropertyFromName
bool ExtractAttrPropertyFromName(const clang::Decl &decl, const std::string &propName, std::string &propValue)
This routine counts on the "propName<separator>propValue" format.
Definition: TClingUtils.cxx:1704
ROOT::TMetaUtils::CreateNameTypeMap
void CreateNameTypeMap(clang::CXXRecordDecl const &, std::map< std::string, ROOT::Internal::TSchemaType > &)
ROOT::TMetaUtils::GetFuncWithProto
const clang::FunctionDecl * GetFuncWithProto(const clang::Decl *cinfo, const char *method, const char *proto, const cling::Interpreter &gInterp, bool diagnose)
Definition: TClingUtils.cxx:1525
ROOT::kSTLforwardlist
@ kSTLforwardlist
Definition: ESTLType.h:53
ROOT::TMetaUtils::IsLinkdefFile
bool IsLinkdefFile(const char *filename)
Definition: TClingUtils.cxx:5068
ROOT::TMetaUtils::TNormalizedCtxt::~TNormalizedCtxt
~TNormalizedCtxt()
Definition: TClingUtils.cxx:341
ROOT::TMetaUtils::RemoveTemplateArgsFromName
int RemoveTemplateArgsFromName(std::string &name, unsigned int)
Remove the last n template arguments from the name.
Definition: TClingUtils.cxx:4796
ROOT::TMetaUtils::HasNewMerge
bool HasNewMerge(clang::CXXRecordDecl const *, const cling::Interpreter &)
Return true if the class has a method Merge(TCollection*,TFileMergeInfo*)
Definition: TClingUtils.cxx:1282
ROOT::TMetaUtils::VALID
@ VALID
Definition: TClingUtils.h:118
ROOT::WriteSchemaList
void WriteSchemaList(std::list< SchemaRuleMap_t > &rules, const std::string &listName, std::ostream &output)
Write schema rules.
Definition: RConversionRuleParser.cxx:765
ROOT::TMetaUtils::IsHeaderName
bool IsHeaderName(const std::string &filename)
Definition: TClingUtils.cxx:5093
ROOT::TMetaUtils::AnnotatedRecordDecl::RootFlag
int RootFlag() const
Definition: TClingUtils.h:280
a
auto * a
Definition: textangle.C:12
TClassEdit::IsSTLBitset
bool IsSTLBitset(const char *type)
Return true is the name is std::bitset<number> or bitset<number>
Definition: TClassEdit.cxx:1295
ROOT::TMetaUtils::extractAttrString
int extractAttrString(clang::Attr *attribute, std::string &attrString)
Extract attr string.
Definition: TClingUtils.cxx:1663
ROOT::TMetaUtils::TNormalizedCtxt::TypesCont_t
std::set< const clang::Type * > TypesCont_t
Definition: TClingUtils.h:143
dumpDeclForAssert
int dumpDeclForAssert(const clang::Decl &D, const char *commentStart)
Definition: TClingUtils.cxx:4159
ROOT::TMetaUtils::TNormalizedCtxt::TNormalizedCtxt
TNormalizedCtxt(const cling::LookupHelper &lh)
Definition: TClingUtils.cxx:333
ROOT::R::function
void function(const Char_t *name_, T fun, const Char_t *docstring=0)
Definition: RExports.h:151
ROOT::TMetaUtils::CallWriteStreamer_t
void(* CallWriteStreamer_t)(const AnnotatedRecordDecl &cl, const cling::Interpreter &interp, const TNormalizedCtxt &normCtxt, std::ostream &dictStream, bool isAutoStreamer)
Definition: TClingUtils.h:120