blob: 2b648cbb1d4b441346aa9957b00d7367630d8205 [file] [log] [blame]
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +00001//===--- CommentBriefParser.cpp - Dumb comment parser ---------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "clang/AST/CommentBriefParser.h"
Dmitri Gribenkoca7f80a2012-08-09 00:03:17 +000010#include "clang/AST/CommentCommandTraits.h"
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +000011
12namespace clang {
13namespace comments {
14
Dmitri Gribenko0743f942012-06-28 01:38:21 +000015namespace {
Dmitri Gribenko75eea892012-08-21 21:15:34 +000016inline bool isWhitespace(char C) {
17 return C == ' ' || C == '\n' || C == '\r' ||
18 C == '\t' || C == '\f' || C == '\v';
19}
20
Dmitri Gribenko0743f942012-06-28 01:38:21 +000021/// Convert all whitespace into spaces, remove leading and trailing spaces,
22/// compress multiple spaces into one.
23void cleanupBrief(std::string &S) {
24 bool PrevWasSpace = true;
25 std::string::iterator O = S.begin();
26 for (std::string::iterator I = S.begin(), E = S.end();
27 I != E; ++I) {
28 const char C = *I;
Dmitri Gribenko75eea892012-08-21 21:15:34 +000029 if (isWhitespace(C)) {
Dmitri Gribenko0743f942012-06-28 01:38:21 +000030 if (!PrevWasSpace) {
31 *O++ = ' ';
32 PrevWasSpace = true;
33 }
34 continue;
35 } else {
36 *O++ = C;
37 PrevWasSpace = false;
38 }
39 }
40 if (O != S.begin() && *(O - 1) == ' ')
41 --O;
42
43 S.resize(O - S.begin());
44}
Dmitri Gribenko75eea892012-08-21 21:15:34 +000045
46bool isWhitespace(StringRef Text) {
47 for (StringRef::const_iterator I = Text.begin(), E = Text.end();
48 I != E; ++I) {
49 if (!isWhitespace(*I))
50 return false;
51 }
52 return true;
53}
Dmitri Gribenko0743f942012-06-28 01:38:21 +000054} // unnamed namespace
55
Dmitri Gribenkoca7f80a2012-08-09 00:03:17 +000056BriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) :
57 L(L), Traits(Traits) {
58 // Get lookahead token.
59 ConsumeToken();
60}
61
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +000062std::string BriefParser::Parse() {
Dmitri Gribenko77369ee2012-07-20 17:01:34 +000063 std::string FirstParagraphOrBrief;
64 std::string ReturnsParagraph;
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +000065 bool InFirstParagraph = true;
66 bool InBrief = false;
Dmitri Gribenko77369ee2012-07-20 17:01:34 +000067 bool InReturns = false;
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +000068
69 while (Tok.isNot(tok::eof)) {
70 if (Tok.is(tok::text)) {
Dmitri Gribenko99e09422012-06-27 01:17:34 +000071 if (InFirstParagraph || InBrief)
Dmitri Gribenko77369ee2012-07-20 17:01:34 +000072 FirstParagraphOrBrief += Tok.getText();
73 else if (InReturns)
74 ReturnsParagraph += Tok.getText();
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +000075 ConsumeToken();
76 continue;
77 }
78
Fariborz Jahaniane400cb72013-03-02 02:39:57 +000079 if (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) {
Dmitri Gribenko7acbf002012-09-10 20:32:42 +000080 const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
81 if (Info->IsBriefCommand) {
Dmitri Gribenko77369ee2012-07-20 17:01:34 +000082 FirstParagraphOrBrief.clear();
Dmitri Gribenkoa1e9c8e2012-06-28 00:01:41 +000083 InBrief = true;
84 ConsumeToken();
85 continue;
86 }
Dmitri Gribenko7acbf002012-09-10 20:32:42 +000087 if (Info->IsReturnsCommand) {
Dmitri Gribenko77369ee2012-07-20 17:01:34 +000088 InReturns = true;
Dmitri Gribenko75eea892012-08-21 21:15:34 +000089 InBrief = false;
90 InFirstParagraph = false;
Dmitri Gribenko77369ee2012-07-20 17:01:34 +000091 ReturnsParagraph += "Returns ";
Dmitri Gribenko75eea892012-08-21 21:15:34 +000092 ConsumeToken();
93 continue;
Dmitri Gribenko77369ee2012-07-20 17:01:34 +000094 }
Dmitri Gribenko025d5182012-06-29 18:19:20 +000095 // Block commands implicitly start a new paragraph.
Dmitri Gribenko7acbf002012-09-10 20:32:42 +000096 if (Info->IsBlockCommand) {
Dmitri Gribenkoa1e9c8e2012-06-28 00:01:41 +000097 // We found an implicit paragraph end.
98 InFirstParagraph = false;
Dmitri Gribenko767ea0f2012-07-03 18:10:20 +000099 if (InBrief)
Dmitri Gribenkoa1e9c8e2012-06-28 00:01:41 +0000100 break;
Dmitri Gribenkoa1e9c8e2012-06-28 00:01:41 +0000101 }
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +0000102 }
103
104 if (Tok.is(tok::newline)) {
Dmitri Gribenko99e09422012-06-27 01:17:34 +0000105 if (InFirstParagraph || InBrief)
Dmitri Gribenko77369ee2012-07-20 17:01:34 +0000106 FirstParagraphOrBrief += ' ';
107 else if (InReturns)
108 ReturnsParagraph += ' ';
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +0000109 ConsumeToken();
110
Dmitri Gribenko75eea892012-08-21 21:15:34 +0000111 // If the next token is a whitespace only text, ignore it. Thus we allow
112 // two paragraphs to be separated by line that has only whitespace in it.
113 //
114 // We don't need to add a space to the parsed text because we just added
115 // a space for the newline.
116 if (Tok.is(tok::text)) {
117 if (isWhitespace(Tok.getText()))
118 ConsumeToken();
119 }
120
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +0000121 if (Tok.is(tok::newline)) {
122 ConsumeToken();
Dmitri Gribenko75eea892012-08-21 21:15:34 +0000123 // We found a paragraph end. This ends the brief description if
Adrian Prantl9fc8faf2018-05-09 01:00:01 +0000124 // \command or its equivalent was explicitly used.
125 // Stop scanning text because an explicit \paragraph is the
Dmitri Gribenko75eea892012-08-21 21:15:34 +0000126 // preffered one.
Dmitri Gribenko767ea0f2012-07-03 18:10:20 +0000127 if (InBrief)
Dmitri Gribenkoa1e9c8e2012-06-28 00:01:41 +0000128 break;
Dmitri Gribenko75eea892012-08-21 21:15:34 +0000129 // End first paragraph if we found some non-whitespace text.
130 if (InFirstParagraph && !isWhitespace(FirstParagraphOrBrief))
131 InFirstParagraph = false;
132 // End the \\returns paragraph because we found the paragraph end.
133 InReturns = false;
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +0000134 }
135 continue;
136 }
137
138 // We didn't handle this token, so just drop it.
139 ConsumeToken();
140 }
141
Dmitri Gribenko77369ee2012-07-20 17:01:34 +0000142 cleanupBrief(FirstParagraphOrBrief);
143 if (!FirstParagraphOrBrief.empty())
144 return FirstParagraphOrBrief;
145
146 cleanupBrief(ReturnsParagraph);
147 return ReturnsParagraph;
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +0000148}
149
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +0000150} // end namespace comments
151} // end namespace clang
152
153