blob: 618d82354ed7d36d48db485834cb748653fc2b94 [file] [log] [blame]
Zhongxing Xu66847a22009-09-11 04:13:42 +00001//===--- CallInliner.cpp - Transfer function that inlines callee ----------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the callee inlining transfer function.
11//
12//===----------------------------------------------------------------------===//
13
Zhongxing Xu3ff84812009-12-23 08:56:18 +000014#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
15#include "clang/Analysis/PathSensitive/GRState.h"
16#include "clang/Analysis/LocalCheckers.h"
Zhongxing Xu66847a22009-09-11 04:13:42 +000017
18using namespace clang;
19
20namespace {
Zhongxing Xu3ff84812009-12-23 08:56:18 +000021class CallInliner : public Checker {
Zhongxing Xu598278b2009-12-24 02:25:21 +000022
23 /// CallSitePosition - Map the call site to its CFG block and stmt index. This
24 /// is used when exiting from a callee.
25 llvm::DenseMap<const Stmt *, std::pair<CFGBlock*,unsigned> > CallSitePosition;
26
Zhongxing Xu66847a22009-09-11 04:13:42 +000027public:
Zhongxing Xu3ff84812009-12-23 08:56:18 +000028 static void *getTag() {
29 static int x;
30 return &x;
31 }
Zhongxing Xu66847a22009-09-11 04:13:42 +000032
Zhongxing Xu3ff84812009-12-23 08:56:18 +000033 virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu598278b2009-12-24 02:25:21 +000034 virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng);
Zhongxing Xu66847a22009-09-11 04:13:42 +000035};
Zhongxing Xu66847a22009-09-11 04:13:42 +000036}
37
Zhongxing Xu3ff84812009-12-23 08:56:18 +000038void clang::RegisterCallInliner(GRExprEngine &Eng) {
39 Eng.registerCheck(new CallInliner());
40}
41
42bool CallInliner::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
43 const GRState *state = C.getState();
44 const Expr *Callee = CE->getCallee();
45 SVal L = state->getSVal(Callee);
46
47 const FunctionDecl *FD = L.getAsFunctionDecl();
Zhongxing Xuc9f4af62009-10-13 02:36:42 +000048 if (!FD)
Zhongxing Xu3ff84812009-12-23 08:56:18 +000049 return false;
50
51 if (!FD->isThisDeclarationADefinition())
52 return false;
Zhongxing Xuc9f4af62009-10-13 02:36:42 +000053
54 // Make a new LocationContext.
Zhongxing Xu3ff84812009-12-23 08:56:18 +000055 const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD,
56 C.getPredecessor()->getLocationContext(), CE);
Zhongxing Xuc9f4af62009-10-13 02:36:42 +000057
58 CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry());
59
60 assert (Entry->empty() && "Entry block must be empty.");
61
62 assert (Entry->succ_size() == 1 && "Entry block must have 1 successor.");
63
64 // Get the solitary successor.
65 CFGBlock const *SuccB = *(Entry->succ_begin());
66
67 // Construct an edge representing the starting location in the function.
68 BlockEdge Loc(Entry, SuccB, LocCtx);
69
Zhongxing Xu3ff84812009-12-23 08:56:18 +000070 state = C.getStoreManager().EnterStackFrame(state, LocCtx);
Zhongxing Xuc9f4af62009-10-13 02:36:42 +000071 // This is a hack. We really should not use the GRStmtNodeBuilder.
Zhongxing Xu3ff84812009-12-23 08:56:18 +000072 bool isNew;
73 GRExprEngine &Eng = C.getEngine();
74 ExplodedNode *Pred = C.getPredecessor();
75 GRStmtNodeBuilder &Builder = C.getNodeBuilder();
76
77 ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew);
78 SuccN->addPredecessor(Pred, Eng.getGraph());
79 C.getNodeBuilder().Deferred.erase(Pred);
80
Zhongxing Xuc9f4af62009-10-13 02:36:42 +000081 if (isNew)
82 Builder.getWorkList()->Enqueue(SuccN);
83
84 Builder.HasGeneratedNode = true;
Zhongxing Xu3ff84812009-12-23 08:56:18 +000085
Zhongxing Xu598278b2009-12-24 02:25:21 +000086 // Record the call site position.
87 CallSitePosition[CE] = std::make_pair(Builder.getBlock(), Builder.getIndex());
Zhongxing Xu3ff84812009-12-23 08:56:18 +000088 return true;
Zhongxing Xu66847a22009-09-11 04:13:42 +000089}
Zhongxing Xu3ff84812009-12-23 08:56:18 +000090
Zhongxing Xu598278b2009-12-24 02:25:21 +000091void CallInliner::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
92 GRExprEngine &Eng) {
93 const GRState *state = B.getState();
94 ExplodedNode *Pred = B.getPredecessor();
95 const StackFrameContext *LocCtx =
96 cast<StackFrameContext>(Pred->getLocationContext());
97
98 const Stmt *CE = LocCtx->getCallSite();
99
100 // Check if this is the top level stack frame.
101 if (!LocCtx->getParent())
102 return;
103
104 PostStmt NodeLoc(CE, LocCtx->getParent());
105
106 bool isNew;
107 ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew);
108 Succ->addPredecessor(Pred, Eng.getGraph());
109
110 assert(CallSitePosition.find(CE) != CallSitePosition.end());
111
112 // When creating the new work list unit, increment the statement index to
113 // point to the statement after the CallExpr.
114 if (isNew)
115 B.getWorkList().Enqueue(Succ, *CallSitePosition[CE].first,
116 CallSitePosition[CE].second + 1);
117
118 B.HasGeneratedNode = true;
119}