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