slang_rs_object_ref_count.cpp revision 2bb67db8364162b30e6920baddf6c2e890b3ce79
1/*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "slang_rs_object_ref_count.h"
18
19#include <list>
20
21#include "clang/AST/DeclGroup.h"
22#include "clang/AST/Expr.h"
23#include "clang/AST/OperationKinds.h"
24#include "clang/AST/Stmt.h"
25#include "clang/AST/StmtVisitor.h"
26
27#include "slang_assert.h"
28#include "slang_rs.h"
29#include "slang_rs_export_type.h"
30
31namespace slang {
32
33clang::FunctionDecl *RSObjectRefCount::
34    RSSetObjectFD[RSExportPrimitiveType::LastRSObjectType -
35                  RSExportPrimitiveType::FirstRSObjectType + 1];
36clang::FunctionDecl *RSObjectRefCount::
37    RSClearObjectFD[RSExportPrimitiveType::LastRSObjectType -
38                    RSExportPrimitiveType::FirstRSObjectType + 1];
39
40void RSObjectRefCount::GetRSRefCountingFunctions(clang::ASTContext &C) {
41  for (unsigned i = 0;
42       i < (sizeof(RSClearObjectFD) / sizeof(clang::FunctionDecl*));
43       i++) {
44    RSSetObjectFD[i] = NULL;
45    RSClearObjectFD[i] = NULL;
46  }
47
48  clang::TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl();
49
50  for (clang::DeclContext::decl_iterator I = TUDecl->decls_begin(),
51          E = TUDecl->decls_end(); I != E; I++) {
52    if ((I->getKind() >= clang::Decl::firstFunction) &&
53        (I->getKind() <= clang::Decl::lastFunction)) {
54      clang::FunctionDecl *FD = static_cast<clang::FunctionDecl*>(*I);
55
56      // points to RSSetObjectFD or RSClearObjectFD
57      clang::FunctionDecl **RSObjectFD;
58
59      if (FD->getName() == "rsSetObject") {
60        slangAssert((FD->getNumParams() == 2) &&
61                    "Invalid rsSetObject function prototype (# params)");
62        RSObjectFD = RSSetObjectFD;
63      } else if (FD->getName() == "rsClearObject") {
64        slangAssert((FD->getNumParams() == 1) &&
65                    "Invalid rsClearObject function prototype (# params)");
66        RSObjectFD = RSClearObjectFD;
67      } else {
68        continue;
69      }
70
71      const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
72      clang::QualType PVT = PVD->getOriginalType();
73      // The first parameter must be a pointer like rs_allocation*
74      slangAssert(PVT->isPointerType() &&
75          "Invalid rs{Set,Clear}Object function prototype (pointer param)");
76
77      // The rs object type passed to the FD
78      clang::QualType RST = PVT->getPointeeType();
79      RSExportPrimitiveType::DataType DT =
80          RSExportPrimitiveType::GetRSSpecificType(RST.getTypePtr());
81      slangAssert(RSExportPrimitiveType::IsRSObjectType(DT)
82             && "must be RS object type");
83
84      RSObjectFD[(DT - RSExportPrimitiveType::FirstRSObjectType)] = FD;
85    }
86  }
87}
88
89namespace {
90
91static void AppendToCompoundStatement(clang::ASTContext& C,
92                                      clang::CompoundStmt *CS,
93                                      std::list<clang::Stmt*> &StmtList,
94                                      bool InsertAtEndOfBlock) {
95  // Destructor code will be inserted before any return statement.
96  // Any subsequent statements in the compound statement are then placed
97  // after our new code.
98  // TODO(srhines): This should also handle the case of goto/break/continue.
99
100  clang::CompoundStmt::body_iterator bI = CS->body_begin();
101
102  unsigned OldStmtCount = 0;
103  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
104    OldStmtCount++;
105  }
106
107  unsigned NewStmtCount = StmtList.size();
108
109  clang::Stmt **UpdatedStmtList;
110  UpdatedStmtList = new clang::Stmt*[OldStmtCount+NewStmtCount];
111
112  unsigned UpdatedStmtCount = 0;
113  bool FoundReturn = false;
114  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
115    if ((*bI)->getStmtClass() == clang::Stmt::ReturnStmtClass) {
116      FoundReturn = true;
117      break;
118    }
119    UpdatedStmtList[UpdatedStmtCount++] = *bI;
120  }
121
122  // Always insert before a return that we found, or if we are told
123  // to insert at the end of the block
124  if (FoundReturn || InsertAtEndOfBlock) {
125    std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
126    for (std::list<clang::Stmt*>::const_iterator I = StmtList.begin();
127         I != StmtList.end();
128         I++) {
129      UpdatedStmtList[UpdatedStmtCount++] = *I;
130    }
131  }
132
133  // Pick up anything left over after a return statement
134  for ( ; bI != CS->body_end(); bI++) {
135    UpdatedStmtList[UpdatedStmtCount++] = *bI;
136  }
137
138  CS->setStmts(C, UpdatedStmtList, UpdatedStmtCount);
139
140  delete [] UpdatedStmtList;
141
142  return;
143}
144
145static void AppendAfterStmt(clang::ASTContext& C,
146                            clang::CompoundStmt *CS,
147                            clang::Stmt *OldStmt,
148                            clang::Stmt *NewStmt) {
149  slangAssert(CS && OldStmt && NewStmt);
150  clang::CompoundStmt::body_iterator bI = CS->body_begin();
151  unsigned StmtCount = 1;  // Take into account new statement
152  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
153    StmtCount++;
154  }
155
156  clang::Stmt **UpdatedStmtList = new clang::Stmt*[StmtCount];
157
158  unsigned UpdatedStmtCount = 0;
159  unsigned Once = 0;
160  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
161    UpdatedStmtList[UpdatedStmtCount++] = *bI;
162    if (*bI == OldStmt) {
163      Once++;
164      slangAssert(Once == 1);
165      UpdatedStmtList[UpdatedStmtCount++] = NewStmt;
166    }
167  }
168
169  CS->setStmts(C, UpdatedStmtList, UpdatedStmtCount);
170
171  delete [] UpdatedStmtList;
172
173  return;
174}
175
176static void ReplaceInCompoundStmt(clang::ASTContext& C,
177                                  clang::CompoundStmt *CS,
178                                  clang::Stmt* OldStmt,
179                                  clang::Stmt* NewStmt) {
180  clang::CompoundStmt::body_iterator bI = CS->body_begin();
181
182  unsigned StmtCount = 0;
183  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
184    StmtCount++;
185  }
186
187  clang::Stmt **UpdatedStmtList = new clang::Stmt*[StmtCount];
188
189  unsigned UpdatedStmtCount = 0;
190  for (bI = CS->body_begin(); bI != CS->body_end(); bI++) {
191    if (*bI == OldStmt) {
192      UpdatedStmtList[UpdatedStmtCount++] = NewStmt;
193    } else {
194      UpdatedStmtList[UpdatedStmtCount++] = *bI;
195    }
196  }
197
198  CS->setStmts(C, UpdatedStmtList, UpdatedStmtCount);
199
200  delete [] UpdatedStmtList;
201
202  return;
203}
204
205
206// This class visits a compound statement and inserts the StmtList containing
207// destructors in proper locations. This includes inserting them before any
208// return statement in any sub-block, at the end of the logical enclosing
209// scope (compound statement), and/or before any break/continue statement that
210// would resume outside the declared scope. We will not handle the case for
211// goto statements that leave a local scope.
212// TODO(srhines): Make this work properly for break/continue.
213class DestructorVisitor : public clang::StmtVisitor<DestructorVisitor> {
214 private:
215  clang::ASTContext &mC;
216  std::list<clang::Stmt*> &mStmtList;
217  bool mTopLevel;
218 public:
219  DestructorVisitor(clang::ASTContext &C, std::list<clang::Stmt*> &StmtList);
220  void VisitStmt(clang::Stmt *S);
221  void VisitCompoundStmt(clang::CompoundStmt *CS);
222};
223
224DestructorVisitor::DestructorVisitor(clang::ASTContext &C,
225                                     std::list<clang::Stmt*> &StmtList)
226  : mC(C),
227    mStmtList(StmtList),
228    mTopLevel(true) {
229  return;
230}
231
232void DestructorVisitor::VisitCompoundStmt(clang::CompoundStmt *CS) {
233  if (!CS->body_empty()) {
234    AppendToCompoundStatement(mC, CS, mStmtList, mTopLevel);
235    mTopLevel = false;
236    VisitStmt(CS);
237  }
238  return;
239}
240
241void DestructorVisitor::VisitStmt(clang::Stmt *S) {
242  for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
243       I != E;
244       I++) {
245    if (clang::Stmt *Child = *I) {
246      Visit(Child);
247    }
248  }
249  return;
250}
251
252clang::Expr *ClearSingleRSObject(clang::ASTContext &C,
253                                 clang::Expr *RefRSVar,
254                                 clang::SourceLocation Loc) {
255  slangAssert(RefRSVar);
256  const clang::Type *T = RefRSVar->getType().getTypePtr();
257  slangAssert(!T->isArrayType() &&
258              "Should not be destroying arrays with this function");
259
260  clang::FunctionDecl *ClearObjectFD = RSObjectRefCount::GetRSClearObjectFD(T);
261  slangAssert((ClearObjectFD != NULL) &&
262              "rsClearObject doesn't cover all RS object types");
263
264  clang::QualType ClearObjectFDType = ClearObjectFD->getType();
265  clang::QualType ClearObjectFDArgType =
266      ClearObjectFD->getParamDecl(0)->getOriginalType();
267
268  // Example destructor for "rs_font localFont;"
269  //
270  // (CallExpr 'void'
271  //   (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
272  //     (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
273  //   (UnaryOperator 'rs_font *' prefix '&'
274  //     (DeclRefExpr 'rs_font':'rs_font' Var='localFont')))
275
276  // Get address of targeted RS object
277  clang::Expr *AddrRefRSVar =
278      new(C) clang::UnaryOperator(RefRSVar,
279                                  clang::UO_AddrOf,
280                                  ClearObjectFDArgType,
281                                  Loc);
282
283  clang::Expr *RefRSClearObjectFD =
284      clang::DeclRefExpr::Create(C,
285                                 NULL,
286                                 ClearObjectFD->getQualifierRange(),
287                                 ClearObjectFD,
288                                 ClearObjectFD->getLocation(),
289                                 ClearObjectFDType);
290
291  clang::Expr *RSClearObjectFP =
292      clang::ImplicitCastExpr::Create(C,
293                                      C.getPointerType(ClearObjectFDType),
294                                      clang::CK_FunctionToPointerDecay,
295                                      RefRSClearObjectFD,
296                                      NULL,
297                                      clang::VK_RValue);
298
299  clang::CallExpr *RSClearObjectCall =
300      new(C) clang::CallExpr(C,
301                             RSClearObjectFP,
302                             &AddrRefRSVar,
303                             1,
304                             ClearObjectFD->getCallResultType(),
305                             Loc);
306
307  return RSClearObjectCall;
308}
309
310static int ArrayDim(const clang::Type *T) {
311  if (!T || !T->isArrayType()) {
312    return 0;
313  }
314
315  const clang::ConstantArrayType *CAT =
316    static_cast<const clang::ConstantArrayType *>(T);
317  return static_cast<int>(CAT->getSize().getSExtValue());
318}
319
320static clang::Stmt *ClearStructRSObject(
321    clang::ASTContext &C,
322    clang::DeclContext *DC,
323    clang::Expr *RefRSStruct,
324    clang::SourceRange Range,
325    clang::SourceLocation Loc);
326
327static clang::Stmt *ClearArrayRSObject(
328    clang::ASTContext &C,
329    clang::DeclContext *DC,
330    clang::Expr *RefRSArr,
331    clang::SourceRange Range,
332    clang::SourceLocation Loc) {
333  const clang::Type *BaseType = RefRSArr->getType().getTypePtr();
334  slangAssert(BaseType->isArrayType());
335
336  int NumArrayElements = ArrayDim(BaseType);
337  // Actually extract out the base RS object type for use later
338  BaseType = BaseType->getArrayElementTypeNoTypeQual();
339
340  clang::Stmt *StmtArray[2] = {NULL};
341  int StmtCtr = 0;
342
343  if (NumArrayElements <= 0) {
344    return NULL;
345  }
346
347  // Example destructor loop for "rs_font fontArr[10];"
348  //
349  // (CompoundStmt
350  //   (DeclStmt "int rsIntIter")
351  //   (ForStmt
352  //     (BinaryOperator 'int' '='
353  //       (DeclRefExpr 'int' Var='rsIntIter')
354  //       (IntegerLiteral 'int' 0))
355  //     (BinaryOperator 'int' '<'
356  //       (DeclRefExpr 'int' Var='rsIntIter')
357  //       (IntegerLiteral 'int' 10)
358  //     NULL << CondVar >>
359  //     (UnaryOperator 'int' postfix '++'
360  //       (DeclRefExpr 'int' Var='rsIntIter'))
361  //     (CallExpr 'void'
362  //       (ImplicitCastExpr 'void (*)(rs_font *)' <FunctionToPointerDecay>
363  //         (DeclRefExpr 'void (rs_font *)' FunctionDecl='rsClearObject'))
364  //       (UnaryOperator 'rs_font *' prefix '&'
365  //         (ArraySubscriptExpr 'rs_font':'rs_font'
366  //           (ImplicitCastExpr 'rs_font *' <ArrayToPointerDecay>
367  //             (DeclRefExpr 'rs_font [10]' Var='fontArr'))
368  //           (DeclRefExpr 'int' Var='rsIntIter')))))))
369
370  // Create helper variable for iterating through elements
371  clang::IdentifierInfo& II = C.Idents.get("rsIntIter");
372  clang::VarDecl *IIVD =
373      clang::VarDecl::Create(C,
374                             DC,
375                             Loc,
376                             &II,
377                             C.IntTy,
378                             C.getTrivialTypeSourceInfo(C.IntTy),
379                             clang::SC_None,
380                             clang::SC_None);
381  clang::Decl *IID = (clang::Decl *)IIVD;
382
383  clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(C, &IID, 1);
384  StmtArray[StmtCtr++] = new(C) clang::DeclStmt(DGR, Loc, Loc);
385
386  // Form the actual destructor loop
387  // for (Init; Cond; Inc)
388  //   RSClearObjectCall;
389
390  // Init -> "rsIntIter = 0"
391  clang::DeclRefExpr *RefrsIntIter =
392      clang::DeclRefExpr::Create(C,
393                                 NULL,
394                                 Range,
395                                 IIVD,
396                                 Loc,
397                                 C.IntTy);
398
399  clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
400      llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
401
402  clang::BinaryOperator *Init =
403      new(C) clang::BinaryOperator(RefrsIntIter,
404                                   Int0,
405                                   clang::BO_Assign,
406                                   C.IntTy,
407                                   Loc);
408
409  // Cond -> "rsIntIter < NumArrayElements"
410  clang::Expr *NumArrayElementsExpr = clang::IntegerLiteral::Create(C,
411      llvm::APInt(C.getTypeSize(C.IntTy), NumArrayElements), C.IntTy, Loc);
412
413  clang::BinaryOperator *Cond =
414      new(C) clang::BinaryOperator(RefrsIntIter,
415                                   NumArrayElementsExpr,
416                                   clang::BO_LT,
417                                   C.IntTy,
418                                   Loc);
419
420  // Inc -> "rsIntIter++"
421  clang::UnaryOperator *Inc =
422      new(C) clang::UnaryOperator(RefrsIntIter,
423                                  clang::UO_PostInc,
424                                  C.IntTy,
425                                  Loc);
426
427  // Body -> "rsClearObject(&VD[rsIntIter]);"
428  // Destructor loop operates on individual array elements
429
430  clang::Expr *RefRSArrPtr =
431      clang::ImplicitCastExpr::Create(C,
432          C.getPointerType(BaseType->getCanonicalTypeInternal()),
433          clang::CK_ArrayToPointerDecay,
434          RefRSArr,
435          NULL,
436          clang::VK_RValue);
437
438  clang::Expr *RefRSArrPtrSubscript =
439      new(C) clang::ArraySubscriptExpr(RefRSArrPtr,
440                                       RefrsIntIter,
441                                       BaseType->getCanonicalTypeInternal(),
442                                       Loc);
443
444  RSExportPrimitiveType::DataType DT =
445      RSExportPrimitiveType::GetRSSpecificType(BaseType);
446
447  clang::Stmt *RSClearObjectCall = NULL;
448  if (BaseType->isArrayType()) {
449    RSClearObjectCall =
450        ClearArrayRSObject(C, DC, RefRSArrPtrSubscript, Range, Loc);
451  } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
452    RSClearObjectCall =
453        ClearStructRSObject(C, DC, RefRSArrPtrSubscript, Range, Loc);
454  } else {
455    RSClearObjectCall = ClearSingleRSObject(C, RefRSArrPtrSubscript, Loc);
456  }
457
458  clang::ForStmt *DestructorLoop =
459      new(C) clang::ForStmt(C,
460                            Init,
461                            Cond,
462                            NULL,  // no condVar
463                            Inc,
464                            RSClearObjectCall,
465                            Loc,
466                            Loc,
467                            Loc);
468
469  StmtArray[StmtCtr++] = DestructorLoop;
470  slangAssert(StmtCtr == 2);
471
472  clang::CompoundStmt *CS =
473      new(C) clang::CompoundStmt(C, StmtArray, StmtCtr, Loc, Loc);
474
475  return CS;
476}
477
478static unsigned CountRSObjectTypes(const clang::Type *T) {
479  slangAssert(T);
480  unsigned RSObjectCount = 0;
481
482  if (T->isArrayType()) {
483    return CountRSObjectTypes(T->getArrayElementTypeNoTypeQual());
484  }
485
486  RSExportPrimitiveType::DataType DT =
487      RSExportPrimitiveType::GetRSSpecificType(T);
488  if (DT != RSExportPrimitiveType::DataTypeUnknown) {
489    return (RSExportPrimitiveType::IsRSObjectType(DT) ? 1 : 0);
490  }
491
492  if (!T->isStructureType()) {
493    return 0;
494  }
495
496  clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
497  RD = RD->getDefinition();
498  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
499         FE = RD->field_end();
500       FI != FE;
501       FI++) {
502    const clang::FieldDecl *FD = *FI;
503    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
504    if (CountRSObjectTypes(FT)) {
505      // Sub-structs should only count once (as should arrays, etc.)
506      RSObjectCount++;
507    }
508  }
509
510  return RSObjectCount;
511}
512
513static clang::Stmt *ClearStructRSObject(
514    clang::ASTContext &C,
515    clang::DeclContext *DC,
516    clang::Expr *RefRSStruct,
517    clang::SourceRange Range,
518    clang::SourceLocation Loc) {
519  const clang::Type *BaseType = RefRSStruct->getType().getTypePtr();
520
521  slangAssert(!BaseType->isArrayType());
522
523  RSExportPrimitiveType::DataType DT =
524      RSExportPrimitiveType::GetRSSpecificType(BaseType);
525
526  // Structs should show up as unknown primitive types
527  slangAssert(DT == RSExportPrimitiveType::DataTypeUnknown);
528
529  unsigned FieldsToDestroy = CountRSObjectTypes(BaseType);
530
531  unsigned StmtCount = 0;
532  clang::Stmt **StmtArray = new clang::Stmt*[FieldsToDestroy];
533  for (unsigned i = 0; i < FieldsToDestroy; i++) {
534    StmtArray[i] = NULL;
535  }
536
537  // Populate StmtArray by creating a destructor for each RS object field
538  clang::RecordDecl *RD = BaseType->getAsStructureType()->getDecl();
539  RD = RD->getDefinition();
540  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
541         FE = RD->field_end();
542       FI != FE;
543       FI++) {
544    // We just look through all field declarations to see if we find a
545    // declaration for an RS object type (or an array of one).
546    bool IsArrayType = false;
547    clang::FieldDecl *FD = *FI;
548    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
549    const clang::Type *OrigType = FT;
550    while (FT && FT->isArrayType()) {
551      FT = FT->getArrayElementTypeNoTypeQual();
552      IsArrayType = true;
553    }
554
555    if (RSExportPrimitiveType::IsRSObjectType(FT)) {
556      clang::DeclAccessPair FoundDecl =
557          clang::DeclAccessPair::make(FD, clang::AS_none);
558      clang::MemberExpr *RSObjectMember =
559          clang::MemberExpr::Create(C,
560                                    RefRSStruct,
561                                    false,
562                                    NULL,
563                                    Range,
564                                    FD,
565                                    FoundDecl,
566                                    clang::DeclarationNameInfo(),
567                                    NULL,
568                                    OrigType->getCanonicalTypeInternal());
569
570      slangAssert(StmtCount < FieldsToDestroy);
571
572      if (IsArrayType) {
573        StmtArray[StmtCount++] = ClearArrayRSObject(C,
574                                                    DC,
575                                                    RSObjectMember,
576                                                    Range,
577                                                    Loc);
578      } else {
579        StmtArray[StmtCount++] = ClearSingleRSObject(C,
580                                                     RSObjectMember,
581                                                     Loc);
582      }
583    } else if (FT->isStructureType() && CountRSObjectTypes(FT)) {
584      // In this case, we have a nested struct. We may not end up filling all
585      // of the spaces in StmtArray (sub-structs should handle themselves
586      // with separate compound statements).
587      clang::DeclAccessPair FoundDecl =
588          clang::DeclAccessPair::make(FD, clang::AS_none);
589      clang::MemberExpr *RSObjectMember =
590          clang::MemberExpr::Create(C,
591                                    RefRSStruct,
592                                    false,
593                                    NULL,
594                                    Range,
595                                    FD,
596                                    FoundDecl,
597                                    clang::DeclarationNameInfo(),
598                                    NULL,
599                                    OrigType->getCanonicalTypeInternal());
600
601      if (IsArrayType) {
602        StmtArray[StmtCount++] = ClearArrayRSObject(C,
603                                                    DC,
604                                                    RSObjectMember,
605                                                    Range,
606                                                    Loc);
607      } else {
608        StmtArray[StmtCount++] = ClearStructRSObject(C,
609                                                     DC,
610                                                     RSObjectMember,
611                                                     Range,
612                                                     Loc);
613      }
614    }
615  }
616
617  slangAssert(StmtCount > 0);
618  clang::CompoundStmt *CS =
619      new(C) clang::CompoundStmt(C, StmtArray, StmtCount, Loc, Loc);
620
621  delete [] StmtArray;
622
623  return CS;
624}
625
626static clang::Stmt *CreateSingleRSSetObject(clang::ASTContext &C,
627                                            clang::Diagnostic *Diags,
628                                            clang::Expr *DstExpr,
629                                            clang::Expr *SrcExpr,
630                                            clang::SourceLocation Loc) {
631  const clang::Type *T = DstExpr->getType().getTypePtr();
632  clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(T);
633  slangAssert((SetObjectFD != NULL) &&
634              "rsSetObject doesn't cover all RS object types");
635
636  clang::QualType SetObjectFDType = SetObjectFD->getType();
637  clang::QualType SetObjectFDArgType[2];
638  SetObjectFDArgType[0] = SetObjectFD->getParamDecl(0)->getOriginalType();
639  SetObjectFDArgType[1] = SetObjectFD->getParamDecl(1)->getOriginalType();
640
641  clang::Expr *RefRSSetObjectFD =
642      clang::DeclRefExpr::Create(C,
643                                 NULL,
644                                 SetObjectFD->getQualifierRange(),
645                                 SetObjectFD,
646                                 Loc,
647                                 SetObjectFDType);
648
649  clang::Expr *RSSetObjectFP =
650      clang::ImplicitCastExpr::Create(C,
651                                      C.getPointerType(SetObjectFDType),
652                                      clang::CK_FunctionToPointerDecay,
653                                      RefRSSetObjectFD,
654                                      NULL,
655                                      clang::VK_RValue);
656
657  clang::Expr *ArgList[2];
658  ArgList[0] = new(C) clang::UnaryOperator(DstExpr,
659                                           clang::UO_AddrOf,
660                                           SetObjectFDArgType[0],
661                                           Loc);
662  ArgList[1] = SrcExpr;
663
664  clang::CallExpr *RSSetObjectCall =
665      new(C) clang::CallExpr(C,
666                             RSSetObjectFP,
667                             ArgList,
668                             2,
669                             SetObjectFD->getCallResultType(),
670                             Loc);
671
672  return RSSetObjectCall;
673}
674
675static clang::Stmt *CreateStructRSSetObject(clang::ASTContext &C,
676                                            clang::Diagnostic *Diags,
677                                            clang::Expr *LHS,
678                                            clang::Expr *RHS,
679                                            clang::SourceLocation Loc);
680
681static clang::Stmt *CreateArrayRSSetObject(clang::ASTContext &C,
682                                           clang::Diagnostic *Diags,
683                                           clang::Expr *DstArr,
684                                           clang::Expr *SrcArr,
685                                           clang::SourceLocation Loc) {
686  clang::DeclContext *DC = NULL;
687  clang::SourceRange Range;
688  const clang::Type *BaseType = DstArr->getType().getTypePtr();
689  slangAssert(BaseType->isArrayType());
690
691  int NumArrayElements = ArrayDim(BaseType);
692  // Actually extract out the base RS object type for use later
693  BaseType = BaseType->getArrayElementTypeNoTypeQual();
694
695  clang::Stmt *StmtArray[2] = {NULL};
696  int StmtCtr = 0;
697
698  if (NumArrayElements <= 0) {
699    return NULL;
700  }
701
702  // Create helper variable for iterating through elements
703  clang::IdentifierInfo& II = C.Idents.get("rsIntIter");
704  clang::VarDecl *IIVD =
705      clang::VarDecl::Create(C,
706                             DC,
707                             Loc,
708                             &II,
709                             C.IntTy,
710                             C.getTrivialTypeSourceInfo(C.IntTy),
711                             clang::SC_None,
712                             clang::SC_None);
713  clang::Decl *IID = (clang::Decl *)IIVD;
714
715  clang::DeclGroupRef DGR = clang::DeclGroupRef::Create(C, &IID, 1);
716  StmtArray[StmtCtr++] = new(C) clang::DeclStmt(DGR, Loc, Loc);
717
718  // Form the actual loop
719  // for (Init; Cond; Inc)
720  //   RSSetObjectCall;
721
722  // Init -> "rsIntIter = 0"
723  clang::DeclRefExpr *RefrsIntIter =
724      clang::DeclRefExpr::Create(C,
725                                 NULL,
726                                 Range,
727                                 IIVD,
728                                 Loc,
729                                 C.IntTy);
730
731  clang::Expr *Int0 = clang::IntegerLiteral::Create(C,
732      llvm::APInt(C.getTypeSize(C.IntTy), 0), C.IntTy, Loc);
733
734  clang::BinaryOperator *Init =
735      new(C) clang::BinaryOperator(RefrsIntIter,
736                                   Int0,
737                                   clang::BO_Assign,
738                                   C.IntTy,
739                                   Loc);
740
741  // Cond -> "rsIntIter < NumArrayElements"
742  clang::Expr *NumArrayElementsExpr = clang::IntegerLiteral::Create(C,
743      llvm::APInt(C.getTypeSize(C.IntTy), NumArrayElements), C.IntTy, Loc);
744
745  clang::BinaryOperator *Cond =
746      new(C) clang::BinaryOperator(RefrsIntIter,
747                                   NumArrayElementsExpr,
748                                   clang::BO_LT,
749                                   C.IntTy,
750                                   Loc);
751
752  // Inc -> "rsIntIter++"
753  clang::UnaryOperator *Inc =
754      new(C) clang::UnaryOperator(RefrsIntIter,
755                                  clang::UO_PostInc,
756                                  C.IntTy,
757                                  Loc);
758
759  // Body -> "rsSetObject(&Dst[rsIntIter], Src[rsIntIter]);"
760  // Loop operates on individual array elements
761
762  clang::Expr *DstArrPtr =
763      clang::ImplicitCastExpr::Create(C,
764          C.getPointerType(BaseType->getCanonicalTypeInternal()),
765          clang::CK_ArrayToPointerDecay,
766          DstArr,
767          NULL,
768          clang::VK_RValue);
769
770  clang::Expr *DstArrPtrSubscript =
771      new(C) clang::ArraySubscriptExpr(DstArrPtr,
772                                       RefrsIntIter,
773                                       BaseType->getCanonicalTypeInternal(),
774                                       Loc);
775
776  clang::Expr *SrcArrPtr =
777      clang::ImplicitCastExpr::Create(C,
778          C.getPointerType(BaseType->getCanonicalTypeInternal()),
779          clang::CK_ArrayToPointerDecay,
780          SrcArr,
781          NULL,
782          clang::VK_RValue);
783
784  clang::Expr *SrcArrPtrSubscript =
785      new(C) clang::ArraySubscriptExpr(SrcArrPtr,
786                                       RefrsIntIter,
787                                       BaseType->getCanonicalTypeInternal(),
788                                       Loc);
789
790  RSExportPrimitiveType::DataType DT =
791      RSExportPrimitiveType::GetRSSpecificType(BaseType);
792
793  clang::Stmt *RSSetObjectCall = NULL;
794  if (BaseType->isArrayType()) {
795    RSSetObjectCall = CreateArrayRSSetObject(C, Diags, DstArrPtrSubscript,
796                                             SrcArrPtrSubscript, Loc);
797  } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
798    RSSetObjectCall = CreateStructRSSetObject(C, Diags, DstArrPtrSubscript,
799                                              SrcArrPtrSubscript, Loc);
800  } else {
801    RSSetObjectCall = CreateSingleRSSetObject(C, Diags, DstArrPtrSubscript,
802                                              SrcArrPtrSubscript, Loc);
803  }
804
805  clang::ForStmt *DestructorLoop =
806      new(C) clang::ForStmt(C,
807                            Init,
808                            Cond,
809                            NULL,  // no condVar
810                            Inc,
811                            RSSetObjectCall,
812                            Loc,
813                            Loc,
814                            Loc);
815
816  StmtArray[StmtCtr++] = DestructorLoop;
817  slangAssert(StmtCtr == 2);
818
819  clang::CompoundStmt *CS =
820      new(C) clang::CompoundStmt(C, StmtArray, StmtCtr, Loc, Loc);
821
822  return CS;
823}
824
825static clang::Stmt *CreateStructRSSetObject(clang::ASTContext &C,
826                                            clang::Diagnostic *Diags,
827                                            clang::Expr *LHS,
828                                            clang::Expr *RHS,
829                                            clang::SourceLocation Loc) {
830  clang::SourceRange Range;
831  clang::QualType QT = LHS->getType();
832  const clang::Type *T = QT.getTypePtr();
833  slangAssert(T->isStructureType());
834  slangAssert(!RSExportPrimitiveType::IsRSObjectType(T));
835
836  // Keep an extra slot for the original copy (memcpy)
837  unsigned FieldsToSet = CountRSObjectTypes(T) + 1;
838
839  unsigned StmtCount = 0;
840  clang::Stmt **StmtArray = new clang::Stmt*[FieldsToSet];
841  for (unsigned i = 0; i < FieldsToSet; i++) {
842    StmtArray[i] = NULL;
843  }
844
845  clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
846  RD = RD->getDefinition();
847  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
848         FE = RD->field_end();
849       FI != FE;
850       FI++) {
851    bool IsArrayType = false;
852    clang::FieldDecl *FD = *FI;
853    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
854    const clang::Type *OrigType = FT;
855
856    if (!CountRSObjectTypes(FT)) {
857      // Skip to next if we don't have any viable RS object types
858      continue;
859    }
860
861    clang::DeclAccessPair FoundDecl =
862        clang::DeclAccessPair::make(FD, clang::AS_none);
863    clang::MemberExpr *DstMember =
864        clang::MemberExpr::Create(C,
865                                  LHS,
866                                  false,
867                                  NULL,
868                                  Range,
869                                  FD,
870                                  FoundDecl,
871                                  clang::DeclarationNameInfo(),
872                                  NULL,
873                                  OrigType->getCanonicalTypeInternal());
874
875    clang::MemberExpr *SrcMember =
876        clang::MemberExpr::Create(C,
877                                  RHS,
878                                  false,
879                                  NULL,
880                                  Range,
881                                  FD,
882                                  FoundDecl,
883                                  clang::DeclarationNameInfo(),
884                                  NULL,
885                                  OrigType->getCanonicalTypeInternal());
886
887    if (FT->isArrayType()) {
888      FT = FT->getArrayElementTypeNoTypeQual();
889      IsArrayType = true;
890    }
891
892    RSExportPrimitiveType::DataType DT =
893        RSExportPrimitiveType::GetRSSpecificType(FT);
894
895    if (IsArrayType) {
896      Diags->Report(Diags->getCustomDiagID(clang::Diagnostic::Error,
897           "Arrays of RS object types within structures cannot be copied"));
898      // TODO(srhines): Support setting arrays of RS objects
899      // StmtArray[StmtCount++] =
900      //    CreateArrayRSSetObject(C, Diags, DstMember, SrcMember, Loc);
901    } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
902      StmtArray[StmtCount++] =
903          CreateStructRSSetObject(C, Diags, DstMember, SrcMember, Loc);
904    } else if (RSExportPrimitiveType::IsRSObjectType(DT)) {
905      StmtArray[StmtCount++] =
906          CreateSingleRSSetObject(C, Diags, DstMember, SrcMember, Loc);
907    } else {
908      slangAssert(false);
909    }
910  }
911
912  slangAssert(StmtCount > 0 && StmtCount < FieldsToSet);
913
914  // We still need to actually do the overall struct copy. For simplicity,
915  // we just do a straight-up assignment (which will still preserve all
916  // the proper RS object reference counts).
917  clang::BinaryOperator *CopyStruct =
918      new(C) clang::BinaryOperator(LHS, RHS, clang::BO_Assign, QT, Loc);
919  StmtArray[StmtCount++] = CopyStruct;
920
921  clang::CompoundStmt *CS =
922      new(C) clang::CompoundStmt(C, StmtArray, StmtCount, Loc, Loc);
923
924  delete [] StmtArray;
925
926  return CS;
927}
928
929}  // namespace
930
931void RSObjectRefCount::Scope::ReplaceRSObjectAssignment(
932    clang::BinaryOperator *AS,
933    clang::Diagnostic *Diags) {
934
935  clang::QualType QT = AS->getType();
936
937  clang::ASTContext &C = RSObjectRefCount::GetRSSetObjectFD(
938      RSExportPrimitiveType::DataTypeRSFont)->getASTContext();
939
940  clang::SourceLocation Loc = AS->getLocEnd();
941  clang::Stmt *UpdatedStmt = NULL;
942
943  if (!RSExportPrimitiveType::IsRSObjectType(QT.getTypePtr())) {
944    // By definition, this is a struct assignment if we get here
945    UpdatedStmt =
946        CreateStructRSSetObject(C, Diags, AS->getLHS(), AS->getRHS(), Loc);
947  } else {
948    UpdatedStmt =
949        CreateSingleRSSetObject(C, Diags, AS->getLHS(), AS->getRHS(), Loc);
950  }
951
952  ReplaceInCompoundStmt(C, mCS, AS, UpdatedStmt);
953  return;
954}
955
956void RSObjectRefCount::Scope::AppendRSObjectInit(
957    clang::VarDecl *VD,
958    clang::DeclStmt *DS,
959    RSExportPrimitiveType::DataType DT,
960    clang::Expr *InitExpr) {
961  slangAssert(VD);
962
963  if (!InitExpr) {
964    return;
965  }
966
967  if (DT == RSExportPrimitiveType::DataTypeIsStruct) {
968    // TODO(srhines): Skip struct initialization right now
969    return;
970  }
971
972  clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(DT);
973  slangAssert((SetObjectFD != NULL) &&
974              "rsSetObject doesn't cover all RS object types");
975  clang::ASTContext &C = SetObjectFD->getASTContext();
976
977  clang::QualType SetObjectFDType = SetObjectFD->getType();
978  clang::QualType SetObjectFDArgType[2];
979  SetObjectFDArgType[0] = SetObjectFD->getParamDecl(0)->getOriginalType();
980  SetObjectFDArgType[1] = SetObjectFD->getParamDecl(1)->getOriginalType();
981
982  clang::SourceLocation Loc = SetObjectFD->getLocation();
983  clang::Expr *RefRSSetObjectFD =
984      clang::DeclRefExpr::Create(C,
985                                 NULL,
986                                 SetObjectFD->getQualifierRange(),
987                                 SetObjectFD,
988                                 Loc,
989                                 SetObjectFDType);
990
991  clang::Expr *RSSetObjectFP =
992      clang::ImplicitCastExpr::Create(C,
993                                      C.getPointerType(SetObjectFDType),
994                                      clang::CK_FunctionToPointerDecay,
995                                      RefRSSetObjectFD,
996                                      NULL,
997                                      clang::VK_RValue);
998
999  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1000  clang::DeclRefExpr *RefRSVar =
1001      clang::DeclRefExpr::Create(C,
1002                                 NULL,
1003                                 VD->getQualifierRange(),
1004                                 VD,
1005                                 Loc,
1006                                 T->getCanonicalTypeInternal());
1007
1008  clang::Expr *ArgList[2];
1009  ArgList[0] = new(C) clang::UnaryOperator(RefRSVar,
1010                                           clang::UO_AddrOf,
1011                                           SetObjectFDArgType[0],
1012                                           Loc);
1013  ArgList[1] = InitExpr;
1014
1015  clang::CallExpr *RSSetObjectCall =
1016      new(C) clang::CallExpr(C,
1017                             RSSetObjectFP,
1018                             ArgList,
1019                             2,
1020                             SetObjectFD->getCallResultType(),
1021                             Loc);
1022
1023  AppendAfterStmt(C, mCS, DS, RSSetObjectCall);
1024
1025  return;
1026}
1027
1028void RSObjectRefCount::Scope::InsertLocalVarDestructors() {
1029  std::list<clang::Stmt*> RSClearObjectCalls;
1030  for (std::list<clang::VarDecl*>::const_iterator I = mRSO.begin(),
1031          E = mRSO.end();
1032        I != E;
1033        I++) {
1034    clang::Stmt *S = ClearRSObject(*I);
1035    if (S) {
1036      RSClearObjectCalls.push_back(S);
1037    }
1038  }
1039  if (RSClearObjectCalls.size() > 0) {
1040    DestructorVisitor DV((*mRSO.begin())->getASTContext(), RSClearObjectCalls);
1041    DV.Visit(mCS);
1042  }
1043  return;
1044}
1045
1046clang::Stmt *RSObjectRefCount::Scope::ClearRSObject(clang::VarDecl *VD) {
1047  slangAssert(VD);
1048  clang::ASTContext &C = VD->getASTContext();
1049  clang::DeclContext *DC = VD->getDeclContext();
1050  clang::SourceRange Range = VD->getQualifierRange();
1051  clang::SourceLocation Loc = VD->getLocation();
1052  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1053
1054  // Reference expr to target RS object variable
1055  clang::DeclRefExpr *RefRSVar =
1056      clang::DeclRefExpr::Create(C,
1057                                 NULL,
1058                                 Range,
1059                                 VD,
1060                                 Loc,
1061                                 T->getCanonicalTypeInternal());
1062
1063  if (T->isArrayType()) {
1064    return ClearArrayRSObject(C, DC, RefRSVar, Range, Loc);
1065  }
1066
1067  RSExportPrimitiveType::DataType DT =
1068      RSExportPrimitiveType::GetRSSpecificType(T);
1069
1070  if (DT == RSExportPrimitiveType::DataTypeUnknown ||
1071      DT == RSExportPrimitiveType::DataTypeIsStruct) {
1072    return ClearStructRSObject(C, DC, RefRSVar, Range, Loc);
1073  }
1074
1075  slangAssert((RSExportPrimitiveType::IsRSObjectType(DT)) &&
1076              "Should be RS object");
1077
1078  return ClearSingleRSObject(C, RefRSVar, Loc);
1079}
1080
1081bool RSObjectRefCount::InitializeRSObject(clang::VarDecl *VD,
1082                                          RSExportPrimitiveType::DataType *DT,
1083                                          clang::Expr **InitExpr) {
1084  slangAssert(VD && DT && InitExpr);
1085  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1086
1087  // Loop through array types to get to base type
1088  while (T && T->isArrayType()) {
1089    T = T->getArrayElementTypeNoTypeQual();
1090  }
1091
1092  bool DataTypeIsStructWithRSObject = false;
1093  *DT = RSExportPrimitiveType::GetRSSpecificType(T);
1094
1095  if (*DT == RSExportPrimitiveType::DataTypeUnknown) {
1096    if (RSExportPrimitiveType::IsStructureTypeWithRSObject(T)) {
1097      *DT = RSExportPrimitiveType::DataTypeIsStruct;
1098      DataTypeIsStructWithRSObject = true;
1099    } else {
1100      return false;
1101    }
1102  }
1103
1104  bool DataTypeIsRSObject = false;
1105  if (DataTypeIsStructWithRSObject) {
1106    DataTypeIsRSObject = true;
1107  } else {
1108    DataTypeIsRSObject = RSExportPrimitiveType::IsRSObjectType(*DT);
1109  }
1110  *InitExpr = VD->getInit();
1111
1112  if (!DataTypeIsRSObject && *InitExpr) {
1113    // If we already have an initializer for a matrix type, we are done.
1114    return DataTypeIsRSObject;
1115  }
1116
1117  clang::Expr *ZeroInitializer =
1118      CreateZeroInitializerForRSSpecificType(*DT,
1119                                             VD->getASTContext(),
1120                                             VD->getLocation());
1121
1122  if (ZeroInitializer) {
1123    ZeroInitializer->setType(T->getCanonicalTypeInternal());
1124    VD->setInit(ZeroInitializer);
1125  }
1126
1127  return DataTypeIsRSObject;
1128}
1129
1130clang::Expr *RSObjectRefCount::CreateZeroInitializerForRSSpecificType(
1131    RSExportPrimitiveType::DataType DT,
1132    clang::ASTContext &C,
1133    const clang::SourceLocation &Loc) {
1134  clang::Expr *Res = NULL;
1135  switch (DT) {
1136    case RSExportPrimitiveType::DataTypeIsStruct:
1137    case RSExportPrimitiveType::DataTypeRSElement:
1138    case RSExportPrimitiveType::DataTypeRSType:
1139    case RSExportPrimitiveType::DataTypeRSAllocation:
1140    case RSExportPrimitiveType::DataTypeRSSampler:
1141    case RSExportPrimitiveType::DataTypeRSScript:
1142    case RSExportPrimitiveType::DataTypeRSMesh:
1143    case RSExportPrimitiveType::DataTypeRSProgramFragment:
1144    case RSExportPrimitiveType::DataTypeRSProgramVertex:
1145    case RSExportPrimitiveType::DataTypeRSProgramRaster:
1146    case RSExportPrimitiveType::DataTypeRSProgramStore:
1147    case RSExportPrimitiveType::DataTypeRSFont: {
1148      //    (ImplicitCastExpr 'nullptr_t'
1149      //      (IntegerLiteral 0)))
1150      llvm::APInt Zero(C.getTypeSize(C.IntTy), 0);
1151      clang::Expr *Int0 = clang::IntegerLiteral::Create(C, Zero, C.IntTy, Loc);
1152      clang::Expr *CastToNull =
1153          clang::ImplicitCastExpr::Create(C,
1154                                          C.NullPtrTy,
1155                                          clang::CK_IntegralToPointer,
1156                                          Int0,
1157                                          NULL,
1158                                          clang::VK_RValue);
1159
1160      Res = new(C) clang::InitListExpr(C, Loc, &CastToNull, 1, Loc);
1161      break;
1162    }
1163    case RSExportPrimitiveType::DataTypeRSMatrix2x2:
1164    case RSExportPrimitiveType::DataTypeRSMatrix3x3:
1165    case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
1166      // RS matrix is not completely an RS object. They hold data by themselves.
1167      // (InitListExpr rs_matrix2x2
1168      //   (InitListExpr float[4]
1169      //     (FloatingLiteral 0)
1170      //     (FloatingLiteral 0)
1171      //     (FloatingLiteral 0)
1172      //     (FloatingLiteral 0)))
1173      clang::QualType FloatTy = C.FloatTy;
1174      // Constructor sets value to 0.0f by default
1175      llvm::APFloat Val(C.getFloatTypeSemantics(FloatTy));
1176      clang::FloatingLiteral *Float0Val =
1177          clang::FloatingLiteral::Create(C,
1178                                         Val,
1179                                         /* isExact = */true,
1180                                         FloatTy,
1181                                         Loc);
1182
1183      unsigned N = 0;
1184      if (DT == RSExportPrimitiveType::DataTypeRSMatrix2x2)
1185        N = 2;
1186      else if (DT == RSExportPrimitiveType::DataTypeRSMatrix3x3)
1187        N = 3;
1188      else if (DT == RSExportPrimitiveType::DataTypeRSMatrix4x4)
1189        N = 4;
1190
1191      // Directly allocate 16 elements instead of dynamically allocate N*N
1192      clang::Expr *InitVals[16];
1193      for (unsigned i = 0; i < sizeof(InitVals) / sizeof(InitVals[0]); i++)
1194        InitVals[i] = Float0Val;
1195      clang::Expr *InitExpr =
1196          new(C) clang::InitListExpr(C, Loc, InitVals, N * N, Loc);
1197      InitExpr->setType(C.getConstantArrayType(FloatTy,
1198                                               llvm::APInt(32, 4),
1199                                               clang::ArrayType::Normal,
1200                                               /* EltTypeQuals = */0));
1201
1202      Res = new(C) clang::InitListExpr(C, Loc, &InitExpr, 1, Loc);
1203      break;
1204    }
1205    case RSExportPrimitiveType::DataTypeUnknown:
1206    case RSExportPrimitiveType::DataTypeFloat16:
1207    case RSExportPrimitiveType::DataTypeFloat32:
1208    case RSExportPrimitiveType::DataTypeFloat64:
1209    case RSExportPrimitiveType::DataTypeSigned8:
1210    case RSExportPrimitiveType::DataTypeSigned16:
1211    case RSExportPrimitiveType::DataTypeSigned32:
1212    case RSExportPrimitiveType::DataTypeSigned64:
1213    case RSExportPrimitiveType::DataTypeUnsigned8:
1214    case RSExportPrimitiveType::DataTypeUnsigned16:
1215    case RSExportPrimitiveType::DataTypeUnsigned32:
1216    case RSExportPrimitiveType::DataTypeUnsigned64:
1217    case RSExportPrimitiveType::DataTypeBoolean:
1218    case RSExportPrimitiveType::DataTypeUnsigned565:
1219    case RSExportPrimitiveType::DataTypeUnsigned5551:
1220    case RSExportPrimitiveType::DataTypeUnsigned4444:
1221    case RSExportPrimitiveType::DataTypeMax: {
1222      slangAssert(false && "Not RS object type!");
1223    }
1224    // No default case will enable compiler detecting the missing cases
1225  }
1226
1227  return Res;
1228}
1229
1230void RSObjectRefCount::VisitDeclStmt(clang::DeclStmt *DS) {
1231  for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
1232       I != E;
1233       I++) {
1234    clang::Decl *D = *I;
1235    if (D->getKind() == clang::Decl::Var) {
1236      clang::VarDecl *VD = static_cast<clang::VarDecl*>(D);
1237      RSExportPrimitiveType::DataType DT =
1238          RSExportPrimitiveType::DataTypeUnknown;
1239      clang::Expr *InitExpr = NULL;
1240      if (InitializeRSObject(VD, &DT, &InitExpr)) {
1241        getCurrentScope()->addRSObject(VD);
1242        getCurrentScope()->AppendRSObjectInit(VD, DS, DT, InitExpr);
1243      }
1244    }
1245  }
1246  return;
1247}
1248
1249void RSObjectRefCount::VisitCompoundStmt(clang::CompoundStmt *CS) {
1250  if (!CS->body_empty()) {
1251    // Push a new scope
1252    Scope *S = new Scope(CS);
1253    mScopeStack.push(S);
1254
1255    VisitStmt(CS);
1256
1257    // Destroy the scope
1258    slangAssert((getCurrentScope() == S) && "Corrupted scope stack!");
1259    S->InsertLocalVarDestructors();
1260    mScopeStack.pop();
1261    delete S;
1262  }
1263  return;
1264}
1265
1266void RSObjectRefCount::VisitBinAssign(clang::BinaryOperator *AS) {
1267  clang::QualType QT = AS->getType();
1268
1269  if (CountRSObjectTypes(QT.getTypePtr())) {
1270    getCurrentScope()->ReplaceRSObjectAssignment(AS, mDiags);
1271  }
1272
1273  return;
1274}
1275
1276void RSObjectRefCount::VisitStmt(clang::Stmt *S) {
1277  for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
1278       I != E;
1279       I++) {
1280    if (clang::Stmt *Child = *I) {
1281      Visit(Child);
1282    }
1283  }
1284  return;
1285}
1286
1287}  // namespace slang
1288