r206882 - Comment parsing: in the generated XML file, mark HTML that is safe to pass

Dmitri Gribenko gribozavr at gmail.com
Tue Apr 22 03:59:13 PDT 2014


Author: gribozavr
Date: Tue Apr 22 05:59:13 2014
New Revision: 206882

URL: http://llvm.org/viewvc/llvm-project?rev=206882&view=rev
Log:
Comment parsing: in the generated XML file, mark HTML that is safe to pass
through to the output even if the input comment comes from an untrusted source

Attribute filtering is currently based on a blacklist, which right now includes
all event handler attributes (they contain JavaScipt code).  It should be
switched to a whitelist, but going over all of the HTML5 spec requires a
significant amount of time.

Modified:
    cfe/trunk/bindings/xml/comment-xml-schema.rng
    cfe/trunk/include/clang/AST/Comment.h
    cfe/trunk/include/clang/AST/CommentHTMLTags.td
    cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td
    cfe/trunk/lib/AST/CommentSema.cpp
    cfe/trunk/lib/Index/CommentToXML.cpp
    cfe/trunk/test/Index/Inputs/CommentXML/valid-function-02.xml
    cfe/trunk/test/Index/comment-to-html-xml-conversion.cpp
    cfe/trunk/test/Sema/warn-documentation.cpp
    cfe/trunk/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp

Modified: cfe/trunk/bindings/xml/comment-xml-schema.rng
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/bindings/xml/comment-xml-schema.rng?rev=206882&r1=206881&r2=206882&view=diff
==============================================================================
--- cfe/trunk/bindings/xml/comment-xml-schema.rng (original)
+++ cfe/trunk/bindings/xml/comment-xml-schema.rng Tue Apr 22 05:59:13 2014
@@ -580,6 +580,12 @@
         </data>
       </element>
       <element name="rawHTML">
+        <optional>
+          <!-- If not specified, the default value is 'false'. -->
+          <attribute name="isSafeToPassThrough">
+            <data type="boolean" />
+          </attribute>
+        </optional>
         <!-- Non-empty text content. -->
         <data type="string">
           <param name="pattern">.*\S.*</param>

Modified: cfe/trunk/include/clang/AST/Comment.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Comment.h?rev=206882&r1=206881&r2=206882&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Comment.h (original)
+++ cfe/trunk/include/clang/AST/Comment.h Tue Apr 22 05:59:13 2014
@@ -100,16 +100,27 @@ protected:
   };
   enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 10 };
 
+  class HTMLTagCommentBitfields {
+    friend class HTMLTagComment;
+
+    unsigned : NumInlineContentCommentBits;
+
+    /// True if this tag is safe to pass through to HTML output even if the
+    /// comment comes from an untrusted source.
+    unsigned IsSafeToPassThrough : 1;
+  };
+  enum { NumHTMLTagCommentBits = NumInlineContentCommentBits + 1 };
+
   class HTMLStartTagCommentBitfields {
     friend class HTMLStartTagComment;
 
-    unsigned : NumInlineContentCommentBits;
+    unsigned : NumHTMLTagCommentBits;
 
     /// True if this tag is self-closing (e. g., <br />).  This is based on tag
     /// spelling in comment (plain <br> would not set this flag).
     unsigned IsSelfClosing : 1;
   };
-  enum { NumHTMLStartTagCommentBits = NumInlineContentCommentBits + 1 };
+  enum { NumHTMLStartTagCommentBits = NumHTMLTagCommentBits + 1 };
 
   class ParagraphCommentBitfields {
     friend class ParagraphComment;
@@ -155,6 +166,7 @@ protected:
     InlineContentCommentBitfields InlineContentCommentBits;
     TextCommentBitfields TextCommentBits;
     InlineCommandCommentBitfields InlineCommandCommentBits;
+    HTMLTagCommentBitfields HTMLTagCommentBits;
     HTMLStartTagCommentBitfields HTMLStartTagCommentBits;
     ParagraphCommentBitfields ParagraphCommentBits;
     BlockCommandCommentBitfields BlockCommandCommentBits;
@@ -360,8 +372,7 @@ public:
 };
 
 /// Abstract class for opening and closing HTML tags.  HTML tags are always
-/// treated as inline content (regardless HTML semantics); opening and closing
-/// tags are not matched.
+/// treated as inline content (regardless HTML semantics).
 class HTMLTagComment : public InlineContentComment {
 protected:
   StringRef TagName;
@@ -377,6 +388,7 @@ protected:
       TagName(TagName),
       TagNameRange(TagNameBegin, TagNameEnd) {
     setLocation(TagNameBegin);
+    HTMLTagCommentBits.IsSafeToPassThrough = 1;
   }
 
 public:
@@ -392,6 +404,14 @@ public:
     return SourceRange(L.getLocWithOffset(1),
                        L.getLocWithOffset(1 + TagName.size()));
   }
+
+  bool isSafeToPassThrough() const {
+    return HTMLTagCommentBits.IsSafeToPassThrough;
+  }
+
+  void setUnsafeToPassThrough() {
+    HTMLTagCommentBits.IsSafeToPassThrough = 0;
+  }
 };
 
 /// An opening HTML tag with attributes.

Modified: cfe/trunk/include/clang/AST/CommentHTMLTags.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CommentHTMLTags.td?rev=206882&r1=206881&r2=206882&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/CommentHTMLTags.td (original)
+++ cfe/trunk/include/clang/AST/CommentHTMLTags.td Tue Apr 22 05:59:13 2014
@@ -52,3 +52,83 @@ def Tr      : Tag<"tr"> { let EndTagOpti
 def Th      : Tag<"th"> { let EndTagOptional = 1; }
 def Td      : Tag<"td"> { let EndTagOptional = 1; }
 
+// Define a blacklist of attributes that are not safe to pass through to HTML
+// output if the input is untrusted.
+//
+// FIXME: this should be a whitelist.  When changing this to a whitelist, don't
+// forget to change the default in the TableGen backend.
+class Attribute<string spelling> {
+  string Spelling = spelling;
+  bit IsSafeToPassThrough = 1;
+}
+class EventHandlerContentAttribute<string spelling> : Attribute<spelling> {
+  let IsSafeToPassThrough = 0;
+}
+
+// This list is based on HTML5 draft as of 04 February 2014.
+//
+// The list is intentionally organized as one item per line to make it easier
+// to compare with the HTML spec.
+foreach AttrName = [
+    "onabort",
+    "onblur",
+    "oncancel",
+    "oncanplay",
+    "oncanplaythrough",
+    "onchange",
+    "onclick",
+    "onclose",
+    "oncuechange",
+    "ondblclick",
+    "ondrag",
+    "ondragend",
+    "ondragenter",
+    "ondragexit",
+    "ondragleave",
+    "ondragover",
+    "ondragstart",
+    "ondrop",
+    "ondurationchange",
+    "onemptied",
+    "onended",
+    "onerror",
+    "onfocus",
+    "oninput",
+    "oninvalid",
+    "onkeydown",
+    "onkeypress",
+    "onkeyup",
+    "onload",
+    "onloadeddata",
+    "onloadedmetadata",
+    "onloadstart",
+    "onmousedown",
+    "onmouseenter",
+    "onmouseleave",
+    "onmousemove",
+    "onmouseout",
+    "onmouseover",
+    "onmouseup",
+    "onmousewheel",
+    "onpause",
+    "onplay",
+    "onplaying",
+    "onprogress",
+    "onratechange",
+    "onreset",
+    "onresize",
+    "onscroll",
+    "onseeked",
+    "onseeking",
+    "onselect",
+    "onshow",
+    "onstalled",
+    "onsubmit",
+    "onsuspend",
+    "ontimeupdate",
+    "ontoggle",
+    "onvolumechange",
+    "onwaiting"
+  ] in {
+  def Attr#AttrName : EventHandlerContentAttribute<AttrName>;
+}

Modified: cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td?rev=206882&r1=206881&r2=206882&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td Tue Apr 22 05:59:13 2014
@@ -41,6 +41,10 @@ def warn_doc_html_start_end_mismatch : W
 def note_doc_html_end_tag : Note<
   "end tag">;
 
+def warn_doc_html_missing_end_tag : Warning<
+  "HTML tag '%0' requires an end tag">,
+  InGroup<DocumentationHTML>, DefaultIgnore;
+
 // Commands
 
 def warn_doc_block_command_empty_paragraph : Warning<

Modified: cfe/trunk/lib/AST/CommentSema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CommentSema.cpp?rev=206882&r1=206881&r2=206882&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CommentSema.cpp (original)
+++ cfe/trunk/lib/AST/CommentSema.cpp Tue Apr 22 05:59:13 2014
@@ -467,6 +467,11 @@ void Sema::actOnHTMLStartTagFinish(
                               SourceLocation GreaterLoc,
                               bool IsSelfClosing) {
   Tag->setAttrs(Attrs);
+  for (const auto &Attr : Attrs) {
+    if (!isHTMLAttributeSafeToPassThrough(Attr.Name))
+      Tag->setUnsafeToPassThrough();
+  }
+
   Tag->setGreaterLoc(GreaterLoc);
   if (IsSelfClosing)
     Tag->setSelfClosing();
@@ -482,6 +487,7 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag
   if (isHTMLEndTagForbidden(TagName)) {
     Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
       << TagName << HET->getSourceRange();
+    HET->setUnsafeToPassThrough();
     return HET;
   }
 
@@ -497,14 +503,19 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag
   if (!FoundOpen) {
     Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
       << HET->getSourceRange();
+    HET->setUnsafeToPassThrough();
     return HET;
   }
 
   while (!HTMLOpenTags.empty()) {
-    const HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
+    HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
     StringRef LastNotClosedTagName = HST->getTagName();
-    if (LastNotClosedTagName == TagName)
+    if (LastNotClosedTagName == TagName) {
+      // If the start tag is unsafe, end tag is unsafe as well.
+      if (!HST->isSafeToPassThrough())
+        HET->setUnsafeToPassThrough();
       break;
+    }
 
     if (isHTMLEndTagOptional(LastNotClosedTagName))
       continue;
@@ -518,16 +529,18 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag
                                                 HET->getLocation(),
                                                 &CloseLineInvalid);
 
-    if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine)
+    if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
       Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
         << HST->getTagName() << HET->getTagName()
         << HST->getSourceRange() << HET->getSourceRange();
-    else {
+      HST->setUnsafeToPassThrough();
+    } else {
       Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
         << HST->getTagName() << HET->getTagName()
         << HST->getSourceRange();
       Diag(HET->getLocation(), diag::note_doc_html_end_tag)
         << HET->getSourceRange();
+      HST->setUnsafeToPassThrough();
     }
   }
 
@@ -538,6 +551,18 @@ FullComment *Sema::actOnFullComment(
                               ArrayRef<BlockContentComment *> Blocks) {
   FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
   resolveParamCommandIndexes(FC);
+
+  // Complain about HTML tags that are not closed.
+  while (!HTMLOpenTags.empty()) {
+    HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
+    if (isHTMLEndTagOptional(HST->getTagName()))
+      continue;
+
+    Diag(HST->getLocation(), diag::warn_doc_html_missing_end_tag)
+      << HST->getTagName() << HST->getSourceRange();
+    HST->setUnsafeToPassThrough();
+  }
+
   return FC;
 }
 

Modified: cfe/trunk/lib/Index/CommentToXML.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/CommentToXML.cpp?rev=206882&r1=206881&r2=206882&view=diff
==============================================================================
--- cfe/trunk/lib/Index/CommentToXML.cpp (original)
+++ cfe/trunk/lib/Index/CommentToXML.cpp Tue Apr 22 05:59:13 2014
@@ -667,14 +667,20 @@ void CommentASTToXMLConverter::visitInli
 
 void CommentASTToXMLConverter::visitHTMLStartTagComment(
     const HTMLStartTagComment *C) {
-  Result << "<rawHTML><![CDATA[";
+  Result << "<rawHTML";
+  if (C->isSafeToPassThrough())
+    Result << " isSafeToPassThrough=\"1\"";
+  Result << "><![CDATA[";
   printHTMLStartTagComment(C, Result);
   Result << "]]></rawHTML>";
 }
 
 void
 CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
-  Result << "<rawHTML></" << C->getTagName() << "></rawHTML>";
+  Result << "<rawHTML";
+  if (C->isSafeToPassThrough())
+    Result << " isSafeToPassThrough=\"1\"";
+  Result << "></" << C->getTagName() << "></rawHTML>";
 }
 
 void

Modified: cfe/trunk/test/Index/Inputs/CommentXML/valid-function-02.xml
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/Inputs/CommentXML/valid-function-02.xml?rev=206882&r1=206881&r2=206882&view=diff
==============================================================================
--- cfe/trunk/test/Index/Inputs/CommentXML/valid-function-02.xml (original)
+++ cfe/trunk/test/Index/Inputs/CommentXML/valid-function-02.xml Tue Apr 22 05:59:13 2014
@@ -1,5 +1,14 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Function>
 <Name>aaa</Name>
-<Abstract><Para>Aaa <bold>bbb</bold> <monospaced>ccc</monospaced> <emphasized>ddd</emphasized>.</Para></Abstract>
+<Abstract>
+  <Para>Aaa
+    <bold>bbb</bold>
+    <monospaced>ccc</monospaced>
+    <emphasized>ddd</emphasized>
+    <rawHTML><eee></rawHTML>
+    <rawHTML isSafeToPassThrough="0"><fff></rawHTML>
+    <rawHTML isSafeToPassThrough="1"><ggg></rawHTML>.
+  </Para>
+</Abstract>
 </Function>

Modified: cfe/trunk/test/Index/comment-to-html-xml-conversion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/comment-to-html-xml-conversion.cpp?rev=206882&r1=206881&r2=206882&view=diff
==============================================================================
--- cfe/trunk/test/Index/comment-to-html-xml-conversion.cpp (original)
+++ cfe/trunk/test/Index/comment-to-html-xml-conversion.cpp Tue Apr 22 05:59:13 2014
@@ -472,7 +472,7 @@ void test_full_comment_1(int x1, int x2)
 /// <br><a href="http://example.com/">Aaa</a>
 void comment_to_html_conversion_24();
 
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_24:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <br><a href="http://example.com/">Aaa</a></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_24</Name><USR>c:@F at comment_to_html_conversion_24#</USR><Declaration>void comment_to_html_conversion_24()</Declaration><Abstract><Para> <rawHTML><![CDATA[<br>]]></rawHTML><rawHTML><![CDATA[<a href="http://example.com/">]]></rawHTML>Aaa<rawHTML></a></rawHTML></Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_24:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <br><a href="http://example.com/">Aaa</a></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_24</Name><USR>c:@F at comment_to_html_conversion_24#</USR><Declaration>void comment_to_html_conversion_24()</Declaration><Abstract><Para> <rawHTML isSafeToPassThrough="1"><![CDATA[<br>]]></rawHTML><rawHTML isSafeToPassThrough="1"><![CDATA[<a href="http://example.com/">]]></rawHTML>Aaa<rawHTML isSafeToPassThrough="1"></a></rawHTML></Para></Abstract></Function>]
 // CHECK-NEXT:  CommentAST=[
 // CHECK-NEXT:    (CXComment_FullComment
 // CHECK-NEXT:       (CXComment_Paragraph
@@ -678,7 +678,7 @@ void comment_to_html_conversion_33();
 /// <em>0<i</em>
 void comment_to_html_conversion_34();
 
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_34:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>0<i</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_34</Name><USR>c:@F at comment_to_html_conversion_34#</USR><Declaration>void comment_to_html_conversion_34()</Declaration><Abstract><Para> <rawHTML><![CDATA[<em>]]></rawHTML>0<i<rawHTML></em></rawHTML></Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_34:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>0<i</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_34</Name><USR>c:@F at comment_to_html_conversion_34#</USR><Declaration>void comment_to_html_conversion_34()</Declaration><Abstract><Para> <rawHTML isSafeToPassThrough="1"><![CDATA[<em>]]></rawHTML>0<i<rawHTML isSafeToPassThrough="1"></em></rawHTML></Para></Abstract></Function>]
 // CHECK-NEXT:  CommentAST=[
 // CHECK-NEXT:    (CXComment_FullComment
 // CHECK-NEXT:       (CXComment_Paragraph
@@ -853,6 +853,34 @@ enum class comment_to_xml_conversion_17
 // CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:3: EnumConstantDecl=comment_to_xml_conversion_18:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="3"><Name>comment_to_xml_conversion_18</Name><USR>c:@E at comment_to_xml_conversion_17@comment_to_xml_conversion_18</USR><Declaration>comment_to_xml_conversion_18</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
 };
 
+/// <a href="http://example.org/">
+void comment_to_xml_conversion_unsafe_html_01();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_01:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_01</Name><USR>c:@F at comment_to_xml_conversion_unsafe_html_01#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_01()</Declaration><Abstract><Para> <rawHTML><![CDATA[<a href="http://example.org/">]]></rawHTML></Para></Abstract></Function>]
+
+/// <a href="http://example.org/"><em>Aaa</em>
+void comment_to_xml_conversion_unsafe_html_02();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_02:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_02</Name><USR>c:@F at comment_to_xml_conversion_unsafe_html_02#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_02()</Declaration><Abstract><Para> <rawHTML><![CDATA[<a href="http://example.org/">]]></rawHTML><rawHTML isSafeToPassThrough="1"><![CDATA[<em>]]></rawHTML>Aaa<rawHTML isSafeToPassThrough="1"></em></rawHTML></Para></Abstract></Function>]
+
+/// <em>Aaa
+void comment_to_xml_conversion_unsafe_html_03();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_03:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_03</Name><USR>c:@F at comment_to_xml_conversion_unsafe_html_03#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_03()</Declaration><Abstract><Para> <rawHTML><![CDATA[<em>]]></rawHTML>Aaa</Para></Abstract></Function>]
+
+/// <em>Aaa</b></em>
+void comment_to_xml_conversion_unsafe_html_04();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_04:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_04</Name><USR>c:@F at comment_to_xml_conversion_unsafe_html_04#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_04()</Declaration><Abstract><Para> <rawHTML isSafeToPassThrough="1"><![CDATA[<em>]]></rawHTML>Aaa<rawHTML></b></rawHTML><rawHTML isSafeToPassThrough="1"></em></rawHTML></Para></Abstract></Function>]
+
+/// <em>Aaa</em></b>
+void comment_to_xml_conversion_unsafe_html_05();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_05:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_05</Name><USR>c:@F at comment_to_xml_conversion_unsafe_html_05#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_05()</Declaration><Abstract><Para> <rawHTML isSafeToPassThrough="1"><![CDATA[<em>]]></rawHTML>Aaa<rawHTML isSafeToPassThrough="1"></em></rawHTML><rawHTML></b></rawHTML></Para></Abstract></Function>]
+
+/// </table>
+void comment_to_xml_conversion_unsafe_html_06();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_06:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_06</Name><USR>c:@F at comment_to_xml_conversion_unsafe_html_06#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_06()</Declaration><Abstract><Para> <rawHTML></table></rawHTML></Para></Abstract></Function>]
+
+/// <div onclick="alert('meow');">Aaa</div>
+void comment_to_xml_conversion_unsafe_html_07();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_07:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_07</Name><USR>c:@F at comment_to_xml_conversion_unsafe_html_07#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_07()</Declaration><Abstract><Para> <rawHTML><![CDATA[<div onclick="alert('meow');">]]></rawHTML>Aaa<rawHTML></div></rawHTML></Para></Abstract></Function>]
+
 //===---
 // Check that we attach comments from the base class to derived classes if they don't have a comment.
 // rdar://13647476

Modified: cfe/trunk/test/Sema/warn-documentation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-documentation.cpp?rev=206882&r1=206881&r2=206882&view=diff
==============================================================================
--- cfe/trunk/test/Sema/warn-documentation.cpp (original)
+++ cfe/trunk/test/Sema/warn-documentation.cpp Tue Apr 22 05:59:13 2014
@@ -4,35 +4,43 @@
 // RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng %s | FileCheck %s -check-prefix=WRONG
 // WRONG-NOT: CommentXMLInvalid
 
+// expected-warning at +2 {{HTML tag 'a' requires an end tag}}
 // expected-warning at +1 {{expected quoted string after equals sign}}
 /// <a href=>
 int test_html1(int);
 
+// expected-warning at +2 {{HTML tag 'a' requires an end tag}}
 // expected-warning at +1 {{expected quoted string after equals sign}}
 /// <a href==>
 int test_html2(int);
 
+// expected-warning at +3 {{HTML tag 'a' requires an end tag}}
 // expected-warning at +2 {{expected quoted string after equals sign}}
 // expected-warning at +1 {{HTML start tag prematurely ended, expected attribute name or '>'}}
 /// <a href= blah
 int test_html3(int);
 
+// expected-warning at +2 {{HTML tag 'a' requires an end tag}}
 // expected-warning at +1 {{HTML start tag prematurely ended, expected attribute name or '>'}}
 /// <a =>
 int test_html4(int);
 
+// expected-warning at +2 {{HTML tag 'a' requires an end tag}}
 // expected-warning at +1 {{HTML start tag prematurely ended, expected attribute name or '>'}}
 /// <a "aaa">
 int test_html5(int);
 
+// expected-warning at +2 {{HTML tag 'a' requires an end tag}}
 // expected-warning at +1 {{HTML start tag prematurely ended, expected attribute name or '>'}}
 /// <a a="b" =>
 int test_html6(int);
 
+// expected-warning at +2 {{HTML tag 'a' requires an end tag}}
 // expected-warning at +1 {{HTML start tag prematurely ended, expected attribute name or '>'}}
 /// <a a="b" "aaa">
 int test_html7(int);
 
+// expected-warning at +2 {{HTML tag 'a' requires an end tag}}
 // expected-warning at +1 {{HTML start tag prematurely ended, expected attribute name or '>'}}
 /// <a a="b" =
 int test_html8(int);
@@ -67,6 +75,8 @@ int test_html_nesting3(int);
 /// Bbb</p>
 int test_html_nesting4(int);
 
+// expected-warning at +3 {{HTML tag 'b' requires an end tag}}
+// expected-warning at +2 {{HTML tag 'i' requires an end tag}}
 // expected-warning at +1 {{HTML end tag does not match any start tag}}
 /// <b><i>Meow</a>
 int test_html_nesting5(int);
@@ -81,6 +91,9 @@ int test_html_nesting6(int);
 /// <b><i>Meow</b></i>
 int test_html_nesting7(int);
 
+// expected-warning at +1 {{HTML tag 'b' requires an end tag}}
+/// <b>Meow
+int test_html_nesting8(int);
 
 // expected-warning at +1 {{empty paragraph passed to '\brief' command}}
 /// \brief\returns Aaa

Modified: cfe/trunk/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp?rev=206882&r1=206881&r2=206882&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp Tue Apr 22 05:59:13 2014
@@ -12,6 +12,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "TableGenBackends.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringMatcher.h"
 #include "llvm/TableGen/TableGenBackend.h"
@@ -19,14 +20,11 @@
 
 using namespace llvm;
 
-namespace clang {
-void EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS) {
   std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Tag");
   std::vector<StringMatcher::StringPair> Matches;
-  for (std::vector<Record *>::iterator I = Tags.begin(), E = Tags.end();
-       I != E; ++I) {
-    Record &Tag = **I;
-    std::string Spelling = Tag.getValueAsString("Spelling");
+  for (Record *Tag : Tags) {
+    std::string Spelling = Tag->getValueAsString("Spelling");
     Matches.push_back(StringMatcher::StringPair(Spelling, "return true;"));
   }
 
@@ -38,19 +36,17 @@ void EmitClangCommentHTMLTags(RecordKeep
      << "}\n\n";
 }
 
-void EmitClangCommentHTMLTagsProperties(RecordKeeper &Records,
-                                        raw_ostream &OS) {
+void clang::EmitClangCommentHTMLTagsProperties(RecordKeeper &Records,
+                                               raw_ostream &OS) {
   std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Tag");
   std::vector<StringMatcher::StringPair> MatchesEndTagOptional;
   std::vector<StringMatcher::StringPair> MatchesEndTagForbidden;
-  for (std::vector<Record *>::iterator I = Tags.begin(), E = Tags.end();
-       I != E; ++I) {
-    Record &Tag = **I;
-    std::string Spelling = Tag.getValueAsString("Spelling");
+  for (Record *Tag : Tags) {
+    std::string Spelling = Tag->getValueAsString("Spelling");
     StringMatcher::StringPair Match(Spelling, "return true;");
-    if (Tag.getValueAsBit("EndTagOptional"))
+    if (Tag->getValueAsBit("EndTagOptional"))
       MatchesEndTagOptional.push_back(Match);
-    if (Tag.getValueAsBit("EndTagForbidden"))
+    if (Tag->getValueAsBit("EndTagForbidden"))
       MatchesEndTagForbidden.push_back(Match);
   }
 
@@ -65,6 +61,21 @@ void EmitClangCommentHTMLTagsProperties(
   StringMatcher("Name", MatchesEndTagForbidden, OS).Emit();
   OS << "  return false;\n"
      << "}\n\n";
+
+  std::vector<Record *> Attributes =
+      Records.getAllDerivedDefinitions("Attribute");
+  std::vector<StringMatcher::StringPair> Matches;
+  for (Record *Attribute : Attributes) {
+    std::string Spelling = Attribute->getValueAsString("Spelling");
+    if (!Attribute->getValueAsBit("IsSafeToPassThrough"))
+      Matches.push_back(StringMatcher::StringPair(Spelling, "return false;"));
+  }
+
+  emitSourceFileHeader("HTML attribute name matcher", OS);
+
+  OS << "bool isHTMLAttributeSafeToPassThrough(StringRef Name) {\n";
+  StringMatcher("Name", Matches, OS).Emit();
+  OS << "  return true;\n"
+     << "}\n\n";
 }
-} // end namespace clang
 





More information about the cfe-commits mailing list