blob: d94994b194376c2c6807faf29d38728ce6cd4fd6 [file] [log] [blame]
Shih-wei Liaof8fd82b2010-02-10 11:10:31 -08001//===--- 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
14#include "clang/Checker/PathSensitive/CheckerVisitor.h"
15#include "clang/Checker/PathSensitive/GRState.h"
16#include "clang/Checker/Checkers/LocalCheckers.h"
17
18using namespace clang;
19
20namespace {
21class CallInliner : public Checker {
22public:
23 static void *getTag() {
24 static int x;
25 return &x;
26 }
27
28 virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
29 virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng);
30};
31}
32
33void clang::RegisterCallInliner(GRExprEngine &Eng) {
34 Eng.registerCheck(new CallInliner());
35}
36
37bool CallInliner::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
38 const GRState *state = C.getState();
39 const Expr *Callee = CE->getCallee();
40 SVal L = state->getSVal(Callee);
41
42 const FunctionDecl *FD = L.getAsFunctionDecl();
43 if (!FD)
44 return false;
45
46 if (!FD->isThisDeclarationADefinition())
47 return false;
48
49 GRStmtNodeBuilder &Builder = C.getNodeBuilder();
50 // Make a new LocationContext.
51 const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD,
52 C.getPredecessor()->getLocationContext(), CE,
53 Builder.getBlock(), Builder.getIndex());
54
55 CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry());
56
57 assert (Entry->empty() && "Entry block must be empty.");
58
59 assert (Entry->succ_size() == 1 && "Entry block must have 1 successor.");
60
61 // Get the solitary successor.
62 CFGBlock const *SuccB = *(Entry->succ_begin());
63
64 // Construct an edge representing the starting location in the function.
65 BlockEdge Loc(Entry, SuccB, LocCtx);
66
67 state = C.getStoreManager().EnterStackFrame(state, LocCtx);
68 // This is a hack. We really should not use the GRStmtNodeBuilder.
69 bool isNew;
70 GRExprEngine &Eng = C.getEngine();
71 ExplodedNode *Pred = C.getPredecessor();
72
73
74 ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew);
75 SuccN->addPredecessor(Pred, Eng.getGraph());
76 C.getNodeBuilder().Deferred.erase(Pred);
77
78 if (isNew)
79 Builder.getWorkList()->Enqueue(SuccN);
80
81 Builder.HasGeneratedNode = true;
82
83 return true;
84}
85
86void CallInliner::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
87 GRExprEngine &Eng) {
88 const GRState *state = B.getState();
89 ExplodedNode *Pred = B.getPredecessor();
90 const StackFrameContext *LocCtx =
91 cast<StackFrameContext>(Pred->getLocationContext());
92
93 const Stmt *CE = LocCtx->getCallSite();
94
95 // Check if this is the top level stack frame.
96 if (!LocCtx->getParent())
97 return;
98
99 PostStmt NodeLoc(CE, LocCtx->getParent());
100
101 bool isNew;
102 ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew);
103 Succ->addPredecessor(Pred, Eng.getGraph());
104
105 // When creating the new work list unit, increment the statement index to
106 // point to the statement after the CallExpr.
107 if (isNew)
108 B.getWorkList().Enqueue(Succ,
109 *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()),
110 LocCtx->getIndex() + 1);
111
112 B.HasGeneratedNode = true;
113}