Logo ROOT   6.07/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 }
304 
305 const ClassSelectionRule *SelectionRules::IsDeclSelected(const clang::RecordDecl *D) const
306 {
307  std::string qual_name;
308  GetDeclQualName(D,qual_name);
309  return IsClassSelected(D, qual_name);
310 }
311 
312 const ClassSelectionRule *SelectionRules::IsDeclSelected(const clang::TypedefNameDecl *D) const
313 {
314  std::string qual_name;
315  GetDeclQualName(D,qual_name);
316  return IsClassSelected(D, qual_name);
317 }
318 
319 const ClassSelectionRule *SelectionRules::IsDeclSelected(const clang::NamespaceDecl *D) const
320 {
321  std::string qual_name;
322  GetDeclQualName(D,qual_name);
323  return IsNamespaceSelected(D, qual_name);
324 }
325 
326 const BaseSelectionRule *SelectionRules::IsDeclSelected(const clang::EnumDecl *D) const
327 {
328  // Currently rootcling does not need any information on enums, except
329  // for the PCM / proto classes that register them to build TEnums without
330  // parsing. This can be removed once (real) PCMs are available.
331  // Note that the code below was *not* properly matching the case
332  // typedef enum { ... } abc;
333  // as the typedef is stored as an anonymous EnumDecl in clang.
334  // It is likely that using a direct lookup on the name would
335  // return the appropriate typedef (and then we would need to
336  // select 'both' the typedef and the anonymous enums.
337 
338 #if defined(R__MUST_REVISIT)
339 # if R__MUST_REVISIT(6,4)
340  "Can become no-op once PCMs are available."
341 # endif
342 #endif
343 
344  std::string str_name; // name of the Decl
345  std::string qual_name; // fully qualified name of the Decl
346  GetDeclName(D, str_name, qual_name);
347 
348  if (IsParentClass(D)) {
349  const BaseSelectionRule *selector = IsMemberSelected(D, str_name);
350  if (!selector) // if the parent class is deselected, we could still select the enum
351  return IsEnumSelected(D, qual_name);
352  else // if the parent class is selected so are all nested enums
353  return selector;
354  }
355 
356  // Enum is not part of a class
357  else {
358  if (IsLinkdefFile())
359  return IsLinkdefEnumSelected(D, qual_name);
360  return IsEnumSelected(D, qual_name);
361  }
362 
363  return 0;
364 }
365 
366 const BaseSelectionRule *SelectionRules::IsDeclSelected(const clang::VarDecl* D) const
367 {
368  std::string qual_name; // fully qualified name of the Decl
369  GetDeclQualName(D, qual_name);
370 
371  if (IsLinkdefFile())
372  return IsLinkdefVarSelected(D, qual_name);
373  else
374  return IsVarSelected(D, qual_name);
375 
376 }
377 
378 const BaseSelectionRule *SelectionRules::IsDeclSelected(const clang::FieldDecl* /* D */) const
379 {
380  // Currently rootcling does not need any information about fields.
381  return 0;
382 #if 0
383  std::string str_name; // name of the Decl
384  std::string qual_name; // fully qualified name of the Decl
385  GetDeclName(D, str_name, qual_name);
386 
387  return IsMemberSelected(D, str_name);
388 #endif
389 }
390 
391 const BaseSelectionRule *SelectionRules::IsDeclSelected(const clang::FunctionDecl* D) const
392 {
393  // Implement a simple matching for functions
394  std::string qual_name; // fully qualified name of the Decl
395  GetDeclQualName(D, qual_name);
396  if (IsLinkdefFile())
397  return IsLinkdefFunSelected(D, qual_name);
398  else
399  return IsFunSelected(D, qual_name);
400 }
401 
402 const BaseSelectionRule *SelectionRules::IsDeclSelected(const clang::Decl *D) const
403 {
404  if (!D) {
405  return 0;
406  }
407 
408  clang::Decl::Kind declkind = D->getKind();
409 
410  switch (declkind) {
411  case clang::Decl::CXXRecord:
412  case clang::Decl::ClassTemplateSpecialization:
413  case clang::Decl::ClassTemplatePartialSpecialization:
414  // structs, unions and classes are all CXXRecords
415  return IsDeclSelected(llvm::dyn_cast<clang::RecordDecl>(D));
416  case clang::Decl::Namespace:
417  return IsDeclSelected(llvm::dyn_cast<clang::NamespaceDecl>(D));
418  case clang::Decl::Enum:
419  // Enum is part of a class
420  return IsDeclSelected(llvm::dyn_cast<clang::EnumDecl>(D));
421  case clang::Decl::Var:
422  return IsDeclSelected(llvm::dyn_cast<clang::VarDecl>(D));
423 #if ROOTCLING_NEEDS_FUNCTIONS_SELECTION
424  case clang::Decl::Function:
425  return IsDeclSelected(llvm::dyn_cast<clang::FunctionDecl>(D));
426  case clang::Decl::CXXMethod:
427  case clang::Decl::CXXConstructor:
428  case clang::Decl::CXXDestructor: {
429  // std::string proto;
430  // if (GetFunctionPrototype(D,proto))
431  // std::cout<<"\n\tFunction prototype: "<<str_name + proto;
432  // else
433  // std::cout<<"Error in prototype formation";
434  std::string str_name; // name of the Decl
435  std::string qual_name; // fully qualified name of the Decl
436  GetDeclName(D, str_name, qual_name);
437  if (IsLinkdefFile()) {
438  return IsLinkdefMethodSelected(D, qual_name);
439  }
440  return IsMemberSelected(D, str_name);
441  }
442 #endif
443  case clang::Decl::Field:
444  return IsDeclSelected(llvm::dyn_cast<clang::FieldDecl>(D));
445  default:
446  // Humm we are not treating this case!
447  return 0;
448  }
449 
450  // std::string str_name; // name of the Decl
451  // std::string qual_name; // fully qualified name of the Decl
452  // GetDeclName(D, str_name, qual_name);
453  // fprintf(stderr,"IsDeclSelected: %s %s\n", str_name.c_str(), qual_name.c_str());
454 }
455 
456 
457 bool SelectionRules::GetDeclName(const clang::Decl* D, std::string& name, std::string& qual_name) const
458 {
459  const clang::NamedDecl* N = llvm::dyn_cast<clang::NamedDecl> (D);
460 
461  if (!N)
462  return false;
463 
464  // the identifier is NULL for some special methods like constructors, destructors and operators
465  if (N->getIdentifier()) {
466  name = N->getNameAsString();
467  }
468  else if (N->isCXXClassMember()) { // for constructors, destructors, operator=, etc. methods
469  name = N->getNameAsString(); // we use this (unefficient) method to Get the name in that case
470  }
471  llvm::raw_string_ostream stream(qual_name);
472  N->getNameForDiagnostic(stream,N->getASTContext().getPrintingPolicy(),true);
473  return true;
474 }
475 
476 void SelectionRules::GetDeclQualName(const clang::Decl* D, std::string& qual_name) const{
477  const clang::NamedDecl* N = static_cast<const clang::NamedDecl*> (D);
478  llvm::raw_string_ostream stream(qual_name);
479  N->getNameForDiagnostic(stream,N->getASTContext().getPrintingPolicy(),true);
480  }
481 
482 bool SelectionRules::GetFunctionPrototype(const clang::FunctionDecl* F, std::string& prototype) const {
483 
484  if (!F) {
485  return false;
486  }
487 
488  const std::vector<std::string> quals={"*","&"};
489 
490  prototype = "";
491  // iterate through all the function parameters
492  std::string type;
493  for (auto I = F->param_begin(), E = F->param_end(); I != E; ++I) {
494 
495  clang::ParmVarDecl* P = *I;
496 
497  if (prototype != "")
498  prototype += ",";
499 
501 
502  // We need to get rid of the "class " string if present
503  ROOT::TMetaUtils::ReplaceAll(type,"class ", "");
504  // We need to get rid of the "restrict " string if present
505  ROOT::TMetaUtils::ReplaceAll(type,"restrict", "");
506 
507  // pointers are returned in the form "int *" and I need them in the form "int*"
508  // same for &
509  for (auto& qual : quals){
510  auto pos = type.find(" "+qual);
511  if (pos != std::string::npos)
512  type.replace( pos, 2, qual );
513  }
514 // for (auto& qual : quals){
515 // if (type.at(type.length()-1) == qual && type.at(type.length()-2) == ' ') {
516 // type.at(type.length()-2) = qual;
517 // type.erase(type.length()-1);
518 // }
519 // }
520  prototype += type;
521  }
522  prototype = "(" + prototype + ")";
523  return true;
524 
525 }
526 
527 
528 bool SelectionRules::IsParentClass(const clang::Decl* D) const
529 {
530  //TagDecl has methods to understand of what kind is the Decl - class, struct or union
531  if (const clang::TagDecl* T
532  = llvm::dyn_cast<clang::TagDecl>(D->getDeclContext()))
533  return T->isClass() || T->isStruct();
534  return false;
535 }
536 
537 
538 bool SelectionRules::IsParentClass(const clang::Decl* D, std::string& parent_name, std::string& parent_qual_name) const
539 {
540  if (const clang::TagDecl* parent
541  = llvm::dyn_cast<clang::TagDecl>(D->getDeclContext())) {
542  if (parent->isClass()|| parent->isStruct()) {
543  GetDeclName(parent, parent_name, parent_qual_name);
544  return true;
545  }
546  }
547  return false;
548 }
549 
550 bool SelectionRules::GetParentName(const clang::Decl* D, std::string& parent_name, std::string& parent_qual_name) const
551 {
552  if (const clang::RecordDecl* parent
553  = llvm::dyn_cast<clang::RecordDecl>(D->getDeclContext())) {
554  GetDeclName(parent, parent_name, parent_qual_name);
555  return true;
556  }
557  return false;
558 }
559 
560 /* This is the method that crashes
561  bool SelectionRules::GetParent(clang::Decl* D, clang::Decl* parent)
562  {
563  clang::DeclContext *ctx = D->GetDeclContext();
564 
565  if (ctx->isRecord()){
566  //DEBUG std::cout<<"\n\tDeclContext is Record";
567  parent = llvm::dyn_cast<clang::Decl> (ctx);
568  if (!parent) {
569  return false;
570  }
571  else {
572  return true;
573  }
574  }
575  else return false;
576  }
577  */
578 
579 
580 // isClassSelected checks if a class is selected or not. Thre is a difference between the
581 // behaviour of rootcint and genreflex especially with regard to class pattern processing.
582 // In genreflex if we have <class pattern = "*" /> this will select all the classes
583 // (and structs) found in the header file. In rootcint if we have something similar, i.e.
584 // #pragma link C++ class *, we will select only the outer classes - for the nested
585 // classes we have to specifie #pragma link C++ class *::*. And yet this is only valid
586 // for one level of nesting - if you need it for many levels of nesting, you will
587 // probably have to implement it yourself.
588 // Here the idea is the following - we traverse the list of class selection rules.
589 // For every class we check do we have a class selection rule. We use here the
590 // method isSelected() (defined in BaseSelectionRule.cxx). This method returns true
591 // only if we have class selection rule which says "Select". Otherwise it returns
592 // false - in which case we have to check wether we found a class selection rule
593 // which says "Veto" (noName = false and don't Care = false; OR noName = false and
594 // don't Care = true and we don't have neither method nor field selection rules -
595 // which is for the selection.xml file case). If noName is true than we just continue -
596 // this means that the current class selection rule isn't applicable for this class.
597 
598 const ClassSelectionRule *SelectionRules::IsNamespaceSelected(const clang::Decl* D, const std::string& qual_name) const
599 {
600  const clang::NamespaceDecl* N = llvm::dyn_cast<clang::NamespaceDecl> (D); //TagDecl has methods to understand of what kind is the Decl
601  if (N==0) {
602  std::cout<<"\n\tCouldn't cast Decl to NamespaceDecl";
603  return 0;
604  }
605 
606  const ClassSelectionRule *selector = 0;
607  int fImplNo = 0;
608  const ClassSelectionRule *explicit_selector = 0;
609  const ClassSelectionRule *specific_pattern_selector = 0;
610  int fFileNo = 0;
611 
612  // NOTE: should we separate namespaces from classes in the rules?
613  std::list<ClassSelectionRule>::const_iterator it = fClassSelectionRules.begin();
614  // iterate through all class selection rles
615  std::string name_value;
616  std::string pattern_value;
618  for(; it != fClassSelectionRules.end(); ++it) {
619 
620  match = it->Match(N,qual_name,"",IsLinkdefFile());
621 
622  if (match != BaseSelectionRule::kNoMatch) {
623  // If we have a match.
624  if (it->GetSelected() == BaseSelectionRule::kYes) {
625  selector = &(*it);
626  if (IsLinkdefFile()){
627  // rootcint prefers explicit rules over pattern rules
628  if (match == BaseSelectionRule::kName) {
629  explicit_selector = &(*it);
630  } else if (match == BaseSelectionRule::kPattern) {
631  // NOTE: weird ...
632  if (it->GetAttributeValue("pattern", pattern_value) &&
633  pattern_value != "*" && pattern_value != "*::*") specific_pattern_selector = &(*it);
634  }
635  }
636  } else if (it->GetSelected() == BaseSelectionRule::kNo) {
637  if (!IsLinkdefFile()) {
638  // in genreflex - we could explicitly select classes from other source files
639  if (match == BaseSelectionRule::kFile) ++fFileNo; // if we have veto because of class defined in other source file -> implicit No
640  else {
641 
642 #ifdef SELECTION_DEBUG
643  std::cout<<"\tNo returned"<<std::endl;
644 #endif
645 
646  return 0; // explicit No returned
647  }
648  }
649  if (match == BaseSelectionRule::kPattern) {
650  //this is for the Linkdef selection
651  if (it->GetAttributeValue("pattern", pattern_value) &&
652  (pattern_value == "*" || pattern_value == "*::*")) ++fImplNo;
653  else
654  return 0;
655  }
656  else
657  return 0;
658  }
659  else if (it->GetSelected() == BaseSelectionRule::kDontCare && !(it->HasMethodSelectionRules()) && !(it->HasFieldSelectionRules())) {
660 
661 #ifdef SELECTION_DEBUG
662  std::cout<<"Empty dontC returned = No"<<std::endl;
663 #endif
664 
665  return 0;
666  }
667  }
668  }
669  if (IsLinkdefFile()) {
670  // for rootcint explicit (name) Yes is stronger than implicit (pattern) No which is stronger than implicit (pattern) Yes
671 
672 #ifdef SELECTION_DEBUG
673  std::cout<<"\n\tfYes = "<<fYes<<", fImplNo = "<<fImplNo<<std::endl;
674 #endif
675 
676  if (explicit_selector) return explicit_selector;
677  else if (specific_pattern_selector) return specific_pattern_selector;
678  else if (fImplNo > 0) return 0;
679  else return selector;
680  }
681  else {
682  // for genreflex explicit Yes is stronger than implicit file No
683 
684 #ifdef SELECTION_DEBUG
685  std::cout<<"\n\tfYes = "<<fYes<<", fFileNo = "<<fFileNo<<std::endl;
686 #endif
687 
688  if (selector)
689  return selector;
690  else
691  return 0;
692  }
693 
694 }
695 
696 
697 const ClassSelectionRule *SelectionRules::IsClassSelected(const clang::Decl* D, const std::string& qual_name) const
698 {
699  const clang::TagDecl* tagDecl = llvm::dyn_cast<clang::TagDecl> (D); //TagDecl has methods to understand of what kind is the Decl
700  const clang::TypedefNameDecl* typeDefNameDecl = llvm::dyn_cast<clang::TypedefNameDecl> (D);
701 
702  if (!tagDecl && !typeDefNameDecl) { // Ill posed
703  ROOT::TMetaUtils::Error("SelectionRules::IsClassSelected",
704  "Cannot cast Decl to TagDecl and Decl is not a typedef.\n");
705  return 0;
706  }
707 
708  if (!tagDecl && typeDefNameDecl){ // Let's try to fetch the underlying RecordDecl
709  clang::RecordDecl* recordDecl = ROOT::TMetaUtils::GetUnderlyingRecordDecl(typeDefNameDecl->getUnderlyingType());
710  if (!recordDecl){
711  ROOT::TMetaUtils::Error("SelectionRules::IsClassSelected",
712  "Cannot get RecordDecl behind TypedefDecl.\n");
713  return 0;
714  }
715  tagDecl = recordDecl;
716  }
717 
718  // At this point tagDecl must be well defined
719  const bool isLinkDefFile = IsLinkdefFile();
720  if (!( isLinkDefFile || tagDecl->isClass() || tagDecl->isStruct() ))
721  return 0; // Union for Genreflex
722 
723  const ClassSelectionRule *selector = 0;
724  int fImplNo = 0;
725  const ClassSelectionRule *explicit_selector = 0;
726  const ClassSelectionRule *specific_pattern_selector = 0;
727  int fFileNo = 0;
728 
729  // iterate through all class selection rles
730  bool earlyReturn=false;
731  const ClassSelectionRule* retval = nullptr;
732  const clang::NamedDecl* nDecl(llvm::dyn_cast<clang::NamedDecl>(D));
733  for(auto& rule : fClassSelectionRules) {
734  BaseSelectionRule::EMatchType match = rule.Match(nDecl, qual_name, "", isLinkDefFile);
735  if (match != BaseSelectionRule::kNoMatch) {
736  // Check if the template must have its arguments manipulated
737  if (const clang::ClassTemplateSpecializationDecl* ctsd =
738  llvm::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(D))
739  if(const clang::ClassTemplateDecl* ctd = ctsd->getSpecializedTemplate()){
740  const std::string& nArgsToKeep = rule.GetAttributeNArgsToKeep();
741  if (!nArgsToKeep.empty()){
742  fNormCtxt.AddTemplAndNargsToKeep(ctd->getCanonicalDecl(),
743  std::atoi(nArgsToKeep.c_str()));
744  }
745  }
746 
747  if (earlyReturn) continue;
748 
749  // If we have a match.
750  selector = &(rule);
751  if (rule.GetSelected() == BaseSelectionRule::kYes) {
752 
753  if (isLinkDefFile){
754  // rootcint prefers explicit rules over pattern rules
755  if (match == BaseSelectionRule::kName) {
756  explicit_selector = &(rule);
757  } else if (match == BaseSelectionRule::kPattern) {
758  // NOTE: weird ...
759  const std::string& pattern_value=rule.GetAttributePattern();
760  if (!pattern_value.empty() &&
761  pattern_value != "*" &&
762  pattern_value != "*::*") specific_pattern_selector = &(rule);
763  }
764  }
765  } else if (rule.GetSelected() == BaseSelectionRule::kNo) {
766 
767  if (!isLinkDefFile) {
768  // in genreflex - we could explicitly select classes from other source files
769  if (match == BaseSelectionRule::kFile) ++fFileNo; // if we have veto because of class defined in other source file -> implicit No
770  else {
771  retval = selector;
772  earlyReturn=true; // explicit No returned
773  }
774  }
775  if (match == BaseSelectionRule::kPattern) {
776  //this is for the Linkdef selection
777  const std::string& pattern_value=rule.GetAttributePattern();
778  if (!pattern_value.empty() &&
779  (pattern_value == "*" || pattern_value == "*::*")) ++fImplNo;
780  else
781  earlyReturn=true;
782  }
783  else
784  earlyReturn=true;
785  }
786  else if (rule.GetSelected() == BaseSelectionRule::kDontCare && !(rule.HasMethodSelectionRules()) && !(rule.HasFieldSelectionRules())) {
787  earlyReturn=true;
788  }
789  }
790  } // Loop over the rules.
791 
792  if (earlyReturn) return retval;
793 
794  if (isLinkDefFile) {
795  // for rootcint explicit (name) Yes is stronger than implicit (pattern) No which is stronger than implicit (pattern) Yes
796  if (explicit_selector) return explicit_selector;
797  else if (specific_pattern_selector) return specific_pattern_selector;
798  else if (fImplNo > 0) return 0;
799  else return selector;
800  }
801  else {
802  // for genreflex explicit Yes is stronger than implicit file No
803  return selector; // it can be nullptr
804  }
805 
806 }
807 
808 const BaseSelectionRule *SelectionRules::IsVarSelected(const clang::VarDecl* D, const std::string& qual_name) const
809 {
810  std::list<VariableSelectionRule>::const_iterator it = fVariableSelectionRules.begin();
811  std::list<VariableSelectionRule>::const_iterator it_end = fVariableSelectionRules.end();
812 
813  const BaseSelectionRule *selector = 0;
814 
815  // iterate through all the rules
816  // we call this method only for genrefex variables, functions and enums - it is simpler than the class case:
817  // if we have No - it is veto even if we have explicit yes as well
818  for(; it != it_end; ++it) {
819  if (BaseSelectionRule::kNoMatch != it->Match(llvm::dyn_cast<clang::NamedDecl>(D), qual_name, "", false)) {
820  if (it->GetSelected() == BaseSelectionRule::kNo) {
821  // The rule did explicitly request to not select this entity.
822  return 0;
823  } else {
824  selector = &(*it);
825  }
826  }
827  }
828 
829  return selector;
830 }
831 
832 const BaseSelectionRule *SelectionRules::IsFunSelected(const clang::FunctionDecl *D, const std::string &qual_name) const
833 {
834 
835  if (fFunctionSelectionRules.size() == 0 ||
836  D->getPrimaryTemplate() != nullptr ||
837  llvm::isa<clang::CXXMethodDecl>(D)) return nullptr;
838 
839  std::string prototype;
840  GetFunctionPrototype(D, prototype);
841  prototype = qual_name + prototype;
842 
843  const BaseSelectionRule *selector = nullptr;
844  // iterate through all the rules
845  // we call this method only for genrefex variables, functions and enums - it is simpler than the class case:
846  // if we have No - it is veto even if we have explicit yes as well
847  for (const auto & rule : fFunctionSelectionRules) {
848  if (BaseSelectionRule::kNoMatch != rule.Match(D, qual_name, prototype, false)) {
849  if (rule.GetSelected() == BaseSelectionRule::kNo) {
850  // The rule did explicitly request to not select this entity.
851  return nullptr;
852  } else {
853  selector = &(rule);
854  }
855  }
856  }
857 
858  return selector;
859 }
860 
861 const BaseSelectionRule *SelectionRules::IsEnumSelected(const clang::EnumDecl* D, const std::string& qual_name) const
862 {
863  const BaseSelectionRule *selector = 0;
864 
865  // iterate through all the rules
866  // we call this method only for genrefex variables, functions and enums - it is simpler than the class case:
867  // if we have No - it is veto even if we have explicit yes as well
868  for(const auto& rule: fEnumSelectionRules) {
869  if (BaseSelectionRule::kNoMatch != rule.Match(llvm::dyn_cast<clang::NamedDecl>(D), qual_name, "", false)) {
870  if (rule.GetSelected() == BaseSelectionRule::kNo) {
871  // The rule did explicitly request to not select this entity.
872  return 0;
873  } else {
874  selector = &rule;
875  }
876  }
877  }
878 
879  return selector;
880 }
881 
882 const BaseSelectionRule *SelectionRules::IsLinkdefVarSelected(const clang::VarDecl* D, const std::string& qual_name) const
883 {
884 
885 
886  const BaseSelectionRule *selector = 0;
887  int fImplNo = 0;
888  const BaseSelectionRule *explicit_selector = 0;
889 
890  std::string name_value;
891  std::string pattern_value;
892  for(auto& selRule: fVariableSelectionRules) {
894  = selRule.Match(llvm::dyn_cast<clang::NamedDecl>(D), qual_name, "", false);
895  if (match != BaseSelectionRule::kNoMatch) {
896  if (selRule.GetSelected() == BaseSelectionRule::kYes) {
897  // explicit rules are with stronger priority in rootcint
898  if (IsLinkdefFile()){
899  if (match == BaseSelectionRule::kName) {
900  explicit_selector = &selRule;
901  } else if (match == BaseSelectionRule::kPattern) {
902  if (selRule.GetAttributeValue("pattern", pattern_value)) {
903  explicit_selector=&selRule;
904  // NOTE: Weird ... This is a strange definition of explicit.
905  //if (pattern_value != "*" && pattern_value != "*::*") explicit_selector = selRule;
906  }
907  }
908  }
909  }
910  else {
911  if (!IsLinkdefFile()) return 0;
912  else {
913  if (selRule.GetAttributeValue("pattern", pattern_value)) {
914  if (pattern_value == "*" || pattern_value == "*::*") ++fImplNo;
915  else
916  return 0;
917  }
918  else
919  return 0;
920  }
921  }
922  }
923  }
924 
925  if (IsLinkdefFile()) {
926 
927 #ifdef SELECTION_DEBUG
928  std::cout<<"\n\tfYes = "<<fYes<<", fImplNo = "<<fImplNo<<std::endl;
929 #endif
930 
931  if (explicit_selector) return explicit_selector;
932  else if (fImplNo > 0) return 0;
933  else return selector;
934  }
935  else{
936  return selector;
937  }
938 }
939 
940 const BaseSelectionRule *SelectionRules::IsLinkdefFunSelected(const clang::FunctionDecl* D, const std::string& qual_name) const
941 {
942 
943  if (fFunctionSelectionRules.size() == 0 ||
944  D->getPrimaryTemplate() != nullptr ||
945  llvm::isa<clang::CXXMethodDecl>(D)) return nullptr;
946 
947  std::string prototype;
948 
949  GetFunctionPrototype(D, prototype);
950  prototype = qual_name + prototype;
951 
952  const BaseSelectionRule *selector = 0;
953  int fImplNo = 0;
954  const BaseSelectionRule *explicit_selector = 0;
955 
956  std::string pattern_value;
957  for(auto& selRule : fFunctionSelectionRules) {
959  = selRule.Match(llvm::dyn_cast<clang::NamedDecl>(D), qual_name, prototype, false);
960  if (match != BaseSelectionRule::kNoMatch) {
961  if (selRule.GetSelected() == BaseSelectionRule::kYes) {
962  // explicit rules are with stronger priority in rootcint
963  if (IsLinkdefFile()){
964  if (match == BaseSelectionRule::kName) {
965  explicit_selector = &selRule;
966  } else if (match == BaseSelectionRule::kPattern) {
967  if (selRule.GetAttributeValue("pattern", pattern_value)) {
968  explicit_selector = &selRule;
969  // NOTE: Weird ... This is a strange definition of explicit.
970  //if (pattern_value != "*" && pattern_value != "*::*") explicit_selector = &selRule;
971  }
972  }
973  }
974  }
975  else {
976  if (!IsLinkdefFile()) return 0;
977  else {
978  if (selRule.GetAttributeValue("pattern", pattern_value)) {
979  if (pattern_value == "*" || pattern_value == "*::*") ++fImplNo;
980  else
981  return 0;
982  }
983  else
984  return 0;
985  }
986  }
987  }
988  }
989 
990  if (IsLinkdefFile()) {
991  if (explicit_selector) return explicit_selector;
992  else if (fImplNo > 0) return 0;
993  else return selector;
994  }
995  else{
996  return selector;
997  }
998 }
999 
1000 const BaseSelectionRule *SelectionRules::IsLinkdefEnumSelected(const clang::EnumDecl* D, const std::string& qual_name) const
1001 {
1002  std::list<VariableSelectionRule>::const_iterator it;
1003  std::list<VariableSelectionRule>::const_iterator it_end;
1004 
1005  it = fEnumSelectionRules.begin();
1006  it_end = fEnumSelectionRules.end();
1007 
1008  const BaseSelectionRule *selector = 0;
1009  int fImplNo = 0;
1010  const BaseSelectionRule *explicit_selector = 0;
1011 
1012  std::string name_value;
1013  std::string pattern_value;
1014  for(; it != it_end; ++it) {
1016  it->Match(llvm::dyn_cast<clang::NamedDecl>(D), qual_name, "", false);
1017  if (match != BaseSelectionRule::kNoMatch) {
1018  if (it->GetSelected() == BaseSelectionRule::kYes) {
1019  // explicit rules are with stronger priority in rootcint
1020  if (IsLinkdefFile()){
1021  if (match == BaseSelectionRule::kName){
1022  explicit_selector = &(*it);
1023  } else if (match == BaseSelectionRule::kPattern &&
1024  it->GetAttributeValue("pattern", pattern_value)) {
1025  // Note: Weird ... This is a strange definition of explicit.
1026  if (pattern_value != "*" && pattern_value != "*::*") explicit_selector = &(*it);
1027  }
1028  }
1029  }
1030  else {
1031  if (!IsLinkdefFile()) return 0;
1032  else {
1033  if (it->GetAttributeValue("pattern", pattern_value)) {
1034  if (pattern_value == "*" || pattern_value == "*::*") ++fImplNo;
1035  else
1036  return 0;
1037  }
1038  else
1039  return 0;
1040  }
1041  }
1042  }
1043  }
1044 
1045  if (IsLinkdefFile()) {
1046 
1047 #ifdef SELECTION_DEBUG
1048  std::cout<<"\n\tfYes = "<<fYes<<", fImplNo = "<<fImplNo<<std::endl;
1049 #endif
1050 
1051  if (explicit_selector) return explicit_selector;
1052  else if (fImplNo > 0) return 0;
1053  else return selector;
1054  }
1055  else{
1056  return selector;
1057  }
1058 }
1059 
1060 // In rootcint we could select and deselect methods independantly of the class/struct/union rules
1061 // That's why we first have to check the explicit rules for the functions - to see if there
1062 // is rule corresponding to our method.
1063 // Which is more - if we have (and we can have) a pattern for the parent class, than a pattern for the
1064 // nested class, than a pattern for certain methods in the nested class, than a rule for a
1065 // method (name or prototype) in the nested class - the valid rule is the last one.
1066 // This is true irrespective of the rules (select/deselect). This is not the case for genreflex -
1067 // in genreflex if there is a pattern deselecting something even if we have an explicit rule
1068 // to select it, it still will not be selected.
1069 // This method (isLinkdefMethodSelected()) might be incomplete (but I didn't have the time to think
1070 // of anything better)
1071 //
1072 
1073 const BaseSelectionRule *SelectionRules::IsLinkdefMethodSelected(const clang::Decl* D, const std::string& qual_name) const
1074 {
1075  std::list<FunctionSelectionRule>::const_iterator it = fFunctionSelectionRules.begin();
1076  std::list<FunctionSelectionRule>::const_iterator it_end = fFunctionSelectionRules.end();
1077  std::string prototype;
1078 
1079  if (const clang::FunctionDecl* F = llvm::dyn_cast<clang::FunctionDecl> (D))
1080  GetFunctionPrototype(F, prototype);
1081  prototype = qual_name + prototype;
1082 
1083 #ifdef SELECTION_DEBUG
1084  std::cout<<"\tFunction prototype = "<<prototype<<std::endl;
1085 #endif
1086 
1087  int expl_Yes = 0, impl_r_Yes = 0, impl_rr_Yes = 0;
1088  int impl_r_No = 0, impl_rr_No = 0;
1089  const BaseSelectionRule *explicit_r = 0;
1090  const BaseSelectionRule *implicit_r = 0;
1091  const BaseSelectionRule *implicit_rr = 0;
1092 
1093  if (D->getKind() == clang::Decl::CXXMethod){
1094  // we first check the explicit rules for the method (in case of constructors and destructors we check the parent)
1095  std::string pat_value;
1096  for(; it != it_end; ++it) {
1098  = it->Match(llvm::dyn_cast<clang::NamedDecl>(D), qual_name, prototype, false);
1099 
1100  if (match == BaseSelectionRule::kName) {
1101  // here I should implement my implicit/explicit thing
1102  // I have included two levels of implicitness - "A::Get_*" is stronger than "*"
1103  explicit_r = &(*it);
1104  if (it->GetSelected() == BaseSelectionRule::kYes) ++expl_Yes;
1105  else {
1106 
1107 #ifdef SELECTION_DEBUG
1108  std::cout<<"\tExplicit rule BaseSelectionRule::kNo found"<<std::endl;
1109 #endif
1110 
1111  return 0; // == explicit BaseSelectionRule::kNo
1112 
1113  }
1114  } else if (match == BaseSelectionRule::kPattern) {
1115 
1116  if (it->GetAttributeValue("pattern", pat_value)) {
1117  if (pat_value == "*") continue; // we discard the global selection rules
1118 
1119  std::string par_name, par_qual_name;
1120  GetParentName(D, par_name, par_qual_name);
1121  std::string par_pat = par_qual_name + "::*";
1122 
1123  if (pat_value == par_pat) {
1124  implicit_rr = &(*it);
1125  if (it->GetSelected() == BaseSelectionRule::kYes) {
1126 
1127 #ifdef SELECTION_DEBUG
1128  std::cout<<"Implicit_rr rule ("<<pat_value<<"), selected = "<<selected<<std::endl;
1129 #endif
1130 
1131  ++impl_rr_Yes;
1132  }
1133  else {
1134 
1135 #ifdef SELECTION_DEBUG
1136  std::cout<<"Implicit_rr rule ("<<pat_value<<"), selected = "<<selected<<std::endl;
1137 #endif
1138 
1139  ++impl_rr_No;
1140  }
1141  }
1142  else {
1143  implicit_r = &(*it);
1144  if (it->GetSelected() == BaseSelectionRule::kYes) {
1145 
1146 #ifdef SELECTION_DEBUG
1147  std::cout<<"Implicit_r rule ("<<pat_value<<"), selected = "<<selected<<std::endl;
1148 #endif
1149 
1150  ++impl_r_Yes;
1151  }
1152  else {
1153 
1154 #ifdef SELECTION_DEBUG
1155  std::cout<<"Implicit_r rule ("<<pat_value<<"), selected = "<<selected<<std::endl;
1156 #endif
1157 
1158  ++impl_r_No;
1159  }
1160  }
1161  }
1162  }
1163  }
1164  }
1165  if (explicit_r /*&& expl_Yes > 0*/){
1166 
1167 #ifdef SELECTION_DEBUG
1168  std::cout<<"\tExplicit rule BaseSelectionRule::BaseSelectionRule::kYes found"<<std::endl;
1169 #endif
1170 
1171  return explicit_r; // if we have excplicit BaseSelectionRule::kYes
1172  }
1173  else if (implicit_rr) {
1174  if (impl_rr_No > 0) {
1175 
1176 #ifdef SELECTION_DEBUG
1177  std::cout<<"\tImplicit_rr rule BaseSelectionRule::kNo found"<<std::endl;
1178 #endif
1179 
1180  return 0;
1181  }
1182  else {
1183 
1184 #ifdef SELECTION_DEBUG
1185  std::cout<<"\tImplicit_rr rule BaseSelectionRule::kYes found"<<std::endl;
1186 #endif
1187 
1188  return implicit_rr;
1189  }
1190  }
1191  else if (implicit_r) {
1192  if (impl_r_No > 0) {
1193 
1194 #ifdef SELECTION_DEBUG
1195  std::cout<<"\tImplicit_r rule BaseSelectionRule::kNo found"<<std::endl;
1196 #endif
1197 
1198  return 0;
1199  }
1200  else {
1201 
1202 #ifdef SELECTION_DEBUG
1203  std::cout<<"\tImplicit_r rule BaseSelectionRule::kYes found"<<std::endl;
1204 #endif
1205 
1206  return implicit_r;
1207  }
1208  }
1209  else {
1210 
1211 #ifdef SELECTION_DEBUG
1212  std::cout<<"\tChecking parent class rules"<<std::endl;
1213 #endif
1214  // check parent
1215 
1216 
1217  std::string parent_name, parent_qual_name;
1218  if (!GetParentName(D, parent_name, parent_qual_name)) return 0;
1219 
1220  const BaseSelectionRule *selector = 0;
1221  int fImplNo = 0;
1222  const BaseSelectionRule *explicit_selector = 0;
1223 
1224  // the same as with isClass selected
1225  // I wanted to use GetParentDecl and then to pass is to isClassSelected because I didn't wanted to repeat
1226  // code but than GetParentDecl crashes (or returns non-sence Decl) for the built-in structs (__va_*)
1227  std::list<ClassSelectionRule>::const_iterator it = fClassSelectionRules.begin();
1228  std::string name_value;
1229  std::string pattern_value;
1230  for(; it != fClassSelectionRules.end(); ++it) {
1232  = it->Match(llvm::dyn_cast<clang::NamedDecl>(D), parent_qual_name, "", true); // == BaseSelectionRule::kYes
1233 
1234  if (match != BaseSelectionRule::kNoMatch) {
1235  if (it->GetSelected() == BaseSelectionRule::kYes) {
1236  selector = &(*it);
1237 
1238  if (match == BaseSelectionRule::kName) {
1239  explicit_selector = &(*it);
1240  } else if (match == BaseSelectionRule::kPattern) {
1241  if (it->GetAttributeValue("pattern", pattern_value)) {
1242  // NOTE: weird ...
1243  if (pattern_value != "*" && pattern_value != "*::*") explicit_selector = &(*it);
1244  }
1245  }
1246  }
1247  else { // == BaseSelectionRule::kNo
1248 
1249  if (it->GetAttributeValue("pattern", pattern_value)) {
1250  if (pattern_value == "*" || pattern_value == "*::*") ++fImplNo;
1251  else
1252  return 0;
1253  }
1254  else
1255  return 0;
1256  }
1257  }
1258  }
1259 
1260 #ifdef SELECTION_DEBUG
1261  std::cout<<"\n\tfYes = "<<fYes<<", fImplNo = "<<fImplNo<<std::endl;
1262 #endif
1263 
1264  if (explicit_selector) {
1265 
1266 #ifdef SELECTION_DEBUG
1267  std::cout<<"\tReturning Yes"<<std::endl;
1268 #endif
1269 
1270  return explicit_selector;
1271  }
1272  else if (fImplNo > 0) {
1273 #ifdef SELECTION_DEBUG
1274  std::cout<<"\tReturning No"<<std::endl;
1275 #endif
1276 
1277  return 0;
1278  }
1279  else {
1280 
1281 #ifdef SELECTION_DEBUG
1282  std::cout<<"\tReturning Yes"<<std::endl;
1283 #endif
1284 
1285  return selector;
1286  }
1287  }
1288 
1289  return 0;
1290 
1291 }
1292 
1293 const BaseSelectionRule *SelectionRules::IsMemberSelected(const clang::Decl* D, const std::string& str_name) const
1294 {
1295  std::string parent_name;
1296  std::string parent_qual_name;
1297 
1298  if (IsParentClass(D))
1299  {
1300  if (!GetParentName(D, parent_name, parent_qual_name)) return 0;
1301 
1302  const BaseSelectionRule *selector = 0;
1303  Int_t fImplNo = 0;
1304  const BaseSelectionRule *explicit_selector = 0;
1305  int fFileNo = 0;
1306 
1307  //DEBUG std::cout<<"\n\tParent is class";
1308  std::list<ClassSelectionRule>::const_iterator it = fClassSelectionRules.begin();
1309  std::string name_value;
1310  std::string pattern_value;
1311  for(; it != fClassSelectionRules.end(); ++it) {
1313  = it->Match(llvm::dyn_cast<clang::NamedDecl>(D), parent_qual_name, "", false);
1314 
1315  if (match != BaseSelectionRule::kNoMatch) {
1316  if (it->GetSelected() == BaseSelectionRule::kYes) {
1317  selector = &(*it);
1318  if (IsLinkdefFile()) {
1319  if (match == BaseSelectionRule::kName) {
1320  explicit_selector = &(*it);
1321  } else if (match == BaseSelectionRule::kPattern) {
1322  if (it->GetAttributeValue("pattern", pattern_value)) {
1323  // NOTE: Weird ... This is a strange definition of explicit.
1324  if (pattern_value != "*" && pattern_value != "*::*") explicit_selector = &(*it);
1325  }
1326  }
1327  }
1328  } else if (it->GetSelected() == BaseSelectionRule::kNo) {
1329  if (!IsLinkdefFile()) {
1330  if (match == BaseSelectionRule::kFile) ++fFileNo;
1331  else {
1332 
1333 #ifdef SELECTION_DEBUG
1334  std::cout<<"\tNo returned"<<std::endl;
1335 #endif
1336 
1337  return 0; // in genreflex we can't have that situation
1338  }
1339  }
1340  else {
1341  if (match == BaseSelectionRule::kPattern && it->GetAttributeValue("pattern", pattern_value)) {
1342  if (pattern_value == "*" || pattern_value == "*::*") ++fImplNo;
1343  else
1344  return 0;
1345  }
1346  else
1347  return 0;
1348  }
1349  }
1350  else if (it->GetSelected() == BaseSelectionRule::kDontCare) // - we check the method and field selection rules for the class
1351  {
1352  if (!it->HasMethodSelectionRules() && !it->HasFieldSelectionRules()) {
1353 
1354 #ifdef SELECTION_DEBUG
1355  std::cout<<"\tNo fields and methods"<<std::endl;
1356 #endif
1357 
1358  return 0; // == BaseSelectionRule::kNo
1359  }
1360  else {
1361  clang::Decl::Kind kind = D->getKind();
1362  if (kind == clang::Decl::Field || kind == clang::Decl::CXXMethod || kind == clang::Decl::CXXConstructor || kind == clang::Decl::CXXDestructor){
1363  std::list<VariableSelectionRule> members;
1364  std::list<VariableSelectionRule>::iterator mem_it;
1365  std::list<VariableSelectionRule>::iterator mem_it_end;
1366  std::string prototype;
1367 
1368  if (kind == clang::Decl::Field) {
1369  members = it->GetFieldSelectionRules();
1370  }
1371  else {
1372  if (const clang::FunctionDecl* F = llvm::dyn_cast<clang::FunctionDecl> (D)){
1373  GetFunctionPrototype(F, prototype);
1374  prototype = str_name + prototype;
1375  }
1376  else{
1377  ROOT::TMetaUtils::Warning("","Warning: could not cast Decl to FunctionDecl\n");
1378  }
1379  members = it->GetMethodSelectionRules();
1380  }
1381  mem_it = members.begin();
1382  mem_it_end = members.end();
1383  for (; mem_it != mem_it_end; ++mem_it) {
1384  if (BaseSelectionRule::kName == mem_it->Match(llvm::dyn_cast<clang::NamedDecl>(D), str_name, prototype, false)) {
1385  if (mem_it->GetSelected() == BaseSelectionRule::kNo) return 0;
1386  }
1387  }
1388  }
1389  }
1390  }
1391  }
1392  }
1393 
1394  if (IsLinkdefFile()) {
1395 
1396 #ifdef SELECTION_DEBUG
1397  std::cout<<"\n\tfYes = "<<fYes<<", fImplNo = "<<fImplNo<<std::endl;
1398 #endif
1399 
1400  if (explicit_selector) {
1401 #ifdef SELECTION_DEBUG
1402  std::cout<<"\tReturning Yes"<<std::endl;
1403 #endif
1404 
1405  return explicit_selector;
1406  }
1407  else if (fImplNo > 0) {
1408 
1409 #ifdef SELECTION_DEBUG
1410  std::cout<<"\tReturning No"<<std::endl;
1411 #endif
1412 
1413  return 0;
1414  }
1415  else {
1416 
1417 #ifdef SELECTION_DEBUG
1418  std::cout<<"\tReturning Yes"<<std::endl;
1419 #endif
1420 
1421  return selector;
1422  }
1423  }
1424  else {
1425 
1426  return selector;
1427  }
1428  }
1429  else {
1430  return 0;
1431  }
1432 }
1433 
1435  for(auto&& rule : fClassSelectionRules){
1436  if (BaseSelectionRule::kNo!=rule.GetSelected() && !rule.GetMatchFound() /* && !GetHasFileNameRule() */ ) {
1437  std::string name;
1438  if (rule.GetAttributeValue("pattern", name)) {
1439  // keep it
1440  } else if (rule.GetAttributeValue("name", name)) {
1441  // keept it
1442  } else {
1443  name.clear();
1444  }
1445  std::string file_name_value;
1446  if (!rule.GetAttributeValue("file_name", file_name_value)) file_name_value.clear();
1447 
1448  if (!file_name_value.empty()) {
1449  // don't complain about defined_in rules
1450  continue;
1451  }
1452 
1453  const char* attrName = nullptr;
1454  const char* attrVal = nullptr;
1455  if (!file_name_value.empty()) {
1456  attrName = "file name";
1457  attrVal = file_name_value.c_str();
1458  } else {
1459  attrName = "class";
1460  if (!name.empty()) attrVal = name.c_str();
1461  }
1462  ROOT::TMetaUtils::Warning(0,"Unused %s rule: %s\n", attrName, attrVal);
1463  }
1464  }
1465 
1466  for(auto&& rule : fVariableSelectionRules){
1467  if (!rule.GetMatchFound() && !GetHasFileNameRule()) {
1468  std::string name;
1469  if (rule.GetAttributeValue("pattern", name)) {
1470  // keep it
1471  } else if (rule.GetAttributeValue("name", name)) {
1472  // keept it
1473  } else {
1474  name.clear();
1475  }
1476  ROOT::TMetaUtils::Warning("","Unused variable rule: %s\n",name.c_str());
1477  if (name.empty()) {
1478  rule.PrintAttributes(std::cout,3);
1479  }
1480  }
1481  }
1482 
1483 #if defined(R__MUST_REVISIT)
1484 #if R__MUST_REVISIT(6,2)
1485 ROOT::TMetaUtils::Warning("SelectionRules::AreAllSelectionRulesUsed",
1486 "Warnings concerning non matching selection rules are suppressed. An action is to be taken.\n");
1487 #endif
1488 #endif
1489 // for(const auto& selRule: fFunctionSelectionRules) {
1490 // if (!selRule.GetMatchFound() && !GetHasFileNameRule()) {
1491 // // Here the slow methods can be used
1492 // std::string name;
1493 // if (selRule.GetAttributeValue("proto_pattern", name)) {
1494 // // keep it
1495 // } else if (selRule.GetAttributeValue("proto_name", name)) {
1496 // // keep it
1497 // } else if (selRule.GetAttributeValue("pattern", name)) {
1498 // // keep it
1499 // } else if (selRule.GetAttributeValue("name", name)) {
1500 // // keept it
1501 // } else {
1502 // name.clear();
1503 // }
1504 // // Make it soft, no error - just warnings
1505 // std::cout<<"Warning - unused function rule: "<<name<<std::endl;
1506 // // if (IsSelectionXMLFile()){
1507 // // std::cout<<"Warning - unused function rule: "<<name<<std::endl;
1508 // // }
1509 // // else {
1510 // // std::cout<<"Error - unused function rule: "<<name<<std::endl;
1511 // // }
1512 // if (name.length() == 0) {
1513 // selRule.PrintAttributes(std::cout,3);
1514 // }
1515 // }
1516 //
1517 // }
1518 
1519 
1520 #if Enums_rules_becomes_useful_for_rootcling
1521  for(auto&& rule : fEnumSelectionRules){
1522  if (!rule.GetMatchFound() && !GetHasFileNameRule()) {
1523  std::string name;
1524  if (rule.GetAttributeValue("pattern", name)) {
1525  // keep it
1526  } else if (rule.GetAttributeValue("name", name)) {
1527  // keept it
1528  } else {
1529  name.clear();
1530  }
1531 
1532  ROOT::TMetaUtils::Warning("","Unused enum rule: %s\n",name.c_str());
1533 
1534  if (name.empty()){
1535  rule.PrintAttributes(std::cout,3);
1536  }
1537  }
1538  }
1539 #endif
1540  return true;
1541 }
1542 
1543 bool SelectionRules::SearchNames(cling::Interpreter &interp)
1544 {
1545  // std::cout<<"Searching Names In Selection Rules:"<<std::endl;
1546  for(std::list<ClassSelectionRule>::iterator it = fClassSelectionRules.begin(),
1547  end = fClassSelectionRules.end();
1548  it != end;
1549  ++it) {
1550  if (it->HasAttributeWithName("name")) {
1551  std::string name_value;
1552  it->GetAttributeValue("name", name_value);
1553  // In Class selection rules, we should be interested in scopes.
1554  const clang::Type *typeptr = 0;
1555  const clang::CXXRecordDecl *target
1556  = ROOT::TMetaUtils::ScopeSearch(name_value.c_str(), interp,
1557  true /*diag*/, &typeptr);
1558  if (target) {
1559  it->SetCXXRecordDecl(target,typeptr);
1560  }
1561  }
1562  }
1563  return true;
1564 }
1565 
1566 
1568 {
1569  // Fill the cache of every selection rule
1570  for (auto& rule : fClassSelectionRules) rule.FillCache();
1571  for (auto& rule : fFunctionSelectionRules) rule.FillCache();
1572  for (auto& rule : fVariableSelectionRules) rule.FillCache();
1573  for (auto& rule : fEnumSelectionRules) rule.FillCache();
1574 }
1575 
1576 
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:333
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),...)
Definition: TMetaUtils.h:767
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
void Info(const char *location, const char *va_(fmt),...)
Definition: TMetaUtils.h:787
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 &#39;name&#39; or std::&#39;name&#39;.
Definition: TMetaUtils.cxx:700
static double P[]
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)
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)
void Warning(const char *location, const char *va_(fmt),...)
Definition: TMetaUtils.h:797
void AddClassSelectionRule(const ClassSelectionRule &classSel)
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
char name[80]
Definition: TGX11.cxx:109
bool SearchNames(cling::Interpreter &interp)
const BaseSelectionRule * IsLinkdefVarSelected(const clang::VarDecl *D, const std::string &qual_name) const