BodyFarm.cpp revision a43df9539644bf1c258e12710cd69d79b0b078cd
1//== BodyFarm.cpp  - Factory for conjuring up fake bodies ----------*- C++ -*-//
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// BodyFarm is a factory for creating faux implementations for functions/methods
11// for analysis purposes.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/ADT/StringSwitch.h"
16#include "clang/AST/ASTContext.h"
17#include "clang/AST/Expr.h"
18#include "clang/AST/Decl.h"
19#include "BodyFarm.h"
20
21using namespace clang;
22
23typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
24
25
26/// Create a fake body for dispatch_sync.
27static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
28  // Check if we have at least two parameters.
29  if (D->param_size() != 2)
30    return 0;
31
32  // Check if the second parameter is a block.
33  const ParmVarDecl *PV = D->getParamDecl(1);
34  QualType Ty = PV->getType();
35  const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
36  if (!BPT)
37    return 0;
38
39  // Check if the block pointer type takes no arguments and
40  // returns void.
41  const FunctionProtoType *FT =
42    BPT->getPointeeType()->getAs<FunctionProtoType>();
43  if (!FT || !FT->getResultType()->isVoidType()  ||
44      FT->getNumArgs() != 0)
45    return 0;
46
47  // Everything checks out.  Create a fake body that just calls the block.
48  // This is basically just an AST dump of:
49  //
50  // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
51  //   block();
52  // }
53  //
54  DeclRefExpr *DR = DeclRefExpr::CreateEmpty(C, false, false, false, false);
55  DR->setDecl(const_cast<ParmVarDecl*>(PV));
56  DR->setValueKind(VK_LValue);
57  ImplicitCastExpr *ICE = ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
58                                                   DR, 0, VK_RValue);
59  CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy,
60                                  VK_RValue, SourceLocation());
61  return CE;
62}
63
64Stmt *BodyFarm::getBody(const FunctionDecl *D) {
65  D = D->getCanonicalDecl();
66
67  llvm::Optional<Stmt *> &Val = Bodies[D];
68  if (Val.hasValue())
69    return Val.getValue();
70
71  Val = 0;
72
73  if (D->getIdentifier() == 0)
74    return 0;
75
76  StringRef Name = D->getName();
77  if (Name.empty())
78    return 0;
79
80  FunctionFarmer FF =
81    llvm::StringSwitch<FunctionFarmer>(Name)
82      .Case("dispatch_sync", create_dispatch_sync)
83      .Default(NULL);
84
85  if (FF) {
86    Val = FF(C, D);
87  }
88
89  return Val.getValue();
90}
91
92