blob: d94994b194376c2c6807faf29d38728ce6cd4fd6 [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
Ted Kremenek1309f9a2010-01-25 04:41:41 +000014#include "clang/Checker/PathSensitive/CheckerVisitor.h"
15#include "clang/Checker/PathSensitive/GRState.h"
Ted Kremenek97053092010-01-26 22:59:55 +000016#include "clang/Checker/Checkers/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 Xu66847a22009-09-11 04:13:42 +000022public:
Zhongxing Xu3ff84812009-12-23 08:56:18 +000023 static void *getTag() {
24 static int x;
25 return &x;
26 }
Zhongxing Xu66847a22009-09-11 04:13:42 +000027
Zhongxing Xu3ff84812009-12-23 08:56:18 +000028 virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
Zhongxing Xu598278b2009-12-24 02:25:21 +000029 virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng);
Zhongxing Xu66847a22009-09-11 04:13:42 +000030};
Zhongxing Xu66847a22009-09-11 04:13:42 +000031}
32
Zhongxing Xu3ff84812009-12-23 08:56:18 +000033void 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);
Zhongxing Xu62d399e2009-12-24 03:34:38 +000041
Zhongxing Xu3ff84812009-12-23 08:56:18 +000042 const FunctionDecl *FD = L.getAsFunctionDecl();
Zhongxing Xuc9f4af62009-10-13 02:36:42 +000043 if (!FD)
Zhongxing Xu3ff84812009-12-23 08:56:18 +000044 return false;
45
46 if (!FD->isThisDeclarationADefinition())
47 return false;
Zhongxing Xuc9f4af62009-10-13 02:36:42 +000048
Zhongxing Xu62d399e2009-12-24 03:34:38 +000049 GRStmtNodeBuilder &Builder = C.getNodeBuilder();
Zhongxing Xuc9f4af62009-10-13 02:36:42 +000050 // Make a new LocationContext.
Zhongxing Xu3ff84812009-12-23 08:56:18 +000051 const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD,
Zhongxing Xu62d399e2009-12-24 03:34:38 +000052 C.getPredecessor()->getLocationContext(), CE,
53 Builder.getBlock(), Builder.getIndex());
Zhongxing Xuc9f4af62009-10-13 02:36:42 +000054
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
Zhongxing Xu3ff84812009-12-23 08:56:18 +000067 state = C.getStoreManager().EnterStackFrame(state, LocCtx);
Zhongxing Xuc9f4af62009-10-13 02:36:42 +000068 // This is a hack. We really should not use the GRStmtNodeBuilder.
Zhongxing Xu3ff84812009-12-23 08:56:18 +000069 bool isNew;
70 GRExprEngine &Eng = C.getEngine();
71 ExplodedNode *Pred = C.getPredecessor();
Zhongxing Xu62d399e2009-12-24 03:34:38 +000072
Zhongxing Xu3ff84812009-12-23 08:56:18 +000073
74 ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew);
75 SuccN->addPredecessor(Pred, Eng.getGraph());
76 C.getNodeBuilder().Deferred.erase(Pred);
77
Zhongxing Xuc9f4af62009-10-13 02:36:42 +000078 if (isNew)
79 Builder.getWorkList()->Enqueue(SuccN);
80
81 Builder.HasGeneratedNode = true;
Zhongxing Xu3ff84812009-12-23 08:56:18 +000082
83 return true;
Zhongxing Xu66847a22009-09-11 04:13:42 +000084}
Zhongxing Xu3ff84812009-12-23 08:56:18 +000085
Zhongxing Xu598278b2009-12-24 02:25:21 +000086void 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
Zhongxing Xu598278b2009-12-24 02:25:21 +0000105 // When creating the new work list unit, increment the statement index to
106 // point to the statement after the CallExpr.
107 if (isNew)
Zhongxing Xu62d399e2009-12-24 03:34:38 +0000108 B.getWorkList().Enqueue(Succ,
109 *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()),
110 LocCtx->getIndex() + 1);
Zhongxing Xu598278b2009-12-24 02:25:21 +0000111
112 B.HasGeneratedNode = true;
113}