Logo ROOT   6.18/05
Reference Guide
TClingDataMemberInfo.cxx
Go to the documentation of this file.
1// @(#)root/core/meta:$Id$
2// Author: Paul Russo 30/07/2012
3
4/*************************************************************************
5 * Copyright (C) 1995-2000, 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/** \class TClingDataMemberInfo
13
14Emulation of the CINT DataMemberInfo class.
15
16The CINT C++ interpreter provides an interface to metadata about
17the data members of a class through the DataMemberInfo class. This
18class provides the same functionality, using an interface as close
19as possible to DataMemberInfo but the data member metadata comes
20from the Clang C++ compiler, not CINT.
21*/
22
24
25#include "TDictionary.h"
26#include "TClingTypeInfo.h"
27#include "TClingUtils.h"
28#include "TClassEdit.h"
29#include "TError.h"
30
31#include "clang/AST/Attr.h"
32#include "clang/AST/ASTContext.h"
33#include "clang/AST/Decl.h"
34#include "clang/AST/GlobalDecl.h"
35#include "clang/AST/Expr.h"
36#include "clang/AST/ExprCXX.h"
37#include "clang/AST/PrettyPrinter.h"
38#include "clang/AST/RecordLayout.h"
39#include "clang/AST/Type.h"
40
41#include "llvm/Support/Casting.h"
42#include "llvm/Support/raw_ostream.h"
43#include "llvm/ADT/APSInt.h"
44#include "llvm/ADT/APFloat.h"
45
46using namespace clang;
47
50: TClingDeclInfo(nullptr), fInterp(interp), fClassInfo(0), fFirstTime(true), fTitle(""), fContextIdx(0U), fIoType(""), fIoName("")
51{
52 if (!ci) {
53 // We are meant to iterate over the global namespace (well at least CINT did).
54 fClassInfo = new TClingClassInfo(interp);
55 } else {
56 fClassInfo = new TClingClassInfo(*ci);
57 }
58 if (fClassInfo->IsValid()) {
59 Decl *D = const_cast<Decl*>(fClassInfo->GetDecl());
60
61 clang::DeclContext *dc = llvm::cast<clang::DeclContext>(D);
62 dc->collectAllContexts(fContexts);
63
64 // Could trigger deserialization of decls.
65 cling::Interpreter::PushTransactionRAII RAII(interp);
66 fIter = llvm::cast<clang::DeclContext>(D)->decls_begin();
67 const TagDecl *TD = ROOT::TMetaUtils::GetAnnotatedRedeclarable(llvm::dyn_cast<TagDecl>(D));
68 if (TD)
69 fIter = TD->decls_begin();
70
71 // Move to first data member.
73 fFirstTime = true;
74 }
75
76}
77
79 const clang::ValueDecl *ValD,
81: TClingDeclInfo(ValD), fInterp(interp), fClassInfo(ci ? new TClingClassInfo(*ci) : new TClingClassInfo(interp, ValD)), fFirstTime(true),
82 fTitle(""), fContextIdx(0U), fIoType(""), fIoName(""){
83
84 using namespace llvm;
85 assert((ci || isa<TranslationUnitDecl>(ValD->getDeclContext()) ||
86 (ValD->getDeclContext()->isTransparentContext() && isa<TranslationUnitDecl>(ValD->getDeclContext()->getParent()) ) ||
87 isa<EnumConstantDecl>(ValD)) && "Not TU?");
88 assert((isa<VarDecl>(ValD) ||
89 isa<FieldDecl>(ValD) ||
90 isa<EnumConstantDecl>(ValD) ||
91 isa<IndirectFieldDecl>(ValD)) &&
92 "The decl should be either VarDecl or FieldDecl or EnumConstDecl");
93
94}
95
97{
98 // Three cases:
99 // 1) 00: none to be checked
100 // 2) 01: type to be checked
101 // 3) 10: none to be checked
102 // 4) 11: both to be checked
103 unsigned int code = fIoType.empty() + (int(fIoName.empty()) << 1);
104
105 if (code == 0) return;
106
107 const Decl* decl = GetDecl();
108
109 if (code == 3 || code == 2) ROOT::TMetaUtils::ExtractAttrPropertyFromName(*decl,"ioname",fIoName);
110 if (code == 3 || code == 1) ROOT::TMetaUtils::ExtractAttrPropertyFromName(*decl,"iotype",fIoType);
111
112}
113
115{
116 if (!IsValid()) {
117 return TDictionary::DeclId_t();
118 }
119 return (const clang::Decl*)(GetDecl()->getCanonicalDecl());
120}
121
123{
124 if (!IsValid()) {
125 return -1;
126 }
127 // Sanity check the current data member.
128 clang::Decl::Kind DK = GetDecl()->getKind();
129 if (
130 (DK != clang::Decl::Field) &&
131 (DK != clang::Decl::Var) &&
132 (DK != clang::Decl::EnumConstant)
133 ) {
134 // Error, was not a data member, variable, or enumerator.
135 return -1;
136 }
137 if (DK == clang::Decl::EnumConstant) {
138 // We know that an enumerator value does not have array type.
139 return 0;
140 }
141 // To get this information we must count the number
142 // of array type nodes in the canonical type chain.
143 const clang::ValueDecl *VD = llvm::dyn_cast<clang::ValueDecl>(GetDecl());
144 clang::QualType QT = VD->getType().getCanonicalType();
145 int cnt = 0;
146 while (1) {
147 if (QT->isArrayType()) {
148 ++cnt;
149 QT = llvm::cast<clang::ArrayType>(QT)->getElementType();
150 continue;
151 }
152 else if (QT->isReferenceType()) {
153 QT = llvm::cast<clang::ReferenceType>(QT)->getPointeeType();
154 continue;
155 }
156 else if (QT->isPointerType()) {
157 QT = llvm::cast<clang::PointerType>(QT)->getPointeeType();
158 continue;
159 }
160 else if (QT->isMemberPointerType()) {
161 QT = llvm::cast<clang::MemberPointerType>(QT)->getPointeeType();
162 continue;
163 }
164 break;
165 }
166 return cnt;
167}
168
170{
171 if (!IsValid()) {
172 return -1;
173 }
174 // Sanity check the current data member.
175 clang::Decl::Kind DK = GetDecl()->getKind();
176 if (
177 (DK != clang::Decl::Field) &&
178 (DK != clang::Decl::Var) &&
179 (DK != clang::Decl::EnumConstant)
180 ) {
181 // Error, was not a data member, variable, or enumerator.
182 return -1;
183 }
184 if (DK == clang::Decl::EnumConstant) {
185 // We know that an enumerator value does not have array type.
186 return 0;
187 }
188 // To get this information we must count the number
189 // of array type nodes in the canonical type chain.
190 const clang::ValueDecl *VD = llvm::dyn_cast<clang::ValueDecl>(GetDecl());
191 clang::QualType QT = VD->getType().getCanonicalType();
192 int paran = ArrayDim();
193 if ((dim < 0) || (dim >= paran)) {
194 // Passed dimension is out of bounds.
195 return -1;
196 }
197 int cnt = dim;
198 int max = 0;
199 while (1) {
200 if (QT->isArrayType()) {
201 if (cnt == 0) {
202 if (const clang::ConstantArrayType *CAT =
203 llvm::dyn_cast<clang::ConstantArrayType>(QT)
204 ) {
205 max = static_cast<int>(CAT->getSize().getZExtValue());
206 }
207 else if (llvm::dyn_cast<clang::IncompleteArrayType>(QT)) {
208 max = INT_MAX;
209 }
210 else {
211 max = -1;
212 }
213 break;
214 }
215 --cnt;
216 QT = llvm::cast<clang::ArrayType>(QT)->getElementType();
217 continue;
218 }
219 else if (QT->isReferenceType()) {
220 QT = llvm::cast<clang::ReferenceType>(QT)->getPointeeType();
221 continue;
222 }
223 else if (QT->isPointerType()) {
224 QT = llvm::cast<clang::PointerType>(QT)->getPointeeType();
225 continue;
226 }
227 else if (QT->isMemberPointerType()) {
228 QT = llvm::cast<clang::MemberPointerType>(QT)->getPointeeType();
229 continue;
230 }
231 break;
232 }
233 return max;
234}
235
237{
238 assert(!fDecl
239 && "This is a single decl, not an iterator!");
240
241 fNameCache.clear(); // invalidate the cache.
242 bool increment = true;
243 // Move to next acceptable data member.
244 while (fFirstTime || *fIter) {
245 // Move to next decl in context.
246 if (fFirstTime) {
247 fFirstTime = false;
248 }
249 else if (increment) {
250 ++fIter;
251 } else {
252 increment = true;
253 }
254
255 // Handle reaching end of current decl context.
256 if (!*fIter) {
257 if (fIterStack.size()) {
258 // End of current decl context, and we have more to go.
259 fIter = fIterStack.back();
260 fIterStack.pop_back();
261 continue;
262 }
263 while (!*fIter) {
264 // Check the next decl context (of namespace)
265 ++fContextIdx;
266 if (fContextIdx >= fContexts.size()) {
267 // Iterator is now invalid.
268 return 0;
269 }
270 clang::DeclContext *dc = fContexts[fContextIdx];
271 // Could trigger deserialization of decls.
272 cling::Interpreter::PushTransactionRAII RAII(fInterp);
273 fIter = dc->decls_begin();
274 if (*fIter) {
275 // Good, a non-empty context.
276 break;
277 }
278 }
279 }
280
281 // Valid decl, recurse into it, accept it, or reject it.
282 clang::Decl::Kind DK = fIter->getKind();
283 if (DK == clang::Decl::Enum) {
284 // We have an enum, recurse into these.
285 // Note: For C++11 we will have to check for a transparent context.
286 fIterStack.push_back(fIter);
287 cling::Interpreter::PushTransactionRAII RAII(fInterp);
288 fIter = llvm::dyn_cast<clang::DeclContext>(*fIter)->decls_begin();
289 increment = false; // avoid the next incrementation
290 continue;
291 }
292 if ((DK == clang::Decl::Field) || (DK == clang::Decl::EnumConstant) ||
293 (DK == clang::Decl::Var)) {
294 // Stop on class data members, enumerator values,
295 // and namespace variable members.
296 return 1;
297 }
298 }
299 return 0;
300}
301
303{
304 using namespace clang;
305
306 if (!IsValid()) {
307 return -1L;
308 }
309
310 const Decl *D = GetDecl();
311 ASTContext& C = D->getASTContext();
312 if (const FieldDecl *FldD = dyn_cast<FieldDecl>(D)) {
313 // The current member is a non-static data member.
314 const clang::RecordDecl *RD = FldD->getParent();
315 const clang::ASTRecordLayout &Layout = C.getASTRecordLayout(RD);
316 uint64_t bits = Layout.getFieldOffset(FldD->getFieldIndex());
317 int64_t offset = C.toCharUnitsFromBits(bits).getQuantity();
318 return static_cast<long>(offset);
319 }
320 else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
321 // Could trigger deserialization of decls, in particular in case
322 // of constexpr, like:
323 // static constexpr Long64_t something = std::numeric_limits<Long64_t>::max();
324 cling::Interpreter::PushTransactionRAII RAII(fInterp);
325
326 if (long addr = reinterpret_cast<long>(fInterp->getAddressOfGlobal(GlobalDecl(VD))))
327 return addr;
328 auto evalStmt = VD->ensureEvaluatedStmt();
329 if (evalStmt && evalStmt->Value) {
330 if (const APValue* val = VD->evaluateValue()) {
331 if (VD->getType()->isIntegralType(C)) {
332 return reinterpret_cast<long>(val->getInt().getRawData());
333 } else {
334 // The VD stores the init value; its lifetime should the lifetime of
335 // this offset.
336 switch (val->getKind()) {
337 case APValue::Int: {
338 if (val->getInt().isSigned())
339 fConstInitVal.fLong = (long)val->getInt().getSExtValue();
340 else
341 fConstInitVal.fLong = (long)val->getInt().getZExtValue();
342 return (long) &fConstInitVal.fLong;
343 }
344 case APValue::Float:
345 if (&val->getFloat().getSemantics()
346 == (const llvm::fltSemantics*)&llvm::APFloat::IEEEsingle()) {
347 fConstInitVal.fFloat = val->getFloat().convertToFloat();
348 return (long)&fConstInitVal.fFloat;
349 } else if (&val->getFloat().getSemantics()
350 == (const llvm::fltSemantics*) &llvm::APFloat::IEEEdouble()) {
351 fConstInitVal.fDouble = val->getFloat().convertToDouble();
352 return (long)&fConstInitVal.fDouble;
353 }
354 // else fall-through
355 default:
356 ;// fall-through
357 };
358 // fall-through
359 } // not integral type
360 } // have an APValue
361 } // have an initializing value
362 }
363 // FIXME: We have to explicitly check for not enum constant because the
364 // implementation of getAddressOfGlobal relies on mangling the name and in
365 // clang there is misbehaviour in MangleContext::shouldMangleDeclName.
366 // enum constants are essentially numbers and don't get addresses. However
367 // ROOT expects the address to the enum constant initializer to be returned.
368 else if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
369 // The raw data is stored as a long long, so we need to find the 'long'
370 // part.
371#ifdef R__BYTESWAP
372 // In this case at the beginning.
373 return reinterpret_cast<long>(ECD->getInitVal().getRawData());
374#else
375 // In this case in the second part.
376 return reinterpret_cast<long>(((char*)ECD->getInitVal().getRawData())+sizeof(long) );
377#endif
378 return -1L;
379}
380
382{
383 if (!IsValid()) {
384 return 0L;
385 }
386 long property = 0L;
387 const clang::Decl *declaccess = GetDecl();
388 if (declaccess->getDeclContext()->isTransparentContext()) {
389 declaccess = llvm::dyn_cast<clang::Decl>(declaccess->getDeclContext());
390 if (!declaccess) declaccess = GetDecl();
391 }
392 switch (declaccess->getAccess()) {
393 case clang::AS_public:
394 property |= kIsPublic;
395 break;
396 case clang::AS_protected:
397 property |= kIsProtected;
398 break;
399 case clang::AS_private:
400 property |= kIsPrivate;
401 break;
402 case clang::AS_none:
403 if (declaccess->getDeclContext()->isNamespace()) {
404 property |= kIsPublic;
405 } else {
406 // IMPOSSIBLE
407 }
408 break;
409 default:
410 // IMPOSSIBLE
411 break;
412 }
413 if (const clang::VarDecl *vard = llvm::dyn_cast<clang::VarDecl>(GetDecl())) {
414 if (vard->getStorageClass() == clang::SC_Static) {
415 property |= kIsStatic;
416 } else if (declaccess->getDeclContext()->isNamespace()) {
417 // Data members of a namespace are global variable which were
418 // considered to be 'static' in the CINT (and thus ROOT) scheme.
419 property |= kIsStatic;
420 }
421 }
422 if (llvm::isa<clang::EnumConstantDecl>(GetDecl())) {
423 // Enumeration constant are considered to be 'static' data member in
424 // the CINT (and thus ROOT) scheme.
425 property |= kIsStatic;
426 }
427 const clang::ValueDecl *vd = llvm::dyn_cast<clang::ValueDecl>(GetDecl());
428 clang::QualType qt = vd->getType();
429 if (llvm::isa<clang::TypedefType>(qt)) {
430 property |= kIsTypedef;
431 }
432 qt = qt.getCanonicalType();
433 if (qt.isConstQualified()) {
434 property |= kIsConstant;
435 }
436 while (1) {
437 if (qt->isArrayType()) {
438 property |= kIsArray;
439 qt = llvm::cast<clang::ArrayType>(qt)->getElementType();
440 continue;
441 }
442 else if (qt->isReferenceType()) {
443 property |= kIsReference;
444 qt = llvm::cast<clang::ReferenceType>(qt)->getPointeeType();
445 continue;
446 }
447 else if (qt->isPointerType()) {
448 property |= kIsPointer;
449 if (qt.isConstQualified()) {
450 property |= kIsConstPointer;
451 }
452 qt = llvm::cast<clang::PointerType>(qt)->getPointeeType();
453 continue;
454 }
455 else if (qt->isMemberPointerType()) {
456 qt = llvm::cast<clang::MemberPointerType>(qt)->getPointeeType();
457 continue;
458 }
459 break;
460 }
461 if (qt->isBuiltinType()) {
462 property |= kIsFundamental;
463 }
464 if (qt.isConstQualified()) {
465 property |= kIsConstant;
466 }
467 const clang::TagType *tt = qt->getAs<clang::TagType>();
468 if (tt) {
469 const clang::TagDecl *td = tt->getDecl();
470 if (td->isClass()) {
471 property |= kIsClass;
472 }
473 else if (td->isStruct()) {
474 property |= kIsStruct;
475 }
476 else if (td->isUnion()) {
477 property |= kIsUnion;
478 }
479 else if (td->isEnum()) {
480 property |= kIsEnum;
481 }
482 }
483 // We can't be a namespace, can we?
484 // if (dc->isNamespace() && !dc->isTranslationUnit()) {
485 // property |= kIsNamespace;
486 // }
487 return property;
488}
489
491{
492 if (!IsValid()) {
493 return 0L;
494 }
495 const clang::ValueDecl *vd = llvm::dyn_cast<clang::ValueDecl>(GetDecl());
496 clang::QualType qt = vd->getType();
497 return TClingTypeInfo(fInterp, qt).Property();
498}
499
501{
502 if (!IsValid()) {
503 return -1;
504 }
505
506 // Sanity check the current data member.
507 clang::Decl::Kind dk = GetDecl()->getKind();
508 if ((dk != clang::Decl::Field) && (dk != clang::Decl::Var) &&
509 (dk != clang::Decl::EnumConstant)) {
510 // Error, was not a data member, variable, or enumerator.
511 return -1;
512 }
513 const clang::ValueDecl *vd = llvm::dyn_cast<clang::ValueDecl>(GetDecl());
514 clang::QualType qt = vd->getType();
515 if (qt->isIncompleteType()) {
516 // We cannot determine the size of forward-declared types.
517 return -1;
518 }
519 clang::ASTContext &context = GetDecl()->getASTContext();
520 // Truncate cast to fit to cint interface.
521 return static_cast<int>(context.getTypeSizeInChars(qt).getQuantity());
522}
523
525{
526 if (!IsValid()) {
527 return 0;
528 }
529
531 if (!fIoType.empty()) return fIoType.c_str();
532
533 // Note: This must be static because we return a pointer inside it!
534 static std::string buf;
535 buf.clear();
536 if (const clang::ValueDecl *vd = llvm::dyn_cast<clang::ValueDecl>(GetDecl())) {
537 clang::QualType vdType = vd->getType();
538 // In CINT's version, the type name returns did *not* include any array
539 // information, ROOT's existing code depends on it.
540 while (vdType->isArrayType()) {
541 vdType = GetDecl()->getASTContext().getQualifiedType(vdType->getBaseElementTypeUnsafe(),vdType.getQualifiers());
542 }
543
544 // if (we_need_to_do_the_subst_because_the_class_is_a_template_instance_of_double32_t)
545 vdType = ROOT::TMetaUtils::ReSubstTemplateArg(vdType, fClassInfo->GetType() );
546
547 ROOT::TMetaUtils::GetFullyQualifiedTypeName(buf, vdType, *fInterp);
548
549 return buf.c_str();
550 }
551 return 0;
552}
553
554const char *TClingDataMemberInfo::TypeTrueName(const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt) const
555{
556 if (!IsValid()) {
557 return 0;
558 }
559
561 if (!fIoType.empty()) return fIoType.c_str();
562
563 // Note: This must be static because we return a pointer inside it!
564 static std::string buf;
565 buf.clear();
566 if (const clang::ValueDecl *vd = llvm::dyn_cast<clang::ValueDecl>(GetDecl())) {
567 // if (we_need_to_do_the_subst_because_the_class_is_a_template_instance_of_double32_t)
568 clang::QualType vdType = ROOT::TMetaUtils::ReSubstTemplateArg(vd->getType(), fClassInfo->GetType());
569
570 ROOT::TMetaUtils::GetNormalizedName(buf, vdType, *fInterp, normCtxt);
571
572 // In CINT's version, the type name returns did *not* include any array
573 // information, ROOT's existing code depends on it.
574 // This might become part of the implementation of GetNormalizedName.
575 while (buf.length() && buf[buf.length()-1] == ']') {
576 size_t last = buf.rfind('['); // if this is not the bracket we are looking, the type is malformed.
577 if (last != std::string::npos) {
578 buf.erase(last);
579 }
580 }
581 return buf.c_str();
582 }
583 return 0;
584}
585
587{
588 if (!IsValid()) {
589 return 0;
590 }
591
593 if (!fIoName.empty()) return fIoName.c_str();
594
595 return TClingDeclInfo::Name();
596}
597
599{
600 if (!IsValid()) {
601 return 0;
602 }
603
604 //NOTE: We can't use it as a cache due to the "thoughtful" self iterator
605 //if (fTitle.size())
606 // return fTitle.c_str();
607
608 bool titleFound=false;
609 // Try to get the comment either from the annotation or the header file if present
610 std::string attribute_s;
611 const Decl* decl = GetDecl();
612 for (Decl::attr_iterator attrIt = decl->attr_begin();
613 attrIt!=decl->attr_end() && !titleFound ;++attrIt){
614 if (0 == ROOT::TMetaUtils::extractAttrString(*attrIt, attribute_s) &&
615 attribute_s.find(ROOT::TMetaUtils::propNames::separator) == std::string::npos){
616 fTitle = attribute_s;
617 titleFound=true;
618 }
619 }
620
621 if (!titleFound && !GetDecl()->isFromASTFile()) {
622 // Try to get the comment from the header file if present
623 // but not for decls from AST file, where rootcling would have
624 // created an annotation
625 fTitle = ROOT::TMetaUtils::GetComment(*GetDecl()).str();
626 }
627
628 return fTitle.c_str();
629}
630
631// ValidArrayIndex return a static string (so use it or copy it immediately, do not
632// call GrabIndex twice in the same expression) containing the size of the
633// array data member.
635{
636 if (!IsValid()) {
637 return llvm::StringRef();
638 }
639 const clang::DeclaratorDecl *FD = llvm::dyn_cast<clang::DeclaratorDecl>(GetDecl());
640 if (FD) return ROOT::TMetaUtils::DataMemberInfo__ValidArrayIndex(*FD);
641 else return llvm::StringRef();
642}
643
@ kIsPublic
Definition: TDictionary.h:74
@ kIsPointer
Definition: TDictionary.h:77
@ kIsConstant
Definition: TDictionary.h:86
@ kIsClass
Definition: TDictionary.h:65
@ kIsReference
Definition: TDictionary.h:81
@ kIsEnum
Definition: TDictionary.h:68
@ kIsPrivate
Definition: TDictionary.h:76
@ kIsConstPointer
Definition: TDictionary.h:88
@ kIsFundamental
Definition: TDictionary.h:70
@ kIsArray
Definition: TDictionary.h:78
@ kIsStatic
Definition: TDictionary.h:79
@ kIsStruct
Definition: TDictionary.h:66
@ kIsProtected
Definition: TDictionary.h:75
@ kIsUnion
Definition: TDictionary.h:67
@ kIsTypedef
Definition: TDictionary.h:69
Emulation of the CINT ClassInfo class.
const clang::Type * GetType() const
const char * TypeName() const
union TClingDataMemberInfo::@30 fConstInitVal
clang::DeclContext::decl_iterator fIter
const clang::Decl * GetDecl() const override
const char * TypeTrueName(const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt) const
const char * Name() override
int MaxIndex(int dim) const
TClingClassInfo * fClassInfo
std::vector< clang::DeclContext::decl_iterator > fIterStack
TClingDataMemberInfo(cling::Interpreter *interp)
cling::Interpreter * fInterp
llvm::SmallVector< clang::DeclContext *, 2 > fContexts
llvm::StringRef ValidArrayIndex() const
const clang::Decl * fDecl
virtual const char * Name()
virtual bool IsValid() const
std::string fNameCache
virtual const clang::Decl * GetDecl() const
Emulation of the CINT TypeInfo class.
long Property() const
const void * DeclId_t
Definition: TDictionary.h:206
static double C[]
double Var(const RVec< T > &v)
Get the variance of the elements of an RVec.
Definition: RVec.hxx:859
RooCmdArg Layout(Double_t xmin, Double_t xmax=0.99, Double_t ymin=0.95)
void GetNormalizedName(std::string &norm_name, std::string_view name)
Return the normalized name.
Definition: TClassEdit.cxx:821
static constexpr double L
Definition: TString.h:845
const char * Float
const char * Int
const char * cnt
Definition: TXMLSetup.cxx:74
auto * tt
Definition: textangle.C:16