CommentBriefParser.cpp 4.0 KB

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