Add caching for TextComment::isWhitespace(), ParagraphComment::isWhitespace().


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160452 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/Comment.h b/include/clang/AST/Comment.h
index 39753cf..f59b5e5 100644
--- a/include/clang/AST/Comment.h
+++ b/include/clang/AST/Comment.h
@@ -48,7 +48,20 @@
     /// (There is no separate AST node for a newline.)
     unsigned HasTrailingNewline : 1;
   };
-  enum { NumInlineContentCommentBits = 9 };
+  enum { NumInlineContentCommentBits = NumCommentBits + 1 };
+
+  class TextCommentBitfields {
+    friend class TextComment;
+
+    unsigned : NumInlineContentCommentBits;
+
+    /// True if \c IsWhitespace field contains a valid value.
+    mutable unsigned IsWhitespaceValid : 1;
+
+    /// True if this comment AST node contains only whitespace.
+    mutable unsigned IsWhitespace : 1;
+  };
+  enum { NumTextCommentBits = NumInlineContentCommentBits + 2 };
 
   class HTMLStartTagCommentBitfields {
     friend class HTMLStartTagComment;
@@ -60,6 +73,19 @@
     unsigned IsSelfClosing : 1;
   };
 
+  class ParagraphCommentBitfields {
+    friend class ParagraphComment;
+
+    unsigned : NumCommentBits;
+
+    /// True if \c IsWhitespace field contains a valid value.
+    mutable unsigned IsWhitespaceValid : 1;
+
+    /// True if this comment AST node contains only whitespace.
+    mutable unsigned IsWhitespace : 1;
+  };
+  enum { NumParagraphCommentBits = NumCommentBits + 2 };
+
   class ParamCommandCommentBitfields {
     friend class ParamCommandComment;
 
@@ -76,7 +102,9 @@
   union {
     CommentBitfields CommentBits;
     InlineContentCommentBitfields InlineContentCommentBits;
+    TextCommentBitfields TextCommentBits;
     HTMLStartTagCommentBitfields HTMLStartTagCommentBits;
+    ParagraphCommentBitfields ParagraphCommentBits;
     ParamCommandCommentBitfields ParamCommandCommentBits;
   };
 
@@ -180,8 +208,9 @@
               SourceLocation LocEnd,
               StringRef Text) :
       InlineContentComment(TextCommentKind, LocBegin, LocEnd),
-      Text(Text)
-  { }
+      Text(Text) {
+    TextCommentBits.IsWhitespaceValid = false;
+  }
 
   static bool classof(const Comment *C) {
     return C->getCommentKind() == TextCommentKind;
@@ -195,7 +224,17 @@
 
   StringRef getText() const LLVM_READONLY { return Text; }
 
-  bool isWhitespace() const;
+  bool isWhitespace() const {
+    if (TextCommentBits.IsWhitespaceValid)
+      return TextCommentBits.IsWhitespace;
+
+    TextCommentBits.IsWhitespace = isWhitespaceNoCache();
+    TextCommentBits.IsWhitespaceValid = true;
+    return TextCommentBits.IsWhitespace;
+  }
+
+private:
+  bool isWhitespaceNoCache() const;
 };
 
 /// A command with word-like arguments that is considered inline content.
@@ -442,8 +481,13 @@
                           SourceLocation(),
                           SourceLocation()),
       Content(Content) {
-    if (Content.empty())
+    if (Content.empty()) {
+      ParagraphCommentBits.IsWhitespace = true;
+      ParagraphCommentBits.IsWhitespaceValid = true;
       return;
+    }
+
+    ParagraphCommentBits.IsWhitespaceValid = false;
 
     setSourceRange(SourceRange(Content.front()->getLocStart(),
                                Content.back()->getLocEnd()));
@@ -464,7 +508,17 @@
     return reinterpret_cast<child_iterator>(Content.end());
   }
 
-  bool isWhitespace() const;
+  bool isWhitespace() const {
+    if (ParagraphCommentBits.IsWhitespaceValid)
+      return ParagraphCommentBits.IsWhitespace;
+
+    ParagraphCommentBits.IsWhitespace = isWhitespaceNoCache();
+    ParagraphCommentBits.IsWhitespaceValid = true;
+    return ParagraphCommentBits.IsWhitespace;
+  }
+
+private:
+  bool isWhitespaceNoCache() const;
 };
 
 /// A command that has zero or more word-like arguments (number of word-like
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index e215e63..f3f4d9b 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -100,7 +100,7 @@
   llvm_unreachable("Unknown comment kind!");
 }
 
-bool TextComment::isWhitespace() const {
+bool TextComment::isWhitespaceNoCache() const {
   for (StringRef::const_iterator I = Text.begin(), E = Text.end();
        I != E; ++I) {
     const char C = *I;
@@ -111,7 +111,7 @@
   return true;
 }
 
-bool ParagraphComment::isWhitespace() const {
+bool ParagraphComment::isWhitespaceNoCache() const {
   for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) {
     if (const TextComment *TC = dyn_cast<TextComment>(*I)) {
       if (!TC->isWhitespace())