CommentBriefParser.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. //===--- CommentBriefParser.cpp - Dumb comment parser ---------------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "clang/AST/CommentBriefParser.h"
  10. #include "clang/AST/CommentCommandTraits.h"
  11. #include "llvm/ADT/StringSwitch.h"
  12. namespace clang {
  13. namespace comments {
  14. namespace {
  15. inline bool isWhitespace(char C) {
  16. return C == ' ' || C == '\n' || C == '\r' ||
  17. C == '\t' || C == '\f' || C == '\v';
  18. }
  19. /// Convert all whitespace into spaces, remove leading and trailing spaces,
  20. /// compress multiple spaces into one.
  21. void cleanupBrief(std::string &S) {
  22. bool PrevWasSpace = true;
  23. std::string::iterator O = S.begin();
  24. for (std::string::iterator I = S.begin(), E = S.end();
  25. I != E; ++I) {
  26. const char C = *I;
  27. if (isWhitespace(C)) {
  28. if (!PrevWasSpace) {
  29. *O++ = ' ';
  30. PrevWasSpace = true;
  31. }
  32. continue;
  33. } else {
  34. *O++ = C;
  35. PrevWasSpace = false;
  36. }
  37. }
  38. if (O != S.begin() && *(O - 1) == ' ')
  39. --O;
  40. S.resize(O - S.begin());
  41. }
  42. bool isWhitespace(StringRef Text) {
  43. for (StringRef::const_iterator I = Text.begin(), E = Text.end();
  44. I != E; ++I) {
  45. if (!isWhitespace(*I))
  46. return false;
  47. }
  48. return true;
  49. }
  50. } // unnamed namespace
  51. BriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) :
  52. L(L), Traits(Traits) {
  53. // Get lookahead token.
  54. ConsumeToken();
  55. }
  56. std::string BriefParser::Parse() {
  57. std::string FirstParagraphOrBrief;
  58. std::string ReturnsParagraph;
  59. bool InFirstParagraph = true;
  60. bool InBrief = false;
  61. bool InReturns = false;
  62. while (Tok.isNot(tok::eof)) {
  63. if (Tok.is(tok::text)) {
  64. if (InFirstParagraph || InBrief)
  65. FirstParagraphOrBrief += Tok.getText();
  66. else if (InReturns)
  67. ReturnsParagraph += Tok.getText();
  68. ConsumeToken();
  69. continue;
  70. }
  71. if (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) {
  72. const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
  73. if (Info->IsBriefCommand) {
  74. FirstParagraphOrBrief.clear();
  75. InBrief = true;
  76. ConsumeToken();
  77. continue;
  78. }
  79. if (Info->IsReturnsCommand) {
  80. InReturns = true;
  81. InBrief = false;
  82. InFirstParagraph = false;
  83. ReturnsParagraph += "Returns ";
  84. ConsumeToken();
  85. continue;
  86. }
  87. // Block commands implicitly start a new paragraph.
  88. if (Info->IsBlockCommand) {
  89. // We found an implicit paragraph end.
  90. InFirstParagraph = false;
  91. if (InBrief)
  92. break;
  93. }
  94. }
  95. if (Tok.is(tok::newline)) {
  96. if (InFirstParagraph || InBrief)
  97. FirstParagraphOrBrief += ' ';
  98. else if (InReturns)
  99. ReturnsParagraph += ' ';
  100. ConsumeToken();
  101. // If the next token is a whitespace only text, ignore it. Thus we allow
  102. // two paragraphs to be separated by line that has only whitespace in it.
  103. //
  104. // We don't need to add a space to the parsed text because we just added
  105. // a space for the newline.
  106. if (Tok.is(tok::text)) {
  107. if (isWhitespace(Tok.getText()))
  108. ConsumeToken();
  109. }
  110. if (Tok.is(tok::newline)) {
  111. ConsumeToken();
  112. // We found a paragraph end. This ends the brief description if
  113. // \\brief command or its equivalent was explicitly used.
  114. // Stop scanning text because an explicit \\brief paragraph is the
  115. // preffered one.
  116. if (InBrief)
  117. break;
  118. // End first paragraph if we found some non-whitespace text.
  119. if (InFirstParagraph && !isWhitespace(FirstParagraphOrBrief))
  120. InFirstParagraph = false;
  121. // End the \\returns paragraph because we found the paragraph end.
  122. InReturns = false;
  123. }
  124. continue;
  125. }
  126. // We didn't handle this token, so just drop it.
  127. ConsumeToken();
  128. }
  129. cleanupBrief(FirstParagraphOrBrief);
  130. if (!FirstParagraphOrBrief.empty())
  131. return FirstParagraphOrBrief;
  132. cleanupBrief(ReturnsParagraph);
  133. return ReturnsParagraph;
  134. }
  135. } // end namespace comments
  136. } // end namespace clang