CommentBriefParser.cpp 4.2 KB

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