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