slang_rs_object_ref_count.cpp revision e2597ac5a8ba7a45a1d5f342973cd43a3a1932cf
1709a0978ae141198018ca9769f8d96292a8928e6Jason Sams/*
2709a0978ae141198018ca9769f8d96292a8928e6Jason Sams * Copyright 2010, The Android Open Source Project
3709a0978ae141198018ca9769f8d96292a8928e6Jason Sams *
4709a0978ae141198018ca9769f8d96292a8928e6Jason Sams * Licensed under the Apache License, Version 2.0 (the "License");
5709a0978ae141198018ca9769f8d96292a8928e6Jason Sams * you may not use this file except in compliance with the License.
6709a0978ae141198018ca9769f8d96292a8928e6Jason Sams * You may obtain a copy of the License at
7709a0978ae141198018ca9769f8d96292a8928e6Jason Sams *
8709a0978ae141198018ca9769f8d96292a8928e6Jason Sams *     http://www.apache.org/licenses/LICENSE-2.0
9709a0978ae141198018ca9769f8d96292a8928e6Jason Sams *
10709a0978ae141198018ca9769f8d96292a8928e6Jason Sams * Unless required by applicable law or agreed to in writing, software
11709a0978ae141198018ca9769f8d96292a8928e6Jason Sams * distributed under the License is distributed on an "AS IS" BASIS,
12709a0978ae141198018ca9769f8d96292a8928e6Jason Sams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13709a0978ae141198018ca9769f8d96292a8928e6Jason Sams * See the License for the specific language governing permissions and
14709a0978ae141198018ca9769f8d96292a8928e6Jason Sams * limitations under the License.
15709a0978ae141198018ca9769f8d96292a8928e6Jason Sams */
16709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
17709a0978ae141198018ca9769f8d96292a8928e6Jason Sams#include "slang_rs_object_ref_count.h"
18709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
19709a0978ae141198018ca9769f8d96292a8928e6Jason Sams#include <list>
20709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
21709a0978ae141198018ca9769f8d96292a8928e6Jason Sams#include "clang/AST/DeclGroup.h"
22709a0978ae141198018ca9769f8d96292a8928e6Jason Sams#include "clang/AST/Expr.h"
2325e3af55a43faddced1a9931574dfdc3cc8ad8fdStephen Hines#include "clang/AST/NestedNameSpecifier.h"
2429809d1f95d4cd4cbc6b2f9384b3321759691e13Tim Murray#include "clang/AST/OperationKinds.h"
2529809d1f95d4cd4cbc6b2f9384b3321759691e13Tim Murray#include "clang/AST/Stmt.h"
2625e3af55a43faddced1a9931574dfdc3cc8ad8fdStephen Hines#include "clang/AST/StmtVisitor.h"
2725e3af55a43faddced1a9931574dfdc3cc8ad8fdStephen Hines
28709a0978ae141198018ca9769f8d96292a8928e6Jason Sams#include "slang_assert.h"
29709a0978ae141198018ca9769f8d96292a8928e6Jason Sams#include "slang_rs.h"
30709a0978ae141198018ca9769f8d96292a8928e6Jason Sams#include "slang_rs_ast_replace.h"
31709a0978ae141198018ca9769f8d96292a8928e6Jason Sams#include "slang_rs_export_type.h"
32709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
33709a0978ae141198018ca9769f8d96292a8928e6Jason Samsnamespace slang {
34709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
359ab5094dd32352b33e251e540934f6e814c5fa5bJean-Luc Brouilletclang::FunctionDecl *RSObjectRefCount::
369ab5094dd32352b33e251e540934f6e814c5fa5bJean-Luc Brouillet    RSSetObjectFD[RSExportPrimitiveType::LastRSObjectType -
379ab5094dd32352b33e251e540934f6e814c5fa5bJean-Luc Brouillet                  RSExportPrimitiveType::FirstRSObjectType + 1];
389ab5094dd32352b33e251e540934f6e814c5fa5bJean-Luc Brouilletclang::FunctionDecl *RSObjectRefCount::
39709a0978ae141198018ca9769f8d96292a8928e6Jason Sams    RSClearObjectFD[RSExportPrimitiveType::LastRSObjectType -
40709a0978ae141198018ca9769f8d96292a8928e6Jason Sams                    RSExportPrimitiveType::FirstRSObjectType + 1];
41709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
42709a0978ae141198018ca9769f8d96292a8928e6Jason Samsvoid RSObjectRefCount::GetRSRefCountingFunctions(clang::ASTContext &C) {
43709a0978ae141198018ca9769f8d96292a8928e6Jason Sams  for (unsigned i = 0;
44709a0978ae141198018ca9769f8d96292a8928e6Jason Sams       i < (sizeof(RSClearObjectFD) / sizeof(clang::FunctionDecl*));
45709a0978ae141198018ca9769f8d96292a8928e6Jason Sams       i++) {
46709a0978ae141198018ca9769f8d96292a8928e6Jason Sams    RSSetObjectFD[i] = NULL;
4780ef693674f69c0343c41564e30f80e7fb513b60Chris Wailes    RSClearObjectFD[i] = NULL;
48709a0978ae141198018ca9769f8d96292a8928e6Jason Sams  }
499ed79105cc6a8dbfaf959875249f36022cc2c798Chris Wailes
50dc0d8f7c0f1f43f25c34fbc04656ad578f6e953bPirama Arumuga Nainar  clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
51110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams
52110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams  for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(),
53110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams          E = TUDecl->decls_end(); I != E; I++) {
54dc0d8f7c0f1f43f25c34fbc04656ad578f6e953bPirama Arumuga Nainar    if ((I->getKind() >= clang::Decl::firstFunction) &&
55110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams        (I->getKind() <= clang::Decl::lastFunction)) {
56110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams      clang::FunctionDecl *FD = static_cast<clang::FunctionDecl*>(*I);
57709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
58709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      // points to RSSetObjectFD or RSClearObjectFD
59005113297b19ed256b6db9d6bc293ed9266899fcStephen Hines      clang::FunctionDecl **RSObjectFD;
6044bef6fba6244292b751387f3d6c31cca96c28adChris Wailes
61709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      if (FD->getName() == "rsSetObject") {
62709a0978ae141198018ca9769f8d96292a8928e6Jason Sams        slangAssert((FD->getNumParams() == 2) &&
63709a0978ae141198018ca9769f8d96292a8928e6Jason Sams                    "Invalid rsSetObject function prototype (# params)");
64709a0978ae141198018ca9769f8d96292a8928e6Jason Sams        RSObjectFD = RSSetObjectFD;
65f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes      } else if (FD->getName() == "rsClearObject") {
66f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes        slangAssert((FD->getNumParams() == 1) &&
6717e3cdc24776d8fdbf1ce16287b9b4dcd516708fJason Sams                    "Invalid rsClearObject function prototype (# params)");
68f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes        RSObjectFD = RSClearObjectFD;
69f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes      } else {
70f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes        continue;
71f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes      }
72f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes
73709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
74f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes      clang::QualType PVT = PVD->getOriginalType();
75f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes      // The first parameter must be a pointer like rs_allocation*
76f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes      slangAssert(PVT->isPointerType() &&
77f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes          "Invalid rs{Set,Clear}Object function prototype (pointer param)");
78f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes
79f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes      // The rs object type passed to the FD
80f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes      clang::QualType RST = PVT->getPointeeType();
81709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      RSExportPrimitiveType::DataType DT =
82709a0978ae141198018ca9769f8d96292a8928e6Jason Sams          RSExportPrimitiveType::GetRSSpecificType(RST.getTypePtr());
83709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      slangAssert(RSExportPrimitiveType::IsRSObjectType(DT)
84709a0978ae141198018ca9769f8d96292a8928e6Jason Sams             && "must be RS object type");
859c64239ebbfa4170190ede812e69150035e008e0Tim Murray
86709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      RSObjectFD[(DT - RSExportPrimitiveType::FirstRSObjectType)] = FD;
87ac8d146a41f18afad5314ac8af440d6aedbe20bfStephen Hines    }
88709a0978ae141198018ca9769f8d96292a8928e6Jason Sams  }
89709a0978ae141198018ca9769f8d96292a8928e6Jason Sams}
90709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
91709a0978ae141198018ca9769f8d96292a8928e6Jason Samsnamespace {
92709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
93709a0978ae141198018ca9769f8d96292a8928e6Jason Sams// This function constructs a new CompoundStmt from the input StmtList.
94709a0978ae141198018ca9769f8d96292a8928e6Jason Samsstatic clang::CompoundStmt* BuildCompoundStmt(clang::ASTContext &C,
95709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      std::list<clang::Stmt*> &StmtList, clang::SourceLocation Loc) {
96709a0978ae141198018ca9769f8d96292a8928e6Jason Sams  unsigned NewStmtCount = StmtList.size();
974b3c34e6833e39bc89c2128002806b654b8e623dChris Wailes  unsigned CompoundStmtCount = 0;
984b3c34e6833e39bc89c2128002806b654b8e623dChris Wailes
994b3c34e6833e39bc89c2128002806b654b8e623dChris Wailes  clang::Stmt **CompoundStmtList;
1004b3c34e6833e39bc89c2128002806b654b8e623dChris Wailes  CompoundStmtList = new clang::Stmt*[NewStmtCount];
101709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
102709a0978ae141198018ca9769f8d96292a8928e6Jason Sams  std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
103709a0978ae141198018ca9769f8d96292a8928e6Jason Sams  std::list<clang::Stmt*>::const_iterator E = StmtList.end();
104709a0978ae141198018ca9769f8d96292a8928e6Jason Sams  for ( ; I != E; I++) {
105709a0978ae141198018ca9769f8d96292a8928e6Jason Sams    CompoundStmtList[CompoundStmtCount++] = *I;
106709a0978ae141198018ca9769f8d96292a8928e6Jason Sams  }
107709a0978ae141198018ca9769f8d96292a8928e6Jason Sams  slangAssert(CompoundStmtCount == NewStmtCount);
108dc0d8f7c0f1f43f25c34fbc04656ad578f6e953bPirama Arumuga Nainar
109709a0978ae141198018ca9769f8d96292a8928e6Jason Sams  clang::CompoundStmt *CS = new(C) clang::CompoundStmt(C,
110709a0978ae141198018ca9769f8d96292a8928e6Jason Sams                                                       CompoundStmtList,
111709a0978ae141198018ca9769f8d96292a8928e6Jason Sams                                                       CompoundStmtCount,
112709a0978ae141198018ca9769f8d96292a8928e6Jason Sams                                                       Loc,
113dc0d8f7c0f1f43f25c34fbc04656ad578f6e953bPirama Arumuga Nainar                                                       Loc);
114709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
115110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams  delete [] CompoundStmtList;
11640e35cdbe217ec8bf9fc3c69873c7d62fc14158fJean-Luc Brouillet
11740e35cdbe217ec8bf9fc3c69873c7d62fc14158fJean-Luc Brouillet  return CS;
1189ab5094dd32352b33e251e540934f6e814c5fa5bJean-Luc Brouillet}
11929809d1f95d4cd4cbc6b2f9384b3321759691e13Tim Murray
120709a0978ae141198018ca9769f8d96292a8928e6Jason Samsstatic void AppendAfterStmt(clang::ASTContext &C,
12145e753a46e587c69b3b0d0c5138e88715a24a29aStephen Hines                            clang::CompoundStmt *CS,
12245e753a46e587c69b3b0d0c5138e88715a24a29aStephen Hines                            clang::Stmt *S,
123110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams                            std::list<clang::Stmt*> &StmtList) {
124110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams  slangAssert(CS);
125110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams  clang::CompoundStmt::body_iterator bI = CS->body_begin();
126110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams  clang::CompoundStmt::body_iterator bE = CS->body_end();
127110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams  clang::Stmt **UpdatedStmtList =
128110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams      new clang::Stmt*[CS->size() + StmtList.size()];
129110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams
130110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams  unsigned UpdatedStmtCount = 0;
131110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams  unsigned Once = 0;
132110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams  for ( ; bI != bE; bI++) {
133110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams    if (!S && ((*bI)->getStmtClass() == clang::Stmt::ReturnStmtClass)) {
134110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams      // If we come across a return here, we don't have anything we can
135110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams      // reasonably replace. We should have already inserted our destructor
136709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      // code in the proper spot, so we just clean up and return.
137709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      delete [] UpdatedStmtList;
138709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
139709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      return;
140709a0978ae141198018ca9769f8d96292a8928e6Jason Sams    }
141709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
142709a0978ae141198018ca9769f8d96292a8928e6Jason Sams    UpdatedStmtList[UpdatedStmtCount++] = *bI;
143709a0978ae141198018ca9769f8d96292a8928e6Jason Sams
144709a0978ae141198018ca9769f8d96292a8928e6Jason Sams    if ((*bI == S) && !Once) {
145709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      Once++;
146709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
147709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      std::list<clang::Stmt*>::const_iterator E = StmtList.end();
148709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      for ( ; I != E; I++) {
149709a0978ae141198018ca9769f8d96292a8928e6Jason Sams        UpdatedStmtList[UpdatedStmtCount++] = *I;
150709a0978ae141198018ca9769f8d96292a8928e6Jason Sams      }
151709a0978ae141198018ca9769f8d96292a8928e6Jason Sams    }
152709a0978ae141198018ca9769f8d96292a8928e6Jason Sams  }
153  slangAssert(Once <= 1);
154
155  // When S is NULL, we are appending to the end of the CompoundStmt.
156  if (!S) {
157    slangAssert(Once == 0);
158    std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
159    std::list<clang::Stmt*>::const_iterator E = StmtList.end();
160    for ( ; I != E; I++) {
161      UpdatedStmtList[UpdatedStmtCount++] = *I;
162    }
163  }
164
165  CS->setStmts(C, UpdatedStmtList, UpdatedStmtCount);
166
167  delete [] UpdatedStmtList;
168
169  return;
170}
171
172// This class visits a compound statement and inserts DtorStmt
173// in proper locations. This includes inserting it before any
174// return statement in any sub-block, at the end of the logical enclosing
175// scope (compound statement), and/or before any break/continue statement that
176// would resume outside the declared scope. We will not handle the case for
177// goto statements that leave a local scope.
178//
179// To accomplish these goals, it collects a list of sub-Stmt's that
180// correspond to scope exit points. It then uses an RSASTReplace visitor to
181// transform the AST, inserting appropriate destructors before each of those
182// sub-Stmt's (and also before the exit of the outermost containing Stmt for
183// the scope).
184class DestructorVisitor : public clang::StmtVisitor<DestructorVisitor> {
185 private:
186  clang::ASTContext &mCtx;
187
188  // The loop depth of the currently visited node.
189  int mLoopDepth;
190
191  // The switch statement depth of the currently visited node.
192  // Note that this is tracked separately from the loop depth because
193  // SwitchStmt-contained ContinueStmt's should have destructors for the
194  // corresponding loop scope.
195  int mSwitchDepth;
196
197  // The outermost statement block that we are currently visiting.
198  // This should always be a CompoundStmt.
199  clang::Stmt *mOuterStmt;
200
201  // The destructor to execute for this scope/variable.
202  clang::Stmt* mDtorStmt;
203
204  // The stack of statements which should be replaced by a compound statement
205  // containing the new destructor call followed by the original Stmt.
206  std::stack<clang::Stmt*> mReplaceStmtStack;
207
208  // The source location for the variable declaration that we are trying to
209  // insert destructors for. Note that InsertDestructors() will not generate
210  // destructor calls for source locations that occur lexically before this
211  // location.
212  clang::SourceLocation mVarLoc;
213
214 public:
215  DestructorVisitor(clang::ASTContext &C,
216                    clang::Stmt* OuterStmt,
217                    clang::Stmt* DtorStmt,
218                    clang::SourceLocation VarLoc);
219
220  // This code walks the collected list of Stmts to replace and actually does
221  // the replacement. It also finishes up by appending the destructor to the
222  // current outermost CompoundStmt.
223  void InsertDestructors() {
224    clang::Stmt *S = NULL;
225    clang::SourceManager &SM = mCtx.getSourceManager();
226    std::list<clang::Stmt *> StmtList;
227    StmtList.push_back(mDtorStmt);
228
229    while (!mReplaceStmtStack.empty()) {
230      S = mReplaceStmtStack.top();
231      mReplaceStmtStack.pop();
232
233      // Skip all source locations that occur before the variable's
234      // declaration, since it won't have been initialized yet.
235      if (SM.isBeforeInTranslationUnit(S->getLocStart(), mVarLoc)) {
236        continue;
237      }
238
239      StmtList.push_back(S);
240      clang::CompoundStmt *CS =
241          BuildCompoundStmt(mCtx, StmtList, S->getLocEnd());
242      StmtList.pop_back();
243
244      RSASTReplace R(mCtx);
245      R.ReplaceStmt(mOuterStmt, S, CS);
246    }
247    clang::CompoundStmt *CS =
248      llvm::dyn_cast<clang::CompoundStmt>(mOuterStmt);
249    slangAssert(CS);
250    AppendAfterStmt(mCtx, CS, NULL, StmtList);
251  }
252
253  void VisitStmt(clang::Stmt *S);
254  void VisitCompoundStmt(clang::CompoundStmt *CS);
255
256  void VisitBreakStmt(clang::BreakStmt *BS);
257  void VisitCaseStmt(clang::CaseStmt *CS);
258  void VisitContinueStmt(clang::ContinueStmt *CS);
259  void VisitDefaultStmt(clang::DefaultStmt *DS);
260  void VisitDoStmt(clang::DoStmt *DS);
261  void VisitForStmt(clang::ForStmt *FS);
262  void VisitIfStmt(clang::IfStmt *IS);
263  void VisitReturnStmt(clang::ReturnStmt *RS);
264  void VisitSwitchCase(clang::SwitchCase *SC);
265  void VisitSwitchStmt(clang::SwitchStmt *SS);
266  void VisitWhileStmt(clang::WhileStmt *WS);
267};
268
269DestructorVisitor::DestructorVisitor(clang::ASTContext &C,
270                         clang::Stmt *OuterStmt,
271                         clang::Stmt *DtorStmt,
272                         clang::SourceLocation VarLoc)
273  : mCtx(C),
274    mLoopDepth(0),
275    mSwitchDepth(0),
276    mOuterStmt(OuterStmt),
277    mDtorStmt(DtorStmt),
278    mVarLoc(VarLoc) {
279  return;
280}
281
282void DestructorVisitor::VisitStmt(clang::Stmt *S) {
283  for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
284       I != E;
285       I++) {
286    if (clang::Stmt *Child = *I) {
287      Visit(Child);
288    }
289  }
290  return;
291}
292
293void DestructorVisitor::VisitCompoundStmt(clang::CompoundStmt *CS) {
294  VisitStmt(CS);
295  return;
296}
297
298void DestructorVisitor::VisitBreakStmt(clang::BreakStmt *BS) {
299  VisitStmt(BS);
300  if ((mLoopDepth == 0) && (mSwitchDepth == 0)) {
301    mReplaceStmtStack.push(BS);
302  }
303  return;
304}
305
306void DestructorVisitor::VisitCaseStmt(clang::CaseStmt *CS) {
307  VisitStmt(CS);
308  return;
309}
310
311void DestructorVisitor::VisitContinueStmt(clang::ContinueStmt *CS) {
312  VisitStmt(CS);
313  if (mLoopDepth == 0) {
314    // Switch statements can have nested continues.
315    mReplaceStmtStack.push(CS);
316  }
317  return;
318}
319
320void DestructorVisitor::VisitDefaultStmt(clang::DefaultStmt *DS) {
321  VisitStmt(DS);
322  return;
323}
324
325void DestructorVisitor::VisitDoStmt(clang::DoStmt *DS) {
326  mLoopDepth++;
327  VisitStmt(DS);
328  mLoopDepth--;
329  return;
330}
331
332void DestructorVisitor::VisitForStmt(clang::ForStmt *FS) {
333  mLoopDepth++;
334  VisitStmt(FS);
335  mLoopDepth--;
336  return;
337}
338
339void DestructorVisitor::VisitIfStmt(clang::IfStmt *IS) {
340  VisitStmt(IS);
341  return;
342}
343
344void DestructorVisitor::VisitReturnStmt(clang::ReturnStmt *RS) {
345  mReplaceStmtStack.push(RS);
346  return;
347}
348
349void DestructorVisitor::VisitSwitchCase(clang::SwitchCase *SC) {
350  slangAssert(false && "Both case and default have specialized handlers");
351  VisitStmt(SC);
352  return;
353}
354
355void DestructorVisitor::VisitSwitchStmt(clang::SwitchStmt *SS) {
356  mSwitchDepth++;
357  VisitStmt(SS);
358  mSwitchDepth--;
359  return;
360}
361
362void DestructorVisitor::VisitWhileStmt(clang::WhileStmt *WS) {
363  mLoopDepth++;
364  VisitStmt(WS);
365  mLoopDepth--;
366  return;
367}
368
369clang::Expr *ClearSingleRSObject(clang::ASTContext &C,
370                                 clang::Expr *RefRSVar,
371                                 clang::SourceLocation Loc) {
372  slangAssert(RefRSVar);
373  const clang::Type *T = RefRSVar->getType().getTypePtr();
374  slangAssert(!T->isArrayType() &&
375              "Should not be destroying arrays with this function");
376
377  clang::FunctionDecl *ClearObjectFD = RSObjectRefCount::GetRSClearObjectFD(T);
378  slangAssert((ClearObjectFD != NULL) &&
379              "rsClearObject doesn't cover all RS object types");
380
381  clang::QualType ClearObjectFDType = ClearObjectFD->getType();
382  clang::QualType ClearObjectFDArgType =
383      ClearObjectFD->getParamDecl(0)->getOriginalType();
384
385  // Example destructor for "rs_font localFont;"
386  //
387  // (CallExpr 'void'
388  //   (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
389  //     (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
390  //   (UnaryOperator 'rs_font *' prefix '&'
391  //     (DeclRefExpr 'rs_font':'rs_font' Var='localFont')))
392
393  // Get address of targeted RS object
394  clang::Expr *AddrRefRSVar =
395      new(C) clang::UnaryOperator(RefRSVar,
396                                  clang::UO_AddrOf,
397                                  ClearObjectFDArgType,
398                                  clang::VK_RValue,
399                                  clang::OK_Ordinary,
400                                  Loc);
401
402  clang::Expr *RefRSClearObjectFD =
403      clang::DeclRefExpr::Create(C,
404                                 clang::NestedNameSpecifierLoc(),
405                                 clang::SourceLocation(),
406                                 ClearObjectFD,
407                                 false,
408                                 ClearObjectFD->getLocation(),
409                                 ClearObjectFDType,
410                                 clang::VK_RValue,
411                                 NULL);
412
413  clang::Expr *RSClearObjectFP =
414      clang::ImplicitCastExpr::Create(C,
415                                      C.getPointerType(ClearObjectFDType),
416                                      clang::CK_FunctionToPointerDecay,
417                                      RefRSClearObjectFD,
418                                      NULL,
419                                      clang::VK_RValue);
420
421  clang::CallExpr *RSClearObjectCall =
422      new(C) clang::CallExpr(C,
423                             RSClearObjectFP,
424                             &AddrRefRSVar,
425                             1,
426                             ClearObjectFD->getCallResultType(),
427                             clang::VK_RValue,
428                             Loc);
429
430  return RSClearObjectCall;
431}
432
433static int ArrayDim(const clang::Type *T) {
434  if (!T || !T->isArrayType()) {
435    return 0;
436  }
437
438  const clang::ConstantArrayType *CAT =
439    static_cast<const clang::ConstantArrayType *>(T);
440  return static_cast<int>(CAT->getSize().getSExtValue());
441}
442
443static clang::Stmt *ClearStructRSObject(
444    clang::ASTContext &C,
445    clang::DeclContext *DC,
446    clang::Expr *RefRSStruct,
447    clang::SourceLocation StartLoc,
448    clang::SourceLocation Loc);
449
450static clang::Stmt *ClearArrayRSObject(
451    clang::ASTContext &C,
452    clang::DeclContext *DC,
453    clang::Expr *RefRSArr,
454    clang::SourceLocation StartLoc,
455    clang::SourceLocation Loc) {
456  const clang::Type *BaseType = RefRSArr->getType().getTypePtr();
457  slangAssert(BaseType->isArrayType());
458
459  int NumArrayElements = ArrayDim(BaseType);
460  // Actually extract out the base RS object type for use later
461  BaseType = BaseType->getArrayElementTypeNoTypeQual();
462
463  clang::Stmt *StmtArray[2] = {NULL};
464  int StmtCtr = 0;
465
466  if (NumArrayElements <= 0) {
467    return NULL;
468  }
469
470  // Example destructor loop for "rs_font fontArr[10];"
471  //
472  // (CompoundStmt
473  //   (DeclStmt "int rsIntIter")
474  //   (ForStmt
475  //     (BinaryOperator 'int' '='
476  //       (DeclRefExpr 'int' Var='rsIntIter')
477  //       (IntegerLiteral 'int' 0))
478  //     (BinaryOperator 'int' '<'
479  //       (DeclRefExpr 'int' Var='rsIntIter')
480  //       (IntegerLiteral 'int' 10)
481  //     NULL << CondVar >>
482  //     (UnaryOperator 'int' postfix '++'
483  //       (DeclRefExpr 'int' Var='rsIntIter'))
484  //     (CallExpr 'void'
485  //       (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
486  //         (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
487  //       (UnaryOperator 'rs_font *' prefix '&'
488  //         (ArraySubscriptExpr 'rs_font':'rs_font'
489  //           (ImplicitCastExpr 'rs_font *' <ArrayToPointerDecay>
490  //             (DeclRefExpr 'rs_font [10]' Var='fontArr'))
491  //           (DeclRefExpr 'int' Var='rsIntIter')))))))
492
493  // Create helper variable for iterating through elements
494  clang::IdentifierInfo& II = C.Idents.get("rsIntIter");
495  clang::VarDecl *IIVD =
496      clang::VarDecl::Create(C,
497                             DC,
498                             StartLoc,
499                             Loc,
500                             &II,
501                             C.IntTy,
502                             C.getTrivialTypeSourceInfo(C.IntTy),
503                             clang::SC_None,
504                             clang::SC_None);
505  clang::Decl *IID = (clang::Decl *)IIVD;
506
507  clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(C, &IID, 1);
508  StmtArray[StmtCtr++] = new(C) clang::DeclStmt(DGR, Loc, Loc);
509
510  // Form the actual destructor loop
511  // for (Init; Cond; Inc)
512  //   RSClearObjectCall;
513
514  // Init -> "rsIntIter = 0"
515  clang::DeclRefExpr *RefrsIntIter =
516      clang::DeclRefExpr::Create(C,
517                                 clang::NestedNameSpecifierLoc(),
518                                 clang::SourceLocation(),
519                                 IIVD,
520                                 false,
521                                 Loc,
522                                 C.IntTy,
523                                 clang::VK_RValue,
524                                 NULL);
525
526  clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
527      llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
528
529  clang::BinaryOperator *Init =
530      new(C) clang::BinaryOperator(RefrsIntIter,
531                                   Int0,
532                                   clang::BO_Assign,
533                                   C.IntTy,
534                                   clang::VK_RValue,
535                                   clang::OK_Ordinary,
536                                   Loc);
537
538  // Cond -> "rsIntIter < NumArrayElements"
539  clang::Expr *NumArrayElementsExpr = clang::IntegerLiteral::Create(C,
540      llvm::APInt(C.getTypeSize(C.IntTy), NumArrayElements), C.IntTy, Loc);
541
542  clang::BinaryOperator *Cond =
543      new(C) clang::BinaryOperator(RefrsIntIter,
544                                   NumArrayElementsExpr,
545                                   clang::BO_LT,
546                                   C.IntTy,
547                                   clang::VK_RValue,
548                                   clang::OK_Ordinary,
549                                   Loc);
550
551  // Inc -> "rsIntIter++"
552  clang::UnaryOperator *Inc =
553      new(C) clang::UnaryOperator(RefrsIntIter,
554                                  clang::UO_PostInc,
555                                  C.IntTy,
556                                  clang::VK_RValue,
557                                  clang::OK_Ordinary,
558                                  Loc);
559
560  // Body -> "rsClearObject(&VD[rsIntIter]);"
561  // Destructor loop operates on individual array elements
562
563  clang::Expr *RefRSArrPtr =
564      clang::ImplicitCastExpr::Create(C,
565          C.getPointerType(BaseType->getCanonicalTypeInternal()),
566          clang::CK_ArrayToPointerDecay,
567          RefRSArr,
568          NULL,
569          clang::VK_RValue);
570
571  clang::Expr *RefRSArrPtrSubscript =
572      new(C) clang::ArraySubscriptExpr(RefRSArrPtr,
573                                       RefrsIntIter,
574                                       BaseType->getCanonicalTypeInternal(),
575                                       clang::VK_RValue,
576                                       clang::OK_Ordinary,
577                                       Loc);
578
579  RSExportPrimitiveType::DataType DT =
580      RSExportPrimitiveType::GetRSSpecificType(BaseType);
581
582  clang::Stmt *RSClearObjectCall = NULL;
583  if (BaseType->isArrayType()) {
584    RSClearObjectCall =
585        ClearArrayRSObject(C, DC, RefRSArrPtrSubscript, StartLoc, Loc);
586  } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
587    RSClearObjectCall =
588        ClearStructRSObject(C, DC, RefRSArrPtrSubscript, StartLoc, Loc);
589  } else {
590    RSClearObjectCall = ClearSingleRSObject(C, RefRSArrPtrSubscript, Loc);
591  }
592
593  clang::ForStmt *DestructorLoop =
594      new(C) clang::ForStmt(C,
595                            Init,
596                            Cond,
597                            NULL,  // no condVar
598                            Inc,
599                            RSClearObjectCall,
600                            Loc,
601                            Loc,
602                            Loc);
603
604  StmtArray[StmtCtr++] = DestructorLoop;
605  slangAssert(StmtCtr == 2);
606
607  clang::CompoundStmt *CS =
608      new(C) clang::CompoundStmt(C, StmtArray, StmtCtr, Loc, Loc);
609
610  return CS;
611}
612
613static unsigned CountRSObjectTypes(clang::ASTContext &C,
614                                   const clang::Type *T,
615                                   clang::SourceLocation Loc) {
616  slangAssert(T);
617  unsigned RSObjectCount = 0;
618
619  if (T->isArrayType()) {
620    return CountRSObjectTypes(C, T->getArrayElementTypeNoTypeQual(), Loc);
621  }
622
623  RSExportPrimitiveType::DataType DT =
624      RSExportPrimitiveType::GetRSSpecificType(T);
625  if (DT != RSExportPrimitiveType::DataTypeUnknown) {
626    return (RSExportPrimitiveType::IsRSObjectType(DT) ? 1 : 0);
627  }
628
629  if (T->isUnionType()) {
630    clang::RecordDecl *RD = T->getAsUnionType()->getDecl();
631    RD = RD->getDefinition();
632    for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
633           FE = RD->field_end();
634         FI != FE;
635         FI++) {
636      const clang::FieldDecl *FD = *FI;
637      const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
638      if (CountRSObjectTypes(C, FT, Loc)) {
639        slangAssert(false && "can't have unions with RS object types!");
640        return 0;
641      }
642    }
643  }
644
645  if (!T->isStructureType()) {
646    return 0;
647  }
648
649  clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
650  RD = RD->getDefinition();
651  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
652         FE = RD->field_end();
653       FI != FE;
654       FI++) {
655    const clang::FieldDecl *FD = *FI;
656    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
657    if (CountRSObjectTypes(C, FT, Loc)) {
658      // Sub-structs should only count once (as should arrays, etc.)
659      RSObjectCount++;
660    }
661  }
662
663  return RSObjectCount;
664}
665
666static clang::Stmt *ClearStructRSObject(
667    clang::ASTContext &C,
668    clang::DeclContext *DC,
669    clang::Expr *RefRSStruct,
670    clang::SourceLocation StartLoc,
671    clang::SourceLocation Loc) {
672  const clang::Type *BaseType = RefRSStruct->getType().getTypePtr();
673
674  slangAssert(!BaseType->isArrayType());
675
676  // Structs should show up as unknown primitive types
677  slangAssert(RSExportPrimitiveType::GetRSSpecificType(BaseType) ==
678              RSExportPrimitiveType::DataTypeUnknown);
679
680  unsigned FieldsToDestroy = CountRSObjectTypes(C, BaseType, Loc);
681
682  unsigned StmtCount = 0;
683  clang::Stmt **StmtArray = new clang::Stmt*[FieldsToDestroy];
684  for (unsigned i = 0; i < FieldsToDestroy; i++) {
685    StmtArray[i] = NULL;
686  }
687
688  // Populate StmtArray by creating a destructor for each RS object field
689  clang::RecordDecl *RD = BaseType->getAsStructureType()->getDecl();
690  RD = RD->getDefinition();
691  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
692         FE = RD->field_end();
693       FI != FE;
694       FI++) {
695    // We just look through all field declarations to see if we find a
696    // declaration for an RS object type (or an array of one).
697    bool IsArrayType = false;
698    clang::FieldDecl *FD = *FI;
699    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
700    const clang::Type *OrigType = FT;
701    while (FT && FT->isArrayType()) {
702      FT = FT->getArrayElementTypeNoTypeQual();
703      IsArrayType = true;
704    }
705
706    if (RSExportPrimitiveType::IsRSObjectType(FT)) {
707      clang::DeclAccessPair FoundDecl =
708          clang::DeclAccessPair::make(FD, clang::AS_none);
709      clang::MemberExpr *RSObjectMember =
710          clang::MemberExpr::Create(C,
711                                    RefRSStruct,
712                                    false,
713                                    clang::NestedNameSpecifierLoc(),
714                                    clang::SourceLocation(),
715                                    FD,
716                                    FoundDecl,
717                                    clang::DeclarationNameInfo(),
718                                    NULL,
719                                    OrigType->getCanonicalTypeInternal(),
720                                    clang::VK_RValue,
721                                    clang::OK_Ordinary);
722
723      slangAssert(StmtCount < FieldsToDestroy);
724
725      if (IsArrayType) {
726        StmtArray[StmtCount++] = ClearArrayRSObject(C,
727                                                    DC,
728                                                    RSObjectMember,
729                                                    StartLoc,
730                                                    Loc);
731      } else {
732        StmtArray[StmtCount++] = ClearSingleRSObject(C,
733                                                     RSObjectMember,
734                                                     Loc);
735      }
736    } else if (FT->isStructureType() && CountRSObjectTypes(C, FT, Loc)) {
737      // In this case, we have a nested struct. We may not end up filling all
738      // of the spaces in StmtArray (sub-structs should handle themselves
739      // with separate compound statements).
740      clang::DeclAccessPair FoundDecl =
741          clang::DeclAccessPair::make(FD, clang::AS_none);
742      clang::MemberExpr *RSObjectMember =
743          clang::MemberExpr::Create(C,
744                                    RefRSStruct,
745                                    false,
746                                    clang::NestedNameSpecifierLoc(),
747                                    clang::SourceLocation(),
748                                    FD,
749                                    FoundDecl,
750                                    clang::DeclarationNameInfo(),
751                                    NULL,
752                                    OrigType->getCanonicalTypeInternal(),
753                                    clang::VK_RValue,
754                                    clang::OK_Ordinary);
755
756      if (IsArrayType) {
757        StmtArray[StmtCount++] = ClearArrayRSObject(C,
758                                                    DC,
759                                                    RSObjectMember,
760                                                    StartLoc,
761                                                    Loc);
762      } else {
763        StmtArray[StmtCount++] = ClearStructRSObject(C,
764                                                     DC,
765                                                     RSObjectMember,
766                                                     StartLoc,
767                                                     Loc);
768      }
769    }
770  }
771
772  slangAssert(StmtCount > 0);
773  clang::CompoundStmt *CS =
774      new(C) clang::CompoundStmt(C, StmtArray, StmtCount, Loc, Loc);
775
776  delete [] StmtArray;
777
778  return CS;
779}
780
781static clang::Stmt *CreateSingleRSSetObject(clang::ASTContext &C,
782                                            clang::Expr *DstExpr,
783                                            clang::Expr *SrcExpr,
784                                            clang::SourceLocation StartLoc,
785                                            clang::SourceLocation Loc) {
786  const clang::Type *T = DstExpr->getType().getTypePtr();
787  clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(T);
788  slangAssert((SetObjectFD != NULL) &&
789              "rsSetObject doesn't cover all RS object types");
790
791  clang::QualType SetObjectFDType = SetObjectFD->getType();
792  clang::QualType SetObjectFDArgType[2];
793  SetObjectFDArgType[0] = SetObjectFD->getParamDecl(0)->getOriginalType();
794  SetObjectFDArgType[1] = SetObjectFD->getParamDecl(1)->getOriginalType();
795
796  clang::Expr *RefRSSetObjectFD =
797      clang::DeclRefExpr::Create(C,
798                                 clang::NestedNameSpecifierLoc(),
799                                 clang::SourceLocation(),
800                                 SetObjectFD,
801                                 false,
802                                 Loc,
803                                 SetObjectFDType,
804                                 clang::VK_RValue,
805                                 NULL);
806
807  clang::Expr *RSSetObjectFP =
808      clang::ImplicitCastExpr::Create(C,
809                                      C.getPointerType(SetObjectFDType),
810                                      clang::CK_FunctionToPointerDecay,
811                                      RefRSSetObjectFD,
812                                      NULL,
813                                      clang::VK_RValue);
814
815  clang::Expr *ArgList[2];
816  ArgList[0] = new(C) clang::UnaryOperator(DstExpr,
817                                           clang::UO_AddrOf,
818                                           SetObjectFDArgType[0],
819                                           clang::VK_RValue,
820                                           clang::OK_Ordinary,
821                                           Loc);
822  ArgList[1] = SrcExpr;
823
824  clang::CallExpr *RSSetObjectCall =
825      new(C) clang::CallExpr(C,
826                             RSSetObjectFP,
827                             ArgList,
828                             2,
829                             SetObjectFD->getCallResultType(),
830                             clang::VK_RValue,
831                             Loc);
832
833  return RSSetObjectCall;
834}
835
836static clang::Stmt *CreateStructRSSetObject(clang::ASTContext &C,
837                                            clang::Expr *LHS,
838                                            clang::Expr *RHS,
839                                            clang::SourceLocation StartLoc,
840                                            clang::SourceLocation Loc);
841
842/*static clang::Stmt *CreateArrayRSSetObject(clang::ASTContext &C,
843                                           clang::Expr *DstArr,
844                                           clang::Expr *SrcArr,
845                                           clang::SourceLocation StartLoc,
846                                           clang::SourceLocation Loc) {
847  clang::DeclContext *DC = NULL;
848  const clang::Type *BaseType = DstArr->getType().getTypePtr();
849  slangAssert(BaseType->isArrayType());
850
851  int NumArrayElements = ArrayDim(BaseType);
852  // Actually extract out the base RS object type for use later
853  BaseType = BaseType->getArrayElementTypeNoTypeQual();
854
855  clang::Stmt *StmtArray[2] = {NULL};
856  int StmtCtr = 0;
857
858  if (NumArrayElements <= 0) {
859    return NULL;
860  }
861
862  // Create helper variable for iterating through elements
863  clang::IdentifierInfo& II = C.Idents.get("rsIntIter");
864  clang::VarDecl *IIVD =
865      clang::VarDecl::Create(C,
866                             DC,
867                             StartLoc,
868                             Loc,
869                             &II,
870                             C.IntTy,
871                             C.getTrivialTypeSourceInfo(C.IntTy),
872                             clang::SC_None,
873                             clang::SC_None);
874  clang::Decl *IID = (clang::Decl *)IIVD;
875
876  clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(C, &IID, 1);
877  StmtArray[StmtCtr++] = new(C) clang::DeclStmt(DGR, Loc, Loc);
878
879  // Form the actual loop
880  // for (Init; Cond; Inc)
881  //   RSSetObjectCall;
882
883  // Init -> "rsIntIter = 0"
884  clang::DeclRefExpr *RefrsIntIter =
885      clang::DeclRefExpr::Create(C,
886                                 clang::NestedNameSpecifierLoc(),
887                                 IIVD,
888                                 Loc,
889                                 C.IntTy,
890                                 clang::VK_RValue,
891                                 NULL);
892
893  clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
894      llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
895
896  clang::BinaryOperator *Init =
897      new(C) clang::BinaryOperator(RefrsIntIter,
898                                   Int0,
899                                   clang::BO_Assign,
900                                   C.IntTy,
901                                   clang::VK_RValue,
902                                   clang::OK_Ordinary,
903                                   Loc);
904
905  // Cond -> "rsIntIter < NumArrayElements"
906  clang::Expr *NumArrayElementsExpr = clang::IntegerLiteral::Create(C,
907      llvm::APInt(C.getTypeSize(C.IntTy), NumArrayElements), C.IntTy, Loc);
908
909  clang::BinaryOperator *Cond =
910      new(C) clang::BinaryOperator(RefrsIntIter,
911                                   NumArrayElementsExpr,
912                                   clang::BO_LT,
913                                   C.IntTy,
914                                   clang::VK_RValue,
915                                   clang::OK_Ordinary,
916                                   Loc);
917
918  // Inc -> "rsIntIter++"
919  clang::UnaryOperator *Inc =
920      new(C) clang::UnaryOperator(RefrsIntIter,
921                                  clang::UO_PostInc,
922                                  C.IntTy,
923                                  clang::VK_RValue,
924                                  clang::OK_Ordinary,
925                                  Loc);
926
927  // Body -> "rsSetObject(&Dst[rsIntIter], Src[rsIntIter]);"
928  // Loop operates on individual array elements
929
930  clang::Expr *DstArrPtr =
931      clang::ImplicitCastExpr::Create(C,
932          C.getPointerType(BaseType->getCanonicalTypeInternal()),
933          clang::CK_ArrayToPointerDecay,
934          DstArr,
935          NULL,
936          clang::VK_RValue);
937
938  clang::Expr *DstArrPtrSubscript =
939      new(C) clang::ArraySubscriptExpr(DstArrPtr,
940                                       RefrsIntIter,
941                                       BaseType->getCanonicalTypeInternal(),
942                                       clang::VK_RValue,
943                                       clang::OK_Ordinary,
944                                       Loc);
945
946  clang::Expr *SrcArrPtr =
947      clang::ImplicitCastExpr::Create(C,
948          C.getPointerType(BaseType->getCanonicalTypeInternal()),
949          clang::CK_ArrayToPointerDecay,
950          SrcArr,
951          NULL,
952          clang::VK_RValue);
953
954  clang::Expr *SrcArrPtrSubscript =
955      new(C) clang::ArraySubscriptExpr(SrcArrPtr,
956                                       RefrsIntIter,
957                                       BaseType->getCanonicalTypeInternal(),
958                                       clang::VK_RValue,
959                                       clang::OK_Ordinary,
960                                       Loc);
961
962  RSExportPrimitiveType::DataType DT =
963      RSExportPrimitiveType::GetRSSpecificType(BaseType);
964
965  clang::Stmt *RSSetObjectCall = NULL;
966  if (BaseType->isArrayType()) {
967    RSSetObjectCall = CreateArrayRSSetObject(C, DstArrPtrSubscript,
968                                             SrcArrPtrSubscript,
969                                             StartLoc, Loc);
970  } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
971    RSSetObjectCall = CreateStructRSSetObject(C, DstArrPtrSubscript,
972                                              SrcArrPtrSubscript,
973                                              StartLoc, Loc);
974  } else {
975    RSSetObjectCall = CreateSingleRSSetObject(C, DstArrPtrSubscript,
976                                              SrcArrPtrSubscript,
977                                              StartLoc, Loc);
978  }
979
980  clang::ForStmt *DestructorLoop =
981      new(C) clang::ForStmt(C,
982                            Init,
983                            Cond,
984                            NULL,  // no condVar
985                            Inc,
986                            RSSetObjectCall,
987                            Loc,
988                            Loc,
989                            Loc);
990
991  StmtArray[StmtCtr++] = DestructorLoop;
992  slangAssert(StmtCtr == 2);
993
994  clang::CompoundStmt *CS =
995      new(C) clang::CompoundStmt(C, StmtArray, StmtCtr, Loc, Loc);
996
997  return CS;
998} */
999
1000static clang::Stmt *CreateStructRSSetObject(clang::ASTContext &C,
1001                                            clang::Expr *LHS,
1002                                            clang::Expr *RHS,
1003                                            clang::SourceLocation StartLoc,
1004                                            clang::SourceLocation Loc) {
1005  clang::QualType QT = LHS->getType();
1006  const clang::Type *T = QT.getTypePtr();
1007  slangAssert(T->isStructureType());
1008  slangAssert(!RSExportPrimitiveType::IsRSObjectType(T));
1009
1010  // Keep an extra slot for the original copy (memcpy)
1011  unsigned FieldsToSet = CountRSObjectTypes(C, T, Loc) + 1;
1012
1013  unsigned StmtCount = 0;
1014  clang::Stmt **StmtArray = new clang::Stmt*[FieldsToSet];
1015  for (unsigned i = 0; i < FieldsToSet; i++) {
1016    StmtArray[i] = NULL;
1017  }
1018
1019  clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
1020  RD = RD->getDefinition();
1021  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
1022         FE = RD->field_end();
1023       FI != FE;
1024       FI++) {
1025    bool IsArrayType = false;
1026    clang::FieldDecl *FD = *FI;
1027    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
1028    const clang::Type *OrigType = FT;
1029
1030    if (!CountRSObjectTypes(C, FT, Loc)) {
1031      // Skip to next if we don't have any viable RS object types
1032      continue;
1033    }
1034
1035    clang::DeclAccessPair FoundDecl =
1036        clang::DeclAccessPair::make(FD, clang::AS_none);
1037    clang::MemberExpr *DstMember =
1038        clang::MemberExpr::Create(C,
1039                                  LHS,
1040                                  false,
1041                                  clang::NestedNameSpecifierLoc(),
1042                                  clang::SourceLocation(),
1043                                  FD,
1044                                  FoundDecl,
1045                                  clang::DeclarationNameInfo(),
1046                                  NULL,
1047                                  OrigType->getCanonicalTypeInternal(),
1048                                  clang::VK_RValue,
1049                                  clang::OK_Ordinary);
1050
1051    clang::MemberExpr *SrcMember =
1052        clang::MemberExpr::Create(C,
1053                                  RHS,
1054                                  false,
1055                                  clang::NestedNameSpecifierLoc(),
1056                                  clang::SourceLocation(),
1057                                  FD,
1058                                  FoundDecl,
1059                                  clang::DeclarationNameInfo(),
1060                                  NULL,
1061                                  OrigType->getCanonicalTypeInternal(),
1062                                  clang::VK_RValue,
1063                                  clang::OK_Ordinary);
1064
1065    if (FT->isArrayType()) {
1066      FT = FT->getArrayElementTypeNoTypeQual();
1067      IsArrayType = true;
1068    }
1069
1070    RSExportPrimitiveType::DataType DT =
1071        RSExportPrimitiveType::GetRSSpecificType(FT);
1072
1073    if (IsArrayType) {
1074      clang::DiagnosticsEngine &DiagEngine = C.getDiagnostics();
1075      DiagEngine.Report(
1076        clang::FullSourceLoc(Loc, C.getSourceManager()),
1077        DiagEngine.getCustomDiagID(
1078          clang::DiagnosticsEngine::Error,
1079          "Arrays of RS object types within structures cannot be copied"));
1080      // TODO(srhines): Support setting arrays of RS objects
1081      // StmtArray[StmtCount++] =
1082      //    CreateArrayRSSetObject(C, DstMember, SrcMember, StartLoc, Loc);
1083    } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
1084      StmtArray[StmtCount++] =
1085          CreateStructRSSetObject(C, DstMember, SrcMember, StartLoc, Loc);
1086    } else if (RSExportPrimitiveType::IsRSObjectType(DT)) {
1087      StmtArray[StmtCount++] =
1088          CreateSingleRSSetObject(C, DstMember, SrcMember, StartLoc, Loc);
1089    } else {
1090      slangAssert(false);
1091    }
1092  }
1093
1094  slangAssert(StmtCount > 0 && StmtCount < FieldsToSet);
1095
1096  // We still need to actually do the overall struct copy. For simplicity,
1097  // we just do a straight-up assignment (which will still preserve all
1098  // the proper RS object reference counts).
1099  clang::BinaryOperator *CopyStruct =
1100      new(C) clang::BinaryOperator(LHS, RHS, clang::BO_Assign, QT,
1101                                   clang::VK_RValue, clang::OK_Ordinary, Loc);
1102  StmtArray[StmtCount++] = CopyStruct;
1103
1104  clang::CompoundStmt *CS =
1105      new(C) clang::CompoundStmt(C, StmtArray, StmtCount, Loc, Loc);
1106
1107  delete [] StmtArray;
1108
1109  return CS;
1110}
1111
1112}  // namespace
1113
1114void RSObjectRefCount::Scope::ReplaceRSObjectAssignment(
1115    clang::BinaryOperator *AS) {
1116
1117  clang::QualType QT = AS->getType();
1118
1119  clang::ASTContext &C = RSObjectRefCount::GetRSSetObjectFD(
1120      RSExportPrimitiveType::DataTypeRSFont)->getASTContext();
1121
1122  clang::SourceLocation Loc = AS->getExprLoc();
1123  clang::SourceLocation StartLoc = AS->getLHS()->getExprLoc();
1124  clang::Stmt *UpdatedStmt = NULL;
1125
1126  if (!RSExportPrimitiveType::IsRSObjectType(QT.getTypePtr())) {
1127    // By definition, this is a struct assignment if we get here
1128    UpdatedStmt =
1129        CreateStructRSSetObject(C, AS->getLHS(), AS->getRHS(), StartLoc, Loc);
1130  } else {
1131    UpdatedStmt =
1132        CreateSingleRSSetObject(C, AS->getLHS(), AS->getRHS(), StartLoc, Loc);
1133  }
1134
1135  RSASTReplace R(C);
1136  R.ReplaceStmt(mCS, AS, UpdatedStmt);
1137  return;
1138}
1139
1140void RSObjectRefCount::Scope::AppendRSObjectInit(
1141    clang::VarDecl *VD,
1142    clang::DeclStmt *DS,
1143    RSExportPrimitiveType::DataType DT,
1144    clang::Expr *InitExpr) {
1145  slangAssert(VD);
1146
1147  if (!InitExpr) {
1148    return;
1149  }
1150
1151  clang::ASTContext &C = RSObjectRefCount::GetRSSetObjectFD(
1152      RSExportPrimitiveType::DataTypeRSFont)->getASTContext();
1153  clang::SourceLocation Loc = RSObjectRefCount::GetRSSetObjectFD(
1154      RSExportPrimitiveType::DataTypeRSFont)->getLocation();
1155  clang::SourceLocation StartLoc = RSObjectRefCount::GetRSSetObjectFD(
1156      RSExportPrimitiveType::DataTypeRSFont)->getInnerLocStart();
1157
1158  if (DT == RSExportPrimitiveType::DataTypeIsStruct) {
1159    const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1160    clang::DeclRefExpr *RefRSVar =
1161        clang::DeclRefExpr::Create(C,
1162                                   clang::NestedNameSpecifierLoc(),
1163                                   clang::SourceLocation(),
1164                                   VD,
1165                                   false,
1166                                   Loc,
1167                                   T->getCanonicalTypeInternal(),
1168                                   clang::VK_RValue,
1169                                   NULL);
1170
1171    clang::Stmt *RSSetObjectOps =
1172        CreateStructRSSetObject(C, RefRSVar, InitExpr, StartLoc, Loc);
1173
1174    std::list<clang::Stmt*> StmtList;
1175    StmtList.push_back(RSSetObjectOps);
1176    AppendAfterStmt(C, mCS, DS, StmtList);
1177    return;
1178  }
1179
1180  clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(DT);
1181  slangAssert((SetObjectFD != NULL) &&
1182              "rsSetObject doesn't cover all RS object types");
1183
1184  clang::QualType SetObjectFDType = SetObjectFD->getType();
1185  clang::QualType SetObjectFDArgType[2];
1186  SetObjectFDArgType[0] = SetObjectFD->getParamDecl(0)->getOriginalType();
1187  SetObjectFDArgType[1] = SetObjectFD->getParamDecl(1)->getOriginalType();
1188
1189  clang::Expr *RefRSSetObjectFD =
1190      clang::DeclRefExpr::Create(C,
1191                                 clang::NestedNameSpecifierLoc(),
1192                                 clang::SourceLocation(),
1193                                 SetObjectFD,
1194                                 false,
1195                                 Loc,
1196                                 SetObjectFDType,
1197                                 clang::VK_RValue,
1198                                 NULL);
1199
1200  clang::Expr *RSSetObjectFP =
1201      clang::ImplicitCastExpr::Create(C,
1202                                      C.getPointerType(SetObjectFDType),
1203                                      clang::CK_FunctionToPointerDecay,
1204                                      RefRSSetObjectFD,
1205                                      NULL,
1206                                      clang::VK_RValue);
1207
1208  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1209  clang::DeclRefExpr *RefRSVar =
1210      clang::DeclRefExpr::Create(C,
1211                                 clang::NestedNameSpecifierLoc(),
1212                                 clang::SourceLocation(),
1213                                 VD,
1214                                 false,
1215                                 Loc,
1216                                 T->getCanonicalTypeInternal(),
1217                                 clang::VK_RValue,
1218                                 NULL);
1219
1220  clang::Expr *ArgList[2];
1221  ArgList[0] = new(C) clang::UnaryOperator(RefRSVar,
1222                                           clang::UO_AddrOf,
1223                                           SetObjectFDArgType[0],
1224                                           clang::VK_RValue,
1225                                           clang::OK_Ordinary,
1226                                           Loc);
1227  ArgList[1] = InitExpr;
1228
1229  clang::CallExpr *RSSetObjectCall =
1230      new(C) clang::CallExpr(C,
1231                             RSSetObjectFP,
1232                             ArgList,
1233                             2,
1234                             SetObjectFD->getCallResultType(),
1235                             clang::VK_RValue,
1236                             Loc);
1237
1238  std::list<clang::Stmt*> StmtList;
1239  StmtList.push_back(RSSetObjectCall);
1240  AppendAfterStmt(C, mCS, DS, StmtList);
1241
1242  return;
1243}
1244
1245void RSObjectRefCount::Scope::InsertLocalVarDestructors() {
1246  for (std::list<clang::VarDecl*>::const_iterator I = mRSO.begin(),
1247          E = mRSO.end();
1248        I != E;
1249        I++) {
1250    clang::VarDecl *VD = *I;
1251    clang::Stmt *RSClearObjectCall = ClearRSObject(VD, VD->getDeclContext());
1252    if (RSClearObjectCall) {
1253      DestructorVisitor DV((*mRSO.begin())->getASTContext(),
1254                           mCS,
1255                           RSClearObjectCall,
1256                           VD->getSourceRange().getBegin());
1257      DV.Visit(mCS);
1258      DV.InsertDestructors();
1259    }
1260  }
1261  return;
1262}
1263
1264clang::Stmt *RSObjectRefCount::Scope::ClearRSObject(
1265    clang::VarDecl *VD,
1266    clang::DeclContext *DC) {
1267  slangAssert(VD);
1268  clang::ASTContext &C = VD->getASTContext();
1269  clang::SourceLocation Loc = VD->getLocation();
1270  clang::SourceLocation StartLoc = VD->getInnerLocStart();
1271  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1272
1273  // Reference expr to target RS object variable
1274  clang::DeclRefExpr *RefRSVar =
1275      clang::DeclRefExpr::Create(C,
1276                                 clang::NestedNameSpecifierLoc(),
1277                                 clang::SourceLocation(),
1278                                 VD,
1279                                 false,
1280                                 Loc,
1281                                 T->getCanonicalTypeInternal(),
1282                                 clang::VK_RValue,
1283                                 NULL);
1284
1285  if (T->isArrayType()) {
1286    return ClearArrayRSObject(C, DC, RefRSVar, StartLoc, Loc);
1287  }
1288
1289  RSExportPrimitiveType::DataType DT =
1290      RSExportPrimitiveType::GetRSSpecificType(T);
1291
1292  if (DT == RSExportPrimitiveType::DataTypeUnknown ||
1293      DT == RSExportPrimitiveType::DataTypeIsStruct) {
1294    return ClearStructRSObject(C, DC, RefRSVar, StartLoc, Loc);
1295  }
1296
1297  slangAssert((RSExportPrimitiveType::IsRSObjectType(DT)) &&
1298              "Should be RS object");
1299
1300  return ClearSingleRSObject(C, RefRSVar, Loc);
1301}
1302
1303bool RSObjectRefCount::InitializeRSObject(clang::VarDecl *VD,
1304                                          RSExportPrimitiveType::DataType *DT,
1305                                          clang::Expr **InitExpr) {
1306  slangAssert(VD && DT && InitExpr);
1307  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1308
1309  // Loop through array types to get to base type
1310  while (T && T->isArrayType()) {
1311    T = T->getArrayElementTypeNoTypeQual();
1312  }
1313
1314  bool DataTypeIsStructWithRSObject = false;
1315  *DT = RSExportPrimitiveType::GetRSSpecificType(T);
1316
1317  if (*DT == RSExportPrimitiveType::DataTypeUnknown) {
1318    if (RSExportPrimitiveType::IsStructureTypeWithRSObject(T)) {
1319      *DT = RSExportPrimitiveType::DataTypeIsStruct;
1320      DataTypeIsStructWithRSObject = true;
1321    } else {
1322      return false;
1323    }
1324  }
1325
1326  bool DataTypeIsRSObject = false;
1327  if (DataTypeIsStructWithRSObject) {
1328    DataTypeIsRSObject = true;
1329  } else {
1330    DataTypeIsRSObject = RSExportPrimitiveType::IsRSObjectType(*DT);
1331  }
1332  *InitExpr = VD->getInit();
1333
1334  if (!DataTypeIsRSObject && *InitExpr) {
1335    // If we already have an initializer for a matrix type, we are done.
1336    return DataTypeIsRSObject;
1337  }
1338
1339  clang::Expr *ZeroInitializer =
1340      CreateZeroInitializerForRSSpecificType(*DT,
1341                                             VD->getASTContext(),
1342                                             VD->getLocation());
1343
1344  if (ZeroInitializer) {
1345    ZeroInitializer->setType(T->getCanonicalTypeInternal());
1346    VD->setInit(ZeroInitializer);
1347  }
1348
1349  return DataTypeIsRSObject;
1350}
1351
1352clang::Expr *RSObjectRefCount::CreateZeroInitializerForRSSpecificType(
1353    RSExportPrimitiveType::DataType DT,
1354    clang::ASTContext &C,
1355    const clang::SourceLocation &Loc) {
1356  clang::Expr *Res = NULL;
1357  switch (DT) {
1358    case RSExportPrimitiveType::DataTypeIsStruct:
1359    case RSExportPrimitiveType::DataTypeRSElement:
1360    case RSExportPrimitiveType::DataTypeRSType:
1361    case RSExportPrimitiveType::DataTypeRSAllocation:
1362    case RSExportPrimitiveType::DataTypeRSSampler:
1363    case RSExportPrimitiveType::DataTypeRSScript:
1364    case RSExportPrimitiveType::DataTypeRSMesh:
1365    case RSExportPrimitiveType::DataTypeRSPath:
1366    case RSExportPrimitiveType::DataTypeRSProgramFragment:
1367    case RSExportPrimitiveType::DataTypeRSProgramVertex:
1368    case RSExportPrimitiveType::DataTypeRSProgramRaster:
1369    case RSExportPrimitiveType::DataTypeRSProgramStore:
1370    case RSExportPrimitiveType::DataTypeRSFont: {
1371      //    (ImplicitCastExpr 'nullptr_t'
1372      //      (IntegerLiteral 0)))
1373      llvm::APInt Zero(C.getTypeSize(C.IntTy), 0);
1374      clang::Expr *Int0 = clang::IntegerLiteral::Create(C, Zero, C.IntTy, Loc);
1375      clang::Expr *CastToNull =
1376          clang::ImplicitCastExpr::Create(C,
1377                                          C.NullPtrTy,
1378                                          clang::CK_IntegralToPointer,
1379                                          Int0,
1380                                          NULL,
1381                                          clang::VK_RValue);
1382
1383      Res = new(C) clang::InitListExpr(C, Loc, &CastToNull, 1, Loc);
1384      break;
1385    }
1386    case RSExportPrimitiveType::DataTypeRSMatrix2x2:
1387    case RSExportPrimitiveType::DataTypeRSMatrix3x3:
1388    case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
1389      // RS matrix is not completely an RS object. They hold data by themselves.
1390      // (InitListExpr rs_matrix2x2
1391      //   (InitListExpr float[4]
1392      //     (FloatingLiteral 0)
1393      //     (FloatingLiteral 0)
1394      //     (FloatingLiteral 0)
1395      //     (FloatingLiteral 0)))
1396      clang::QualType FloatTy = C.FloatTy;
1397      // Constructor sets value to 0.0f by default
1398      llvm::APFloat Val(C.getFloatTypeSemantics(FloatTy));
1399      clang::FloatingLiteral *Float0Val =
1400          clang::FloatingLiteral::Create(C,
1401                                         Val,
1402                                         /* isExact = */true,
1403                                         FloatTy,
1404                                         Loc);
1405
1406      unsigned N = 0;
1407      if (DT == RSExportPrimitiveType::DataTypeRSMatrix2x2)
1408        N = 2;
1409      else if (DT == RSExportPrimitiveType::DataTypeRSMatrix3x3)
1410        N = 3;
1411      else if (DT == RSExportPrimitiveType::DataTypeRSMatrix4x4)
1412        N = 4;
1413
1414      // Directly allocate 16 elements instead of dynamically allocate N*N
1415      clang::Expr *InitVals[16];
1416      for (unsigned i = 0; i < sizeof(InitVals) / sizeof(InitVals[0]); i++)
1417        InitVals[i] = Float0Val;
1418      clang::Expr *InitExpr =
1419          new(C) clang::InitListExpr(C, Loc, InitVals, N * N, Loc);
1420      InitExpr->setType(C.getConstantArrayType(FloatTy,
1421                                               llvm::APInt(32, N * N),
1422                                               clang::ArrayType::Normal,
1423                                               /* EltTypeQuals = */0));
1424
1425      Res = new(C) clang::InitListExpr(C, Loc, &InitExpr, 1, Loc);
1426      break;
1427    }
1428    case RSExportPrimitiveType::DataTypeUnknown:
1429    case RSExportPrimitiveType::DataTypeFloat16:
1430    case RSExportPrimitiveType::DataTypeFloat32:
1431    case RSExportPrimitiveType::DataTypeFloat64:
1432    case RSExportPrimitiveType::DataTypeSigned8:
1433    case RSExportPrimitiveType::DataTypeSigned16:
1434    case RSExportPrimitiveType::DataTypeSigned32:
1435    case RSExportPrimitiveType::DataTypeSigned64:
1436    case RSExportPrimitiveType::DataTypeUnsigned8:
1437    case RSExportPrimitiveType::DataTypeUnsigned16:
1438    case RSExportPrimitiveType::DataTypeUnsigned32:
1439    case RSExportPrimitiveType::DataTypeUnsigned64:
1440    case RSExportPrimitiveType::DataTypeBoolean:
1441    case RSExportPrimitiveType::DataTypeUnsigned565:
1442    case RSExportPrimitiveType::DataTypeUnsigned5551:
1443    case RSExportPrimitiveType::DataTypeUnsigned4444:
1444    case RSExportPrimitiveType::DataTypeMax: {
1445      slangAssert(false && "Not RS object type!");
1446    }
1447    // No default case will enable compiler detecting the missing cases
1448  }
1449
1450  return Res;
1451}
1452
1453void RSObjectRefCount::VisitDeclStmt(clang::DeclStmt *DS) {
1454  for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
1455       I != E;
1456       I++) {
1457    clang::Decl *D = *I;
1458    if (D->getKind() == clang::Decl::Var) {
1459      clang::VarDecl *VD = static_cast<clang::VarDecl*>(D);
1460      RSExportPrimitiveType::DataType DT =
1461          RSExportPrimitiveType::DataTypeUnknown;
1462      clang::Expr *InitExpr = NULL;
1463      if (InitializeRSObject(VD, &DT, &InitExpr)) {
1464        getCurrentScope()->addRSObject(VD);
1465        getCurrentScope()->AppendRSObjectInit(VD, DS, DT, InitExpr);
1466      }
1467    }
1468  }
1469  return;
1470}
1471
1472void RSObjectRefCount::VisitCompoundStmt(clang::CompoundStmt *CS) {
1473  if (!CS->body_empty()) {
1474    // Push a new scope
1475    Scope *S = new Scope(CS);
1476    mScopeStack.push(S);
1477
1478    VisitStmt(CS);
1479
1480    // Destroy the scope
1481    slangAssert((getCurrentScope() == S) && "Corrupted scope stack!");
1482    S->InsertLocalVarDestructors();
1483    mScopeStack.pop();
1484    delete S;
1485  }
1486  return;
1487}
1488
1489void RSObjectRefCount::VisitBinAssign(clang::BinaryOperator *AS) {
1490  clang::QualType QT = AS->getType();
1491
1492  if (CountRSObjectTypes(mCtx, QT.getTypePtr(), AS->getExprLoc())) {
1493    getCurrentScope()->ReplaceRSObjectAssignment(AS);
1494  }
1495
1496  return;
1497}
1498
1499void RSObjectRefCount::VisitStmt(clang::Stmt *S) {
1500  for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
1501       I != E;
1502       I++) {
1503    if (clang::Stmt *Child = *I) {
1504      Visit(Child);
1505    }
1506  }
1507  return;
1508}
1509
1510// This function walks the list of global variables and (potentially) creates
1511// a single global static destructor function that properly decrements
1512// reference counts on the contained RS object types.
1513clang::FunctionDecl *RSObjectRefCount::CreateStaticGlobalDtor() {
1514  Init();
1515
1516  clang::DeclContext *DC = mCtx.getTranslationUnitDecl();
1517  clang::SourceLocation loc;
1518
1519  llvm::StringRef SR(".rs.dtor");
1520  clang::IdentifierInfo &II = mCtx.Idents.get(SR);
1521  clang::DeclarationName N(&II);
1522  clang::FunctionProtoType::ExtProtoInfo EPI;
1523  clang::QualType T = mCtx.getFunctionType(mCtx.VoidTy, NULL, 0, EPI);
1524  clang::FunctionDecl *FD = NULL;
1525
1526  // Generate rsClearObject() call chains for every global variable
1527  // (whether static or extern).
1528  std::list<clang::Stmt *> StmtList;
1529  for (clang::DeclContext::decl_iterator I = DC->decls_begin(),
1530          E = DC->decls_end(); I != E; I++) {
1531    clang::VarDecl *VD = llvm::dyn_cast<clang::VarDecl>(*I);
1532    if (VD) {
1533      if (CountRSObjectTypes(mCtx, VD->getType().getTypePtr(), loc)) {
1534        if (!FD) {
1535          // Only create FD if we are going to use it.
1536          FD = clang::FunctionDecl::Create(mCtx, DC, loc, loc, N, T, NULL);
1537        }
1538        // Make sure to create any helpers within the function's DeclContext,
1539        // not the one associated with the global translation unit.
1540        clang::Stmt *RSClearObjectCall = Scope::ClearRSObject(VD, FD);
1541        StmtList.push_back(RSClearObjectCall);
1542      }
1543    }
1544  }
1545
1546  // Nothing needs to be destroyed, so don't emit a dtor.
1547  if (StmtList.empty()) {
1548    return NULL;
1549  }
1550
1551  clang::CompoundStmt *CS = BuildCompoundStmt(mCtx, StmtList, loc);
1552
1553  FD->setBody(CS);
1554
1555  return FD;
1556}
1557
1558}  // namespace slang
1559