ROOT  6.06/09
Reference Guide
SelectionRules.cxx
Go to the documentation of this file.
1 // @(#)root/core/utils:$Id: SelectionRules.cxx 41697 2011-11-01 21:03:41Z pcanal $
2 // Author: Velislava Spasova September 2010
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 \class SelectionRules
14 The class representing the collection of selection rules.
15 */
16 #include <iostream>
17 #include <sstream>
18 #include <algorithm>
19 #include "fnmatch.h"
20 #include "SelectionRules.h"
21 #include "TString.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include "clang/Basic/SourceLocation.h"
24 #include "clang/Basic/SourceManager.h"
25 #include "clang/AST/ASTContext.h"
26 #include "clang/AST/DeclCXX.h"
27 #include "clang/AST/DeclTemplate.h"
28 
29 #include "cling/Interpreter/Interpreter.h"
30 
31 const clang::CXXRecordDecl *R__ScopeSearch(const char *name, const clang::Type** resultType = 0) ;
32 
34 {
35  fRulesCounter++;
36  fClassSelectionRules.push_front(classSel);
37  if (!classSel.HasInterpreter())
38  fClassSelectionRules.begin()->SetInterpreter(fInterp);
39  if (classSel.GetIndex() < 0)
40  fClassSelectionRules.begin()->SetIndex(fRulesCounter);
41 }
42 
44 {
45  fRulesCounter++;
46  fFunctionSelectionRules.push_back(funcSel);
47  if (!funcSel.HasInterpreter())
48  fFunctionSelectionRules.begin()->SetInterpreter(fInterp);
49  if (funcSel.GetIndex() < 0)
50  fFunctionSelectionRules.begin()->SetIndex(fRulesCounter);
51 }
52 
54 {
55  fRulesCounter++;
56  fVariableSelectionRules.push_back(varSel);
57  if (!varSel.HasInterpreter())
58  fVariableSelectionRules.begin()->SetInterpreter(fInterp);
59  if (varSel.GetIndex() < 0)
60  fVariableSelectionRules.begin()->SetIndex(fRulesCounter);
61 }
62 
64 {
65  fRulesCounter++;
66  fEnumSelectionRules.push_back(enumSel);
67  if (!enumSel.HasInterpreter())
68  fEnumSelectionRules.begin()->SetInterpreter(fInterp);
69  if (enumSel.GetIndex() < 0)
70  fEnumSelectionRules.begin()->SetIndex( fRulesCounter );
71 }
72 
74 {
75  std::cout<<"Printing Selection Rules:"<<std::endl;
76  if (!fClassSelectionRules.empty()) {
77  int i = 0;
78  for(std::list<ClassSelectionRule>::const_iterator it = fClassSelectionRules.begin();
79  it != fClassSelectionRules.end(); ++it, ++i) {
80  std::cout<<"\tClass sel rule "<<i<<":"<<std::endl;
81  std::cout<< *it;
82  }
83  }
84  else {
85  std::cout<<"\tNo Class Selection Rules"<<std::endl;
86  }
87 
88  if (!fFunctionSelectionRules.empty()) {
89  //std::cout<<""<<std::endl;
90  std::list<FunctionSelectionRule>::const_iterator it2;
91  int i = 0;
92 
93  for (it2 = fFunctionSelectionRules.begin(); it2 != fFunctionSelectionRules.end(); ++it2, ++i) {
94  std::cout<<"\tFunction sel rule "<<i<<":"<<std::endl;
95  std::cout<<"\t\tSelected: ";
96  switch(it2->GetSelected()){
97  case BaseSelectionRule::kYes: std::cout<<"Yes"<<std::endl;
98  break;
99  case BaseSelectionRule::kNo: std::cout<<"No"<<std::endl;
100  break;
101  case BaseSelectionRule::kDontCare: std::cout<<"Don't Care"<<std::endl;
102  break;
103  default: std::cout<<"Unspecified"<<std::endl;
104  }
105  it2->PrintAttributes(std::cout,2);
106  }
107  }
108  else {
109  std::cout<<"\tNo function sel rules"<<std::endl;
110  }
111 
112  if (!fVariableSelectionRules.empty()) {
113  std::list<VariableSelectionRule>::const_iterator it3;
114  int i = 0;
115 
116  for (it3 = fVariableSelectionRules.begin(); it3 != fVariableSelectionRules.end(); ++it3, ++i) {
117  std::cout<<"\tVariable sel rule "<<i<<":"<<std::endl;
118  std::cout<<"\t\tSelected: ";
119  switch(it3->GetSelected()){
120  case BaseSelectionRule::kYes: std::cout<<"Yes"<<std::endl;
121  break;
122  case BaseSelectionRule::kNo: std::cout<<"No"<<std::endl;
123  break;
124  case BaseSelectionRule::kDontCare: std::cout<<"Don't Care"<<std::endl;
125  break;
126  default: std::cout<<"Unspecified"<<std::endl;
127  }
128  it3->PrintAttributes(std::cout,2);
129  }
130  }
131  else {
132  std::cout<<"\tNo variable sel rules"<<std::endl;
133  }
134 
135  if (!fEnumSelectionRules.empty()) {
136  std::list<EnumSelectionRule>::const_iterator it4;
137  int i = 0;
138 
139  for (it4 = fEnumSelectionRules.begin(); it4 != fEnumSelectionRules.end(); ++it4, ++i) {
140  std::cout<<"\tEnum sel rule "<<i<<":"<<std::endl;
141  std::cout<<"\t\tSelected: ";
142  switch(it4->GetSelected()){
143  case BaseSelectionRule::kYes: std::cout<<"Yes"<<std::endl;
144  break;
145  case BaseSelectionRule::kNo: std::cout<<"No"<<std::endl;
146  break;
147  case BaseSelectionRule::kDontCare: std::cout<<"Don't Care"<<std::endl;
148  break;
149  default: std::cout<<"Unspecified"<<std::endl;
150  }
151  it4->PrintAttributes(std::cout,2);
152  }
153  }
154  else {
155  std::cout<<"\tNo enum sel rules"<<std::endl;
156  }
157 }
158 
160 {
161  fClassSelectionRules.clear();
162  fFunctionSelectionRules.clear();
163  fVariableSelectionRules.clear();
164  fEnumSelectionRules.clear();
165 }
166 
167 template<class RULE>
168 static bool HasDuplicate(RULE* rule,
169  std::unordered_map<std::string,RULE*>& storedRules,
170  const std::string& attrName){
171  auto itRetCodePair = storedRules.emplace( attrName, rule );
172 
173  auto storedRule = storedRules[attrName];
174 
175  if (itRetCodePair.second ||
176  storedRule->GetSelected() != rule->GetSelected()) return false;
177  auto areEqual = SelectionRulesUtils::areEqual(storedRule,rule);
178 
179  std::stringstream sstr; sstr << "Rule:\n";
180  rule->Print(sstr);
181  sstr << (areEqual ? "Identical " : "Conflicting ");
182  sstr << "rule already stored:\n";
183  storedRule->Print(sstr);
184  ROOT::TMetaUtils::Warning("SelectionRules::CheckDuplicates",
185  "Duplicated rule found.\n%s",sstr.str().c_str());
186  return !areEqual;
187 }
188 
189 template<class RULESCOLLECTION, class RULE = typename RULESCOLLECTION::value_type>
190 static int CheckDuplicatesImp(RULESCOLLECTION& rules){
191  int nDuplicates = 0;
192  std::unordered_map<std::string, RULE*> patterns,names;
193  for (auto&& rule : rules){
194  if (rule.HasAttributeName() && HasDuplicate(&rule,names,rule.GetAttributeName())) nDuplicates++;
195  if (rule.HasAttributePattern() && HasDuplicate(&rule,patterns,rule.GetAttributePattern())) nDuplicates++;
196  }
197  return nDuplicates;
198 }
199 
201 
202  int nDuplicates = 0;
206  nDuplicates += CheckDuplicatesImp(fEnumSelectionRules);
207  if (0 != nDuplicates){
208  ROOT::TMetaUtils::Error("SelectionRules::CheckDuplicates",
209  "Duplicates in rules were found.\n");
210  }
211  return nDuplicates;
212 }
213 
214 static bool Implies(ClassSelectionRule& patternRule, ClassSelectionRule& nameRule){
215 
216  // Check if these both select or both exclude
217  if (patternRule.GetSelected() != nameRule.GetSelected()) return false;
218 
219  // If the two rules are not compatible modulo their name/pattern, bail out
220  auto nAttrsPattern = patternRule.GetAttributes().size();
221  auto nAttrsName = nameRule.GetAttributes().size();
222  if ((nAttrsPattern != 1 || nAttrsName !=1) &&
223  !SelectionRulesUtils::areEqual(&patternRule, &nameRule, true /*moduloNameOrPattern*/)) {
224  return false;
225  }
226 
227  auto pattern = patternRule.GetAttributePattern().c_str();
228  auto name = nameRule.GetAttributeName().c_str();
229 
230  // Now check if the pattern matches the name
231  auto implies = 0 == fnmatch(pattern, name, FNM_PATHNAME);
232 
233  if (implies){
234  static const auto msg = "The pattern rule %s matches the name rule %s. "
235  "Since the name rule has compatible attributes, "
236  "it will be removed: the pattern rule will match the necessary classes if needed.\n";
237 
238  ROOT::TMetaUtils::Info("SelectionRules::Optimize", msg, pattern, name);
239  }
240 
241 
242  return implies;
243 
244 }
245 
247 
248  // Remove name rules "implied" by pattern rules
249 
250  if (!IsSelectionXMLFile()) return;
251 
252  auto ruleIt = fClassSelectionRules.begin();
253  std::list<decltype(ruleIt)> itPositionsToErase;
254 
255  for (; ruleIt != fClassSelectionRules.end(); ruleIt++ ){
256  if (ruleIt->HasAttributeName()) {
257  for (auto&& intRule : fClassSelectionRules){
258  if (intRule.HasAttributePattern() && Implies(intRule, *ruleIt)){
259  itPositionsToErase.push_back(ruleIt);
260  }
261  }
262  }
263  }
264  itPositionsToErase.unique();
265  for (auto&& itPositionToErase : itPositionsToErase){
266  fClassSelectionRules.erase(itPositionToErase);
267  }
268 
269 }
270 
271 void SelectionRules::SetDeep(bool deep)
272 {
273 
274  fIsDeep=deep;
275  if (!fIsDeep) return; // the adventure stops here
276  // if no selection rules, nothing to go deep into
277  if (fClassSelectionRules.empty()) return;
278  // Get index of the last selection rule
279  long count = fClassSelectionRules.rbegin()->GetIndex() + 1;
280  // Deep for classes
281  // Loop on rules. If name or pattern exist, add a {pattern,name}* rule to go deep
282  std::string patternString;
283  for (std::list<ClassSelectionRule>::iterator classRuleIt = fClassSelectionRules.begin();
284  classRuleIt != fClassSelectionRules.end(); classRuleIt++){
285  if (classRuleIt->HasAttributeWithName("pattern") &&
286  classRuleIt->GetAttributeValue("pattern",patternString)){
287  // If the pattern already does not end with *
288  if (patternString.find_last_of("*")!=patternString.size()-1){
289  ClassSelectionRule csr(count++, fInterp);
290  csr.SetAttributeValue("pattern", patternString+"*");
293  }
294  }
295  if (classRuleIt->HasAttributeWithName("name") &&
296  classRuleIt->GetAttributeValue("name",patternString)){
297  ClassSelectionRule csr(count++, fInterp);
298  csr.SetAttributeValue("pattern", patternString+"*");
301  }
302  }
303 // fIsDeep = deep;
304 // if (fIsDeep) {
305 // long count = 0;
306 // if (!fClassSelectionRules.empty()) {
307 // count = fClassSelectionRules.rbegin()->GetIndex() + 1;
308 // }
309 // ClassSelectionRule csr(count++, fInterp);
310 // csr.SetAttributeValue("pattern", "*");
311 // csr.SetSelected(BaseSelectionRule::kYes);
312 // AddClassSelectionRule(csr);
313 //
314 // ClassSelectionRule csr2(count++, fInterp);
315 // csr2.SetAttributeValue("pattern", "*::*");
316 // csr2.SetSelected(BaseSelectionRule::kYes);
317 // AddClassSelectionRule(csr2);
318 //
319 //
320 // // Should I disable the built-in (automatically generated) structs/classes?
321 // ClassSelectionRule csr3(count++, fInterp);
322 // csr3.SetAttributeValue("pattern", "__va_*"); // <built-in>
323 // csr3.SetSelected(BaseSelectionRule::kNo);
324 // AddClassSelectionRule(csr3);
325  //HasFileNameRule = true;
326 
327  //SetSelectionXMLFile(true);
328 // }
329 }
330 
331 const ClassSelectionRule *SelectionRules::IsDeclSelected(const clang::RecordDecl *D) const
332 {
333  std::string qual_name;
334  GetDeclQualName(D,qual_name);
335  return IsClassSelected(D, qual_name);
336 }
337 
338 const ClassSelectionRule *SelectionRules::IsDeclSelected(const clang::TypedefNameDecl *D) const
339 {
340  std::string qual_name;
341  GetDeclQualName(D,qual_name);
342  return IsClassSelected(D, qual_name);
343 }
344 
345 const ClassSelectionRule *SelectionRules::IsDeclSelected(const clang::NamespaceDecl *D) const
346 {
347  std::string qual_name;
348  GetDeclQualName(D,qual_name);
349  return IsNamespaceSelected(D, qual_name);
350 }
351 
352 const BaseSelectionRule *SelectionRules::IsDeclSelected(const clang::EnumDecl *D) const
353 {
354  // Currently rootcling does not need any information on enums, except
355  // for the PCM / proto classes that register them to build TEnums without
356  // parsing. This can be removed once (real) PCMs are available.
357  // Note that the code below was *not* properly matching the case
358  // typedef enum { ... } abc;
359  // as the typedef is stored as an anonymous EnumDecl in clang.
360  // It is likely that using a direct lookup on the name would
361  // return the appropriate typedef (and then we would need to
362  // select 'both' the typedef and the anonymous enums.
363 
364 #if defined(R__MUST_REVISIT)
365 # if R__MUST_REVISIT(6,4)
366  "Can become no-op once PCMs are available."
367 # endif
368 #endif
369 
370  std::string str_name; // name of the Decl
371  std::string qual_name; // fully qualified name of the Decl
372  GetDeclName(D, str_name, qual_name);
373 
374  if (IsParentClass(D)) {
375  const BaseSelectionRule *selector = IsMemberSelected(D, str_name);
376  if (!selector) // if the parent class is deselected, we could still select the enum
377  return IsEnumSelected(D, qual_name);
378  else // if the parent class is selected so are all nested enums
379  return selector;
380  }
381 
382  // Enum is not part of a class
383  else {
384  if (IsLinkdefFile())
385  return IsLinkdefEnumSelected(D, qual_name);
386  return IsEnumSelected(D, qual_name);
387  }
388 
389  return 0;
390 }
391 
392 const BaseSelectionRule *SelectionRules::IsDeclSelected(const clang::VarDecl* D) const
393 {
394  std::string qual_name; // fully qualified name of the Decl
395  GetDeclQualName(D, qual_name);
396 
397  if (IsLinkdefFile())
398  return IsLinkdefVarSelected(D, qual_name);
399  else
400  return IsVarSelected(D, qual_name);
401 
402 }
403 
404 const BaseSelectionRule *SelectionRules::IsDeclSelected(const clang::FieldDecl* /* D */) const
405 {
406  // Currently rootcling does not need any information about fields.
407  return 0;
408 #if 0
409  std::string str_name; // name of the Decl
410  std::string qual_name; // fully qualified name of the Decl
411  GetDeclName(D, str_name, qual_name);
412 
413  return IsMemberSelected(D, str_name);
414 #endif
415 }
416 
417 const BaseSelectionRule *SelectionRules::IsDeclSelected(const clang::FunctionDecl* D) const
418 {
419  // Implement a simple matching for functions
420  std::string qual_name; // fully qualified name of the Decl
421  GetDeclQualName(D, qual_name);
422  if (IsLinkdefFile())
423  return IsLinkdefFunSelected(D, qual_name);
424  else
425  return IsFunSelected(D, qual_name);
426 }
427 
428 const BaseSelectionRule *SelectionRules::IsDeclSelected(const clang::Decl *D) const
429 {
430  if (!D) {
431  return 0;
432  }
433 
434  clang::Decl::Kind declkind = D->getKind();
435 
436  switch (declkind) {
437  case clang::Decl::CXXRecord:
438  case clang::Decl::ClassTemplateSpecialization:
439  case clang::Decl::ClassTemplatePartialSpecialization:
440  // structs, unions and classes are all CXXRecords
441  return IsDeclSelected(llvm::dyn_cast<clang::RecordDecl>(D));
443  return IsDeclSelected(llvm::dyn_cast<clang::NamespaceDecl>(D));
444  case clang::Decl::Enum:
445  // Enum is part of a class
446  return IsDeclSelected(llvm::dyn_cast<clang::EnumDecl>(D));
447  case clang::Decl::Var:
448  return IsDeclSelected(llvm::dyn_cast<clang::VarDecl>(D));
449 #if ROOTCLING_NEEDS_FUNCTIONS_SELECTION
451  return IsDeclSelected(llvm::dyn_cast<clang::FunctionDecl>(D));
452  case clang::Decl::CXXMethod:
453  case clang::Decl::CXXConstructor:
454  case clang::Decl::CXXDestructor: {
455  // std::string proto;
456  // if (GetFunctionPrototype(D,proto))
457  // std::cout<<"\n\tFunction prototype: "<<str_name + proto;
458  // else
459  // std::cout<<"Error in prototype formation";
460  std::string str_name; // name of the Decl
461  std::string qual_name; // fully qualified name of the Decl
462  GetDeclName(D, str_name, qual_name);
463  if (IsLinkdefFile()) {
464  return IsLinkdefMethodSelected(D, qual_name);
465  }
466  return IsMemberSelected(D, str_name);
467  }
468 #endif
469  case clang::Decl::Field:
470  return IsDeclSelected(llvm::dyn_cast<clang::FieldDecl>(D));
471  default:
472  // Humm we are not treating this case!
473  return 0;
474  }
475 
476  // std::string str_name; // name of the Decl
477  // std::string qual_name; // fully qualified name of the Decl
478  // GetDeclName(D, str_name, qual_name);
479  // fprintf(stderr,"IsDeclSelected: %s %s\n", str_name.c_str(), qual_name.c_str());
480 }
481 
482 
483 bool SelectionRules::GetDeclName(const clang::Decl* D, std::string& name, std::string& qual_name) const
484 {
485  const clang::NamedDecl* N = llvm::dyn_cast<clang::NamedDecl> (D);
486 
487  if (!N)
488  return false;
489 
490  // the identifier is NULL for some special methods like constructors, destructors and operators
491  if (N->getIdentifier()) {
492  name = N->getNameAsString();
493  }
494  else if (N->isCXXClassMember()) { // for constructors, destructors, operator=, etc. methods
495  name = N->getNameAsString(); // we use this (unefficient) method to Get the name in that case
496  }
497  llvm::raw_string_ostream stream(qual_name);
498  N->getNameForDiagnostic(stream,N->getASTContext().getPrintingPolicy(),true);
499  return true;
500 }
501 
502 void SelectionRules::GetDeclQualName(const clang::Decl* D, std::string& qual_name) const{
503  const clang::NamedDecl* N = static_cast<const clang::NamedDecl*> (D);
504  llvm::raw_string_ostream stream(qual_name);
505  N->getNameForDiagnostic(stream,N->getASTContext().getPrintingPolicy(),true);
506  }
507 
508 bool SelectionRules::GetFunctionPrototype(const clang::FunctionDecl* F, std::string& prototype) const {
509 
510  if (!F) {
511  return false;
512  }
513 
514  const std::vector<std::string> quals={"*","&"};
515 
516  prototype = "";
517  // iterate through all the function parameters
518  std::string type;
519  for (auto I = F->param_begin(), E = F->param_end(); I != E; ++I) {
520 
521  clang::ParmVarDecl* P = *I;
522 
523  if (prototype != "")
524  prototype += ",";
525 
527 
528  // We need to get rid of the "class " string if present
529  ROOT::TMetaUtils::ReplaceAll(type,"class ", "");
530  // We need to get rid of the "restrict " string if present
531  ROOT::TMetaUtils::ReplaceAll(type,"restrict", "");
532 
533  // pointers are returned in the form "int *" and I need them in the form "int*"
534  // same for &
535  for (auto& qual : quals){
536  auto pos = type.find(" "+qual);
537  if (pos != std::string::npos)
538  type.replace( pos, 2, qual );
539  }
540 // for (auto& qual : quals){
541 // if (type.at(type.length()-1) == qual && type.at(type.length()-2) == ' ') {
542 // type.at(type.length()-2) = qual;
543 // type.erase(type.length()-1);
544 // }
545 // }
546  prototype += type;
547  }
548  prototype = "(" + prototype + ")";
549  return true;
550 
551 }
552 
553 
554 bool SelectionRules::IsParentClass(const clang::Decl* D) const
555 {
556  //TagDecl has methods to understand of what kind is the Decl - class, struct or union
557  if (const clang::TagDecl* T
558  = llvm::dyn_cast<clang::TagDecl>(D->getDeclContext()))
559  return T->isClass() || T->isStruct();
560  return false;
561 }
562 
563 
564 bool SelectionRules::IsParentClass(const clang::Decl* D, std::string& parent_name, std::string& parent_qual_name) const
565 {
566  if (const clang::TagDecl* parent
567  = llvm::dyn_cast<clang::TagDecl>(D->getDeclContext())) {
568  if (parent->isClass()|| parent->isStruct()) {
569  GetDeclName(parent, parent_name, parent_qual_name);
570  return true;
571  }
572  }
573  return false;
574 }
575 
576 bool SelectionRules::GetParentName(const clang::Decl* D, std::string& parent_name, std::string& parent_qual_name) const
577 {
578  if (const clang::RecordDecl* parent
579  = llvm::dyn_cast<clang::RecordDecl>(D->getDeclContext())) {
580  GetDeclName(parent, parent_name, parent_qual_name);
581  return true;
582  }
583  return false;
584 }
585 
586 /* This is the method that crashes
587  bool SelectionRules::GetParent(clang::Decl* D, clang::Decl* parent)
588  {
589  clang::DeclContext *ctx = D->GetDeclContext();
590 
591  if (ctx->isRecord()){
592  //DEBUG std::cout<<"\n\tDeclContext is Record";
593  parent = llvm::dyn_cast<clang::Decl> (ctx);
594  if (!parent) {
595  return false;
596  }
597  else {
598  return true;
599  }
600  }
601  else return false;
602  }
603  */
604 
605 
606 // isClassSelected checks if a class is selected or not. Thre is a difference between the
607 // behaviour of rootcint and genreflex especially with regard to class pattern processing.
608 // In genreflex if we have <class pattern = "*" /> this will select all the classes
609 // (and structs) found in the header file. In rootcint if we have something similar, i.e.
610 // #pragma link C++ class *, we will select only the outer classes - for the nested
611 // classes we have to specifie #pragma link C++ class *::*. And yet this is only valid
612 // for one level of nesting - if you need it for many levels of nesting, you will
613 // probably have to implement it yourself.
614 // Here the idea is the following - we traverse the list of class selection rules.
615 // For every class we check do we have a class selection rule. We use here the
616 // method isSelected() (defined in BaseSelectionRule.cxx). This method returns true
617 // only if we have class selection rule which says "Select". Otherwise it returns
618 // false - in which case we have to check wether we found a class selection rule
619 // which says "Veto" (noName = false and don't Care = false; OR noName = false and
620 // don't Care = true and we don't have neither method nor field selection rules -
621 // which is for the selection.xml file case). If noName is true than we just continue -
622 // this means that the current class selection rule isn't applicable for this class.
623 
624 const ClassSelectionRule *SelectionRules::IsNamespaceSelected(const clang::Decl* D, const std::string& qual_name) const
625 {
626  const clang::NamespaceDecl* N = llvm::dyn_cast<clang::NamespaceDecl> (D); //TagDecl has methods to understand of what kind is the Decl
627  if (N==0) {
628  std::cout<<"\n\tCouldn't cast Decl to NamespaceDecl";
629  return 0;
630  }
631 
632  const ClassSelectionRule *selector = 0;
633  int fImplNo = 0;
634  const ClassSelectionRule *explicit_selector = 0;
635  const ClassSelectionRule *specific_pattern_selector = 0;
636  int fFileNo = 0;
637 
638  // NOTE: should we separate namespaces from classes in the rules?
639  std::list<ClassSelectionRule>::const_iterator it = fClassSelectionRules.begin();
640  // iterate through all class selection rles
641  std::string name_value;
642  std::string pattern_value;
644  for(; it != fClassSelectionRules.end(); ++it) {
645 
646  match = it->Match(N,qual_name,"",IsLinkdefFile());
647 
648  if (match != BaseSelectionRule::kNoMatch) {
649  // If we have a match.
650  if (it->GetSelected() == BaseSelectionRule::kYes) {
651  selector = &(*it);
652  if (IsLinkdefFile()){
653  // rootcint prefers explicit rules over pattern rules
654  if (match == BaseSelectionRule::kName) {
655  explicit_selector = &(*it);
656  } else if (match == BaseSelectionRule::kPattern) {
657  // NOTE: weird ...
658  if (it->GetAttributeValue("pattern", pattern_value) &&
659  pattern_value != "*" && pattern_value != "*::*") specific_pattern_selector = &(*it);
660  }
661  }
662  } else if (it->GetSelected() == BaseSelectionRule::kNo) {
663  if (!IsLinkdefFile()) {
664  // in genreflex - we could explicitly select classes from other source files
665  if (match == BaseSelectionRule::kFile) ++fFileNo; // if we have veto because of class defined in other source file -> implicit No
666  else {
667 
668 #ifdef SELECTION_DEBUG
669  std::cout<<"\tNo returned"<<std::endl;
670 #endif
671 
672  return 0; // explicit No returned
673  }
674  }
675  if (match == BaseSelectionRule::kPattern) {
676  //this is for the Linkdef selection
677  if (it->GetAttributeValue("pattern", pattern_value) &&
678  (pattern_value == "*" || pattern_value == "*::*")) ++fImplNo;
679  else
680  return 0;
681  }
682  else
683  return 0;
684  }
685  else if (it->GetSelected() == BaseSelectionRule::kDontCare && !(it->HasMethodSelectionRules()) && !(it->HasFieldSelectionRules())) {
686 
687 #ifdef SELECTION_DEBUG
688  std::cout<<"Empty dontC returned = No"<<std::endl;
689 #endif
690 
691  return 0;
692  }
693  }
694  }
695  if (IsLinkdefFile()) {
696  // for rootcint explicit (name) Yes is stronger than implicit (pattern) No which is stronger than implicit (pattern) Yes
697 
698 #ifdef SELECTION_DEBUG
699  std::cout<<"\n\tfYes = "<<fYes<<", fImplNo = "<<fImplNo<<std::endl;
700 #endif
701 
702  if (explicit_selector) return explicit_selector;
703  else if (specific_pattern_selector) return specific_pattern_selector;
704  else if (fImplNo > 0) return 0;
705  else return selector;
706  }
707  else {
708  // for genreflex explicit Yes is stronger than implicit file No
709 
710 #ifdef SELECTION_DEBUG
711  std::cout<<"\n\tfYes = "<<fYes<<", fFileNo = "<<fFileNo<<std::endl;
712 #endif
713 
714  if (selector)
715  return selector;
716  else
717  return 0;
718  }
719 
720 }
721 
722 
723 const ClassSelectionRule *SelectionRules::IsClassSelected(const clang::Decl* D, const std::string& qual_name) const
724 {
725  const clang::TagDecl* tagDecl = llvm::dyn_cast<clang::TagDecl> (D); //TagDecl has methods to understand of what kind is the Decl
726  const clang::TypedefNameDecl* typeDefNameDecl = llvm::dyn_cast<clang::TypedefNameDecl> (D);
727 
728  if (!tagDecl && !typeDefNameDecl) { // Ill posed
729  ROOT::TMetaUtils::Error("SelectionRules::IsClassSelected",
730  "Cannot cast Decl to TagDecl and Decl is not a typedef.\n");
731  return 0;
732  }
733 
734  if (!tagDecl && typeDefNameDecl){ // Let's try to fetch the underlying RecordDecl
735  clang::RecordDecl* recordDecl = ROOT::TMetaUtils::GetUnderlyingRecordDecl(typeDefNameDecl->getUnderlyingType());
736  if (!recordDecl){
737  ROOT::TMetaUtils::Error("SelectionRules::IsClassSelected",
738  "Cannot get RecordDecl behind TypedefDecl.\n");
739  return 0;
740  }
741  tagDecl = recordDecl;
742  }
743 
744  // At this point tagDecl must be well defined
745  const bool isLinkDefFile = IsLinkdefFile();
746  if (!( isLinkDefFile || tagDecl->isClass() || tagDecl->isStruct() ))
747  return 0; // Union for Genreflex
748 
749  const ClassSelectionRule *selector = 0;
750  int fImplNo = 0;
751  const ClassSelectionRule *explicit_selector = 0;
752  const ClassSelectionRule *specific_pattern_selector = 0;
753  int fFileNo = 0;
754 
755  // iterate through all class selection rles
756  bool earlyReturn=false;
757  const ClassSelectionRule* retval = nullptr;
758  const clang::NamedDecl* nDecl(llvm::dyn_cast<clang::NamedDecl>(D));
759  for(auto& rule : fClassSelectionRules) {
760  BaseSelectionRule::EMatchType match = rule.Match(nDecl, qual_name, "", isLinkDefFile);
761  if (match != BaseSelectionRule::kNoMatch) {
762  // Check if the template must have its arguments manipulated
763  if (const clang::ClassTemplateSpecializationDecl* ctsd =
764  llvm::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(D))
765  if(const clang::ClassTemplateDecl* ctd = ctsd->getSpecializedTemplate()){
766  const std::string& nArgsToKeep = rule.GetAttributeNArgsToKeep();
767  if (!nArgsToKeep.empty()){
768  fNormCtxt.AddTemplAndNargsToKeep(ctd->getCanonicalDecl(),
769  std::atoi(nArgsToKeep.c_str()));
770  }
771  }
772 
773  if (earlyReturn) continue;
774 
775  // If we have a match.
776  selector = &(rule);
777  if (rule.GetSelected() == BaseSelectionRule::kYes) {
778 
779  if (isLinkDefFile){
780  // rootcint prefers explicit rules over pattern rules
781  if (match == BaseSelectionRule::kName) {
782  explicit_selector = &(rule);
783  } else if (match == BaseSelectionRule::kPattern) {
784  // NOTE: weird ...
785  const std::string& pattern_value=rule.GetAttributePattern();
786  if (!pattern_value.empty() &&
787  pattern_value != "*" &&
788  pattern_value != "*::*") specific_pattern_selector = &(rule);
789  }
790  }
791  } else if (rule.GetSelected() == BaseSelectionRule::kNo) {
792 
793  if (!isLinkDefFile) {
794  // in genreflex - we could explicitly select classes from other source files
795  if (match == BaseSelectionRule::kFile) ++fFileNo; // if we have veto because of class defined in other source file -> implicit No
796  else {
797  retval = selector;
798  earlyReturn=true; // explicit No returned
799  }
800  }
801  if (match == BaseSelectionRule::kPattern) {
802  //this is for the Linkdef selection
803  const std::string& pattern_value=rule.GetAttributePattern();
804  if (!pattern_value.empty() &&
805  (pattern_value == "*" || pattern_value == "*::*")) ++fImplNo;
806  else
807  earlyReturn=true;
808  }
809  else
810  earlyReturn=true;
811  }
812  else if (rule.GetSelected() == BaseSelectionRule::kDontCare && !(rule.HasMethodSelectionRules()) && !(rule.HasFieldSelectionRules())) {
813  earlyReturn=true;
814  }
815  }
816  } // Loop over the rules.
817 
818  if (earlyReturn) return retval;
819 
820  if (isLinkDefFile) {
821  // for rootcint explicit (name) Yes is stronger than implicit (pattern) No which is stronger than implicit (pattern) Yes
822  if (explicit_selector) return explicit_selector;
823  else if (specific_pattern_selector) return specific_pattern_selector;
824  else if (fImplNo > 0) return 0;
825  else return selector;
826  }
827  else {
828  // for genreflex explicit Yes is stronger than implicit file No
829  return selector; // it can be nullptr
830  }
831 
832 }
833 
834 const BaseSelectionRule *SelectionRules::IsVarSelected(const clang::VarDecl* D, const std::string& qual_name) const
835 {
836  std::list<VariableSelectionRule>::const_iterator it = fVariableSelectionRules.begin();
837  std::list<VariableSelectionRule>::const_iterator it_end = fVariableSelectionRules.end();
838 
839  const BaseSelectionRule *selector = 0;
840 
841  // iterate through all the rules
842  // we call this method only for genrefex variables, functions and enums - it is simpler than the class case:
843  // if we have No - it is veto even if we have explicit yes as well
844  for(; it != it_end; ++it) {
845  if (BaseSelectionRule::kNoMatch != it->Match(llvm::dyn_cast<clang::NamedDecl>(D), qual_name, "", false)) {
846  if (it->GetSelected() == BaseSelectionRule::kNo) {
847  // The rule did explicitly request to not select this entity.
848  return 0;
849  } else {
850  selector = &(*it);
851  }
852  }
853  }
854 
855  return selector;
856 }
857 
858 const BaseSelectionRule *SelectionRules::IsFunSelected(const clang::FunctionDecl *D, const std::string &qual_name) const
859 {
860 
861  if (fFunctionSelectionRules.size() == 0 ||
862  D->getPrimaryTemplate() != nullptr ||
863  llvm::isa<clang::CXXMethodDecl>(D)) return nullptr;
864 
865  std::string prototype;
866  GetFunctionPrototype(D, prototype);
867  prototype = qual_name + prototype;
868 
869  const BaseSelectionRule *selector = nullptr;
870  // iterate through all the rules
871  // we call this method only for genrefex variables, functions and enums - it is simpler than the class case:
872  // if we have No - it is veto even if we have explicit yes as well
873  for (const auto & rule : fFunctionSelectionRules) {
874  if (BaseSelectionRule::kNoMatch != rule.Match(D, qual_name, prototype, false)) {
875  if (rule.GetSelected() == BaseSelectionRule::kNo) {
876  // The rule did explicitly request to not select this entity.
877  return nullptr;
878  } else {
879  selector = &(rule);
880  }
881  }
882  }
883 
884  return selector;
885 }
886 
887 const BaseSelectionRule *SelectionRules::IsEnumSelected(const clang::EnumDecl* D, const std::string& qual_name) const
888 {
889  const BaseSelectionRule *selector = 0;
890 
891  // iterate through all the rules
892  // we call this method only for genrefex variables, functions and enums - it is simpler than the class case:
893  // if we have No - it is veto even if we have explicit yes as well
894  for(const auto& rule: fEnumSelectionRules) {
895  if (BaseSelectionRule::kNoMatch != rule.Match(llvm::dyn_cast<clang::NamedDecl>(D), qual_name, "", false)) {
896  if (rule.GetSelected() == BaseSelectionRule::kNo) {
897  // The rule did explicitly request to not select this entity.
898  return 0;
899  } else {
900  selector = &rule;
901  }
902  }
903  }
904 
905  return selector;
906 }
907 
908 const BaseSelectionRule *SelectionRules::IsLinkdefVarSelected(const clang::VarDecl* D, const std::string& qual_name) const
909 {
910 
911 
912  const BaseSelectionRule *selector = 0;
913  int fImplNo = 0;
914  const BaseSelectionRule *explicit_selector = 0;
915 
916  std::string name_value;
917  std::string pattern_value;
918  for(auto& selRule: fVariableSelectionRules) {
920  = selRule.Match(llvm::dyn_cast<clang::NamedDecl>(D), qual_name, "", false);
921  if (match != BaseSelectionRule::kNoMatch) {
922  if (selRule.GetSelected() == BaseSelectionRule::kYes) {
923  // explicit rules are with stronger priority in rootcint
924  if (IsLinkdefFile()){
925  if (match == BaseSelectionRule::kName) {
926  explicit_selector = &selRule;
927  } else if (match == BaseSelectionRule::kPattern) {
928  if (selRule.GetAttributeValue("pattern", pattern_value)) {
929  explicit_selector=&selRule;
930  // NOTE: Weird ... This is a strange definition of explicit.
931  //if (pattern_value != "*" && pattern_value != "*::*") explicit_selector = selRule;
932  }
933  }
934  }
935  }
936  else {
937  if (!IsLinkdefFile()) return 0;
938  else {
939  if (selRule.GetAttributeValue("pattern", pattern_value)) {
940  if (pattern_value == "*" || pattern_value == "*::*") ++fImplNo;
941  else
942  return 0;
943  }
944  else
945  return 0;
946  }
947  }
948  }
949  }
950 
951  if (IsLinkdefFile()) {
952 
953 #ifdef SELECTION_DEBUG
954  std::cout<<"\n\tfYes = "<<fYes<<", fImplNo = "<<fImplNo<<std::endl;
955 #endif
956 
957  if (explicit_selector) return explicit_selector;
958  else if (fImplNo > 0) return 0;
959  else return selector;
960  }
961  else{
962  return selector;
963  }
964 }
965 
966 const BaseSelectionRule *SelectionRules::IsLinkdefFunSelected(const clang::FunctionDecl* D, const std::string& qual_name) const
967 {
968 
969  if (fFunctionSelectionRules.size() == 0 ||
970  D->getPrimaryTemplate() != nullptr ||
971  llvm::isa<clang::CXXMethodDecl>(D)) return nullptr;
972 
973  std::string prototype;
974 
975  GetFunctionPrototype(D, prototype);
976  prototype = qual_name + prototype;
977 
978  const BaseSelectionRule *selector = 0;
979  int fImplNo = 0;
980  const BaseSelectionRule *explicit_selector = 0;
981 
982  std::string pattern_value;
983  for(auto& selRule : fFunctionSelectionRules) {
985  = selRule.Match(llvm::dyn_cast<clang::NamedDecl>(D), qual_name, prototype, false);
986  if (match != BaseSelectionRule::kNoMatch) {
987  if (selRule.GetSelected() == BaseSelectionRule::kYes) {
988  // explicit rules are with stronger priority in rootcint
989  if (IsLinkdefFile()){
990  if (match == BaseSelectionRule::kName) {
991  explicit_selector = &selRule;
992  } else if (match == BaseSelectionRule::kPattern) {
993  if (selRule.GetAttributeValue("pattern", pattern_value)) {
994  explicit_selector = &selRule;
995  // NOTE: Weird ... This is a strange definition of explicit.
996  //if (pattern_value != "*" && pattern_value != "*::*") explicit_selector = &selRule;
997  }
998  }
999  }
1000  }
1001  else {
1002  if (!IsLinkdefFile()) return 0;
1003  else {
1004  if (selRule.GetAttributeValue("pattern", pattern_value)) {
1005  if (pattern_value == "*" || pattern_value == "*::*") ++fImplNo;
1006  else
1007  return 0;
1008  }
1009  else
1010  return 0;
1011  }
1012  }
1013  }
1014  }
1015 
1016  if (IsLinkdefFile()) {
1017  if (explicit_selector) return explicit_selector;
1018  else if (fImplNo > 0) return 0;
1019  else return selector;
1020  }
1021  else{
1022  return selector;
1023  }
1024 }
1025 
1026 const BaseSelectionRule *SelectionRules::IsLinkdefEnumSelected(const clang::EnumDecl* D, const std::string& qual_name) const
1027 {
1028  std::list<VariableSelectionRule>::const_iterator it;
1029  std::list<VariableSelectionRule>::const_iterator it_end;
1030 
1031  it = fEnumSelectionRules.begin();
1032  it_end = fEnumSelectionRules.end();
1033 
1034  const BaseSelectionRule *selector = 0;
1035  int fImplNo = 0;
1036  const BaseSelectionRule *explicit_selector = 0;
1037 
1038  std::string name_value;
1039  std::string pattern_value;
1040  for(; it != it_end; ++it) {
1042  it->Match(llvm::dyn_cast<clang::NamedDecl>(D), qual_name, "", false);
1043  if (match != BaseSelectionRule::kNoMatch) {
1044  if (it->GetSelected() == BaseSelectionRule::kYes) {
1045  // explicit rules are with stronger priority in rootcint
1046  if (IsLinkdefFile()){
1047  if (match == BaseSelectionRule::kName){
1048  explicit_selector = &(*it);
1049  } else if (match == BaseSelectionRule::kPattern &&
1050  it->GetAttributeValue("pattern", pattern_value)) {
1051  // Note: Weird ... This is a strange definition of explicit.
1052  if (pattern_value != "*" && pattern_value != "*::*") explicit_selector = &(*it);
1053  }
1054  }
1055  }
1056  else {
1057  if (!IsLinkdefFile()) return 0;
1058  else {
1059  if (it->GetAttributeValue("pattern", pattern_value)) {
1060  if (pattern_value == "*" || pattern_value == "*::*") ++fImplNo;
1061  else
1062  return 0;
1063  }
1064  else
1065  return 0;
1066  }
1067  }
1068  }
1069  }
1070 
1071  if (IsLinkdefFile()) {
1072 
1073 #ifdef SELECTION_DEBUG
1074  std::cout<<"\n\tfYes = "<<fYes<<", fImplNo = "<<fImplNo<<std::endl;
1075 #endif
1076 
1077  if (explicit_selector) return explicit_selector;
1078  else if (fImplNo > 0) return 0;
1079  else return selector;
1080  }
1081  else{
1082  return selector;
1083  }
1084 }
1085 
1086 // In rootcint we could select and deselect methods independantly of the class/struct/union rules
1087 // That's why we first have to check the explicit rules for the functions - to see if there
1088 // is rule corresponding to our method.
1089 // Which is more - if we have (and we can have) a pattern for the parent class, than a pattern for the
1090 // nested class, than a pattern for certain methods in the nested class, than a rule for a
1091 // method (name or prototype) in the nested class - the valid rule is the last one.
1092 // This is true irrespective of the rules (select/deselect). This is not the case for genreflex -
1093 // in genreflex if there is a pattern deselecting something even if we have an explicit rule
1094 // to select it, it still will not be selected.
1095 // This method (isLinkdefMethodSelected()) might be incomplete (but I didn't have the time to think
1096 // of anything better)
1097 //
1098 
1099 const BaseSelectionRule *SelectionRules::IsLinkdefMethodSelected(const clang::Decl* D, const std::string& qual_name) const
1100 {
1101  std::list<FunctionSelectionRule>::const_iterator it = fFunctionSelectionRules.begin();
1102  std::list<FunctionSelectionRule>::const_iterator it_end = fFunctionSelectionRules.end();
1103  std::string prototype;
1104 
1105  if (const clang::FunctionDecl* F = llvm::dyn_cast<clang::FunctionDecl> (D))
1106  GetFunctionPrototype(F, prototype);
1107  prototype = qual_name + prototype;
1108 
1109 #ifdef SELECTION_DEBUG
1110  std::cout<<"\tFunction prototype = "<<prototype<<std::endl;
1111 #endif
1112 
1113  int expl_Yes = 0, impl_r_Yes = 0, impl_rr_Yes = 0;
1114  int impl_r_No = 0, impl_rr_No = 0;
1115  const BaseSelectionRule *explicit_r = 0;
1116  const BaseSelectionRule *implicit_r = 0;
1117  const BaseSelectionRule *implicit_rr = 0;
1118 
1119  if (D->getKind() == clang::Decl::CXXMethod){
1120  // we first check the explicit rules for the method (in case of constructors and destructors we check the parent)
1121  std::string pat_value;
1122  for(; it != it_end; ++it) {
1124  = it->Match(llvm::dyn_cast<clang::NamedDecl>(D), qual_name, prototype, false);
1125 
1126  if (match == BaseSelectionRule::kName) {
1127  // here I should implement my implicit/explicit thing
1128  // I have included two levels of implicitness - "A::Get_*" is stronger than "*"
1129  explicit_r = &(*it);
1130  if (it->GetSelected() == BaseSelectionRule::kYes) ++expl_Yes;
1131  else {
1132 
1133 #ifdef SELECTION_DEBUG
1134  std::cout<<"\tExplicit rule BaseSelectionRule::kNo found"<<std::endl;
1135 #endif
1136 
1137  return 0; // == explicit BaseSelectionRule::kNo
1138 
1139  }
1140  } else if (match == BaseSelectionRule::kPattern) {
1141 
1142  if (it->GetAttributeValue("pattern", pat_value)) {
1143  if (pat_value == "*") continue; // we discard the global selection rules
1144 
1145  std::string par_name, par_qual_name;
1146  GetParentName(D, par_name, par_qual_name);
1147  std::string par_pat = par_qual_name + "::*";
1148 
1149  if (pat_value == par_pat) {
1150  implicit_rr = &(*it);
1151  if (it->GetSelected() == BaseSelectionRule::kYes) {
1152 
1153 #ifdef SELECTION_DEBUG
1154  std::cout<<"Implicit_rr rule ("<<pat_value<<"), selected = "<<selected<<std::endl;
1155 #endif
1156 
1157  ++impl_rr_Yes;
1158  }
1159  else {
1160 
1161 #ifdef SELECTION_DEBUG
1162  std::cout<<"Implicit_rr rule ("<<pat_value<<"), selected = "<<selected<<std::endl;
1163 #endif
1164 
1165  ++impl_rr_No;
1166  }
1167  }
1168  else {
1169  implicit_r = &(*it);
1170  if (it->GetSelected() == BaseSelectionRule::kYes) {
1171 
1172 #ifdef SELECTION_DEBUG
1173  std::cout<<"Implicit_r rule ("<<pat_value<<"), selected = "<<selected<<std::endl;
1174 #endif
1175 
1176  ++impl_r_Yes;
1177  }
1178  else {
1179 
1180 #ifdef SELECTION_DEBUG
1181  std::cout<<"Implicit_r rule ("<<pat_value<<"), selected = "<<selected<<std::endl;
1182 #endif
1183 
1184  ++impl_r_No;
1185  }
1186  }
1187  }
1188  }
1189  }
1190  }
1191  if (explicit_r /*&& expl_Yes > 0*/){
1192 
1193 #ifdef SELECTION_DEBUG
1194  std::cout<<"\tExplicit rule BaseSelectionRule::BaseSelectionRule::kYes found"<<std::endl;
1195 #endif
1196 
1197  return explicit_r; // if we have excplicit BaseSelectionRule::kYes
1198  }
1199  else if (implicit_rr) {
1200  if (impl_rr_No > 0) {
1201 
1202 #ifdef SELECTION_DEBUG
1203  std::cout<<"\tImplicit_rr rule BaseSelectionRule::kNo found"<<std::endl;
1204 #endif
1205 
1206  return 0;
1207  }
1208  else {
1209 
1210 #ifdef SELECTION_DEBUG
1211  std::cout<<"\tImplicit_rr rule BaseSelectionRule::kYes found"<<std::endl;
1212 #endif
1213 
1214  return implicit_rr;
1215  }
1216  }
1217  else if (implicit_r) {
1218  if (impl_r_No > 0) {
1219 
1220 #ifdef SELECTION_DEBUG
1221  std::cout<<"\tImplicit_r rule BaseSelectionRule::kNo found"<<std::endl;
1222 #endif
1223 
1224  return 0;
1225  }
1226  else {
1227 
1228 #ifdef SELECTION_DEBUG
1229  std::cout<<"\tImplicit_r rule BaseSelectionRule::kYes found"<<std::endl;
1230 #endif
1231 
1232  return implicit_r;
1233  }
1234  }
1235  else {
1236 
1237 #ifdef SELECTION_DEBUG
1238  std::cout<<"\tChecking parent class rules"<<std::endl;
1239 #endif
1240  // check parent
1241 
1242 
1243  std::string parent_name, parent_qual_name;
1244  if (!GetParentName(D, parent_name, parent_qual_name)) return 0;
1245 
1246  const BaseSelectionRule *selector = 0;
1247  int fImplNo = 0;
1248  const BaseSelectionRule *explicit_selector = 0;
1249 
1250  // the same as with isClass selected
1251  // I wanted to use GetParentDecl and then to pass is to isClassSelected because I didn't wanted to repeat
1252  // code but than GetParentDecl crashes (or returns non-sence Decl) for the built-in structs (__va_*)
1253  std::list<ClassSelectionRule>::const_iterator it = fClassSelectionRules.begin();
1254  std::string name_value;
1255  std::string pattern_value;
1256  for(; it != fClassSelectionRules.end(); ++it) {
1258  = it->Match(llvm::dyn_cast<clang::NamedDecl>(D), parent_qual_name, "", true); // == BaseSelectionRule::kYes
1259 
1260  if (match != BaseSelectionRule::kNoMatch) {
1261  if (it->GetSelected() == BaseSelectionRule::kYes) {
1262  selector = &(*it);
1263 
1264  if (match == BaseSelectionRule::kName) {
1265  explicit_selector = &(*it);
1266  } else if (match == BaseSelectionRule::kPattern) {
1267  if (it->GetAttributeValue("pattern", pattern_value)) {
1268  // NOTE: weird ...
1269  if (pattern_value != "*" && pattern_value != "*::*") explicit_selector = &(*it);
1270  }
1271  }
1272  }
1273  else { // == BaseSelectionRule::kNo
1274 
1275  if (it->GetAttributeValue("pattern", pattern_value)) {
1276  if (pattern_value == "*" || pattern_value == "*::*") ++fImplNo;
1277  else
1278  return 0;
1279  }
1280  else
1281  return 0;
1282  }
1283  }
1284  }
1285 
1286 #ifdef SELECTION_DEBUG
1287  std::cout<<"\n\tfYes = "<<fYes<<", fImplNo = "<<fImplNo<<std::endl;
1288 #endif
1289 
1290  if (explicit_selector) {
1291 
1292 #ifdef SELECTION_DEBUG
1293  std::cout<<"\tReturning Yes"<<std::endl;
1294 #endif
1295 
1296  return explicit_selector;
1297  }
1298  else if (fImplNo > 0) {
1299 #ifdef SELECTION_DEBUG
1300  std::cout<<"\tReturning No"<<std::endl;
1301 #endif
1302 
1303  return 0;
1304  }
1305  else {
1306 
1307 #ifdef SELECTION_DEBUG
1308  std::cout<<"\tReturning Yes"<<std::endl;
1309 #endif
1310 
1311  return selector;
1312  }
1313  }
1314 
1315  return 0;
1316 
1317 }
1318 
1319 const BaseSelectionRule *SelectionRules::IsMemberSelected(const clang::Decl* D, const std::string& str_name) const
1320 {
1321  std::string parent_name;
1322  std::string parent_qual_name;
1323 
1324  if (IsParentClass(D))
1325  {
1326  if (!GetParentName(D, parent_name, parent_qual_name)) return 0;
1327 
1328  const BaseSelectionRule *selector = 0;
1329  Int_t fImplNo = 0;
1330  const BaseSelectionRule *explicit_selector = 0;
1331  int fFileNo = 0;
1332 
1333  //DEBUG std::cout<<"\n\tParent is class";
1334  std::list<ClassSelectionRule>::const_iterator it = fClassSelectionRules.begin();
1335  std::string name_value;
1336  std::string pattern_value;
1337  for(; it != fClassSelectionRules.end(); ++it) {
1339  = it->Match(llvm::dyn_cast<clang::NamedDecl>(D), parent_qual_name, "", false);
1340 
1341  if (match != BaseSelectionRule::kNoMatch) {
1342  if (it->GetSelected() == BaseSelectionRule::kYes) {
1343  selector = &(*it);
1344  if (IsLinkdefFile()) {
1345  if (match == BaseSelectionRule::kName) {
1346  explicit_selector = &(*it);
1347  } else if (match == BaseSelectionRule::kPattern) {
1348  if (it->GetAttributeValue("pattern", pattern_value)) {
1349  // NOTE: Weird ... This is a strange definition of explicit.
1350  if (pattern_value != "*" && pattern_value != "*::*") explicit_selector = &(*it);
1351  }
1352  }
1353  }
1354  } else if (it->GetSelected() == BaseSelectionRule::kNo) {
1355  if (!IsLinkdefFile()) {
1356  if (match == BaseSelectionRule::kFile) ++fFileNo;
1357  else {
1358 
1359 #ifdef SELECTION_DEBUG
1360  std::cout<<"\tNo returned"<<std::endl;
1361 #endif
1362 
1363  return 0; // in genreflex we can't have that situation
1364  }
1365  }
1366  else {
1367  if (match == BaseSelectionRule::kPattern && it->GetAttributeValue("pattern", pattern_value)) {
1368  if (pattern_value == "*" || pattern_value == "*::*") ++fImplNo;
1369  else
1370  return 0;
1371  }
1372  else
1373  return 0;
1374  }
1375  }
1376  else if (it->GetSelected() == BaseSelectionRule::kDontCare) // - we check the method and field selection rules for the class
1377  {
1378  if (!it->HasMethodSelectionRules() && !it->HasFieldSelectionRules()) {
1379 
1380 #ifdef SELECTION_DEBUG
1381  std::cout<<"\tNo fields and methods"<<std::endl;
1382 #endif
1383 
1384  return 0; // == BaseSelectionRule::kNo
1385  }
1386  else {
1387  clang::Decl::Kind kind = D->getKind();
1388  if (kind == clang::Decl::Field || kind == clang::Decl::CXXMethod || kind == clang::Decl::CXXConstructor || kind == clang::Decl::CXXDestructor){
1389  std::list<VariableSelectionRule> members;
1390  std::list<VariableSelectionRule>::iterator mem_it;
1391  std::list<VariableSelectionRule>::iterator mem_it_end;
1392  std::string prototype;
1393 
1394  if (kind == clang::Decl::Field) {
1395  members = it->GetFieldSelectionRules();
1396  }
1397  else {
1398  if (const clang::FunctionDecl* F = llvm::dyn_cast<clang::FunctionDecl> (D)){
1399  GetFunctionPrototype(F, prototype);
1400  prototype = str_name + prototype;
1401  }
1402  else{
1403  ROOT::TMetaUtils::Warning("","Warning: could not cast Decl to FunctionDecl\n");
1404  }
1405  members = it->GetMethodSelectionRules();
1406  }
1407  mem_it = members.begin();
1408  mem_it_end = members.end();
1409  for (; mem_it != mem_it_end; ++mem_it) {
1410  if (BaseSelectionRule::kName == mem_it->Match(llvm::dyn_cast<clang::NamedDecl>(D), str_name, prototype, false)) {
1411  if (mem_it->GetSelected() == BaseSelectionRule::kNo) return 0;
1412  }
1413  }
1414  }
1415  }
1416  }
1417  }
1418  }
1419 
1420  if (IsLinkdefFile()) {
1421 
1422 #ifdef SELECTION_DEBUG
1423  std::cout<<"\n\tfYes = "<<fYes<<", fImplNo = "<<fImplNo<<std::endl;
1424 #endif
1425 
1426  if (explicit_selector) {
1427 #ifdef SELECTION_DEBUG
1428  std::cout<<"\tReturning Yes"<<std::endl;
1429 #endif
1430 
1431  return explicit_selector;
1432  }
1433  else if (fImplNo > 0) {
1434 
1435 #ifdef SELECTION_DEBUG
1436  std::cout<<"\tReturning No"<<std::endl;
1437 #endif
1438 
1439  return 0;
1440  }
1441  else {
1442 
1443 #ifdef SELECTION_DEBUG
1444  std::cout<<"\tReturning Yes"<<std::endl;
1445 #endif
1446 
1447  return selector;
1448  }
1449  }
1450  else {
1451 
1452  return selector;
1453  }
1454  }
1455  else {
1456  return 0;
1457  }
1458 }
1459 
1461  for(auto&& rule : fClassSelectionRules){
1462  if (BaseSelectionRule::kNo!=rule.GetSelected() && !rule.GetMatchFound() /* && !GetHasFileNameRule() */ ) {
1463  std::string name;
1464  if (rule.GetAttributeValue("pattern", name)) {
1465  // keep it
1466  } else if (rule.GetAttributeValue("name", name)) {
1467  // keept it
1468  } else {
1469  name.clear();
1470  }
1471  std::string file_name_value;
1472  if (!rule.GetAttributeValue("file_name", file_name_value)) file_name_value.clear();
1473 
1474  if (!file_name_value.empty()) {
1475  // don't complain about defined_in rules
1476  continue;
1477  }
1478 
1479  const char* attrName = nullptr;
1480  const char* attrVal = nullptr;
1481  if (!file_name_value.empty()) {
1482  attrName = "file name";
1483  attrVal = file_name_value.c_str();
1484  } else {
1485  attrName = "class";
1486  if (!name.empty()) attrVal = name.c_str();
1487  }
1488  ROOT::TMetaUtils::Warning(0,"Unused %s rule: %s\n", attrName, attrVal);
1489  }
1490  }
1491 
1492  for(auto&& rule : fVariableSelectionRules){
1493  if (!rule.GetMatchFound() && !GetHasFileNameRule()) {
1494  std::string name;
1495  if (rule.GetAttributeValue("pattern", name)) {
1496  // keep it
1497  } else if (rule.GetAttributeValue("name", name)) {
1498  // keept it
1499  } else {
1500  name.clear();
1501  }
1502  ROOT::TMetaUtils::Warning("","Unused variable rule: %s\n",name.c_str());
1503  if (name.empty()) {
1504  rule.PrintAttributes(std::cout,3);
1505  }
1506  }
1507  }
1508 
1509 #if defined(R__MUST_REVISIT)
1510 #if R__MUST_REVISIT(6,2)
1511 ROOT::TMetaUtils::Warning("SelectionRules::AreAllSelectionRulesUsed",
1512 "Warnings concerning non matching selection rules are suppressed. An action is to be taken.\n");
1513 #endif
1514 #endif
1515 // for(const auto& selRule: fFunctionSelectionRules) {
1516 // if (!selRule.GetMatchFound() && !GetHasFileNameRule()) {
1517 // // Here the slow methods can be used
1518 // std::string name;
1519 // if (selRule.GetAttributeValue("proto_pattern", name)) {
1520 // // keep it
1521 // } else if (selRule.GetAttributeValue("proto_name", name)) {
1522 // // keep it
1523 // } else if (selRule.GetAttributeValue("pattern", name)) {
1524 // // keep it
1525 // } else if (selRule.GetAttributeValue("name", name)) {
1526 // // keept it
1527 // } else {
1528 // name.clear();
1529 // }
1530 // // Make it soft, no error - just warnings
1531 // std::cout<<"Warning - unused function rule: "<<name<<std::endl;
1532 // // if (IsSelectionXMLFile()){
1533 // // std::cout<<"Warning - unused function rule: "<<name<<std::endl;
1534 // // }
1535 // // else {
1536 // // std::cout<<"Error - unused function rule: "<<name<<std::endl;
1537 // // }
1538 // if (name.length() == 0) {
1539 // selRule.PrintAttributes(std::cout,3);
1540 // }
1541 // }
1542 //
1543 // }
1544 
1545 
1546 #if Enums_rules_becomes_useful_for_rootcling
1547  for(auto&& rule : fEnumSelectionRules){
1548  if (!rule.GetMatchFound() && !GetHasFileNameRule()) {
1549  std::string name;
1550  if (rule.GetAttributeValue("pattern", name)) {
1551  // keep it
1552  } else if (rule.GetAttributeValue("name", name)) {
1553  // keept it
1554  } else {
1555  name.clear();
1556  }
1557 
1558  ROOT::TMetaUtils::Warning("","Unused enum rule: %s\n",name.c_str());
1559 
1560  if (name.empty()){
1561  rule.PrintAttributes(std::cout,3);
1562  }
1563  }
1564  }
1565 #endif
1566  return true;
1567 }
1568 
1569 bool SelectionRules::SearchNames(cling::Interpreter &interp)
1570 {
1571  // std::cout<<"Searching Names In Selection Rules:"<<std::endl;
1572  for(std::list<ClassSelectionRule>::iterator it = fClassSelectionRules.begin(),
1573  end = fClassSelectionRules.end();
1574  it != end;
1575  ++it) {
1576  if (it->HasAttributeWithName("name")) {
1577  std::string name_value;
1578  it->GetAttributeValue("name", name_value);
1579  // In Class selection rules, we should be interested in scopes.
1580  const clang::Type *typeptr = 0;
1581  const clang::CXXRecordDecl *target
1582  = ROOT::TMetaUtils::ScopeSearch(name_value.c_str(), interp,
1583  true /*diag*/, &typeptr);
1584  if (target) {
1585  it->SetCXXRecordDecl(target,typeptr);
1586  }
1587  }
1588  }
1589  return true;
1590 }
1591 
1592 
1594 {
1595  // Fill the cache of every selection rule
1596  for (auto& rule : fClassSelectionRules) rule.FillCache();
1597  for (auto& rule : fFunctionSelectionRules) rule.FillCache();
1598  for (auto& rule : fVariableSelectionRules) rule.FillCache();
1599  for (auto& rule : fEnumSelectionRules) rule.FillCache();
1600 }
1601 
1602 
static const std::string nArgsToKeep("nArgsToKeep")
std::list< ClassSelectionRule > fClassSelectionRules
List of the class selection rules.
bool fIsDeep
if –deep option passed from command line, this should be set to true
void AddTemplAndNargsToKeep(const clang::ClassTemplateDecl *templ, unsigned int i)
Definition: TMetaUtils.cxx:341
const AttributesMap_t & GetAttributes() const
const ClassSelectionRule * IsDeclSelected(const clang::RecordDecl *D) const
ROOT::TMetaUtils::TNormalizedCtxt & fNormCtxt
bool IsLinkdefFile() const
const BaseSelectionRule * IsVarSelected(const clang::VarDecl *D, const std::string &qual_name) const
void Error(const char *location, const char *va_(fmt),...)
Use this function in case an error occured.
bool GetDeclName(const clang::Decl *D, std::string &name, std::string &qual_name) const
double T(double x)
Definition: ChebyshevPol.h:34
bool GetFunctionPrototype(const clang::FunctionDecl *F, std::string &prototype) const
clang::RecordDecl * GetUnderlyingRecordDecl(clang::QualType type)
#define N
int Int_t
Definition: RtypesCore.h:41
bool AreAllSelectionRulesUsed() const
bool GetParentName(const clang::Decl *D, std::string &parent_name, std::string &parent_qual_name) const
std::list< VariableSelectionRule > fVariableSelectionRules
List of the global variables selection rules.
const ClassSelectionRule * IsNamespaceSelected(const clang::Decl *D, const std::string &qual_name) const
void PrintSelectionRules() const
long int fRulesCounter
void ClearSelectionRules()
static const std::string pattern("pattern")
const BaseSelectionRule * IsLinkdefFunSelected(const clang::FunctionDecl *D, const std::string &qual_name) const
void AddFunctionSelectionRule(const FunctionSelectionRule &funcSel)
const BaseSelectionRule * IsLinkdefMethodSelected(const clang::Decl *D, const std::string &qual_name) const
def Namespace(name)
Definition: cppyy.py:193
void Info(const char *location, const char *va_(fmt),...)
Use this function for informational messages.
void GetDeclQualName(const clang::Decl *D, std::string &qual_name) const
const ClassSelectionRule * IsClassSelected(const clang::Decl *D, const std::string &qual_name) const
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, etc.) and adding default template argument for all types except the STL collections where we remove the default template argument if any.
#define F(x, y, z)
const BaseSelectionRule * IsFunSelected(const clang::FunctionDecl *D, const std::string &qual_name) const
const clang::CXXRecordDecl * ScopeSearch(const char *name, const cling::Interpreter &gInterp, bool diagnose, const clang::Type **resultType)
Return the scope corresponding to 'name' or std::'name'.
Definition: TMetaUtils.cxx:710
Double_t E()
Definition: TMath.h:54
static int CheckDuplicatesImp(RULESCOLLECTION &rules)
ESelect GetSelected() const
const clang::CXXRecordDecl * R__ScopeSearch(const char *name, const clang::Type **resultType=0)
void AddVariableSelectionRule(const VariableSelectionRule &varSel)
bool HasInterpreter() const
Type
enumeration specifying the integration types.
EMatchType Match(const clang::NamedDecl *decl, const std::string &name, const std::string &prototype, bool isLinkdef) const
const std::string & GetAttributePattern() const
cling::Interpreter & fInterp
const BaseSelectionRule * IsLinkdefEnumSelected(const clang::EnumDecl *D, const std::string &qual_name) const
const std::string & GetAttributeName() const
void SetDeep(bool deep)
static bool HasDuplicate(RULE *rule, std::unordered_map< std::string, RULE * > &storedRules, const std::string &attrName)
MyComplex< T > P(MyComplex< T > z, T c_real, T c_imag)
[MyComplex]
Definition: mandel.cpp:155
static bool Implies(ClassSelectionRule &patternRule, ClassSelectionRule &nameRule)
std::list< EnumSelectionRule > fEnumSelectionRules
List of the enums selection rules.
bool areEqual(const RULE *r1, const RULE *r2, bool moduloNameOrPattern=false)
int type
Definition: TGX11.cxx:120
bool GetHasFileNameRule() const
void SetSelected(ESelect sel)
Enum
Definition: load.cpp:93
void Warning(const char *location, const char *va_(fmt),...)
Use this function in warning situations.
void AddClassSelectionRule(const ClassSelectionRule &classSel)
#define name(a, b)
Definition: linkTestLib0.cpp:5
void AddEnumSelectionRule(const EnumSelectionRule &enumSel)
void SetAttributeValue(const std::string &attributeName, const std::string &attributeValue)
const BaseSelectionRule * IsEnumSelected(const clang::EnumDecl *D, const std::string &qual_name) const
bool IsSelectionXMLFile() const
long GetIndex() const
void ReplaceAll(std::string &str, const std::string &from, const std::string &to, bool recurse=false)
bool IsParentClass(const clang::Decl *D) const
std::list< FunctionSelectionRule > fFunctionSelectionRules
List of the global functions selection rules.
#define I(x, y, z)
const BaseSelectionRule * IsMemberSelected(const clang::Decl *D, const std::string &str_name) const
bool SearchNames(cling::Interpreter &interp)
const BaseSelectionRule * IsLinkdefVarSelected(const clang::VarDecl *D, const std::string &qual_name) const