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