Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TClingMethodArgInfo.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 TClingMethodArgInfo
13 Emulation of the CINT MethodInfo class.
14 
15 The CINT C++ interpreter provides an interface to metadata about
16 the arguments to a function through the MethodArgInfo class. This
17 class provides the same functionality, using an interface as close
18 as possible to MethodArgInfo but the typedef metadata comes from
19 the Clang C++ compiler, not CINT.
20 */
21 
22 #include "TClingMethodArgInfo.h"
23 
24 #include "TDictionary.h"
25 #include "TClingMethodInfo.h"
26 #include "TClingTypeInfo.h"
27 #include "ThreadLocalStorage.h"
28 
29 #include "cling/Interpreter/Interpreter.h"
30 #include "clang/AST/ASTContext.h"
31 #include "clang/AST/Decl.h"
32 #include "clang/AST/Expr.h"
33 #include "clang/AST/ExprCXX.h"
34 #include "clang/AST/PrettyPrinter.h"
35 #include "clang/AST/Type.h"
36 #include "clang/Sema/Sema.h"
37 
38 #include "llvm/Support/Casting.h"
39 #include "llvm/Support/raw_ostream.h"
40 
41 #include <string>
42 
43 TClingMethodArgInfo::TClingMethodArgInfo(cling::Interpreter *interp, const TClingMethodInfo* mi) : TClingDeclInfo(mi->GetMethodDecl()), fInterp(interp), fIdx(-1) {}
44 
45 bool TClingMethodArgInfo::IsValid() const
46 {
47  // Calling the base class implementation is unsafe because we override the
48  // GetDecl which it forwads to. That implementation depends on fIdx which is
49  // used to determine validity.
50  if (!fDecl)
51  return false;
52 
53  auto FD = llvm::cast_or_null<clang::FunctionDecl>(TClingDeclInfo::GetDecl());
54  int numParams = static_cast<int>(FD->getNumParams());
55  return (fIdx > -1) && (fIdx < numParams);
56 }
57 
58 int TClingMethodArgInfo::Next()
59 {
60  ++fIdx;
61  fNameCache.clear(); // invalidate the cache.
62  return IsValid();
63 }
64 
65 long TClingMethodArgInfo::Property() const
66 {
67  if (!IsValid()) {
68  return 0L;
69  }
70  long property = 0L;
71  const clang::ParmVarDecl *pvd = GetDecl();
72  if (pvd->hasDefaultArg() || pvd->hasInheritedDefaultArg()) {
73  property |= kIsDefault;
74  }
75  clang::QualType qt = pvd->getOriginalType().getCanonicalType();
76  if (qt.isConstQualified()) {
77  property |= kIsConstant;
78  }
79  while (1) {
80  if (qt->isArrayType()) {
81  qt = llvm::cast<clang::ArrayType>(qt)->getElementType();
82  continue;
83  }
84  else if (qt->isReferenceType()) {
85  property |= kIsReference;
86  qt = llvm::cast<clang::ReferenceType>(qt)->getPointeeType();
87  continue;
88  }
89  else if (qt->isPointerType()) {
90  property |= kIsPointer;
91  if (qt.isConstQualified()) {
92  property |= kIsConstPointer;
93  }
94  qt = llvm::cast<clang::PointerType>(qt)->getPointeeType();
95  continue;
96  }
97  else if (qt->isMemberPointerType()) {
98  qt = llvm::cast<clang::MemberPointerType>(qt)->getPointeeType();
99  continue;
100  }
101  break;
102  }
103  if (qt.isConstQualified()) {
104  property |= kIsConstant;
105  }
106  return property;
107 }
108 
109 const char *TClingMethodArgInfo::DefaultValue() const
110 {
111  if (!IsValid()) {
112  return 0;
113  }
114  const clang::ParmVarDecl *pvd = GetDecl();
115  // Instantiate default arg if needed
116  if (pvd->hasUninstantiatedDefaultArg()) {
117  // Could deserialize / create instantiated decls.
118  cling::Interpreter::PushTransactionRAII RAII(fInterp);
119  auto fd = llvm::cast_or_null<clang::FunctionDecl>(TClingDeclInfo::GetDecl());
120  fInterp->getSema().BuildCXXDefaultArgExpr(clang::SourceLocation(),
121  const_cast<clang::FunctionDecl*>(fd),
122  const_cast<clang::ParmVarDecl*>(pvd));
123  }
124  const clang::Expr *expr = 0;
125  if (pvd->hasUninstantiatedDefaultArg()) {
126  // We tried to instantiate it above; if we fail, use the uninstantiated one.
127  expr = pvd->getUninstantiatedDefaultArg();
128  } else {
129  expr = pvd->getDefaultArg();
130  }
131  clang::ASTContext &context = pvd->getASTContext();
132  clang::PrintingPolicy policy(context.getPrintingPolicy());
133  TTHREAD_TLS_DECL( std::string, buf );
134  buf.clear();
135  llvm::raw_string_ostream out(buf);
136  if (!expr) {
137  // CINT returned NULL for non-defaulted args.
138  return 0;
139  }
140  bool implicitInit = false;
141  if (const clang::CXXConstructExpr *construct =
142  llvm::dyn_cast<clang::CXXConstructExpr>(expr)) {
143  implicitInit = (pvd->getInitStyle() == clang::VarDecl::CallInit) &&
144  (construct->getNumArgs() == 0) &&
145  !construct->isListInitialization();
146  }
147  if (!implicitInit) {
148  if (pvd->getInitStyle() == clang::VarDecl::CallInit) {
149  //out << "(";
150  }
151  else if (pvd->getInitStyle() == clang::VarDecl::CInit) {
152  //out << " = ";
153  }
154  expr->printPretty(out, 0, policy, /*Indentation=*/0);
155  if (pvd->getInitStyle() == clang::VarDecl::CallInit) {
156  //out << ")";
157  }
158  out.flush();
159  }
160  return buf.c_str();
161 }
162 
163 const TClingTypeInfo *TClingMethodArgInfo::Type() const
164 {
165  TTHREAD_TLS_DECL_ARG( TClingTypeInfo, ti, fInterp);
166  if (!IsValid()) {
167  return &ti;
168  }
169  const clang::ParmVarDecl *pvd = GetDecl();
170  clang::QualType qt = pvd->getOriginalType();
171  ti.Init(qt);
172  return &ti;
173 }
174 
175 const char *TClingMethodArgInfo::TypeName() const
176 {
177  if (!IsValid()) {
178  return 0;
179  }
180  return Type()->Name();
181 }
182