Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
Scanner.cxx
Go to the documentation of this file.
1 // @(#)root/utils/src:$Id$
2 // Author: Philippe Canal November 2011 ; originated from Zdenek Culik 16/04/2010 and Velislava Spasova.
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/rootcint. *
10  *************************************************************************/
11 
12 #include "Scanner.h"
13 #include "clang/AST/ASTConsumer.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Basic/SourceManager.h"
16 #include "llvm/ADT/SmallSet.h"
17 #include "clang/Sema/Sema.h"
18 #include "clang/Frontend/CompilerInstance.h"
19 
20 #include "cling/Interpreter/Interpreter.h"
21 #include "llvm/Support/Path.h"
22 
23 #include "TClassEdit.h"
24 
25 #include <iostream>
26 #include <sstream> // class ostringstream
27 
28 #include "SelectionRules.h"
29 
30 namespace {
31 
32  class RPredicateIsSameNamespace
33  {
34  private:
35  clang::NamespaceDecl *fTarget;
36  public:
37  RPredicateIsSameNamespace(clang::NamespaceDecl *target) : fTarget(target) {}
38 
39  bool operator()(const RScanner::AnnotatedNamespaceDecl& element)
40  {
41  return (fTarget == element);
42  }
43  };
44 
45 template<class T>
46 inline static bool IsElementPresent(const std::vector<T> &v, const T &el){
47  return std::find(v.begin(),v.end(),el) != v.end();
48 }
49 
50 template<class T>
51 inline static bool IsElementPresent(const std::vector<const T*> &v, T *el){
52  return std::find(v.begin(),v.end(),el) != v.end();
53 }
54 
55 }
56 
57 using namespace ROOT;
58 using namespace clang;
59 
60 extern cling::Interpreter *gInterp;
61 
62 const char* RScanner::fgClangDeclKey = "ClangDecl"; // property key used for connection with Clang objects
63 const char* RScanner::fgClangFuncKey = "ClangFunc"; // property key for demangled names
64 
65 int RScanner::fgAnonymousClassCounter = 0;
66 int RScanner::fgBadClassCounter = 0;
67 int RScanner::fgAnonymousEnumCounter = 0;
68 
69 std::map <clang::Decl*, std::string> RScanner::fgAnonymousClassMap;
70 std::map <clang::Decl*, std::string> RScanner::fgAnonymousEnumMap;
71 
72 ////////////////////////////////////////////////////////////////////////////////
73 /// Regular constructor setting up the scanner to search for entities
74 /// matching the 'rules'.
75 
76 RScanner::RScanner (SelectionRules &rules,
77  EScanType stype,
78  const cling::Interpreter &interpret,
79  ROOT::TMetaUtils::TNormalizedCtxt &normCtxt,
80  unsigned int verbose /* = 0 */) :
81  fVerboseLevel(verbose),
82  fSourceManager(0),
83  fInterpreter(interpret),
84  fRecordDeclCallback(0),
85  fNormCtxt(normCtxt),
86  fSelectionRules(rules),
87  fScanType(stype),
88  fFirstPass(true)
89 {
90  // Build the cache for all selection rules
91  fSelectionRules.FillCache();
92 
93  for (int i = 0; i <= fgDeclLast; i ++)
94  fDeclTable [i] = false;
95 
96  for (int i = 0; i <= fgTypeLast; i ++)
97  fTypeTable [i] = false;
98 
99  fLastDecl = 0;
100 }
101 
102 ////////////////////////////////////////////////////////////////////////////////
103 
104 RScanner::~RScanner ()
105 {
106 }
107 
108 ////////////////////////////////////////////////////////////////////////////////
109 /// Whether we can actually visit this declaration, i.e. if it is reachable
110 /// via name lookup.
111 ///
112 /// RScanner shouldn't touch decls for which this method returns false as we
113 /// call Sema methods on those declarations. Those will fail in strange way as
114 /// they assume those decls are already visible.
115 ///
116 /// The main problem this is supposed to prevent is when we use C++ modules and
117 /// have hidden declarations in our AST. Usually they can't be found as they are
118 /// hidden from name lookup until their module is actually imported, but as the
119 /// RecursiveASTVisitor is not supposed to be restricted by lookup limitations,
120 /// it still reaches those hidden declarations.
121 bool RScanner::shouldVisitDecl(clang::NamedDecl *D)
122 {
123  if (auto M = D->getOwningModule()) {
124  return fInterpreter.getSema().isModuleVisible(M);
125  }
126  return true;
127 }
128 
129 ////////////////////////////////////////////////////////////////////////////////
130 
131 inline void* ToDeclProp(clang::Decl* item)
132 {
133  /* conversion and type check used by AddProperty */
134  return item;
135 }
136 
137 ////////////////////////////////////////////////////////////////////////////////
138 
139 inline size_t APIntToSize(const llvm::APInt& num)
140 {
141  return *num.getRawData();
142 }
143 
144 ////////////////////////////////////////////////////////////////////////////////
145 
146 inline long APIntToLong(const llvm::APInt& num)
147 {
148  return *num.getRawData();
149 }
150 
151 ////////////////////////////////////////////////////////////////////////////////
152 
153 inline std::string APIntToStr(const llvm::APInt& num)
154 {
155  return num.toString(10, true);
156 }
157 
158 ////////////////////////////////////////////////////////////////////////////////
159 
160 inline std::string IntToStr(int num)
161 {
162  std::string txt = "";
163  txt += num;
164  return txt;
165 }
166 
167 ////////////////////////////////////////////////////////////////////////////////
168 
169 inline std::string IntToStd(int num)
170 {
171  std::ostringstream stream;
172  stream << num;
173  return stream.str();
174 }
175 
176 ////////////////////////////////////////////////////////////////////////////////
177 
178 inline std::string Message(const std::string &msg, const std::string &location)
179 {
180  std::string loc = location;
181 
182  if (loc == "")
183  return msg;
184  else
185  return loc + " " + msg;
186 }
187 
188 ////////////////////////////////////////////////////////////////////////////////
189 
190 void RScanner::ShowInfo(const std::string &msg, const std::string &location) const
191 {
192  const std::string message = Message(msg, location);
193  std::cout << message << std::endl;
194 }
195 
196 ////////////////////////////////////////////////////////////////////////////////
197 
198 void RScanner::ShowWarning(const std::string &msg, const std::string &location) const
199 {
200  const std::string message = Message(msg, location);
201  std::cout << message << std::endl;
202 }
203 
204 ////////////////////////////////////////////////////////////////////////////////
205 
206 void RScanner::ShowError(const std::string &msg, const std::string &location) const
207 {
208  const std::string message = Message(msg, location);
209  std::cout << message << std::endl;
210 }
211 
212 ////////////////////////////////////////////////////////////////////////////////
213 
214 void RScanner::ShowTemplateInfo(const std::string &msg, const std::string &location) const
215 {
216  std::string loc = location;
217  if (loc == "")
218  loc = GetLocation (fLastDecl);
219  ShowWarning(msg, loc);
220 }
221 
222 ////////////////////////////////////////////////////////////////////////////////
223 
224 std::string RScanner::GetSrcLocation(clang::SourceLocation L) const
225 {
226  std::string location = "";
227  llvm::raw_string_ostream stream(location);
228  L.print(stream, *fSourceManager);
229  return stream.str();
230 }
231 
232 ////////////////////////////////////////////////////////////////////////////////
233 
234 std::string RScanner::GetLocation(clang::Decl* D) const
235 {
236  if (D == NULL)
237  {
238  return "";
239  }
240  else
241  {
242  std::string location = "";
243  llvm::raw_string_ostream stream(location);
244  D->getLocation().print(stream, *fSourceManager);
245  return stream.str();
246  }
247 }
248 
249 ////////////////////////////////////////////////////////////////////////////////
250 
251 std::string RScanner::GetName(clang::Decl* D) const
252 {
253  std::string name = "";
254  // std::string kind = D->getDeclKindName();
255 
256  if (clang::NamedDecl* ND = dyn_cast <clang::NamedDecl> (D)) {
257  name = ND->getQualifiedNameAsString();
258  }
259 
260  return name;
261 }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 
265 inline std::string AddSpace(const std::string &txt)
266 {
267  if (txt == "")
268  return "";
269  else
270  return txt + " ";
271 }
272 
273 ////////////////////////////////////////////////////////////////////////////////
274 
275 void RScanner::DeclInfo(clang::Decl* D) const
276 {
277  std::string location = GetLocation(D);
278  std::string kind = D->getDeclKindName();
279  std::string name = GetName(D);
280  ShowInfo("Scan: " + kind + " declaration " + name, location);
281 }
282 
283 ////////////////////////////////////////////////////////////////////////////////
284 /// unknown - this kind of declaration was not known to programmer
285 
286 void RScanner::UnknownDecl(clang::Decl* D, const std::string &txt) const
287 {
288  std::string location = GetLocation(D);
289  std::string kind = D->getDeclKindName();
290  std::string name = GetName(D);
291  ShowWarning("Unknown " + AddSpace(txt) + kind + " declaration " + name, location);
292 }
293 
294 ////////////////////////////////////////////////////////////////////////////////
295 /// unexpected - this kind of declaration is unexpected (in concrete place)
296 
297 void RScanner::UnexpectedDecl(clang::Decl* D, const std::string &txt) const
298 {
299  std::string location = GetLocation(D);
300  std::string kind = D->getDeclKindName();
301  std::string name = GetName(D);
302  ShowWarning("Unexpected " + kind + " declaration " + name, location);
303 }
304 
305 ////////////////////////////////////////////////////////////////////////////////
306 /// unsupported - this kind of declaration is probably not used (in current version of C++)
307 
308 void RScanner::UnsupportedDecl(clang::Decl* D, const std::string &txt) const
309 {
310  std::string location = GetLocation(D);
311  std::string kind = D->getDeclKindName();
312  std::string name = GetName(D);
313  ShowWarning("Unsupported " + AddSpace(txt) + kind + " declaration " + name, location);
314 }
315 
316 ////////////////////////////////////////////////////////////////////////////////
317 /// unimportant - this kind of declaration is not stored into reflex
318 
319 void RScanner::UnimportantDecl(clang::Decl* D, const std::string &txt) const
320 {
321 }
322 
323 ////////////////////////////////////////////////////////////////////////////////
324 /// information about item, that should be implemented
325 
326 void RScanner::UnimplementedDecl(clang::Decl* D, const std::string &txt)
327 {
328  clang::Decl::Kind k = D->getKind();
329 
330  bool show = true;
331  if (k <= fgDeclLast) {
332  if (fDeclTable [k])
333  show = false; // already displayed
334  else
335  fDeclTable [k] = true;
336  }
337 
338  if (show)
339  {
340  std::string location = GetLocation(D);
341  std::string kind = D->getDeclKindName();
342  std::string name = GetName(D);
343  std::string msg = "Unimplemented ";
344  if (txt == "") {
345  msg += "declaration";
346  } else {
347  msg += txt;
348  }
349  msg += ": ";
350  msg += kind;
351  msg += " ";
352  msg += name;
353  ShowWarning(msg,location);
354  }
355 }
356 
357 ////////////////////////////////////////////////////////////////////////////////
358 
359 void RScanner::UnknownType(clang::QualType qual_type) const
360 {
361  std::string location = GetLocation(fLastDecl);
362  std::string kind = qual_type.getTypePtr()->getTypeClassName();
363  ShowWarning("Unknown " + kind + " type " + qual_type.getAsString(), location);
364 }
365 
366 ////////////////////////////////////////////////////////////////////////////////
367 
368 void RScanner::UnsupportedType(clang::QualType qual_type) const
369 {
370  std::string location = GetLocation(fLastDecl);
371  std::string kind = qual_type.getTypePtr()->getTypeClassName();
372  ShowWarning("Unsupported " + kind + " type " + qual_type.getAsString(), location);
373 }
374 
375 ////////////////////////////////////////////////////////////////////////////////
376 
377 std::string RScanner::GetEnumName(clang::EnumDecl* D) const
378 {
379  std::string enum_name = D->getQualifiedNameAsString();
380 
381  if (! D->getDeclName ()) {
382  if (fgAnonymousEnumMap.find (D) != fgAnonymousEnumMap.end())
383  {
384  // already encountered anonymous enumeration type
385  enum_name = fgAnonymousEnumMap [D];
386  }
387  else
388  {
389  fgAnonymousEnumCounter ++;
390  enum_name = "_ANONYMOUS_ENUM_" + IntToStd(fgAnonymousEnumCounter) + "_"; // !?
391  fgAnonymousEnumMap [D] = enum_name;
392  // ShowInfo ("anonymous enum " + enum_name, GetLocation (D));
393  }
394  }
395 
396  return enum_name;
397 }
398 
399 ////////////////////////////////////////////////////////////////////////////////
400 
401 std::string RScanner::ExprToStr(clang::Expr* expr) const
402 {
403  clang::LangOptions lang_opts;
404  clang::PrintingPolicy print_opts(lang_opts); // !?
405 
406  std::string text = "";
407  llvm::raw_string_ostream stream(text);
408 
409  expr->printPretty(stream, NULL, print_opts);
410 
411  return stream.str();
412 }
413 
414 ////////////////////////////////////////////////////////////////////////////////
415 
416 std::string RScanner::ConvTemplateName(clang::TemplateName& N) const
417 {
418  clang::LangOptions lang_opts;
419  clang::PrintingPolicy print_opts(lang_opts); // !?
420 
421  std::string text = "";
422  llvm::raw_string_ostream stream(text);
423 
424  N.print(stream, print_opts);
425 
426  return stream.str();
427 }
428 
429 ////////////////////////////////////////////////////////////////////////////////
430 
431 std::string RScanner::FuncParameters(clang::FunctionDecl* D) const
432 {
433  std::string result = "";
434 
435  for (clang::FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) {
436  clang::ParmVarDecl* P = *I;
437 
438  if (result != "")
439  result += ";"; // semicolon, not comma, important
440 
441  std::string type = P->getType().getAsString();
442  std::string name = P->getNameAsString();
443 
444  result += type + " " + name;
445 
446  // NO if (P->hasDefaultArg ()) // check hasUnparsedDefaultArg () and hasUninstantiatedDefaultArg ()
447  if (P->getInit()) {
448  std::string init_value = ExprToStr(P->getDefaultArg());
449  result += "=" + init_value;
450  }
451  }
452 
453  return result;
454 }
455 
456 ////////////////////////////////////////////////////////////////////////////////
457 
458 std::string RScanner::FuncParameterList(clang::FunctionDecl* D) const
459 {
460  std::string result = "";
461 
462  for (clang::FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); I != E; ++I) {
463  clang::ParmVarDecl* P = *I;
464 
465  if (result != "")
466  result += ",";
467 
468  std::string type = P->getType().getAsString();
469  result += type;
470  }
471 
472  return "(" + result + ")";
473 }
474 
475 ////////////////////////////////////////////////////////////////////////////////
476 /// This method visits a namespace node
477 
478 bool RScanner::VisitNamespaceDecl(clang::NamespaceDecl* N)
479 {
480  // We don't need to visit this while creating the big PCM
481  if (fScanType == EScanType::kOnePCM)
482  return true;
483 
484  if (!shouldVisitDecl(N))
485  return true;
486 
487  // in case it is implicit we don't create a builder
488  // [Note: Can N be nullptr?, is so 'ShouldVisitDecl' should test or we should test sooner]
489  if((N && N->isImplicit()) || !N){
490  return true;
491  }
492 
493  bool ret = true;
494 
495  const ClassSelectionRule *selected = fSelectionRules.IsDeclSelected(N);
496  if (selected) {
497 
498  clang::DeclContext* primary_ctxt = N->getPrimaryContext();
499  clang::NamespaceDecl* primary = llvm::dyn_cast<clang::NamespaceDecl>(primary_ctxt);
500 
501  RPredicateIsSameNamespace pred(primary);
502  if ( find_if(fSelectedNamespaces.begin(),fSelectedNamespaces.end(),pred) == fSelectedNamespaces.end() ) {
503  // The namespace is not already registered.
504 
505  if (fVerboseLevel > 0) {
506  std::string qual_name;
507  GetDeclQualName(N,qual_name);
508  // std::cout<<"\tSelected namespace -> " << qual_name << " ptr " << (void*)N << " decl ctxt " << (void*)N->getPrimaryContext() << " classname " <<primary->getNameAsString() << "\n";
509  std::cout<<"\tSelected namespace -> " << qual_name << "\n";
510  }
511  fSelectedNamespaces.push_back(AnnotatedNamespaceDecl(primary,selected->GetIndex(),selected->RequestOnlyTClass()));
512  }
513  ret = true;
514  }
515 
516  return ret;
517 }
518 
519 ////////////////////////////////////////////////////////////////////////////////
520 
521 bool RScanner::VisitRecordDecl(clang::RecordDecl* D)
522 {
523  if (!shouldVisitDecl(D))
524  return true;
525 
526  // This method visits a class node
527  return TreatRecordDeclOrTypedefNameDecl(D);
528 
529 
530 }
531 
532 ////////////////////////////////////////////////////////////////////////////////
533 
534 int RScanner::AddAnnotatedRecordDecl(const ClassSelectionRule* selected,
535  const clang::Type* req_type,
536  const clang::RecordDecl* recordDecl,
537  const std::string& attr_name,
538  const clang::TypedefNameDecl* typedefNameDecl,
539  unsigned int indexOffset)
540 {
541 
542  bool has_attr_name = selected->HasAttributeName();
543 
544  if (recordDecl->isUnion() &&
545  0 != ROOT::TMetaUtils::GetClassVersion(recordDecl,fInterpreter)) {
546  std::string normName;
547  TMetaUtils::GetNormalizedName(normName,
548  recordDecl->getASTContext().getTypeDeclType(recordDecl),
549  fInterpreter,
550  fNormCtxt);
551  ROOT::TMetaUtils::Error(0,"Union %s has been selected for I/O. This is not supported. Interactive usage of unions is supported, as all C++ entities, without the need of dictionaries.\n",normName.c_str());
552  return 1;
553  }
554 
555  if (has_attr_name) {
556  fSelectedClasses.emplace_back(selected->GetIndex() + indexOffset,
557  req_type,
558  recordDecl,
559  attr_name.c_str(),
560  selected->RequestStreamerInfo(),
561  selected->RequestNoStreamer(),
562  selected->RequestNoInputOperator(),
563  selected->RequestOnlyTClass(),
564  selected->RequestedVersionNumber(),
565  fInterpreter,
566  fNormCtxt);
567  } else {
568  fSelectedClasses.emplace_back(selected->GetIndex() + indexOffset,
569  recordDecl,
570  selected->RequestStreamerInfo(),
571  selected->RequestNoStreamer(),
572  selected->RequestNoInputOperator(),
573  selected->RequestOnlyTClass(),
574  selected->RequestedVersionNumber(),
575  fInterpreter,
576  fNormCtxt);
577  }
578 
579  if (fVerboseLevel > 0) {
580  std::string qual_name;
581  GetDeclQualName(recordDecl,qual_name);
582  std::string normName;
583  TMetaUtils::GetNormalizedName(normName,
584  recordDecl->getASTContext().getTypeDeclType(recordDecl),
585  fInterpreter,
586  fNormCtxt);
587  std::string typedef_qual_name;
588  std::string typedefMsg;
589  if (typedefNameDecl){
590  GetDeclQualName(typedefNameDecl,typedef_qual_name);
591  typedefMsg = "(through typedef/alias " + typedef_qual_name + ") ";
592  }
593 
594  std::cout << "Selected class "
595  << typedefMsg
596  << "-> "
597  << qual_name
598  << " for ROOT: "
599  << normName
600  << "\n";
601  }
602  return 0;
603 }
604 
605 ////////////////////////////////////////////////////////////////////////////////
606 
607 bool RScanner::TreatRecordDeclOrTypedefNameDecl(clang::TypeDecl* typeDecl)
608 {
609  // For every class is created a new class buider irrespectful of weather the
610  // class is internal for another class declaration or not.
611  // RecordDecls and TypedefDecls (or RecordDecls!) are treated.
612  // We follow two different codepaths if the typeDecl is a RecordDecl or
613  // a TypedefDecl. If typeDecl is a TypedefDecl, recordDecl becomes the
614  // underlying RecordDecl.
615  // This is done to leverage the selections rule matching in SelectionRules
616  // which works basically with names.
617  // At the end of the method, if the typedef name is matched, an AnnotatedRecordDecl
618  // with the underlying RecordDecl is fed to the machinery.
619 
620  const clang::RecordDecl* recordDecl = clang::dyn_cast<clang::RecordDecl>(typeDecl);
621  const clang::TypedefNameDecl* typedefNameDecl = clang::dyn_cast<clang::TypedefNameDecl>(typeDecl);
622 
623  // If typeDecl is not a RecordDecl, try to fetch the RecordDecl behind the TypedefDecl
624  if (!recordDecl && typedefNameDecl) {
625  recordDecl = ROOT::TMetaUtils::GetUnderlyingRecordDecl(typedefNameDecl->getUnderlyingType());
626  }
627 
628  // If at this point recordDecl is still NULL, we have a problem
629  if (!recordDecl) {
630  ROOT::TMetaUtils::Warning("RScanner::TreatRecordDeclOrTypeNameDecl",
631  "Could not cast typeDecl either to RecordDecl or could not get RecordDecl underneath typedef.\n");
632  return true;
633  }
634 
635  // Do not select unnamed records.
636  if (!recordDecl->getIdentifier())
637  return true;
638 
639  // Do not select dependent types.
640  if (recordDecl->isDependentType())
641  return true;
642 
643  if (fScanType == EScanType::kOnePCM && ROOT::TMetaUtils::IsStdClass(*recordDecl))
644  return true;
645 
646 
647  // At this point, recordDecl must be a RecordDecl pointer.
648 
649  if (fRecordDeclCallback) {
650  // Pass on any declaration. This is usually used to record dependency.
651  // Since rootcint see C++ compliant header files, we can assume that
652  // if a forward declaration or declaration has been inserted, the
653  // classes for which we are creating a dictionary will be using
654  // them either directly or indirectly. Any false positive can be
655  // resolved by removing the spurrious dependency in the (user) header
656  // files.
657  fRecordDeclCallback(recordDecl);
658  }
659 
660  // in case it is implicit or a forward declaration, we are not interested.
661  if(recordDecl->isImplicit() || !recordDecl->isCompleteDefinition()) {
662  return true;
663  }
664 
665  // Never select the class templates themselves.
666  const clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast<clang::CXXRecordDecl>(recordDecl);
667  if (cxxdecl && cxxdecl->getDescribedClassTemplate ()) {
668  return true;
669  }
670 
671  const ClassSelectionRule *selectedFromTypedef = typedefNameDecl ? fSelectionRules.IsDeclSelected(typedefNameDecl) : 0;
672 
673  const ClassSelectionRule *selectedFromRecDecl = fSelectionRules.IsDeclSelected(recordDecl);
674 
675  const ClassSelectionRule *selected = typedefNameDecl ? selectedFromTypedef : selectedFromRecDecl;
676 
677  if (! selected) return true; // early exit. Nothing more to be done.
678 
679  // Selected through typedef but excluded with concrete classname
680  bool excludedFromRecDecl = false;
681  if ( selectedFromRecDecl )
682  excludedFromRecDecl = selectedFromRecDecl->GetSelected() == BaseSelectionRule::kNo;
683 
684  if (selected->GetSelected() != BaseSelectionRule::kYes || excludedFromRecDecl)
685  return true;
686 
687  // Save the typedef
688  if (selectedFromTypedef){
689  if (!IsElementPresent(fSelectedTypedefs, typedefNameDecl))
690  fSelectedTypedefs.push_back(typedefNameDecl);
691  // Early exit here if we are not in presence of XML
692  if (!fSelectionRules.IsSelectionXMLFile()) return true;
693  }
694 
695  if (fSelectionRules.IsSelectionXMLFile() && selected->IsFromTypedef()) {
696  if (!IsElementPresent(fSelectedTypedefs, typedefNameDecl))
697  fSelectedTypedefs.push_back(typedefNameDecl);
698  return true;
699  }
700 
701  if (typedefNameDecl)
702  ROOT::TMetaUtils::Info("RScanner::TreatRecordDeclOrTypedefNameDecl",
703  "Typedef is selected %s.\n", typedefNameDecl->getNameAsString().c_str());
704 
705  // For the case kNo, we could (but don't) remove the node from the pcm
706  // For the case kDontCare, the rule is just a place holder and we are actually trying to exclude some of its children
707  // (this is used only in the selection xml case).
708 
709  // Reject the selection of std::pair on the ground that it is trivial
710  // and can easily be recreated from the AST information.
711  if (recordDecl->getName() == "pair") {
712  const clang::NamespaceDecl *nsDecl = llvm::dyn_cast<clang::NamespaceDecl>(recordDecl->getDeclContext());
713  if (!nsDecl){
714  ROOT::TMetaUtils::Error("RScanner::TreatRecordDeclOrTypedefNameDecl",
715  "Cannot convert context of RecordDecl called pair into a namespace.\n");
716  return true;
717  }
718  const clang::NamespaceDecl *nsCanonical = nsDecl->getCanonicalDecl();
719  if (nsCanonical && nsCanonical == fInterpreter.getCI()->getSema().getStdNamespace()) {
720  if (selected->HasAttributeFileName() || selected->HasAttributeFilePattern()) {
721  return true;
722  }
723  }
724  }
725 
726  // Insert in the selected classes if not already there
727  // We need this check since the same class can be selected through its name or typedef
728  bool rcrdDeclNotAlreadySelected = fselectedRecordDecls.insert((RecordDecl*)recordDecl->getCanonicalDecl()).second;
729  if (!fFirstPass && !rcrdDeclNotAlreadySelected) {
730  // Diagnose conflicting selection rules:
731  auto declSelRuleMapIt = fDeclSelRuleMap.find(recordDecl->getCanonicalDecl());
732  if (declSelRuleMapIt != fDeclSelRuleMap.end() &&
733  declSelRuleMapIt->second != selected) {
734  std::string normName;
735  TMetaUtils::GetNormalizedName(normName,
736  recordDecl->getASTContext().getTypeDeclType(recordDecl),
737  fInterpreter,
738  fNormCtxt);
739 
740  auto previouslyMatchingRule = (const ClassSelectionRule*)declSelRuleMapIt->second;
741  int previouslineno = previouslyMatchingRule->GetLineNumber();
742 
743  std::string cleanFileName = llvm::sys::path::filename(selected->GetSelFileName());
744  auto lineno = selected->GetLineNumber();
745  auto rulesAreCompatible = SelectionRulesUtils::areEqual<ClassSelectionRule>(selected, previouslyMatchingRule, true /*moduloNameOrPattern*/);
746  if (!rulesAreCompatible){
747  std::stringstream message;
748  if (lineno > 1) message << "Selection file " << cleanFileName << ", lines "
749  << lineno << " and " << previouslineno << ". ";
750  message << "Attempt to select a class "<< normName << " with two rules which have incompatible attributes. "
751  << "The attributes such as transiency might not be correctly propagated to the typesystem of ROOT.\n";
752  selected->Print(message);
753  message << "Conflicting rule already matched:\n";
754  previouslyMatchingRule->Print(message);
755  ROOT::TMetaUtils::Warning(0,"%s\n", message.str().c_str());
756  }
757  }
758  }
759 
760  fDeclSelRuleMap[recordDecl->getCanonicalDecl()] = selected;
761 
762  if (!rcrdDeclNotAlreadySelected || fFirstPass)
763  return true;
764 
765  // Before adding the decl to the selected ones, check its access.
766  // We do not yet support I/O of private or protected classes.
767  // See ROOT-7450.
768  // Additionally, private declarations lead to uncompilable code, so just ignore (ROOT-9112).
769  if (recordDecl->getAccess() == AS_private || recordDecl->getAccess() == AS_protected) {
770  // Don't warn about types selected by "everything in that file".
771  auto isFileSelection = selected->HasAttributeFileName() &&
772  selected->HasAttributePattern() &&
773  "*" == selected->GetAttributePattern();
774  if (!isFileSelection) {
775  std::string normName;
776  TMetaUtils::GetNormalizedName(normName,
777  recordDecl->getASTContext().getTypeDeclType(recordDecl),
778  fInterpreter,
779  fNormCtxt);
780  auto msg = "Class or struct %s was selected but its dictionary cannot be generated: "
781  "this is a private or protected class and this is not supported. No direct "
782  "I/O operation of %s instances will be possible.\n";
783  ROOT::TMetaUtils::Warning(0,msg,normName.c_str(),normName.c_str());
784  }
785  return true;
786  }
787 
788  // Replace on the fly the type if the type for IO is different for example
789  // in presence of unique_ptr<T> or collections thereof.
790  // The following lines are very delicate: we need to preserve the special
791  // ROOT opaque typedefs.
792  auto req_type = selected->GetRequestedType();
793  clang::QualType thisType(req_type, 0);
794  std::string attr_name = selected->GetAttributeName().c_str();
795 
796  auto sc = AddAnnotatedRecordDecl(selected, req_type, recordDecl, attr_name, typedefNameDecl);
797  if (sc != 0) {
798  return false;
799  }
800 
801  if (auto CTSD = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(recordDecl)) {
802  fDelayedAnnotatedRecordDecls.emplace_back(DelayedAnnotatedRecordDeclInfo{selected, CTSD, typedefNameDecl});
803  }
804 
805  return true;
806 }
807 
808 void RScanner::AddDelayedAnnotatedRecordDecls()
809 {
810  for (auto &&info: fDelayedAnnotatedRecordDecls) {
811  const clang::Type *thisType = info.fSelected->GetRequestedType();
812  if (!thisType)
813  thisType = info.fDecl->getTypeForDecl();
814  const clang::CXXRecordDecl *recordDecl = info.fDecl;
815  auto nameTypeForIO = ROOT::TMetaUtils::GetNameTypeForIO(clang::QualType(thisType, 0), fInterpreter, fNormCtxt);
816  auto typeForIO = nameTypeForIO.second;
817  // It could be that we have in hands a type which is not a class, e.g.
818  // in presence of unique_ptr<T> we got a T with T=double.
819  if (typeForIO.getTypePtr() == thisType)
820  continue;
821  if (auto recordDeclForIO = typeForIO->getAsCXXRecordDecl()) {
822  const auto canRecordDeclForIO = recordDeclForIO->getCanonicalDecl();
823  if (!fselectedRecordDecls.insert(canRecordDeclForIO).second)
824  continue;
825  recordDecl = canRecordDeclForIO;
826  fDeclSelRuleMap[recordDecl] = info.fSelected;
827  thisType = typeForIO.getTypePtr();
828  }
829 
830  AddAnnotatedRecordDecl(info.fSelected, thisType, recordDecl,
831  nameTypeForIO.first, info.fTypedefNameDecl, 1000);
832  }
833 }
834 
835 ////////////////////////////////////////////////////////////////////////////////
836 /// Visitor for every TypedefNameDecl, i.e. aliases and typedefs
837 /// We check three conditions before trying to match the name:
838 /// 1) If we are creating a big PCM
839 /// 2) If the underlying decl is a RecordDecl
840 /// 3) If the typedef is eventually contained in the std namespace
841 
842 bool RScanner::VisitTypedefNameDecl(clang::TypedefNameDecl* D)
843 {
844  if (fScanType == EScanType::kOnePCM)
845  return true;
846 
847  if (!shouldVisitDecl(D))
848  return true;
849 
850  const clang::DeclContext *ctx = D->getDeclContext();
851 
852  bool isInStd=false;
853  if (ctx) {
854  const clang::NamedDecl *parent = llvm::dyn_cast<clang::NamedDecl> (ctx);
855  isInStd = parent && 0 == parent->getQualifiedNameAsString().compare(0,5,"std::");
856  }
857 
858  if (ROOT::TMetaUtils::GetUnderlyingRecordDecl(D->getUnderlyingType()) &&
859  !isInStd){
860  TreatRecordDeclOrTypedefNameDecl(D);
861  }
862 
863  return true;
864 }
865 
866 ////////////////////////////////////////////////////////////////////////////////
867 
868 bool RScanner::VisitEnumDecl(clang::EnumDecl* D)
869 {
870  if (fScanType == EScanType::kOnePCM)
871  return true;
872 
873  if (!shouldVisitDecl(D))
874  return true;
875 
876  if(fSelectionRules.IsDeclSelected(D) &&
877  !IsElementPresent(fSelectedEnums, D)){ // Removal of duplicates.
878  fSelectedEnums.push_back(D);
879  }
880 
881  return true;
882 }
883 
884 ////////////////////////////////////////////////////////////////////////////////
885 
886 bool RScanner::VisitVarDecl(clang::VarDecl* D)
887 {
888  if (!D->hasGlobalStorage() ||
889  fScanType == EScanType::kOnePCM)
890  return true;
891 
892  if (!shouldVisitDecl(D))
893  return true;
894 
895  if(fSelectionRules.IsDeclSelected(D)){
896  fSelectedVariables.push_back(D);
897  }
898 
899  return true;
900 }
901 
902 ////////////////////////////////////////////////////////////////////////////////
903 /// Nothing to be done here
904 
905 bool RScanner::VisitFieldDecl(clang::FieldDecl* D)
906 {
907  return true;
908 
909 // bool ret = true;
910 //
911 // if(fSelectionRules.IsDeclSelected(D)){
912 //
913 // // if (fVerboseLevel > 0) {
914 // // std::string qual_name;
915 // // GetDeclQualName(D,qual_name);
916 // // std::cout<<"\tSelected field -> " << qual_name << "\n";
917 // // }
918 // }
919 // else {
920 // }
921 //
922 // return ret;
923 }
924 
925 ////////////////////////////////////////////////////////////////////////////////
926 
927 bool RScanner::VisitFunctionDecl(clang::FunctionDecl* D)
928 {
929  if (fScanType == EScanType::kOnePCM)
930  return true;
931 
932  if (!shouldVisitDecl(D))
933  return true;
934 
935  if(clang::FunctionDecl::TemplatedKind::TK_FunctionTemplate == D->getTemplatedKind())
936  return true;
937 
938  if(fSelectionRules.IsDeclSelected(D)){
939  fSelectedFunctions.push_back(D);
940  }
941 
942  return true;
943 }
944 
945 ////////////////////////////////////////////////////////////////////////////////
946 
947 bool RScanner::TraverseDeclContextHelper(DeclContext *DC)
948 {
949  bool ret = true;
950 
951  if (!DC)
952  return true;
953 
954  clang::Decl* D = dyn_cast<clang::Decl>(DC);
955  // skip implicit decls
956  if (D && D->isImplicit()){
957  return true;
958  }
959 
960  if (fScanType == EScanType::kOnePCM){
961  const clang::NamespaceDecl *parent = llvm::dyn_cast<clang::NamespaceDecl> (DC);
962  if (parent && 0 == parent->getQualifiedNameAsString().compare(0,5,"std::"))
963  return true;
964  }
965 
966  for (DeclContext::decl_iterator Child = DC->decls_begin(), ChildEnd = DC->decls_end();
967  ret && (Child != ChildEnd); ++Child) {
968  ret=TraverseDecl(*Child);
969  }
970 
971  return ret;
972 
973 }
974 
975 ////////////////////////////////////////////////////////////////////////////////
976 
977 bool RScanner::GetDeclName(clang::Decl* D, std::string& name) const
978 {
979  clang::NamedDecl* N = dyn_cast<clang::NamedDecl> (D);
980 
981  if (N) {
982  name = N->getNameAsString();
983  return true;
984  }
985  else {
986  name = "UNNAMED";
987  return false;
988  }
989 }
990 
991 ////////////////////////////////////////////////////////////////////////////////
992 
993 bool RScanner::GetDeclQualName(const clang::Decl* D, std::string& qual_name)
994 {
995  auto N = dyn_cast<const clang::NamedDecl> (D);
996 
997  if (N) {
998  llvm::raw_string_ostream stream(qual_name);
999  N->getNameForDiagnostic(stream,D->getASTContext().getPrintingPolicy(),true); // qual_name = N->getQualifiedNameAsString();
1000  return true;
1001  }
1002  else {
1003  return false;
1004  }
1005 }
1006 
1007 ////////////////////////////////////////////////////////////////////////////////
1008 
1009 bool RScanner::GetFunctionPrototype(clang::Decl* D, std::string& prototype) const {
1010  if (!D) {
1011  return false;
1012  }
1013 
1014  clang::FunctionDecl* F = dyn_cast<clang::FunctionDecl> (D);
1015 
1016  if (F) {
1017 
1018  prototype = "";
1019  for (clang::FunctionDecl::param_iterator I = F->param_begin(), E = F->param_end(); I != E; ++I) {
1020  clang::ParmVarDecl* P = *I;
1021 
1022  if (prototype != "")
1023  prototype += ",";
1024 
1025  //std::string type = P->getType().getAsString();
1026  std::string type = P->getType().getAsString();
1027  if (type.at(type.length()-1) == '*') {
1028  type.at(type.length()-2) = '*';
1029  type.erase(type.length()-1);
1030  }
1031  prototype += type;
1032  }
1033 
1034  prototype = "(" + prototype + ")";
1035  return true;
1036  }
1037  else {
1038  ShowWarning("can't convert Decl to FunctionDecl","");
1039  return false;
1040  }
1041 }
1042 
1043 ////////////////////////////////////////////////////////////////////////////////
1044 
1045 void RScanner::Scan(const clang::ASTContext &C)
1046 {
1047  fSourceManager = &C.getSourceManager();
1048 
1049 // if (fVerboseLevel >= 3) fSelectionRules.PrintSelectionRules();
1050 
1051  if (fVerboseLevel > 0 && fSelectionRules.GetHasFileNameRule()) {
1052  std::cout<<"File name detected"<<std::endl;
1053  }
1054 
1055  if (fScanType == EScanType::kTwoPasses)
1056  TraverseDecl(C.getTranslationUnitDecl());
1057 
1058  fFirstPass=false;
1059  fselectedRecordDecls.clear();
1060  fSelectedEnums.clear();
1061  fSelectedTypedefs.clear();
1062  fSelectedVariables.clear();
1063  fSelectedFunctions.clear();
1064  TraverseDecl(C.getTranslationUnitDecl());
1065 
1066  // The RecursiveASTVisitor uses range-based for; we must not modify the AST
1067  // during iteration / visitation. Instead, buffer the lookups that could
1068  // potentially create new template specializations, and handle them here:
1069  AddDelayedAnnotatedRecordDecls();
1070 }
1071 
1072 
1073 ////////////////////////////////////////////////////////////////////////////////
1074 /// Set the callback to the RecordDecl and return the previous one.
1075 
1076 RScanner::DeclCallback RScanner::SetRecordDeclCallback(RScanner::DeclCallback callback)
1077 {
1078  DeclCallback old = fRecordDeclCallback;
1079  fRecordDeclCallback = callback;
1080  return old;
1081 }