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