cling/lib/Interpreter/DynamicLookup.cpp
Vassil Vassilev a047926b87 Usually we have to distinguish between lookup failures. Eg. there are certain
lookups that are expected (by the compiler) to fail and those which should not fail.

I was misled (wasn't thinking at all: Thanks Axel for questioning the checkin) 
because I thought we cannot distinguish those two different cases in the test
callback. 
Silly mistake:
  Revert the changes in the testsuite.
  Revert the default setup of the test callback in enableDynamicLookup

The problem is solved by extracting out the function which determines whether
a lookup is not expected to fail. (It still needs better place.)


git-svn-id: http://root.cern.ch/svn/root/trunk@46438 27541ba8-7e3a-0410-8455-c3a389f83636
2012-10-10 14:37:10 +00:00

854 lines
33 KiB
C++

//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------
#include "DynamicLookup.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"
#include "clang/AST/ASTContext.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Template.h"
using namespace clang;
namespace cling {
// pin the vtable to this file
DynamicIDHandler::~DynamicIDHandler() { }
bool DynamicIDHandler::LookupUnqualified(LookupResult& R, Scope* S) {
// FIXME: Extract out somewhere else.
if (!test::SymbolResolverCallback::IsDynamicLookup(R, S))
return false;
if (getCallbacks() && getCallbacks()->isEnabled()) {
return getCallbacks()->LookupObject(R, S);
}
DeclarationName Name = R.getLookupName();
IdentifierInfo* II = Name.getAsIdentifierInfo();
SourceLocation Loc = R.getNameLoc();
ASTContext& C = R.getSema().getASTContext();
VarDecl* Result = VarDecl::Create(C,
R.getSema().getFunctionLevelDeclContext(),
Loc,
Loc,
II,
C.DependentTy,
/*TypeSourceInfo*/0,
SC_None,
SC_None);
if (Result) {
R.addDecl(Result);
// Say that we can handle the situation. Clang should try to recover
return true;
}
// We cannot handle the situation. Give up
return false;
}
} // end namespace cling
namespace {
class StmtPrinterHelper : public PrinterHelper {
private:
PrintingPolicy m_Policy;
llvm::SmallVector<DeclRefExpr*, 4>& m_Addresses;
Sema* m_Sema;
public:
StmtPrinterHelper(const PrintingPolicy& Policy,
llvm::SmallVector<DeclRefExpr*, 4>& Addresses,
Sema* S) :
m_Policy(Policy), m_Addresses(Addresses), m_Sema(S) {}
virtual ~StmtPrinterHelper() {}
// Handle only DeclRefExprs since they are local and the call wrapper
// won't "see" them. Consequently we don't need to handle:
// * DependentScopeDeclRefExpr
// * CallExpr
// * MemberExpr
// * CXXDependentScopeMemberExpr
virtual bool handledStmt(Stmt* S, llvm::raw_ostream& OS) {
if (DeclRefExpr* Node = dyn_cast<DeclRefExpr>(S))
// Exclude the artificially dependent DeclRefExprs, created by the
// Lookup
if (!Node->isTypeDependent()) {
if (NestedNameSpecifier* Qualifier = Node->getQualifier())
Qualifier->print(OS, m_Policy);
m_Addresses.push_back(Node);
QualType T = Node->getType();
SplitQualType T_split = T.split();
if (!T->isArrayType())
OS << '*';
OS << '(';
ASTContext &Ctx = m_Sema->getASTContext();
OS << Ctx.getBaseElementType(T).getAsString();
// We need to handle the arrays differently
if (const ArrayType* AT = dyn_cast<ArrayType>(T.getTypePtr())) {
OS << "(*)";
T = AT->getElementType();
while ((AT = dyn_cast<ArrayType>(T))) {
// TODO: Fix other types of arrays
if (const ConstantArrayType* CAT
= dyn_cast<ConstantArrayType>(AT))
OS <<'[' << CAT->getSize().getZExtValue() << ']';
T = AT->getElementType();
}
}
else
OS << '*';
if (!Node->getType().isNull()) {
// If the type is sugared, also dump a (shallow) desugared type.
SplitQualType D_split = Node->getType().getSplitDesugaredType();
assert(T_split == D_split && "Trying to print shallow type!");
if (T_split != D_split)
OS << ":" << QualType::getAsString(D_split);
}
// end
OS <<")@";
if (Node->hasExplicitTemplateArgs())
OS << TemplateSpecializationType::PrintTemplateArgumentList(
Node->getTemplateArgs(),
Node->getNumTemplateArgs(),
m_Policy);
if (Node->hasExplicitTemplateArgs())
assert((Node->getTemplateArgs() || Node->getNumTemplateArgs()) && \
"There shouldn't be template paramlist");
return true;
}
return false;
}
};
} // end anonymous namespace
namespace cling {
// Constructors
EvaluateTSynthesizer::EvaluateTSynthesizer(Sema* S)
: TransactionTransformer(S), m_EvalDecl(0), m_LifetimeHandlerDecl(0),
m_LHgetMemoryDecl(0), m_DynamicExprInfoDecl(0), m_DeclContextDecl(0),
m_CurDeclContext(0), m_Context(&S->getASTContext()), m_UniqueNameCounter(0)
{ }
// pin the vtable here.
EvaluateTSynthesizer::~EvaluateTSynthesizer()
{ }
void EvaluateTSynthesizer::Initialize() {
// Most of the declaration we are looking up are in cling::runtime::internal
NamespaceDecl* NSD = utils::Lookup::Namespace(m_Sema, "cling");
NSD = utils::Lookup::Namespace(m_Sema, "runtime", NSD);
NSD = utils::Lookup::Namespace(m_Sema, "internal", NSD);
// Find and set up EvaluateT
DeclarationName Name = &m_Context->Idents.get("EvaluateT");
LookupResult R(*m_Sema, Name, SourceLocation(), Sema::LookupOrdinaryName,
Sema::ForRedeclaration);
m_Sema->LookupQualifiedName(R, NSD);
// We have specialized EvaluateT but we don't care because the templated
// decl is needed.
TemplateDecl* TplD = dyn_cast_or_null<TemplateDecl>(*R.begin());
m_EvalDecl = dyn_cast<FunctionDecl>(TplD->getTemplatedDecl());
assert(m_EvalDecl && "The Eval function not found!");
// Find the LifetimeHandler declaration
R.clear();
Name = &m_Context->Idents.get("LifetimeHandler");
R.setLookupName(Name);
m_Sema->LookupQualifiedName(R, NSD);
m_LifetimeHandlerDecl = R.getAsSingle<CXXRecordDecl>();
assert(m_LifetimeHandlerDecl && "LifetimeHandler could not be found.");
// Find the LifetimeHandler::getMemory declaration
R.clear();
Name = &m_Context->Idents.get("getMemory");
R.setLookupName(Name);
m_Sema->LookupQualifiedName(R, m_LifetimeHandlerDecl);
m_LHgetMemoryDecl = R.getAsSingle<CXXMethodDecl>();
assert(m_LHgetMemoryDecl && "LifetimeHandler::getMemory couldn't be found.");
// Find the DynamicExprInfo declaration
R.clear();
Name = &m_Context->Idents.get("DynamicExprInfo");
R.setLookupName(Name);
m_Sema->LookupQualifiedName(R, NSD);
m_DynamicExprInfoDecl = R.getAsSingle<CXXRecordDecl>();
assert(m_DynamicExprInfoDecl && "DynExprInfo could not be found.");
// Find the DeclContext declaration
R.clear();
Name = &m_Context->Idents.get("DeclContext");
R.setLookupName(Name);
NamespaceDecl* clangNSD = utils::Lookup::Namespace(m_Sema, "clang");
m_Sema->LookupQualifiedName(R, clangNSD);
m_DeclContextDecl = R.getAsSingle<CXXRecordDecl>();
assert(m_DeclContextDecl && "clang::DeclContext decl could not be found.");
// Find and set the source locations to valid ones.
R.clear();
Name
= &m_Context->Idents.get(
"InterpreterGeneratedCodeDiagnosticsMaybeIncorrect");
R.setLookupName(Name);
m_Sema->LookupQualifiedName(R, NSD);
assert(!R.empty() && "Cannot find PrintValue(...)");
NamedDecl* ND = R.getFoundDecl();
m_NoRange = ND->getSourceRange();
m_NoSLoc = m_NoRange.getBegin();
m_NoELoc = m_NoRange.getEnd();
}
void EvaluateTSynthesizer::Transform() {
if (!getTransaction()->getCompilationOpts().DynamicScoping)
return;
// Find DynamicLookup specific builtins
if (!m_EvalDecl) {
Initialize();
}
for (Transaction::const_iterator I = getTransaction()->decls_begin(),
E = getTransaction()->decls_end(); I != E; ++I)
for (DeclGroupRef::const_iterator J = (*I).begin(),
JE = (*I).end(); J != JE; ++J)
if (ShouldVisit(*J) && (*J)->hasBody()) {
if (FunctionDecl* FD = dyn_cast<FunctionDecl>(*J)) {
// Set the decl context, which is needed by Evaluate.
m_CurDeclContext = FD->getDeclContext();
ASTNodeInfo NewBody = Visit((*J)->getBody());
FD->setBody(NewBody.getAsSingleNode());
}
assert ((!isa<BlockDecl>(*J) || !isa<ObjCMethodDecl>(*J))
&& "Not implemented yet!");
}
//TODO: Check for error before returning.
}
// StmtVisitor
ASTNodeInfo EvaluateTSynthesizer::VisitStmt(Stmt* Node) {
for (Stmt::child_iterator
I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
if (*I) {
ASTNodeInfo NewNode = Visit(*I);
assert(NewNode.hasSingleNode() &&
"Cannot have more than one stmt at that point");
if (NewNode.isForReplacement()) {
if (Expr* E = NewNode.getAs<Expr>())
// Assume void if still not escaped
*I = SubstituteUnknownSymbol(m_Context->VoidTy, E);
}
else {
*I = NewNode.getAsSingleNode();
}
}
}
return ASTNodeInfo(Node, 0);
}
// If the dynamic expression is in the conditional clause of the if
// assume that the return type is bool, because we know that
// everything in the condition of IfStmt is implicitly converted into bool
ASTNodeInfo EvaluateTSynthesizer::VisitIfStmt(IfStmt* Node) {
// See whether there is var defined. Eg: if (int i = f->call())
// It will fall into DeclStmt.
if (Node->getConditionVariableDeclStmt()) {
// Removing the const, which shouldn't be dangerous
VisitDeclStmt(const_cast<DeclStmt*>(
Node->getConditionVariableDeclStmt()));
}
// Handle the case where the dynamic expression is in the condition of the
// stmt.
ASTNodeInfo IfCondInfo = Visit(Node->getCond());
if (IfCondInfo.isForReplacement())
if (Expr* IfCondExpr = IfCondInfo.getAs<Expr>()) {
Node->setCond(SubstituteUnknownSymbol(m_Context->BoolTy, IfCondExpr));
return ASTNodeInfo(Node, /*needs eval*/false);
}
// Visit the other parts - they will fall naturally into Stmt or
// CompoundStmt where we know what to do.
Visit(Node->getThen());
if (Stmt* ElseExpr = Node->getElse())
Visit(ElseExpr);
return ASTNodeInfo(Node, false);
}
ASTNodeInfo EvaluateTSynthesizer::VisitCompoundStmt(CompoundStmt* Node) {
ASTNodes Children;
ASTNodes NewChildren;
if (GetChildren(Children, Node)) {
ASTNodes::iterator it;
for (it = Children.begin(); it != Children.end(); ++it) {
ASTNodeInfo NewNode = Visit(*it);
if (!NewNode.hasSingleNode()) {
ASTNodes& NewStmts(NewNode.getNodes());
for(unsigned i = 0; i < NewStmts.size(); ++i)
NewChildren.push_back(NewStmts[i]);
Node->setStmts(*m_Context, NewChildren.data(), NewChildren.size());
// Resolve all 1:n replacements
Visit(Node);
}
else {
if (NewNode.isForReplacement()) {
if (Expr* E = NewNode.getAs<Expr>()) {
// Check whether value printer has been requested
bool valuePrinterReq = false;
if ((it+1) == Children.end() || !isa<NullStmt>(*(it+1)))
valuePrinterReq = true;
// Assume void if still not escaped
NewChildren.push_back(SubstituteUnknownSymbol(m_Context->VoidTy,E,
valuePrinterReq));
}
}
else
NewChildren.push_back(*it);
}
}
}
Node->setStmts(*m_Context, NewChildren.data(), NewChildren.size());
return ASTNodeInfo(Node, 0);
}
ASTNodeInfo EvaluateTSynthesizer::VisitDeclStmt(DeclStmt* Node) {
// Visit all the children, which are the contents of the DeclGroupRef
for (Stmt::child_iterator
I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
if (*I) {
Expr* E = cast_or_null<Expr>(*I);
if (!E || !IsArtificiallyDependent(E))
continue;
//FIXME: don't assume there is only one decl.
assert(Node->isSingleDecl() && "There is more that one decl in stmt");
VarDecl* CuredDecl = cast_or_null<VarDecl>(Node->getSingleDecl());
assert(CuredDecl && "Not a variable declaration!");
QualType CuredDeclTy = CuredDecl->getType();
// check if the case is sometype * somevar = init;
// or some_builtin_type somevar = init;
if (CuredDecl->hasInit() && (CuredDeclTy->isAnyPointerType()
|| !CuredDeclTy->isRecordType())) {
*I = SubstituteUnknownSymbol(CuredDeclTy, CuredDecl->getInit());
continue;
}
// 1. Check whether this is the case of MyClass A(dep->symbol())
// 2. Insert the RuntimeUniverse's LifetimeHandler instance
// 3. Change the A's initializer to *(MyClass*)instance.getMemory()
// 4. Make A reference (&A)
// 5. Set the new initializer of A
if (CuredDeclTy->isLValueReferenceType())
continue;
// Set Sema's Current DeclContext to the one we need
DeclContext* OldDC = m_Sema->CurContext;
m_Sema->CurContext = CuredDecl->getDeclContext();
ASTNodeInfo NewNode;
// 2.1 Get unique name for the LifetimeHandler instance and
// initialize it
std::string UniqueName;
createUniqueName(UniqueName);
IdentifierInfo& II = m_Context->Idents.get(UniqueName);
// Prepare the initialization Exprs.
// We want to call LifetimeHandler(DynamicExprInfo* ExprInfo,
// DeclContext DC,
// const char* type)
llvm::SmallVector<Expr*, 4> Inits;
// Add MyClass in LifetimeHandler unique(DynamicExprInfo* ExprInfo
// DC,
// "MyClass")
// Build Arg0 DynamicExprInfo
Inits.push_back(BuildDynamicExprInfo(E));
// Build Arg1 DeclContext* DC
QualType DCTy = m_Context->getTypeDeclType(m_DeclContextDecl);
Inits.push_back(ConstructCStyleCasePtrExpr(DCTy,
(uint64_t)m_CurDeclContext)
);
// Build Arg2 llvm::StringRef
// Get the type of the type without specifiers
PrintingPolicy Policy(m_Context->getLangOpts());
Policy.SuppressTagKeyword = 1;
std::string Res;
CuredDeclTy.getAsStringInternal(Res, Policy);
Inits.push_back(ConstructConstCharPtrExpr(Res.c_str()));
// 2.3 Create a variable from LifetimeHandler.
QualType HandlerTy = m_Context->getTypeDeclType(m_LifetimeHandlerDecl);
VarDecl* HandlerInstance = VarDecl::Create(*m_Context,
CuredDecl->getDeclContext(),
m_NoSLoc,
m_NoSLoc,
&II,
HandlerTy,
/*TypeSourceInfo**/0,
SC_None,
SC_None);
// 2.4 Call the best-match constructor. The method does overload
// resolution of the constructors and then initializes the new
// variable with it
ExprResult InitExprResult
= m_Sema->ActOnParenListExpr(m_NoSLoc,
m_NoELoc,
Inits);
m_Sema->AddInitializerToDecl(HandlerInstance,
InitExprResult.take(),
/*DirectInit*/ true,
/*TypeMayContainAuto*/ false);
// 2.5 Register the instance in the enclosing context
CuredDecl->getDeclContext()->addDecl(HandlerInstance);
NewNode.addNode(new (m_Context)
DeclStmt(DeclGroupRef(HandlerInstance),
m_NoSLoc,
m_NoELoc)
);
// 3.1 Build a DeclRefExpr, which holds the object
DeclRefExpr* MemberExprBase
= m_Sema->BuildDeclRefExpr(HandlerInstance,
HandlerTy,
VK_LValue,
m_NoSLoc
).takeAs<DeclRefExpr>();
// 3.2 Create a MemberExpr to getMemory from its declaration.
CXXScopeSpec SS;
LookupResult MemberLookup(*m_Sema, m_LHgetMemoryDecl->getDeclName(),
m_NoSLoc, Sema::LookupMemberName);
// Add the declaration as if doesn't exist.
// TODO: Check whether this is the most appropriate variant
MemberLookup.addDecl(m_LHgetMemoryDecl, AS_public);
MemberLookup.resolveKind();
Expr* MemberExpr = m_Sema->BuildMemberReferenceExpr(MemberExprBase,
HandlerTy,
m_NoSLoc,
/*IsArrow=*/false,
SS,
m_NoSLoc,
/*FirstQualifierInScope=*/0,
MemberLookup,
/*TemplateArgs=*/0
).take();
// 3.3 Build the actual call
Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext);
Expr* theCall = m_Sema->ActOnCallExpr(S,
MemberExpr,
m_NoSLoc,
MultiExprArg(),
m_NoELoc).take();
// Cast to the type LHS type
TypeSourceInfo* CuredDeclTSI
= m_Context->CreateTypeSourceInfo(m_Context->getPointerType(
CuredDeclTy));
Expr* Result = m_Sema->BuildCStyleCastExpr(m_NoSLoc,
CuredDeclTSI,
m_NoELoc,
theCall).take();
// Cast once more (dereference the cstyle cast)
Result = m_Sema->BuildUnaryOp(S, m_NoSLoc, UO_Deref, Result).take();
// 4.
CuredDecl->setType(m_Context->getLValueReferenceType(CuredDeclTy));
// 5.
CuredDecl->setInit(Result);
NewNode.addNode(Node);
// Restore Sema's original DeclContext
m_Sema->CurContext = OldDC;
return NewNode;
}
}
return ASTNodeInfo(Node, 0);
}
ASTNodeInfo EvaluateTSynthesizer::VisitExpr(Expr* Node) {
for (Stmt::child_iterator
I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
if (*I) {
ASTNodeInfo NewNode = Visit(*I);
assert(NewNode.hasSingleNode() &&
"Cannot have more than one stmt at that point");
if (NewNode.isForReplacement()) {
if (Expr *E = NewNode.getAs<Expr>())
// Assume void if still not escaped
*I = SubstituteUnknownSymbol(m_Context->VoidTy, E);
}
else {
*I = NewNode.getAsSingleNode();
}
}
}
return ASTNodeInfo(Node, 0);
}
ASTNodeInfo EvaluateTSynthesizer::VisitBinaryOperator(BinaryOperator* Node) {
ASTNodeInfo rhs = Visit(Node->getRHS());
ASTNodeInfo lhs = Visit(Node->getLHS());
assert((lhs.hasSingleNode() || rhs.hasSingleNode()) &&
"1:N replacements are not implemented yet!");
// Try find out the type of the left-hand-side of the operator
// and give the hint to the right-hand-side in order to replace the
// dependent symbol
if (Node->isAssignmentOp() &&
rhs.isForReplacement() &&
!lhs.isForReplacement()) {
if (Expr* LHSExpr = lhs.getAs<Expr>())
if (!IsArtificiallyDependent(LHSExpr)) {
const QualType LHSTy = LHSExpr->getType();
Node->setRHS(SubstituteUnknownSymbol(LHSTy, rhs.castTo<Expr>()));
Node->setTypeDependent(false);
Node->setValueDependent(false);
return ASTNodeInfo(Node, /*needs eval*/false);
}
}
return ASTNodeInfo(Node, IsArtificiallyDependent(Node));
}
ASTNodeInfo EvaluateTSynthesizer::VisitCallExpr(CallExpr* E) {
// FIXME: Maybe we need to handle the arguments
// ASTNodeInfo NewNode = Visit(E->getCallee());
return ASTNodeInfo (E, IsArtificiallyDependent(E));
}
ASTNodeInfo EvaluateTSynthesizer::VisitDeclRefExpr(DeclRefExpr* DRE) {
return ASTNodeInfo(DRE, IsArtificiallyDependent(DRE));
}
ASTNodeInfo EvaluateTSynthesizer::VisitDependentScopeDeclRefExpr(
DependentScopeDeclRefExpr* Node) {
return ASTNodeInfo(Node, IsArtificiallyDependent(Node));
}
// end StmtVisitor
// EvalBuilder
Expr* EvaluateTSynthesizer::SubstituteUnknownSymbol(const QualType InstTy,
Expr* SubTree,
bool ValuePrinterReq) {
assert(SubTree && "No subtree specified!");
//Build the arguments for the call
llvm::SmallVector<Expr*, 2> CallArgs;
// Build Arg0
Expr* Arg0 = BuildDynamicExprInfo(SubTree, ValuePrinterReq);
CallArgs.push_back(Arg0);
// Build Arg1
QualType DCTy = m_Context->getTypeDeclType(m_DeclContextDecl);
Expr* Arg1 = ConstructCStyleCasePtrExpr(DCTy, (uint64_t)m_CurDeclContext);
CallArgs.push_back(Arg1);
// Build the call
assert(Arg0 && Arg1 && "Arguments missing!");
CallExpr* EvalCall = BuildEvalCallExpr(InstTy, SubTree, CallArgs);
// Add substitution mapping
getSubstSymbolMap()[EvalCall] = SubTree;
return EvalCall;
}
Expr* EvaluateTSynthesizer::BuildDynamicExprInfo(Expr* SubTree,
bool ValuePrinterReq) {
// 1. Get the expression containing @-s and get the variable addresses
std::string Template;
llvm::SmallVector<DeclRefExpr*, 4> Addresses;
llvm::raw_string_ostream OS(Template);
const PrintingPolicy& Policy = m_Context->getPrintingPolicy();
StmtPrinterHelper helper(Policy, Addresses, m_Sema);
// In case when we print non paren inits like int i = h->Draw();
// not int i(h->Draw()). This simplifies the LifetimeHandler's
// constructor, there we don't need to add parenthesis while
// wrapping the expression.
if (!isa<ParenListExpr>(SubTree))
OS << '(';
SubTree->printPretty(OS, &helper, Policy);
if (!isa<ParenListExpr>(SubTree))
OS << ')';
OS.flush();
// 2. Build the template
Expr* ExprTemplate = ConstructConstCharPtrExpr(Template.c_str());
// 3. Build the array of addresses
QualType VarAddrTy = m_Sema->BuildArrayType(m_Context->VoidPtrTy,
ArrayType::Normal,
/*ArraySize*/0,
Qualifiers(),
m_NoRange,
DeclarationName() );
llvm::SmallVector<Expr*, 2> Inits;
Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext);
for (unsigned int i = 0; i < Addresses.size(); ++i) {
Expr* UnOp
= m_Sema->BuildUnaryOp(S, m_NoSLoc, UO_AddrOf, Addresses[i]).take();
m_Sema->ImpCastExprToType(UnOp,
m_Context->getPointerType(m_Context->VoidPtrTy),
CK_BitCast);
Inits.push_back(UnOp);
}
// We need valid source locations to avoid assert(InitList.isExplicit()...)
InitListExpr* ILE = m_Sema->ActOnInitList(m_NoSLoc,
Inits,
m_NoELoc).takeAs<InitListExpr>();
Expr* ExprAddresses = m_Sema->BuildCompoundLiteralExpr(m_NoSLoc,
m_Context->CreateTypeSourceInfo(VarAddrTy),
m_NoELoc,
ILE).take();
assert (ExprAddresses && "Could not build the void* array");
m_Sema->ImpCastExprToType(ExprAddresses,
m_Context->getPointerType(m_Context->VoidPtrTy),
CK_ArrayToPointerDecay);
// Is the result of the expression to be printed or not
Expr* VPReq = 0;
if (ValuePrinterReq)
VPReq = m_Sema->ActOnCXXBoolLiteral(m_NoSLoc, tok::kw_true).take();
else
VPReq = m_Sema->ActOnCXXBoolLiteral(m_NoSLoc, tok::kw_false).take();
llvm::SmallVector<Expr*, 4> CtorArgs;
CtorArgs.push_back(ExprTemplate);
CtorArgs.push_back(ExprAddresses);
CtorArgs.push_back(VPReq);
// 4. Call the constructor
QualType ExprInfoTy = m_Context->getTypeDeclType(m_DynamicExprInfoDecl);
ExprResult Initializer = m_Sema->ActOnParenListExpr(m_NoSLoc, m_NoELoc,
CtorArgs);
Expr* Result = m_Sema->BuildCXXNew(m_NoSLoc,
/*UseGlobal=*/false,
m_NoSLoc,
/*PlacementArgs=*/MultiExprArg(),
m_NoELoc,
m_NoRange,
ExprInfoTy,
m_Context->CreateTypeSourceInfo(ExprInfoTy),
/*ArraySize=*/0,
//BuildCXXNew depends on the SLoc to be
//valid!
// TODO: Propose a patch in clang
m_NoRange,
Initializer.take(),
/*TypeMayContainAuto*/false
).take();
return Result;
}
Expr* EvaluateTSynthesizer::ConstructCStyleCasePtrExpr(QualType Ty,
uint64_t Ptr) {
if (!Ty->isPointerType())
Ty = m_Context->getPointerType(Ty);
TypeSourceInfo* TSI = m_Context->CreateTypeSourceInfo(Ty);
const llvm::APInt Addr(8 * sizeof(void *), Ptr);
Expr* Result = IntegerLiteral::Create(*m_Context,
Addr,
m_Context->UnsignedLongTy,
m_NoSLoc);
Result = m_Sema->BuildCStyleCastExpr(m_NoSLoc,
TSI,
m_NoELoc,
Result).take();
return Result;
}
Expr* EvaluateTSynthesizer::ConstructConstCharPtrExpr(const char* Val) {
const QualType CChar = m_Context->CharTy.withConst();
llvm::StringRef Value(Val);
unsigned bitSize = m_Context->getTypeSize(m_Context->VoidPtrTy);
llvm::APInt ArraySize(bitSize, Value.size() + 1);
const QualType CCArray = m_Context->getConstantArrayType(CChar,
ArraySize,
ArrayType::Normal,
/*IndexTypeQuals=*/0);
StringLiteral::StringKind Kind = StringLiteral::Ascii;
Expr* Result = StringLiteral::Create(*m_Context,
Value,
Kind,
/*Pascal=*/false,
CCArray,
m_NoSLoc);
m_Sema->ImpCastExprToType(Result,
m_Context->getPointerType(CChar),
CK_ArrayToPointerDecay);
return Result;
}
// Here is the test Eval function specialization. Here the CallExpr to the
// function is created.
CallExpr*
EvaluateTSynthesizer::BuildEvalCallExpr(const QualType InstTy,
Expr* SubTree,
llvm::SmallVector<Expr*, 2>& CallArgs) {
// Set up new context for the new FunctionDecl
DeclContext* PrevContext = m_Sema->CurContext;
m_Sema->CurContext = m_EvalDecl->getDeclContext();
// Create template arguments
Sema::InstantiatingTemplate Inst(*m_Sema, m_NoSLoc, m_EvalDecl);
TemplateArgument Arg(InstTy);
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, &Arg, 1U);
// Substitute the declaration of the templated function, with the
// specified template argument
Decl* D = m_Sema->SubstDecl(m_EvalDecl,
m_EvalDecl->getDeclContext(),
MultiLevelTemplateArgumentList(TemplateArgs));
FunctionDecl* Fn = dyn_cast<FunctionDecl>(D);
// Creates new body of the substituted declaration
m_Sema->InstantiateFunctionDefinition(Fn->getLocation(), Fn, true, true);
m_Sema->CurContext = PrevContext;
const FunctionProtoType* FPT = Fn->getType()->getAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
QualType FnTy = m_Context->getFunctionType(Fn->getResultType(),
FPT->arg_type_begin(),
FPT->getNumArgs(),
EPI);
DeclRefExpr* DRE = m_Sema->BuildDeclRefExpr(Fn,
FnTy,
VK_RValue,
m_NoSLoc
).takeAs<DeclRefExpr>();
// TODO: Figure out a way to avoid passing in wrong source locations
// of the symbol being replaced. This is important when we calculate the
// size of the memory buffers and may lead to creation of wrong wrappers.
Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext);
CallExpr* EvalCall = m_Sema->ActOnCallExpr(S,
DRE,
SubTree->getLocStart(),
CallArgs,
SubTree->getLocEnd()
).takeAs<CallExpr>();
assert (EvalCall && "Cannot create call to Eval");
return EvalCall;
}
// end EvalBuilder
// Helpers
bool EvaluateTSynthesizer::ShouldVisit(Decl* D) {
while (true) {
if (isa<TemplateTemplateParmDecl>(D))
return false;
if (isa<ClassTemplateDecl>(D))
return false;
if (isa<FriendTemplateDecl>(D))
return false;
if (isa<ClassTemplatePartialSpecializationDecl>(D))
return false;
if (CXXRecordDecl* CXX = dyn_cast<CXXRecordDecl>(D)) {
if (CXX->getDescribedClassTemplate())
return false;
}
if (CXXMethodDecl* CXX = dyn_cast<CXXMethodDecl>(D)) {
if (CXX->getDescribedFunctionTemplate())
return false;
}
if (isa<TranslationUnitDecl>(D)) {
break;
}
if (DeclContext* DC = D->getDeclContext())
if (!(D = dyn_cast<Decl>(DC)))
break;
}
return true;
}
bool EvaluateTSynthesizer::IsArtificiallyDependent(Expr* Node) {
if (!Node->isValueDependent() || !Node->isTypeDependent())
return false;
DeclContext* DC = m_CurDeclContext;
while (DC) {
if (DC->isDependentContext())
return false;
DC = DC->getParent();
}
return true;
}
bool EvaluateTSynthesizer::GetChildren(ASTNodes& Children, Stmt* Node) {
if (std::distance(Node->child_begin(), Node->child_end()) < 1)
return false;
for (Stmt::child_iterator
I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
Children.push_back(*I);
}
return true;
}
void EvaluateTSynthesizer::createUniqueName(std::string& out) {
out = "autoGenName";
llvm::raw_string_ostream(out) << m_UniqueNameCounter++;
}
// end Helpers
} // end namespace cling