/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/CommentBriefParser.cpp
Line | Count | Source |
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 | | |
9 | | #include "clang/AST/CommentBriefParser.h" |
10 | | #include "clang/AST/CommentCommandTraits.h" |
11 | | #include "clang/Basic/CharInfo.h" |
12 | | |
13 | | namespace clang { |
14 | | namespace comments { |
15 | | |
16 | | namespace { |
17 | | |
18 | | /// Convert all whitespace into spaces, remove leading and trailing spaces, |
19 | | /// compress multiple spaces into one. |
20 | 1.17k | void cleanupBrief(std::string &S) { |
21 | 1.17k | bool PrevWasSpace = true; |
22 | 1.17k | std::string::iterator O = S.begin(); |
23 | 1.17k | for (std::string::iterator I = S.begin(), E = S.end(); |
24 | 17.1k | I != E; ++I15.9k ) { |
25 | 15.9k | const char C = *I; |
26 | 15.9k | if (clang::isWhitespace(C)) { |
27 | 3.28k | if (!PrevWasSpace) { |
28 | 1.90k | *O++ = ' '; |
29 | 1.90k | PrevWasSpace = true; |
30 | 1.90k | } |
31 | 12.7k | } else { |
32 | 12.7k | *O++ = C; |
33 | 12.7k | PrevWasSpace = false; |
34 | 12.7k | } |
35 | 15.9k | } |
36 | 1.17k | if (O != S.begin() && *(O - 1) == ' '685 ) |
37 | 684 | --O; |
38 | | |
39 | 1.17k | S.resize(O - S.begin()); |
40 | 1.17k | } |
41 | | |
42 | 662 | bool isWhitespace(StringRef Text) { |
43 | 662 | return llvm::all_of(Text, clang::isWhitespace); |
44 | 662 | } |
45 | | } // unnamed namespace |
46 | | |
47 | | BriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) : |
48 | 901 | L(L), Traits(Traits) { |
49 | | // Get lookahead token. |
50 | 901 | ConsumeToken(); |
51 | 901 | } |
52 | | |
53 | 901 | std::string BriefParser::Parse() { |
54 | 901 | std::string FirstParagraphOrBrief; |
55 | 901 | std::string ReturnsParagraph; |
56 | 901 | bool InFirstParagraph = true; |
57 | 901 | bool InBrief = false; |
58 | 901 | bool InReturns = false; |
59 | | |
60 | 5.14k | while (Tok.isNot(tok::eof)) { |
61 | 4.47k | if (Tok.is(tok::text)) { |
62 | 1.63k | if (InFirstParagraph || InBrief496 ) |
63 | 1.14k | FirstParagraphOrBrief += Tok.getText(); |
64 | 482 | else if (InReturns) |
65 | 82 | ReturnsParagraph += Tok.getText(); |
66 | 1.63k | ConsumeToken(); |
67 | 1.63k | continue; |
68 | 1.63k | } |
69 | | |
70 | 2.84k | if (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)2.13k ) { |
71 | 747 | const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); |
72 | 747 | if (Info->IsBriefCommand) { |
73 | 251 | FirstParagraphOrBrief.clear(); |
74 | 251 | InBrief = true; |
75 | 251 | ConsumeToken(); |
76 | 251 | continue; |
77 | 251 | } |
78 | 496 | if (Info->IsReturnsCommand) { |
79 | 82 | InReturns = true; |
80 | 82 | InBrief = false; |
81 | 82 | InFirstParagraph = false; |
82 | 82 | ReturnsParagraph += "Returns "; |
83 | 82 | ConsumeToken(); |
84 | 82 | continue; |
85 | 82 | } |
86 | | // Block commands implicitly start a new paragraph. |
87 | 414 | if (Info->IsBlockCommand) { |
88 | | // We found an implicit paragraph end. |
89 | 366 | InFirstParagraph = false; |
90 | 366 | if (InBrief) |
91 | 57 | break; |
92 | 366 | } |
93 | 414 | } |
94 | | |
95 | 2.45k | if (Tok.is(tok::newline)) { |
96 | 1.64k | if (InFirstParagraph || InBrief514 ) |
97 | 1.14k | FirstParagraphOrBrief += ' '; |
98 | 495 | else if (InReturns) |
99 | 82 | ReturnsParagraph += ' '; |
100 | 1.64k | ConsumeToken(); |
101 | | |
102 | | // If the next token is a whitespace only text, ignore it. Thus we allow |
103 | | // 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 added |
106 | | // a space for the newline. |
107 | 1.64k | if (Tok.is(tok::text)) { |
108 | 546 | if (isWhitespace(Tok.getText())) |
109 | 437 | ConsumeToken(); |
110 | 546 | } |
111 | | |
112 | 1.64k | if (Tok.is(tok::newline)) { |
113 | 354 | ConsumeToken(); |
114 | | // We found a paragraph end. This ends the brief description if |
115 | | // \command or its equivalent was explicitly used. |
116 | | // Stop scanning text because an explicit \paragraph is the |
117 | | // preferred one. |
118 | 354 | if (InBrief) |
119 | 169 | break; |
120 | | // End first paragraph if we found some non-whitespace text. |
121 | 185 | if (InFirstParagraph && !isWhitespace(FirstParagraphOrBrief)116 ) |
122 | 102 | InFirstParagraph = false; |
123 | | // End the \\returns paragraph because we found the paragraph end. |
124 | 185 | InReturns = false; |
125 | 185 | } |
126 | 1.47k | continue; |
127 | 1.64k | } |
128 | | |
129 | | // We didn't handle this token, so just drop it. |
130 | 811 | ConsumeToken(); |
131 | 811 | } |
132 | | |
133 | 901 | cleanupBrief(FirstParagraphOrBrief); |
134 | 901 | if (!FirstParagraphOrBrief.empty()) |
135 | 631 | return FirstParagraphOrBrief; |
136 | | |
137 | 270 | cleanupBrief(ReturnsParagraph); |
138 | 270 | return ReturnsParagraph; |
139 | 901 | } |
140 | | |
141 | | } // end namespace comments |
142 | | } // end namespace clang |
143 | | |
144 | | |