Documentation parsing: add support for \throws \throw \exception commands

llvm-svn: 194521
diff --git a/clang/bindings/xml/comment-xml-schema.rng b/clang/bindings/xml/comment-xml-schema.rng
index 13cf7ad..a8913a3 100644
--- a/clang/bindings/xml/comment-xml-schema.rng
+++ b/clang/bindings/xml/comment-xml-schema.rng
@@ -75,7 +75,6 @@
       <optional>
         <ref name="USR" />
       </optional>
-      <!-- TODO: Add exception specification. -->
       <optional>
         <ref name="Headerfile" />
       </optional>
@@ -91,6 +90,9 @@
       <optional>
         <ref name="Parameters" />
       </optional>
+      <optional>
+        <ref name="Exceptions" />
+      </optional>
       <zeroOrMore>
         <ref name="Availability" />
       </zeroOrMore>
@@ -440,6 +442,14 @@
     </element>
   </define>
 
+  <define name="Exceptions">
+    <element name="Exceptions">
+      <oneOrMore>
+        <ref name="TextBlockContent" />
+      </oneOrMore>
+    </element>
+  </define>
+
   <define name="Availability">
     <element name="Availability">
       <attribute name="distribution">
diff --git a/clang/include/clang/AST/CommentCommandTraits.h b/clang/include/clang/AST/CommentCommandTraits.h
index 629329d..dde7a14 100644
--- a/clang/include/clang/AST/CommentCommandTraits.h
+++ b/clang/include/clang/AST/CommentCommandTraits.h
@@ -67,6 +67,9 @@
   /// a template parameter (\\tparam or an alias).
   unsigned IsTParamCommand : 1;
 
+  /// True if this command is \\throws or an alias.
+  unsigned IsThrowsCommand : 1;
+
   /// True if this command is \\deprecated or an alias.
   unsigned IsDeprecatedCommand : 1;
 
diff --git a/clang/include/clang/AST/CommentCommands.td b/clang/include/clang/AST/CommentCommands.td
index 4942430..ed323da 100644
--- a/clang/include/clang/AST/CommentCommands.td
+++ b/clang/include/clang/AST/CommentCommands.td
@@ -15,6 +15,7 @@
   bit IsReturnsCommand = 0;
   bit IsParamCommand = 0;
   bit IsTParamCommand = 0;
+  bit IsThrowsCommand = 0;
   bit IsDeprecatedCommand = 0;
   bit IsHeaderfileCommand = 0;
 
@@ -109,6 +110,10 @@
 // HeaderDoc command for template parameter documentation.
 def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; }
 
+def Throws    : BlockCommand<"throws"> { let IsThrowsCommand = 1; }
+def Throw     : BlockCommand<"throw"> { let IsThrowsCommand = 1; }
+def Exception : BlockCommand<"exception"> { let IsThrowsCommand = 1; }
+
 def Deprecated : BlockCommand<"deprecated"> {
   let IsEmptyParagraphAllowed = 1;
   let IsDeprecatedCommand = 1;
diff --git a/clang/test/Index/Inputs/CommentXML/valid-function-07.xml b/clang/test/Index/Inputs/CommentXML/valid-function-07.xml
index e9f5911..b567e6b 100644
--- a/clang/test/Index/Inputs/CommentXML/valid-function-07.xml
+++ b/clang/test/Index/Inputs/CommentXML/valid-function-07.xml
@@ -27,13 +27,17 @@
     <Discussion><Para>Eee</Para></Discussion>
   </Parameter>
 </Parameters>
-<ResultDiscussion>
+<Exceptions>
   <Para>Fff.</Para>
   <Para>Ggg</Para>
+</Exceptions>
+<ResultDiscussion>
+  <Para>Hhh.</Para>
+  <Para>Iii</Para>
 </ResultDiscussion>
 <Discussion>
-  <Para>Hhh</Para>
-  <Verbatim xml:space="preserve" kind="verbatim">Iii</Verbatim>
+  <Para>Jjj</Para>
+  <Verbatim xml:space="preserve" kind="verbatim">Kkk</Verbatim>
 </Discussion>
 </Function>
 
diff --git a/clang/test/Index/comment-to-html-xml-conversion.cpp b/clang/test/Index/comment-to-html-xml-conversion.cpp
index 94e6570..8c0ed21 100644
--- a/clang/test/Index/comment-to-html-xml-conversion.cpp
+++ b/clang/test/Index/comment-to-html-xml-conversion.cpp
@@ -890,6 +890,92 @@
 void comment_to_xml_conversion_todo_4();
 // CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_todo_4:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_todo_4</Name><USR>c:@F@comment_to_xml_conversion_todo_4#</USR><Declaration>void comment_to_xml_conversion_todo_4()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Discussion><Para kind="todo"> Bbb. </Para><Para kind="todo"> Ccc.</Para></Discussion></Function>]
 
+
+//===---
+// Test the representation of exception specifications in AST and XML.
+//===---
+
+/// Aaa.
+/// \throws Bbb.
+void comment_to_xml_conversion_exceptions_1();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_exceptions_1:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_exceptions_1</Name><USR>c:@F@comment_to_xml_conversion_exceptions_1#</USR><Declaration>void comment_to_xml_conversion_exceptions_1()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Exceptions><Para> Bbb.</Para></Exceptions></Function>]
+// CHECK-NEXT:  CommentAST=[
+// CHECK-NEXT:    (CXComment_FullComment
+// CHECK-NEXT:       (CXComment_Paragraph
+// CHECK-NEXT:         (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT:         (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT:       (CXComment_BlockCommand CommandName=[throws]
+// CHECK-NEXT:         (CXComment_Paragraph
+// CHECK-NEXT:           (CXComment_Text Text=[ Bbb.]))))]
+
+/// Aaa.
+/// \throw Bbb.
+void comment_to_xml_conversion_exceptions_2();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_exceptions_2:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_exceptions_2</Name><USR>c:@F@comment_to_xml_conversion_exceptions_2#</USR><Declaration>void comment_to_xml_conversion_exceptions_2()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Exceptions><Para> Bbb.</Para></Exceptions></Function>]
+// CHECK-NEXT:  CommentAST=[
+// CHECK-NEXT:    (CXComment_FullComment
+// CHECK-NEXT:       (CXComment_Paragraph
+// CHECK-NEXT:         (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT:         (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT:       (CXComment_BlockCommand CommandName=[throw]
+// CHECK-NEXT:         (CXComment_Paragraph
+// CHECK-NEXT:           (CXComment_Text Text=[ Bbb.]))))]
+
+/// Aaa.
+/// \exception Bbb.
+void comment_to_xml_conversion_exceptions_3();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_exceptions_3:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_exceptions_3</Name><USR>c:@F@comment_to_xml_conversion_exceptions_3#</USR><Declaration>void comment_to_xml_conversion_exceptions_3()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Exceptions><Para> Bbb.</Para></Exceptions></Function>]
+// CHECK-NEXT:  CommentAST=[
+// CHECK-NEXT:    (CXComment_FullComment
+// CHECK-NEXT:       (CXComment_Paragraph
+// CHECK-NEXT:         (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT:         (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT:       (CXComment_BlockCommand CommandName=[exception]
+// CHECK-NEXT:         (CXComment_Paragraph
+// CHECK-NEXT:           (CXComment_Text Text=[ Bbb.]))))]
+
+/// Aaa.
+/// \throws Bbb.
+/// \throws Ccc.
+/// \throws Ddd.
+void comment_to_xml_conversion_exceptions_4();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_exceptions_4:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_exceptions_4</Name><USR>c:@F@comment_to_xml_conversion_exceptions_4#</USR><Declaration>void comment_to_xml_conversion_exceptions_4()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Exceptions><Para> Bbb. </Para><Para> Ccc. </Para><Para> Ddd.</Para></Exceptions></Function>]
+// CHECK-NEXT:  CommentAST=[
+// CHECK-NEXT:    (CXComment_FullComment
+// CHECK-NEXT:       (CXComment_Paragraph
+// CHECK-NEXT:         (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT:         (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT:       (CXComment_BlockCommand CommandName=[throws]
+// CHECK-NEXT:         (CXComment_Paragraph
+// CHECK-NEXT:           (CXComment_Text Text=[ Bbb.] HasTrailingNewline)
+// CHECK-NEXT:           (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT:       (CXComment_BlockCommand CommandName=[throws]
+// CHECK-NEXT:         (CXComment_Paragraph
+// CHECK-NEXT:           (CXComment_Text Text=[ Ccc.] HasTrailingNewline)
+// CHECK-NEXT:           (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT:       (CXComment_BlockCommand CommandName=[throws]
+// CHECK-NEXT:         (CXComment_Paragraph
+// CHECK-NEXT:           (CXComment_Text Text=[ Ddd.]))))]
+
+/// Aaa.
+/// \throws Bbb.
+/// \throw Ccc.
+void comment_to_xml_conversion_exceptions_5();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_exceptions_5:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_exceptions_5</Name><USR>c:@F@comment_to_xml_conversion_exceptions_5#</USR><Declaration>void comment_to_xml_conversion_exceptions_5()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Exceptions><Para> Bbb. </Para><Para> Ccc.</Para></Exceptions></Function>]
+// CHECK-NEXT:  CommentAST=[
+// CHECK-NEXT:    (CXComment_FullComment
+// CHECK-NEXT:       (CXComment_Paragraph
+// CHECK-NEXT:         (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT:         (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT:       (CXComment_BlockCommand CommandName=[throws]
+// CHECK-NEXT:         (CXComment_Paragraph
+// CHECK-NEXT:           (CXComment_Text Text=[ Bbb.] HasTrailingNewline)
+// CHECK-NEXT:           (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT:       (CXComment_BlockCommand CommandName=[throw]
+// CHECK-NEXT:         (CXComment_Paragraph
+// CHECK-NEXT:           (CXComment_Text Text=[ Ccc.]))))]
+
+
 // rdar://14348912
 #define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
 
diff --git a/clang/tools/libclang/CXComment.cpp b/clang/tools/libclang/CXComment.cpp
index 4658856..1df6e24 100644
--- a/clang/tools/libclang/CXComment.cpp
+++ b/clang/tools/libclang/CXComment.cpp
@@ -25,6 +25,7 @@
 #include "clang/Lex/Lexer.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/TinyPtrVector.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 #include <climits>
@@ -424,6 +425,7 @@
   SmallVector<const BlockCommandComment *, 4> Returns;
   SmallVector<const ParamCommandComment *, 8> Params;
   SmallVector<const TParamCommandComment *, 4> TParams;
+  llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
   SmallVector<const BlockContentComment *, 8> MiscBlocks;
 };
 
@@ -465,6 +467,10 @@
         Returns.push_back(BCC);
         break;
       }
+      if (Info->IsThrowsCommand) {
+        Exceptions.push_back(BCC);
+        break;
+      }
       MiscBlocks.push_back(BCC);
       break;
     }
@@ -1322,6 +1328,13 @@
     Result << "</Parameters>";
   }
 
+  if (Parts.Exceptions.size() != 0) {
+    Result << "<Exceptions>";
+    for (unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
+      visit(Parts.Exceptions[i]);
+    Result << "</Exceptions>";
+  }
+
   if (Parts.Returns.size() != 0) {
     Result << "<ResultDiscussion>";
     for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
diff --git a/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
index cab1c2b..857b22e 100644
--- a/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
+++ b/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
@@ -40,6 +40,7 @@
        << Tag.getValueAsBit("IsReturnsCommand") << ", "
        << Tag.getValueAsBit("IsParamCommand") << ", "
        << Tag.getValueAsBit("IsTParamCommand") << ", "
+       << Tag.getValueAsBit("IsThrowsCommand") << ", "
        << Tag.getValueAsBit("IsDeprecatedCommand") << ", "
        << Tag.getValueAsBit("IsHeaderfileCommand") << ", "
        << Tag.getValueAsBit("IsEmptyParagraphAllowed") << ", "