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