clang: lib/AST/CommentParser.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
15#include "llvm/Support/ErrorHandling.h"
16
18
20 for (StringRef::const_iterator I = S.begin(), E = S.end(); I != E; ++I) {
22 return false;
23 }
24 return true;
25}
26
27namespace comments {
28
29
31 llvm::BumpPtrAllocator &Allocator;
33
34
35 bool NoMoreInterestingTokens;
36
37
39
40
41 struct Position {
42 const char *BufferStart;
43 const char *BufferEnd;
44 const char *BufferPtr;
46 unsigned CurToken;
47 };
48
49
50 Position Pos;
51
52 bool isEnd() const {
53 return Pos.CurToken >= Toks.size();
54 }
55
56
57 void setupBuffer() {
58 assert(!isEnd());
59 const Token &Tok = Toks[Pos.CurToken];
60
61 Pos.BufferStart = Tok.getText().begin();
62 Pos.BufferEnd = Tok.getText().end();
63 Pos.BufferPtr = Pos.BufferStart;
65 }
66
68 const unsigned CharNo = Pos.BufferPtr - Pos.BufferStart;
69 return Pos.BufferStartLoc.getLocWithOffset(CharNo);
70 }
71
72 char peek() const {
73 assert(!isEnd());
74 assert(Pos.BufferPtr != Pos.BufferEnd);
75 return *Pos.BufferPtr;
76 }
77
78 void consumeChar() {
79 assert(!isEnd());
80 assert(Pos.BufferPtr != Pos.BufferEnd);
81 Pos.BufferPtr++;
82 if (Pos.BufferPtr == Pos.BufferEnd) {
83 Pos.CurToken++;
84 if (isEnd() && !addToken())
85 return;
86
87 assert(!isEnd());
88 setupBuffer();
89 }
90 }
91
92
94 unsigned BracketCount = 0;
95 while (!isEnd()) {
96 const char C = peek();
97 WordText.push_back(C);
98 consumeChar();
99 switch (C) {
100 case '<': {
101 BracketCount++;
102 break;
103 }
104 case '>': {
105 BracketCount--;
106 if (!BracketCount)
107 return true;
108 break;
109 }
110 default:
111 break;
112 }
113 }
114 return false;
115 }
116
117
118
119
120 bool addToken() {
121 if (NoMoreInterestingTokens)
122 return false;
123
125
127 P.consumeToken();
129 P.putBack(Newline);
130 NoMoreInterestingTokens = true;
131 return false;
132 }
133 }
135 NoMoreInterestingTokens = true;
136 return false;
137 }
138
139 Toks.push_back(P.Tok);
140 P.consumeToken();
141 if (Toks.size() == 1)
142 setupBuffer();
143 return true;
144 }
145
146 void consumeWhitespace() {
147 while (!isEnd()) {
149 consumeChar();
150 else
151 break;
152 }
153 }
154
157 const char *TokBegin,
158 unsigned TokLength,
159 StringRef Text) {
162 Result.setLength(TokLength);
163#ifndef NDEBUG
164 Result.TextPtr = "";
166#endif
168 }
169
170public:
172 Allocator(Allocator), P(P), NoMoreInterestingTokens(false) {
173 Pos.CurToken = 0;
174 addToken();
175 }
176
177
179 if (isEnd())
180 return false;
181
182
183
184 Position SavedPos = Pos;
185
186
187 consumeWhitespace();
189 const char *WordBegin = Pos.BufferPtr;
191
192 while (!isEnd()) {
193 const char C = peek();
194
195
197 if (C == '<') {
198 if (!lexTemplate(WordText))
199 return false;
200 } else {
201 WordText.push_back(C);
202 consumeChar();
203 }
204 } else {
205 consumeChar();
206 break;
207 }
208 }
209
210 const unsigned Length = WordText.size();
211 if (Length == 0) {
212 Pos = SavedPos;
213 return false;
214 }
215
216 char *TextPtr = Allocator.Allocate<char>(Length + 1);
217
218 memcpy(TextPtr, WordText.c_str(), Length + 1);
219 StringRef Text = StringRef(TextPtr, Length);
220
221 formTokenWithChars(Tok, Loc, WordBegin, Length, Text);
222 return true;
223 }
224
225
227 unsigned Offset = 1;
228
229
230
231
232 while (isWhitespace(*(Pos.BufferPtr - Offset)))
233 Offset++;
234
235
236
237 llvm::StringRef LineStart(Pos.BufferPtr - Offset - 3, 4);
238 return LineStart.starts_with("\\par") || LineStart.starts_with("@par");
239 }
240
241
243 if (isEnd())
244 return false;
245
246 Position SavedPos = Pos;
247
248 consumeWhitespace();
250 const char *WordBegin = Pos.BufferPtr;
252
254 return false;
255
256
257
258 while (!isEnd()) {
259 WordText.push_back(peek());
260 if (Pos.BufferPtr + 1 == Pos.BufferEnd) {
261 consumeChar();
262 break;
263 }
264 consumeChar();
265 }
266
267 unsigned Length = WordText.size();
268 if (Length == 0) {
269 Pos = SavedPos;
270 return false;
271 }
272
273 char *TextPtr = Allocator.Allocate<char>(Length + 1);
274
275 memcpy(TextPtr, WordText.c_str(), Length + 1);
276 StringRef Text = StringRef(TextPtr, Length);
277
278 formTokenWithChars(Tok, Loc, WordBegin, Length, Text);
279 return true;
280 }
281
282
284 if (isEnd())
285 return false;
286
287 Position SavedPos = Pos;
288
289 consumeWhitespace();
291 const char *WordBegin = Pos.BufferPtr;
293 while (!isEnd()) {
294 const char C = peek();
296 WordText.push_back(C);
297 consumeChar();
298 } else
299 break;
300 }
301 const unsigned Length = WordText.size();
302 if (Length == 0) {
303 Pos = SavedPos;
304 return false;
305 }
306
307 char *TextPtr = Allocator.Allocate<char>(Length + 1);
308
309 memcpy(TextPtr, WordText.c_str(), Length + 1);
310 StringRef Text = StringRef(TextPtr, Length);
311
312 formTokenWithChars(Tok, Loc, WordBegin, Length, Text);
313 return true;
314 }
315
317 if (isEnd())
318 return false;
319
320 Position SavedPos = Pos;
321
322 consumeWhitespace();
324 const char *WordBegin = Pos.BufferPtr;
326 bool Error = false;
327 if (!isEnd()) {
328 const char C = peek();
329 if (C == OpenDelim) {
330 WordText.push_back(C);
331 consumeChar();
332 } else
333 Error = true;
334 }
335 char C = '\0';
336 while (!Error && !isEnd()) {
337 C = peek();
338 WordText.push_back(C);
339 consumeChar();
340 if (C == CloseDelim)
341 break;
342 }
343 if (!Error && C != CloseDelim)
344 Error = true;
345
346 if (Error) {
347 Pos = SavedPos;
348 return false;
349 }
350
351 const unsigned Length = WordText.size();
352 char *TextPtr = Allocator.Allocate<char>(Length + 1);
353
354 memcpy(TextPtr, WordText.c_str(), Length + 1);
355 StringRef Text = StringRef(TextPtr, Length);
356
357 formTokenWithChars(Tok, Loc, WordBegin,
358 Pos.BufferPtr - WordBegin, Text);
359 return true;
360 }
361
362
364 if (isEnd())
365 return;
366
367 bool HavePartialTok = false;
368 Token PartialTok;
369 if (Pos.BufferPtr != Pos.BufferStart) {
370 formTokenWithChars(PartialTok, getSourceLocation(),
371 Pos.BufferPtr, Pos.BufferEnd - Pos.BufferPtr,
372 StringRef(Pos.BufferPtr,
373 Pos.BufferEnd - Pos.BufferPtr));
374 HavePartialTok = true;
375 Pos.CurToken++;
376 }
377
378 P.putBack(llvm::ArrayRef(Toks.begin() + Pos.CurToken, Toks.end()));
379 Pos.CurToken = Toks.size();
380
381 if (HavePartialTok)
382 P.putBack(PartialTok);
383 }
384};
385
386Parser::Parser(Lexer &L, Sema &S, llvm::BumpPtrAllocator &Allocator,
389 L(L), S(S), Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags),
390 Traits(Traits) {
391 consumeToken();
392}
393
397
398
404
405 if (Retokenizer.lexWord(Arg))
410}
411
415 if (Retokenizer.lexWord(Arg))
420}
421
424 auto *Args = new (Allocator.Allocate<Comment::Argument>(NumArgs))
426 unsigned ParsedArgs = 0;
428 while (ParsedArgs < NumArgs && Retokenizer.lexWord(Arg)) {
431 ParsedArgs++;
432 }
433
435}
436
439 unsigned NumArgs) {
440 auto *Args = new (Allocator.Allocate<Comment::Argument>(NumArgs))
442 unsigned ParsedArgs = 0;
444
445 while (ParsedArgs < NumArgs && Retokenizer.lexType(Arg)) {
448 ParsedArgs++;
449 }
450
452}
453
456 unsigned NumArgs) {
457 assert(NumArgs > 0);
458 auto *Args = new (Allocator.Allocate<Comment::Argument>(NumArgs))
460 unsigned ParsedArgs = 0;
462
463 while (ParsedArgs < NumArgs && Retokenizer.lexParHeading(Arg)) {
466 ParsedArgs++;
467 }
468
470}
471
474
485 CommandMarker);
490 CommandMarker);
491 } else {
495 CommandMarker);
496 }
497 consumeToken();
498
499 if (isTokBlockCommand()) {
500
501
503 if (PC) {
505 return PC;
506 } else if (TPC) {
508 return TPC;
509 } else {
511 return BC;
512 }
513 }
514
515 if (PC || TPC || Info->NumArgs > 0) {
516
517
519
520 if (PC)
522 else if (TPC)
530 else
532
534 }
535
536
537
538 bool EmptyParagraph = false;
539 if (isTokBlockCommand())
540 EmptyParagraph = true;
542 Token PrevTok = Tok;
543 consumeToken();
544 EmptyParagraph = isTokBlockCommand();
545 putBack(PrevTok);
546 }
547
549 if (EmptyParagraph)
551 else {
553
554
555 Paragraph = cast(Block);
556 }
557
558 if (PC) {
560 return PC;
561 } else if (TPC) {
563 return TPC;
564 } else {
566 return BC;
567 }
568}
569
573
574 const Token CommandTok = Tok;
575 consumeToken();
576
580
584
585 if (Args.size() < Info->NumArgs) {
587 diag::warn_doc_inline_command_not_enough_arguments)
591 }
592
594
595 return IC;
596}
597
603 consumeToken();
604
606 while (true) {
609 Token Ident = Tok;
610 consumeToken();
614 continue;
615 }
616 Token Equals = Tok;
617 consumeToken();
620 diag::warn_doc_html_start_tag_expected_quoted_string)
626 consumeToken();
627 continue;
628 }
632 Equals.getLocation(),
636 consumeToken();
637 continue;
638 }
639
643 false);
644 consumeToken();
645 return HST;
646
650 true);
651 consumeToken();
652 return HST;
653
657 diag::warn_doc_html_start_tag_expected_ident_or_greater);
660 consumeToken();
664 continue;
665
668 false);
669 return HST;
670
671 default:
672
675 false);
676 bool StartLineInvalid;
679 &StartLineInvalid);
680 bool EndLineInvalid;
683 &EndLineInvalid);
684 if (StartLineInvalid || EndLineInvalid || StartLine == EndLine)
686 diag::warn_doc_html_start_tag_expected_ident_or_greater)
688 else {
690 diag::warn_doc_html_start_tag_expected_ident_or_greater);
691 Diag(HST->getLocation(), diag::note_doc_html_tag_started_here)
693 }
694 return HST;
695 }
696 }
697}
698
701 Token TokEndTag = Tok;
702 consumeToken();
706 consumeToken();
707 }
708
712}
713
716
717 while (true) {
722 break;
723
728 consumeToken();
729 continue;
730
735 if (Content.size() == 0)
737 break;
738 }
741 diag::warn_verbatim_block_end_without_start)
743 << Info->Name
745 consumeToken();
746 continue;
747 }
752 consumeToken();
753 continue;
754 }
757 continue;
758 }
759
761 consumeToken();
763 consumeToken();
764 break;
765 }
766
767
769 Token WhitespaceTok = Tok;
770 consumeToken();
772 consumeToken();
773 break;
774 }
775
776 putBack(WhitespaceTok);
777 }
778 if (Content.size() > 0)
779 Content.back()->addTrailingNewline();
780 continue;
781 }
782
783
786 continue;
787
790 continue;
791
796 consumeToken();
797 continue;
798
807 llvm_unreachable("should not see this token");
808 }
809 break;
810 }
811
813}
814
817
821 consumeToken();
822
823
824
826 consumeToken();
827
835 consumeToken();
837 consumeToken();
838 }
839 } else {
840
842 consumeToken();
843 }
844 Lines.push_back(Line);
845 }
846
851 consumeToken();
852 } else {
853
856 }
857
858 return VB;
859}
860
863
864 Token NameTok = Tok;
865 consumeToken();
866
868 StringRef Text;
869
870
874 } else {
877 }
878
881 TextBegin,
883 consumeToken();
884 return VL;
885}
886
896
899
902
913 llvm_unreachable("should not see this token");
914 }
915 llvm_unreachable("bogus token kind");
916}
917
919
921 consumeToken();
922
926
927
929 consumeToken();
930 }
932}
933
934}
935}
Defines the SourceManager interface.
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
Concrete class used by the front-end to report problems and issues.
Encodes a location in the source.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
A trivial tuple used to represent a source range.
Block content (contains inline content).
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...