// 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::VisitBinaryOperator(BinaryOperator* Node) { ASTNodeInfo rhs = Visit(Node->getRHS()); ASTNodeInfo lhs; 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::VisitCompoundStmt(CompoundStmt* Node) { ++m_NestedCompoundStmts; 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 this was the last or the last is not null stmt, means that // we need to value print. // If this is in a wrapper function's body then look for VP. if (FunctionDecl* FD = dyn_cast<FunctionDecl>(m_CurDeclContext)) valuePrinterReq = m_NestedCompoundStmts < 2 && utils::Analyze::IsWrapper(FD) && ((it+1) == Children.end() || ((it+2) == Children.end() && !isa<NullStmt>(*(it+1)))); // 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()); --m_NestedCompoundStmts; 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::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::VisitDependentScopeDeclRefExpr( DependentScopeDeclRefExpr* Node) { return ASTNodeInfo(Node, IsArtificiallyDependent(Node)); }
ASTNodeInfo EvaluateTSynthesizer::VisitDeclRefExpr(DeclRefExpr* DRE) { return ASTNodeInfo(DRE, IsArtificiallyDependent(DRE)); }
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::VisitCXXDeleteExpr(CXXDeleteExpr* Node) { ASTNodeInfo deleteArg = Visit(Node->getArgument()); return ASTNodeInfo(Node, /*needs eval*/deleteArg.isForReplacement()); }
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) // Interpreter* interp) llvm::SmallVector<Expr*, 4> Inits; // Add MyClass in LifetimeHandler unique(DynamicExprInfo* ExprInfo // DC, // "MyClass" // Interpreter* Interp) // Build Arg0 DynamicExprInfo Inits.push_back(BuildDynamicExprInfo(E)); // Build Arg1 DeclContext* DC QualType DCTy = m_Context->getTypeDeclType(m_DeclContextDecl); Inits.push_back(utils::Synthesize::CStyleCastPtrExpr(m_Sema, 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())); // Build Arg3 cling::Interpreter CXXScopeSpec CXXSS; DeclarationNameInfo NameInfo(m_gCling->getDeclName(), m_gCling->getLocStart()); Expr* gClingDRE = m_Sema->BuildDeclarationNameExpr(CXXSS, NameInfo ,m_gCling).take(); Inits.push_back(gClingDRE); // 2.3 Create a variable from LifetimeHandler. QualType HandlerTy = m_Context->getTypeDeclType(m_LifetimeHandlerDecl); TypeSourceInfo* TSI = m_Context->getTrivialTypeSourceInfo(HandlerTy, m_NoSLoc); VarDecl* HandlerInstance = VarDecl::Create(*m_Context, CuredDecl->getDeclContext(), m_NoSLoc, m_NoSLoc, &II, HandlerTy, TSI, 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 Expr* Result = utils::Synthesize::CStyleCastPtrExpr(m_Sema, CuredDeclTy, theCall); // 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); }