Logo ROOT  
Reference Guide
DictSelectionReader.cxx
Go to the documentation of this file.
1 #include "DictSelectionReader.h"
2 
3 #include "clang/AST/AST.h"
4 
5 #include "cling/Interpreter/Interpreter.h"
6 
7 #include "ClassSelectionRule.h"
8 #include "SelectionRules.h"
9 #include "TClingUtils.h"
10 #include "TClassEdit.h"
11 
12 #include "RootMetaSelection.h"
13 
14 #include <iostream>
15 #include <sstream>
16 
17 namespace ROOT {
18 namespace Internal {
19 
20 ////////////////////////////////////////////////////////////////////////////////
21 
22 DictSelectionReader::DictSelectionReader(cling::Interpreter &interp, SelectionRules &selectionRules,
23  const clang::ASTContext &C, ROOT::TMetaUtils::TNormalizedCtxt &normCtxt)
24  : fSelectionRules(selectionRules), fIsFirstPass(true), fNormCtxt(normCtxt)
25 {
26  clang::TranslationUnitDecl *translUnitDecl = C.getTranslationUnitDecl();
27 
28  {
29  // We push a new transaction because we could deserialize decls here
30  cling::Interpreter::PushTransactionRAII RAII(&interp);
31  // Inspect the AST
32  TraverseDecl(translUnitDecl);
33  }
34 
35  // Now re-inspect the AST to find autoselected classes (double-tap)
36  fIsFirstPass = false;
37  if (!fTemplateInfoMap.empty() ||
40  TraverseDecl(translUnitDecl);
41 
42  // Now push all the selection rules
43  for (llvm::StringMap<ClassSelectionRule>::iterator it =
45  it != fClassNameSelectionRuleMap.end();
46  ++it) {
48  }
49 }
50 
51 ////////////////////////////////////////////////////////////////////////////////
52 /// If it's not contained by 2 namespaces, drop it.
53 
54 /**
55  * Check that the recordDecl is enclosed in the ROOT::Meta::Selection namespace,
56  * excluding the portion dedicated the definition of the syntax, which is part
57  * of ROOT, not of the user code.
58  * If performance is needed, an alternative approach to string comparisons
59  * could be adopted. One could use for example hashes of strings in first
60  * approximation.
61  **/
62 bool
63 DictSelectionReader::InSelectionNamespace(const clang::RecordDecl &recordDecl,
64  const std::string &className)
65 {
66  std::list<std::pair<std::string, bool> > enclosingNamespaces;
68  enclosingNamespaces);
69 
70  const unsigned int nNs = enclosingNamespaces.size();
71  if (nNs < 3) return false;
72 
73  if (enclosingNamespaces.back().second || // is inline namespace
74  enclosingNamespaces.back().first != "ROOT")
75  return false;
76 
77  enclosingNamespaces.pop_back();
78  if (enclosingNamespaces.back().second || // is inline namespace
79  enclosingNamespaces.back().first != "Meta")
80  return false;
81 
82  enclosingNamespaces.pop_back();
83  if (enclosingNamespaces.back().second || // is inline namespace
84  enclosingNamespaces.back().first != "Selection")
85  return false;
86 
87  // Exclude the special names identifying the entities of the selection syntax
88  if (className != "" &&
89  (className.find("MemberAttributes") == 0 ||
90  className.find("ClassAttributes") == 0 || className.find("Keep") == 0))
91  return false;
92 
93  return true;
94 }
95 
96 ////////////////////////////////////////////////////////////////////////////////
97 
98 /**
99  * Get the pointer to the template arguments list. Return zero if not available.
100  **/
101 const clang::TemplateArgumentList *
102 DictSelectionReader::GetTmplArgList(const clang::CXXRecordDecl &cxxRcrdDecl)
103 {
104  const clang::ClassTemplateSpecializationDecl *tmplSpecDecl =
105  llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&cxxRcrdDecl);
106 
107  if (!tmplSpecDecl) return nullptr;
108 
109  return &tmplSpecDecl->getTemplateArgs();
110 }
111 
112 ////////////////////////////////////////////////////////////////////////////////
113 
114 /**
115  * Extract the value of the integral template parameter of a CXXRecordDecl when
116  * it has a certain name. If nothing can be extracted, the value of @c zero
117  * is returned.
118  **/
119 template <class T>
120 unsigned int
122  const std::string &pattern)
123 {
124  const clang::RecordDecl *rcrdDecl =
126  const clang::CXXRecordDecl *cxxRcrdDecl =
127  llvm::dyn_cast<clang::CXXRecordDecl>(rcrdDecl);
128 
129  if (!cxxRcrdDecl) return 0;
130 
131  const clang::TemplateArgumentList *tmplArgs = GetTmplArgList(*cxxRcrdDecl);
132  if (!tmplArgs) return 0;
133 
134  if (std::string::npos == cxxRcrdDecl->getNameAsString().find(pattern))
135  return 0;
136 
137  return tmplArgs->get(0).getAsIntegral().getLimitedValue();
138 }
139 
140 ////////////////////////////////////////////////////////////////////////////////
141 /// Iterate on the members to see if
142 /// 1) They are transient
143 /// 2) They imply further selection
144 
145 /**
146  * Loop over the class filelds and take actions according to their properties
147  * 1. Insert a field selection rule marking a member transient
148  * 2. Store in a map the name of the field the type of which should be
149  * autoselected. The key is the name of the class and the value the name of the
150  * field. This information is used in the second pass.
151  **/
152 void DictSelectionReader::ManageFields(const clang::RecordDecl &recordDecl,
153  const std::string &className,
154  ClassSelectionRule &csr,
155  bool autoselect)
156 {
157  std::string pattern = className.substr(0, className.find_first_of("<"));
158 
159  for (auto fieldPtr : recordDecl.fields()) {
160 
161  unsigned int attrCode =
162  ExtractTemplateArgValue(*fieldPtr, "MemberAttributes");
163 
164  if (attrCode == ROOT::Meta::Selection::kMemberNullProperty) continue;
165 
166  const char *fieldName = fieldPtr->getName().data();
167 
168  if (attrCode & ROOT::Meta::Selection::kNonSplittable) {
169  if (!autoselect) {
170  fTemplateInfoMap[pattern].fUnsplittableMembers.insert(fieldName);
171  } else {
175  csr.AddFieldSelectionRule(vsr);
176  }
177  }
178 
179  if (attrCode & ROOT::Meta::Selection::kTransient) {
180  if (!autoselect) {
181  fTemplateInfoMap[pattern].fTransientMembers.insert(fieldName);
182  } else {
186  csr.AddFieldSelectionRule(vsr);
187  }
188  }
189 
191  fAutoSelectedClassFieldNames[className].insert(fieldName);
192  else if (attrCode & ROOT::Meta::Selection::kNoAutoSelected)
193  fNoAutoSelectedClassFieldNames[className].insert(fieldName);
194 
195  } // end loop on fields
196 }
197 
198 ////////////////////////////////////////////////////////////////////////////////
199 /// Check the traits of the class. Useful information may be there
200 /// extract mothers, make a switchcase:
201 /// 1) templates args are to be skipped
202 /// 2) There are properties. Make a loop. make a switch:
203 /// 2a) Is splittable
204 
205 /**
206  * Manage the loop over the base classes.
207  * Initially, the class attributes are identified and selection rules filled
208  * if:
209  * 1. The class is not splittable
210  * Then we look for the traits pointing to the need of hiding template
211  * arguments. This information is stored in the form of a list of pairs, where
212  * the first argument is the pattern of the template instance to match and
213  * the second one the number of arguments to be skipped. This information is
214  * used during the second pass.
215  **/
216 void
217 DictSelectionReader::ManageBaseClasses(const clang::CXXRecordDecl &cxxRcrdDecl,
218  const std::string &className,
219  bool &autoselect)
220 {
221  std::string baseName;
222  clang::ASTContext &C = cxxRcrdDecl.getASTContext();
223  for (auto & base : cxxRcrdDecl.bases()) {
224 
225  if (unsigned int nArgsToKeep = ExtractTemplateArgValue(base, "Keep")) {
226  std::string pattern =
227  className.substr(0, className.find_first_of("<"));
228  // Fill the structure holding the template and the number of args to
229  // skip
231  }
232 
233  // at most one string comparison...
234  if (autoselect) {
235  auto qt = base.getType();
237  if (baseName == "ROOT::Meta::Selection::SelectNoInstance") autoselect = false;
238  }
239 
240  } // end loop on base classes
241 }
242 
243 ////////////////////////////////////////////////////////////////////////////////
244 
245 /**
246  * Manage the first pass over the AST, inspecting only nodes which are within
247  * the selection namespace. Selection rules are directly filled as well as
248  * data sructures re-used during the second pass.
249  **/
250 bool DictSelectionReader::FirstPass(const clang::RecordDecl &recordDecl)
251 {
252  std::string className;
254  className, *recordDecl.getTypeForDecl(), recordDecl);
255 
256  // Strip ROOT::Meta::Selection
257  className.replace(0, 23, "");
258 
259  if (!InSelectionNamespace(recordDecl, className)) return true;
260 
261  if (!fSelectedRecordDecls.insert(&recordDecl).second) return true;
262 
263  bool autoselect = true;
264  if (auto cxxRcrdDecl = llvm::dyn_cast<clang::CXXRecordDecl>(&recordDecl)) {
265  ManageBaseClasses(*cxxRcrdDecl, className, autoselect);
266  }
267 
269  const size_t lWedgePos(className.find_first_of("<"));
270  std::string patternName("");
271  if (lWedgePos != std::string::npos &&
272  llvm::isa<clang::ClassTemplateSpecializationDecl>(recordDecl)) {
273  patternName = PatternifyName(className);
275 
276  } else {
278  }
279 
280  ManageFields(recordDecl, className, csr, autoselect);
281 
282  if (!autoselect) return true;
283 
284  // Finally add the selection rule
285  fClassNameSelectionRuleMap[patternName.empty() ? className : patternName] =
286  csr;
287 
288  return true;
289 }
290 
291 ////////////////////////////////////////////////////////////////////////////////
292 
293 /**
294  * Second pass through the AST. Two operations are performed:
295  * 1. Selection rules for classes to be autoselected are created. The
296  * algorithm works as follows: the members of the classes matching the name of
297  * the classes which contained autoselected members in the selection namespace
298  * are inspected. If a field with the same name of the one which was
299  * autoselected a selection rule based on its typename is built.
300  * 2. If a class is found which is a @c TemplateSpecialisationDecl its
301  * name is checked to match one of the patterns identified during the first
302  * pass. If a match is found, a property is added to the selection rule with
303  * the number of template arguments to keep in order to percolate this
304  * information down to the @c AnnotatedRecordDecl creation which happens in the
305  * @c RScanner .
306  **/
307 bool DictSelectionReader::SecondPass(const clang::RecordDecl &recordDecl)
308 {
309  using namespace ROOT::TMetaUtils;
310 
311  // No interest if we are in the selection namespace
312  if (InSelectionNamespace(recordDecl)) return true;
313 
314  std::string className;
315  GetQualifiedName(className, *recordDecl.getTypeForDecl(), recordDecl);
316 
317  // If the class is not among those which have fields the type of which are to
318  // be autoselected or excluded
319  if (0 != fAutoSelectedClassFieldNames.count(className) ||
320  0 != fNoAutoSelectedClassFieldNames.count(className)) {
321  // Iterate on fields. If the name of the field is among the ones the types
322  // of which should be (no)autoselected, add a class selection rule
323  std::string typeName;
324  clang::ASTContext &C = recordDecl.getASTContext();
325  for (clang::RecordDecl::field_iterator filedsIt =
326  recordDecl.field_begin();
327  filedsIt != recordDecl.field_end();
328  ++filedsIt) {
329  const std::string fieldName(filedsIt->getNameAsString());
330  bool excluded = 1 == fNoAutoSelectedClassFieldNames[className].count(fieldName);
331  bool selected = 1 == fAutoSelectedClassFieldNames[className].count(fieldName);
332  if (!selected && !excluded)
333  continue;
335  GetFullyQualifiedTypeName(typeName, filedsIt->getType(), C);
336  GetPointeeType(typeName);
337  aSelCsr.SetAttributeValue(propNames::name, typeName);
339  }
340  }
341 
342  // If the class is a template instantiation and its name matches one of the
343  // patterns
344 
345  // We don't want anything different from templ specialisations
346  if (auto tmplSpecDecl = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(&recordDecl)) {
347  for (auto & patternInfoPair : fTemplateInfoMap) {
348  const std::string &pattern = patternInfoPair.first;
349  const TemplateInfo &tInfo = patternInfoPair.second;
350  // Check if we have to add a selection rule for this class
351  if (className.find(pattern) != 0) continue;
352 
353  // Take care of the args to keep
354  auto ctd = tmplSpecDecl->getSpecializedTemplate();
355  if (tInfo.fArgsToKeep != -1 && ctd) {
356  fNormCtxt.AddTemplAndNargsToKeep(ctd->getCanonicalDecl(), tInfo.fArgsToKeep);
357  }
358 
359  // Now we take care of the transient and unsplittable members
360  if (tInfo.fTransientMembers.empty() && tInfo.fUnsplittableMembers.empty()) continue;
361  clang::ASTContext &C = recordDecl.getASTContext();
362  clang::SourceRange commentRange; // Empty: this is a fake comment
363  std::string userDefinedProperty;
364  userDefinedProperty.reserve(100);
365  for (auto fieldPtr : recordDecl.fields()) {
366  const auto fieldName = fieldPtr->getName().data();
367  if (tInfo.fTransientMembers.count(fieldName) == 1) {
368  userDefinedProperty = "!";
369  } else if (tInfo.fUnsplittableMembers.count(fieldName) == 1) {
370  userDefinedProperty = propNames::comment + propNames::separator + "||";
371  }
372  if (!userDefinedProperty.empty()) {
373  fieldPtr->addAttr(new(C) clang::AnnotateAttr(commentRange, C, userDefinedProperty, 0));
374  userDefinedProperty = "";
375  }
376  }
377  } // End loop on template info
378  }
379 
380  return true;
381 }
382 
383 ////////////////////////////////////////////////////////////////////////////////
384 
385 bool DictSelectionReader::VisitRecordDecl(clang::RecordDecl *recordDecl)
386 {
387  if (fIsFirstPass)
388  return FirstPass(*recordDecl);
389  else
390  return SecondPass(*recordDecl);
391 }
392 
393 ////////////////////////////////////////////////////////////////////////////////
394 
395 /**
396  * Transform a name of a class instance into a pattern for selection
397  * e.g. myClass<double, int, ...> in the selection namespace
398  * will translate into a pattern of the type myClass<*>
399  **/
400 inline std::string DictSelectionReader::PatternifyName(const std::string &className)
401 {
402  return className.substr(0, className.find_first_of("<")) + "<*>";
403 
404 }
405 
406 ////////////////////////////////////////////////////////////////////////////////
407 
408 /**
409  * Transform the name of the type eliminating the trailing & and *
410  **/
411 inline void DictSelectionReader::GetPointeeType(std::string &typeName)
412 {
413  while (typeName[typeName.size() - 1] == '*' ||
414  typeName[typeName.size() - 1] == '&') {
415  typeName = typeName.substr(0, typeName.size() - 1);
416  }
417 }
418 
419 }
420 }
ROOT::Internal::DictSelectionReader::GetTmplArgList
const clang::TemplateArgumentList * GetTmplArgList(const clang::CXXRecordDecl &)
Get the template arguments list if any.
Definition: DictSelectionReader.cxx:102
ROOT::TMetaUtils::propNames::separator
static const std::string separator("@@@")
ROOT::Meta::Selection::kAutoSelected
@ kAutoSelected
Select the type of the member.
Definition: RootMetaSelection.h:30
ROOT::Internal::DictSelectionReader::ExtractTemplateArgValue
unsigned int ExtractTemplateArgValue(const T &, const std::string &)
Extract the value of the template parameter.
Definition: DictSelectionReader.cxx:121
ROOT::Meta::Selection::kTransient
@ kTransient
The data member is transient.
Definition: RootMetaSelection.h:28
ROOT::Internal::DictSelectionReader::GetPointeeType
void GetPointeeType(std::string &typeName)
Get name of the pointee type.
Definition: DictSelectionReader.cxx:411
ROOT::Internal::DictSelectionReader::TemplateInfo::fTransientMembers
std::unordered_set< std::string > fTransientMembers
Definition: DictSelectionReader.h:259
ROOT::Internal::DictSelectionReader::fTemplateInfoMap
std::unordered_map< std::string, TemplateInfo > fTemplateInfoMap
List template name - properties map.
Definition: DictSelectionReader.h:295
ClassSelectionRule.h
SelectionRules.h
BaseSelectionRule::kNo
@ kNo
Definition: BaseSelectionRule.h:45
ROOT::TMetaUtils::GetFullyQualifiedTypeName
void GetFullyQualifiedTypeName(std::string &name, const clang::QualType &type, const cling::Interpreter &interpreter)
Definition: TClingUtils.cxx:3504
ROOT::Internal::DictSelectionReader::FirstPass
bool FirstPass(const clang::RecordDecl &)
First pass on the AST.
Definition: DictSelectionReader.cxx:250
ROOT::Internal::DictSelectionReader::PatternifyName
std::string PatternifyName(const std::string &className)
Transform instance name in pattern for selection.
Definition: DictSelectionReader.cxx:400
ROOT::TMetaUtils::propNames::nArgsToKeep
static const std::string nArgsToKeep("nArgsToKeep")
ROOT::Internal::DictSelectionReader::fIsFirstPass
bool fIsFirstPass
Keep trance of the number of passes through the AST.
Definition: DictSelectionReader.h:298
ROOT::TMetaUtils::GetUnderlyingRecordDecl
clang::RecordDecl * GetUnderlyingRecordDecl(clang::QualType type)
Definition: TClingUtils.cxx:2845
ROOT::Internal::DictSelectionReader::fNormCtxt
ROOT::TMetaUtils::TNormalizedCtxt & fNormCtxt
The reference to the normalized context.
Definition: DictSelectionReader.h:299
ROOT::Internal::DictSelectionReader::ManageBaseClasses
void ManageBaseClasses(const clang::CXXRecordDecl &, const std::string &, bool &)
Take care of the class bases.
Definition: DictSelectionReader.cxx:217
ROOT::Internal::DictSelectionReader::fSelectionRules
SelectionRules & fSelectionRules
The selection rules to be filled.
Definition: DictSelectionReader.h:286
ROOT::TMetaUtils::TNormalizedCtxt::AddTemplAndNargsToKeep
void AddTemplAndNargsToKeep(const clang::ClassTemplateDecl *templ, unsigned int i)
Definition: TClingUtils.cxx:351
ROOT::Math::Cephes::C
static double C[]
Definition: SpecFuncCephes.cxx:187
ROOT::TMetaUtils::GetQualifiedName
void GetQualifiedName(std::string &qual_name, const clang::QualType &type, const clang::NamedDecl &forcontext)
Main implementation relying on GetFullyQualifiedTypeName All other GetQualifiedName functions leverag...
Definition: TClingUtils.cxx:1369
ROOT::Internal::DictSelectionReader::fSelectedRecordDecls
std::set< const clang::RecordDecl * > fSelectedRecordDecls
The pointers of the selected RecordDecls.
Definition: DictSelectionReader.h:288
VariableSelectionRule
Definition: VariableSelectionRule.h:26
ClassSelectionRule
Definition: ClassSelectionRule.h:34
ROOT::Internal::DictSelectionReader::fClassNameSelectionRuleMap
llvm::StringMap< ClassSelectionRule > fClassNameSelectionRuleMap
Map of the already built sel rules.
Definition: DictSelectionReader.h:297
BaseSelectionRule::kYes
@ kYes
Definition: BaseSelectionRule.h:44
ROOT::Internal::DictSelectionReader::VisitRecordDecl
bool VisitRecordDecl(clang::RecordDecl *)
Visit the entities that needs to be selected.
Definition: DictSelectionReader.cxx:385
ROOT::TMetaUtils::TNormalizedCtxt
Definition: TClingUtils.h:138
ROOT::TMetaUtils
Definition: DictSelectionReader.h:27
ROOT::Internal::DictSelectionReader::TemplateInfo::fUnsplittableMembers
std::unordered_set< std::string > fUnsplittableMembers
Definition: DictSelectionReader.h:260
ROOT::Meta::Selection::kNonSplittable
@ kNonSplittable
The class cannot be split.
Definition: RootMetaSelection.h:34
ROOT::Internal::DictSelectionReader::SecondPass
bool SecondPass(const clang::RecordDecl &)
Second pass on the AST, using the information of the first one.
Definition: DictSelectionReader.cxx:307
ROOT::TMetaUtils::ExtractEnclosingNameSpaces
void ExtractEnclosingNameSpaces(const clang::Decl &, std::list< std::pair< std::string, bool > > &)
Extract the immediately outer namespace and then launch the recursion.
Definition: TClingUtils.cxx:4897
ROOT::Internal::DictSelectionReader::TemplateInfo::fArgsToKeep
int fArgsToKeep
Definition: DictSelectionReader.h:258
ROOT::Meta::Selection::kMemberNullProperty
@ kMemberNullProperty
Indicates absence of properties.
Definition: RootMetaSelection.h:26
ROOT::Internal::DictSelectionReader::ManageFields
void ManageFields(const clang::RecordDecl &, const std::string &, ClassSelectionRule &, bool)
Take care of the class fields.
Definition: DictSelectionReader.cxx:152
BaseSelectionRule::SetAttributeValue
void SetAttributeValue(const std::string &attributeName, const std::string &attributeValue)
Definition: BaseSelectionRule.cxx:125
TClassEdit.h
DictSelectionReader.h
Select classes and assign properties using C++ syntax.
SelectionRules::AddClassSelectionRule
void AddClassSelectionRule(const ClassSelectionRule &classSel)
Definition: SelectionRules.cxx:39
ROOT::Internal::DictSelectionReader::fNoAutoSelectedClassFieldNames
llvm::StringMap< std::set< std::string > > fNoAutoSelectedClassFieldNames
Collect the autoexcluded classes.
Definition: DictSelectionReader.h:294
name
char name[80]
Definition: TGX11.cxx:110
ROOT::Internal::DictSelectionReader::fAutoSelectedClassFieldNames
llvm::StringMap< std::set< std::string > > fAutoSelectedClassFieldNames
Collect the autoselected classes.
Definition: DictSelectionReader.h:292
ROOT::Math::Chebyshev::T
double T(double x)
Definition: ChebyshevPol.h:34
ROOT::Internal::DictSelectionReader::TemplateInfo
Definition: DictSelectionReader.h:255
TClingUtils.h
ROOT::Meta::Selection::kNoAutoSelected
@ kNoAutoSelected
Exclude the type of the member.
Definition: RootMetaSelection.h:32
ROOT::TMetaUtils::propNames::comment
static const std::string comment("comment")
ROOT::Internal::DictSelectionReader::InSelectionNamespace
bool InSelectionNamespace(const clang::RecordDecl &, const std::string &str="")
Check if in the ROOT::Meta::Selection namespace.
Definition: DictSelectionReader.cxx:63
ClassSelectionRule::AddFieldSelectionRule
void AddFieldSelectionRule(const VariableSelectionRule &field)
Definition: ClassSelectionRule.cxx:21
ROOT
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Definition: EExecutionPolicy.hxx:4
ROOT::TMetaUtils::propNames::name
static const std::string name("name")
ROOT::Internal::DictSelectionReader::DictSelectionReader
DictSelectionReader(cling::Interpreter &interp, SelectionRules &, const clang::ASTContext &, ROOT::TMetaUtils::TNormalizedCtxt &)
Take the selection rules as input (for consistency w/ other selector interfaces)
Definition: DictSelectionReader.cxx:22
ROOT::TMetaUtils::propNames::pattern
static const std::string pattern("pattern")
SelectionRules
The class representing the collection of selection rules.
Definition: SelectionRules.h:92
RootMetaSelection.h