slang_rs_object_ref_count.cpp revision 832429f6bf4592cfc2ce58f2462f1e8ecdbaaf52
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(clang::FullSourceLoc(Loc, C.getSourceManager()),
897          Diags->getCustomDiagID(clang::Diagnostic::Error,
898            "Arrays of RS object types within structures cannot be copied"));
899      // TODO(srhines): Support setting arrays of RS objects
900      // StmtArray[StmtCount++] =
901      //    CreateArrayRSSetObject(C, Diags, DstMember, SrcMember, Loc);
902    } else if (DT == RSExportPrimitiveType::DataTypeUnknown) {
903      StmtArray[StmtCount++] =
904          CreateStructRSSetObject(C, Diags, DstMember, SrcMember, Loc);
905    } else if (RSExportPrimitiveType::IsRSObjectType(DT)) {
906      StmtArray[StmtCount++] =
907          CreateSingleRSSetObject(C, Diags, DstMember, SrcMember, Loc);
908    } else {
909      slangAssert(false);
910    }
911  }
912
913  slangAssert(StmtCount > 0 && StmtCount < FieldsToSet);
914
915  // We still need to actually do the overall struct copy. For simplicity,
916  // we just do a straight-up assignment (which will still preserve all
917  // the proper RS object reference counts).
918  clang::BinaryOperator *CopyStruct =
919      new(C) clang::BinaryOperator(LHS, RHS, clang::BO_Assign, QT, Loc);
920  StmtArray[StmtCount++] = CopyStruct;
921
922  clang::CompoundStmt *CS =
923      new(C) clang::CompoundStmt(C, StmtArray, StmtCount, Loc, Loc);
924
925  delete [] StmtArray;
926
927  return CS;
928}
929
930}  // namespace
931
932void RSObjectRefCount::Scope::ReplaceRSObjectAssignment(
933    clang::BinaryOperator *AS,
934    clang::Diagnostic *Diags) {
935
936  clang::QualType QT = AS->getType();
937
938  clang::ASTContext &C = RSObjectRefCount::GetRSSetObjectFD(
939      RSExportPrimitiveType::DataTypeRSFont)->getASTContext();
940
941  clang::SourceLocation Loc = AS->getExprLoc();
942  clang::Stmt *UpdatedStmt = NULL;
943
944  if (!RSExportPrimitiveType::IsRSObjectType(QT.getTypePtr())) {
945    // By definition, this is a struct assignment if we get here
946    UpdatedStmt =
947        CreateStructRSSetObject(C, Diags, AS->getLHS(), AS->getRHS(), Loc);
948  } else {
949    UpdatedStmt =
950        CreateSingleRSSetObject(C, Diags, AS->getLHS(), AS->getRHS(), Loc);
951  }
952
953  ReplaceInCompoundStmt(C, mCS, AS, UpdatedStmt);
954  return;
955}
956
957void RSObjectRefCount::Scope::AppendRSObjectInit(
958    clang::Diagnostic *Diags,
959    clang::VarDecl *VD,
960    clang::DeclStmt *DS,
961    RSExportPrimitiveType::DataType DT,
962    clang::Expr *InitExpr) {
963  slangAssert(VD);
964
965  if (!InitExpr) {
966    return;
967  }
968
969  clang::ASTContext &C = RSObjectRefCount::GetRSSetObjectFD(
970      RSExportPrimitiveType::DataTypeRSFont)->getASTContext();
971  clang::SourceLocation Loc = RSObjectRefCount::GetRSSetObjectFD(
972      RSExportPrimitiveType::DataTypeRSFont)->getLocation();
973
974  if (DT == RSExportPrimitiveType::DataTypeIsStruct) {
975    // TODO(srhines): Skip struct initialization right now
976    const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
977    clang::DeclRefExpr *RefRSVar =
978        clang::DeclRefExpr::Create(C,
979                                   NULL,
980                                   VD->getQualifierRange(),
981                                   VD,
982                                   Loc,
983                                   T->getCanonicalTypeInternal());
984
985    clang::Stmt *RSSetObjectOps =
986        CreateStructRSSetObject(C, Diags, RefRSVar, InitExpr, Loc);
987
988    AppendAfterStmt(C, mCS, DS, RSSetObjectOps);
989    return;
990  }
991
992  clang::FunctionDecl *SetObjectFD = RSObjectRefCount::GetRSSetObjectFD(DT);
993  slangAssert((SetObjectFD != NULL) &&
994              "rsSetObject doesn't cover all RS object types");
995
996  clang::QualType SetObjectFDType = SetObjectFD->getType();
997  clang::QualType SetObjectFDArgType[2];
998  SetObjectFDArgType[0] = SetObjectFD->getParamDecl(0)->getOriginalType();
999  SetObjectFDArgType[1] = SetObjectFD->getParamDecl(1)->getOriginalType();
1000
1001  clang::Expr *RefRSSetObjectFD =
1002      clang::DeclRefExpr::Create(C,
1003                                 NULL,
1004                                 SetObjectFD->getQualifierRange(),
1005                                 SetObjectFD,
1006                                 Loc,
1007                                 SetObjectFDType);
1008
1009  clang::Expr *RSSetObjectFP =
1010      clang::ImplicitCastExpr::Create(C,
1011                                      C.getPointerType(SetObjectFDType),
1012                                      clang::CK_FunctionToPointerDecay,
1013                                      RefRSSetObjectFD,
1014                                      NULL,
1015                                      clang::VK_RValue);
1016
1017  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1018  clang::DeclRefExpr *RefRSVar =
1019      clang::DeclRefExpr::Create(C,
1020                                 NULL,
1021                                 VD->getQualifierRange(),
1022                                 VD,
1023                                 Loc,
1024                                 T->getCanonicalTypeInternal());
1025
1026  clang::Expr *ArgList[2];
1027  ArgList[0] = new(C) clang::UnaryOperator(RefRSVar,
1028                                           clang::UO_AddrOf,
1029                                           SetObjectFDArgType[0],
1030                                           Loc);
1031  ArgList[1] = InitExpr;
1032
1033  clang::CallExpr *RSSetObjectCall =
1034      new(C) clang::CallExpr(C,
1035                             RSSetObjectFP,
1036                             ArgList,
1037                             2,
1038                             SetObjectFD->getCallResultType(),
1039                             Loc);
1040
1041  AppendAfterStmt(C, mCS, DS, RSSetObjectCall);
1042
1043  return;
1044}
1045
1046void RSObjectRefCount::Scope::InsertLocalVarDestructors() {
1047  std::list<clang::Stmt*> RSClearObjectCalls;
1048  for (std::list<clang::VarDecl*>::const_iterator I = mRSO.begin(),
1049          E = mRSO.end();
1050        I != E;
1051        I++) {
1052    clang::Stmt *S = ClearRSObject(*I);
1053    if (S) {
1054      RSClearObjectCalls.push_back(S);
1055    }
1056  }
1057  if (RSClearObjectCalls.size() > 0) {
1058    DestructorVisitor DV((*mRSO.begin())->getASTContext(), RSClearObjectCalls);
1059    DV.Visit(mCS);
1060  }
1061  return;
1062}
1063
1064clang::Stmt *RSObjectRefCount::Scope::ClearRSObject(clang::VarDecl *VD) {
1065  slangAssert(VD);
1066  clang::ASTContext &C = VD->getASTContext();
1067  clang::DeclContext *DC = VD->getDeclContext();
1068  clang::SourceRange Range = VD->getQualifierRange();
1069  clang::SourceLocation Loc = VD->getLocation();
1070  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1071
1072  // Reference expr to target RS object variable
1073  clang::DeclRefExpr *RefRSVar =
1074      clang::DeclRefExpr::Create(C,
1075                                 NULL,
1076                                 Range,
1077                                 VD,
1078                                 Loc,
1079                                 T->getCanonicalTypeInternal());
1080
1081  if (T->isArrayType()) {
1082    return ClearArrayRSObject(C, DC, RefRSVar, Range, Loc);
1083  }
1084
1085  RSExportPrimitiveType::DataType DT =
1086      RSExportPrimitiveType::GetRSSpecificType(T);
1087
1088  if (DT == RSExportPrimitiveType::DataTypeUnknown ||
1089      DT == RSExportPrimitiveType::DataTypeIsStruct) {
1090    return ClearStructRSObject(C, DC, RefRSVar, Range, Loc);
1091  }
1092
1093  slangAssert((RSExportPrimitiveType::IsRSObjectType(DT)) &&
1094              "Should be RS object");
1095
1096  return ClearSingleRSObject(C, RefRSVar, Loc);
1097}
1098
1099bool RSObjectRefCount::InitializeRSObject(clang::VarDecl *VD,
1100                                          RSExportPrimitiveType::DataType *DT,
1101                                          clang::Expr **InitExpr) {
1102  slangAssert(VD && DT && InitExpr);
1103  const clang::Type *T = RSExportType::GetTypeOfDecl(VD);
1104
1105  // Loop through array types to get to base type
1106  while (T && T->isArrayType()) {
1107    T = T->getArrayElementTypeNoTypeQual();
1108  }
1109
1110  bool DataTypeIsStructWithRSObject = false;
1111  *DT = RSExportPrimitiveType::GetRSSpecificType(T);
1112
1113  if (*DT == RSExportPrimitiveType::DataTypeUnknown) {
1114    if (RSExportPrimitiveType::IsStructureTypeWithRSObject(T)) {
1115      *DT = RSExportPrimitiveType::DataTypeIsStruct;
1116      DataTypeIsStructWithRSObject = true;
1117    } else {
1118      return false;
1119    }
1120  }
1121
1122  bool DataTypeIsRSObject = false;
1123  if (DataTypeIsStructWithRSObject) {
1124    DataTypeIsRSObject = true;
1125  } else {
1126    DataTypeIsRSObject = RSExportPrimitiveType::IsRSObjectType(*DT);
1127  }
1128  *InitExpr = VD->getInit();
1129
1130  if (!DataTypeIsRSObject && *InitExpr) {
1131    // If we already have an initializer for a matrix type, we are done.
1132    return DataTypeIsRSObject;
1133  }
1134
1135  clang::Expr *ZeroInitializer =
1136      CreateZeroInitializerForRSSpecificType(*DT,
1137                                             VD->getASTContext(),
1138                                             VD->getLocation());
1139
1140  if (ZeroInitializer) {
1141    ZeroInitializer->setType(T->getCanonicalTypeInternal());
1142    VD->setInit(ZeroInitializer);
1143  }
1144
1145  return DataTypeIsRSObject;
1146}
1147
1148clang::Expr *RSObjectRefCount::CreateZeroInitializerForRSSpecificType(
1149    RSExportPrimitiveType::DataType DT,
1150    clang::ASTContext &C,
1151    const clang::SourceLocation &Loc) {
1152  clang::Expr *Res = NULL;
1153  switch (DT) {
1154    case RSExportPrimitiveType::DataTypeIsStruct:
1155    case RSExportPrimitiveType::DataTypeRSElement:
1156    case RSExportPrimitiveType::DataTypeRSType:
1157    case RSExportPrimitiveType::DataTypeRSAllocation:
1158    case RSExportPrimitiveType::DataTypeRSSampler:
1159    case RSExportPrimitiveType::DataTypeRSScript:
1160    case RSExportPrimitiveType::DataTypeRSMesh:
1161    case RSExportPrimitiveType::DataTypeRSProgramFragment:
1162    case RSExportPrimitiveType::DataTypeRSProgramVertex:
1163    case RSExportPrimitiveType::DataTypeRSProgramRaster:
1164    case RSExportPrimitiveType::DataTypeRSProgramStore:
1165    case RSExportPrimitiveType::DataTypeRSFont: {
1166      //    (ImplicitCastExpr 'nullptr_t'
1167      //      (IntegerLiteral 0)))
1168      llvm::APInt Zero(C.getTypeSize(C.IntTy), 0);
1169      clang::Expr *Int0 = clang::IntegerLiteral::Create(C, Zero, C.IntTy, Loc);
1170      clang::Expr *CastToNull =
1171          clang::ImplicitCastExpr::Create(C,
1172                                          C.NullPtrTy,
1173                                          clang::CK_IntegralToPointer,
1174                                          Int0,
1175                                          NULL,
1176                                          clang::VK_RValue);
1177
1178      Res = new(C) clang::InitListExpr(C, Loc, &CastToNull, 1, Loc);
1179      break;
1180    }
1181    case RSExportPrimitiveType::DataTypeRSMatrix2x2:
1182    case RSExportPrimitiveType::DataTypeRSMatrix3x3:
1183    case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
1184      // RS matrix is not completely an RS object. They hold data by themselves.
1185      // (InitListExpr rs_matrix2x2
1186      //   (InitListExpr float[4]
1187      //     (FloatingLiteral 0)
1188      //     (FloatingLiteral 0)
1189      //     (FloatingLiteral 0)
1190      //     (FloatingLiteral 0)))
1191      clang::QualType FloatTy = C.FloatTy;
1192      // Constructor sets value to 0.0f by default
1193      llvm::APFloat Val(C.getFloatTypeSemantics(FloatTy));
1194      clang::FloatingLiteral *Float0Val =
1195          clang::FloatingLiteral::Create(C,
1196                                         Val,
1197                                         /* isExact = */true,
1198                                         FloatTy,
1199                                         Loc);
1200
1201      unsigned N = 0;
1202      if (DT == RSExportPrimitiveType::DataTypeRSMatrix2x2)
1203        N = 2;
1204      else if (DT == RSExportPrimitiveType::DataTypeRSMatrix3x3)
1205        N = 3;
1206      else if (DT == RSExportPrimitiveType::DataTypeRSMatrix4x4)
1207        N = 4;
1208
1209      // Directly allocate 16 elements instead of dynamically allocate N*N
1210      clang::Expr *InitVals[16];
1211      for (unsigned i = 0; i < sizeof(InitVals) / sizeof(InitVals[0]); i++)
1212        InitVals[i] = Float0Val;
1213      clang::Expr *InitExpr =
1214          new(C) clang::InitListExpr(C, Loc, InitVals, N * N, Loc);
1215      InitExpr->setType(C.getConstantArrayType(FloatTy,
1216                                               llvm::APInt(32, 4),
1217                                               clang::ArrayType::Normal,
1218                                               /* EltTypeQuals = */0));
1219
1220      Res = new(C) clang::InitListExpr(C, Loc, &InitExpr, 1, Loc);
1221      break;
1222    }
1223    case RSExportPrimitiveType::DataTypeUnknown:
1224    case RSExportPrimitiveType::DataTypeFloat16:
1225    case RSExportPrimitiveType::DataTypeFloat32:
1226    case RSExportPrimitiveType::DataTypeFloat64:
1227    case RSExportPrimitiveType::DataTypeSigned8:
1228    case RSExportPrimitiveType::DataTypeSigned16:
1229    case RSExportPrimitiveType::DataTypeSigned32:
1230    case RSExportPrimitiveType::DataTypeSigned64:
1231    case RSExportPrimitiveType::DataTypeUnsigned8:
1232    case RSExportPrimitiveType::DataTypeUnsigned16:
1233    case RSExportPrimitiveType::DataTypeUnsigned32:
1234    case RSExportPrimitiveType::DataTypeUnsigned64:
1235    case RSExportPrimitiveType::DataTypeBoolean:
1236    case RSExportPrimitiveType::DataTypeUnsigned565:
1237    case RSExportPrimitiveType::DataTypeUnsigned5551:
1238    case RSExportPrimitiveType::DataTypeUnsigned4444:
1239    case RSExportPrimitiveType::DataTypeMax: {
1240      slangAssert(false && "Not RS object type!");
1241    }
1242    // No default case will enable compiler detecting the missing cases
1243  }
1244
1245  return Res;
1246}
1247
1248void RSObjectRefCount::VisitDeclStmt(clang::DeclStmt *DS) {
1249  for (clang::DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
1250       I != E;
1251       I++) {
1252    clang::Decl *D = *I;
1253    if (D->getKind() == clang::Decl::Var) {
1254      clang::VarDecl *VD = static_cast<clang::VarDecl*>(D);
1255      RSExportPrimitiveType::DataType DT =
1256          RSExportPrimitiveType::DataTypeUnknown;
1257      clang::Expr *InitExpr = NULL;
1258      if (InitializeRSObject(VD, &DT, &InitExpr)) {
1259        getCurrentScope()->addRSObject(VD);
1260        getCurrentScope()->AppendRSObjectInit(mDiags, VD, DS, DT, InitExpr);
1261      }
1262    }
1263  }
1264  return;
1265}
1266
1267void RSObjectRefCount::VisitCompoundStmt(clang::CompoundStmt *CS) {
1268  if (!CS->body_empty()) {
1269    // Push a new scope
1270    Scope *S = new Scope(CS);
1271    mScopeStack.push(S);
1272
1273    VisitStmt(CS);
1274
1275    // Destroy the scope
1276    slangAssert((getCurrentScope() == S) && "Corrupted scope stack!");
1277    S->InsertLocalVarDestructors();
1278    mScopeStack.pop();
1279    delete S;
1280  }
1281  return;
1282}
1283
1284void RSObjectRefCount::VisitBinAssign(clang::BinaryOperator *AS) {
1285  clang::QualType QT = AS->getType();
1286
1287  if (CountRSObjectTypes(QT.getTypePtr())) {
1288    getCurrentScope()->ReplaceRSObjectAssignment(AS, mDiags);
1289  }
1290
1291  return;
1292}
1293
1294void RSObjectRefCount::VisitStmt(clang::Stmt *S) {
1295  for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
1296       I != E;
1297       I++) {
1298    if (clang::Stmt *Child = *I) {
1299      Visit(Child);
1300    }
1301  }
1302  return;
1303}
1304
1305}  // namespace slang
1306