Improve the AST representation of Objective-C @try/@catch/@finally
statements. Instead of the @try having a single @catch, where all of
the @catch's were chained (using an O(n^2) algorithm nonetheless),
@try just holds an array of its @catch blocks. The resulting AST is
slightly more compact (not important) and better represents the actual
language semantics (good).



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102221 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index ee4a74a..67fd74c 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -392,26 +392,53 @@
   RParenLoc = RPL;
 }
 
+ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
+                             Stmt **CatchStmts, unsigned NumCatchStmts,
+                             Stmt *atFinallyStmt)
+  : Stmt(ObjCAtTryStmtClass), AtTryLoc(atTryLoc),
+    NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != 0)
+{
+  Stmt **Stmts = getStmts();
+  Stmts[0] = atTryStmt;
+  for (unsigned I = 0; I != NumCatchStmts; ++I)
+    Stmts[I + 1] = CatchStmts[I];
+  
+  if (HasFinally)
+    Stmts[NumCatchStmts + 1] = atFinallyStmt;
+}
 
-ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc,
-                                 SourceLocation rparenloc,
-                                 ParmVarDecl *catchVarDecl, Stmt *atCatchStmt,
-                                 Stmt *atCatchList)
-: Stmt(ObjCAtCatchStmtClass) {
-  ExceptionDecl = catchVarDecl;
-  SubExprs[BODY] = atCatchStmt;
-  SubExprs[NEXT_CATCH] = NULL;
-  // FIXME: O(N^2) in number of catch blocks.
-  if (atCatchList) {
-    ObjCAtCatchStmt *AtCatchList = static_cast<ObjCAtCatchStmt*>(atCatchList);
+ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context, 
+                                     SourceLocation atTryLoc, 
+                                     Stmt *atTryStmt,
+                                     Stmt **CatchStmts, 
+                                     unsigned NumCatchStmts,
+                                     Stmt *atFinallyStmt) {
+  unsigned Size = sizeof(ObjCAtTryStmt) + 
+    (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *);
+  void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>());
+  return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts,
+                                 atFinallyStmt);
+}
 
-    while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt())
-      AtCatchList = NextCatch;
+ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context, 
+                                                 unsigned NumCatchStmts,
+                                                 bool HasFinally) {
+  unsigned Size = sizeof(ObjCAtTryStmt) + 
+    (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *);
+  void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>());
+  return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally);  
+}
 
-    AtCatchList->SubExprs[NEXT_CATCH] = this;
-  }
-  AtCatchLoc = atCatchLoc;
-  RParenLoc = rparenloc;
+SourceRange ObjCAtTryStmt::getSourceRange() const {
+  SourceLocation EndLoc;
+  if (HasFinally)
+    EndLoc = getFinallyStmt()->getLocEnd();
+  else if (NumCatchStmts)
+    EndLoc = getCatchStmt(NumCatchStmts - 1)->getLocEnd();
+  else
+    EndLoc = getTryBody()->getLocEnd();
+  
+  return SourceRange(AtTryLoc, EndLoc);
 }
 
 CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
@@ -630,19 +657,18 @@
 }
 
 // ObjCAtCatchStmt
-Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; }
-Stmt::child_iterator ObjCAtCatchStmt::child_end() {
-  return &SubExprs[0]+END_EXPR;
-}
+Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &Body; }
+Stmt::child_iterator ObjCAtCatchStmt::child_end() { return &Body + 1; }
 
 // ObjCAtFinallyStmt
 Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; }
 Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; }
 
 // ObjCAtTryStmt
-Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; }
-Stmt::child_iterator ObjCAtTryStmt::child_end()   {
-  return &SubStmts[0]+END_EXPR;
+Stmt::child_iterator ObjCAtTryStmt::child_begin() { return getStmts(); }
+
+Stmt::child_iterator ObjCAtTryStmt::child_end() {
+  return getStmts() + 1 + NumCatchStmts + HasFinally;
 }
 
 // ObjCAtThrowStmt
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 05adc02..8481055 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -143,6 +143,7 @@
     void DumpCXXTemporary(CXXTemporary *Temporary);
 
     // ObjC
+    void VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node);
     void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
     void VisitObjCMessageExpr(ObjCMessageExpr* Node);
     void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
@@ -524,6 +525,16 @@
   }
 }
 
+void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) {
+  DumpStmt(Node);
+  if (ParmVarDecl *CatchParam = Node->getCatchParamDecl()) {
+    OS << " catch parm = ";
+    DumpDeclarator(CatchParam);
+  } else {
+    OS << " catch all";
+  }
+}
+
 void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
   DumpExpr(Node);
   OS << " ";
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index a895b63..3996528 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -388,11 +388,8 @@
     OS << "\n";
   }
 
-  for (ObjCAtCatchStmt *catchStmt =
-         static_cast<ObjCAtCatchStmt *>(Node->getCatchStmts());
-       catchStmt;
-       catchStmt =
-         static_cast<ObjCAtCatchStmt *>(catchStmt->getNextCatchStmt())) {
+  for (unsigned I = 0, N = Node->getNumCatchStmts(); I != N; ++I) {
+    ObjCAtCatchStmt *catchStmt = Node->getCatchStmt(I);
     Indent() << "@catch(";
     if (catchStmt->getCatchParamDecl()) {
       if (Decl *DS = catchStmt->getCatchParamDecl())