clang: lib/AST/CommentParser.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
16#include "llvm/Support/ErrorHandling.h"
17
19
21 for (StringRef::const_iterator I = S.begin(), E = S.end(); I != E; ++I) {
23 return false;
24 }
25 return true;
26}
27
28namespace comments {
29
30
32 llvm::BumpPtrAllocator &Allocator;
34
35
36 bool NoMoreInterestingTokens;
37
38
40
41
42 struct Position {
43 const char *BufferStart;
44 const char *BufferEnd;
45 const char *BufferPtr;
47 unsigned CurToken;
48 };
49
50
51 Position Pos;
52
53 bool isEnd() const {
54 return Pos.CurToken >= Toks.size();
55 }
56
57
58 void setupBuffer() {
59 assert(!isEnd());
60 const Token &Tok = Toks[Pos.CurToken];
61
62 Pos.BufferStart = Tok.getText().begin();
63 Pos.BufferEnd = Tok.getText().end();
64 Pos.BufferPtr = Pos.BufferStart;
65 Pos.BufferStartLoc = Tok.getLocation();
66 }
67
69 const unsigned CharNo = Pos.BufferPtr - Pos.BufferStart;
71 }
72
73 char peek() const {
74 assert(!isEnd());
75 assert(Pos.BufferPtr != Pos.BufferEnd);
76 return *Pos.BufferPtr;
77 }
78
79 void consumeChar() {
80 assert(!isEnd());
81 assert(Pos.BufferPtr != Pos.BufferEnd);
82 Pos.BufferPtr++;
83 if (Pos.BufferPtr == Pos.BufferEnd) {
84 Pos.CurToken++;
85 if (isEnd() && !addToken())
86 return;
87
88 assert(!isEnd());
89 setupBuffer();
90 }
91 }
92
93
95 unsigned BracketCount = 0;
96 while (!isEnd()) {
97 const char C = peek();
98 WordText.push_back(C);
99 consumeChar();
100 switch (C) {
101 case '<': {
102 BracketCount++;
103 break;
104 }
105 case '>': {
106 BracketCount--;
107 if (!BracketCount)
108 return true;
109 break;
110 }
111 default:
112 break;
113 }
114 }
115 return false;
116 }
117
118
119
120
121 bool addToken() {
122 if (NoMoreInterestingTokens)
123 return false;
124
126
127 Token Newline = P.Tok;
128 P.consumeToken();
130 P.putBack(Newline);
131 NoMoreInterestingTokens = true;
132 return false;
133 }
134 }
136 NoMoreInterestingTokens = true;
137 return false;
138 }
139
140 Toks.push_back(P.Tok);
141 P.consumeToken();
142 if (Toks.size() == 1)
143 setupBuffer();
144 return true;
145 }
146
147 void consumeWhitespace() {
148 while (!isEnd()) {
150 consumeChar();
151 else
152 break;
153 }
154 }
155
158 const char *TokBegin,
159 unsigned TokLength,
160 StringRef Text) {
161 Result.setLocation(Loc);
163 Result.setLength(TokLength);
164#ifndef NDEBUG
165 Result.TextPtr = "";
167#endif
169 }
170
171public:
173 Allocator(Allocator), P(P), NoMoreInterestingTokens(false) {
174 Pos.CurToken = 0;
175 addToken();
176 }
177
178
180 if (isEnd())
181 return false;
182
183
184
185 Position SavedPos = Pos;
186
187
188 consumeWhitespace();
190 const char *WordBegin = Pos.BufferPtr;
192
193 while (!isEnd()) {
194 const char C = peek();
195
196
198 if (C == '<') {
199 if (!lexTemplate(WordText))
200 return false;
201 } else {
202 WordText.push_back(C);
203 consumeChar();
204 }
205 } else {
206 consumeChar();
207 break;
208 }
209 }
210
211 const unsigned Length = WordText.size();
212 if (Length == 0) {
213 Pos = SavedPos;
214 return false;
215 }
216
217 char *TextPtr = Allocator.Allocate<char>(Length + 1);
218
219 memcpy(TextPtr, WordText.c_str(), Length + 1);
220 StringRef Text = StringRef(TextPtr, Length);
221
222 formTokenWithChars(Tok, Loc, WordBegin, Length, Text);
223 return true;
224 }
225
226
228 unsigned Offset = 1;
229
230
231
232
233 while (isWhitespace(*(Pos.BufferPtr - Offset)))
234 Offset++;
235
236
237
238 llvm::StringRef LineStart(Pos.BufferPtr - Offset - 3, 4);
239 return LineStart.starts_with("\\par") || LineStart.starts_with("@par");
240 }
241
242
244 if (isEnd())
245 return false;
246
247 Position SavedPos = Pos;
248
249 consumeWhitespace();
251 const char *WordBegin = Pos.BufferPtr;
253
255 return false;
256
257
258
259 while (!isEnd()) {
260 WordText.push_back(peek());
261 if (Pos.BufferPtr + 1 == Pos.BufferEnd) {
262 consumeChar();
263 break;
264 }
265 consumeChar();
266 }
267
268 unsigned Length = WordText.size();
269 if (Length == 0) {
270 Pos = SavedPos;
271 return false;
272 }
273
274 char *TextPtr = Allocator.Allocate<char>(Length + 1);
275
276 memcpy(TextPtr, WordText.c_str(), Length + 1);
277 StringRef Text = StringRef(TextPtr, Length);
278
279 formTokenWithChars(Tok, Loc, WordBegin, Length, Text);
280 return true;
281 }
282
283
285 if (isEnd())
286 return false;
287
288 Position SavedPos = Pos;
289
290 consumeWhitespace();
292 const char *WordBegin = Pos.BufferPtr;
294 while (!isEnd()) {
295 const char C = peek();
297 WordText.push_back(C);
298 consumeChar();
299 } else
300 break;
301 }
302 const unsigned Length = WordText.size();
303 if (Length == 0) {
304 Pos = SavedPos;
305 return false;
306 }
307
308 char *TextPtr = Allocator.Allocate<char>(Length + 1);
309
310 memcpy(TextPtr, WordText.c_str(), Length + 1);
311 StringRef Text = StringRef(TextPtr, Length);
312
313 formTokenWithChars(Tok, Loc, WordBegin, Length, Text);
314 return true;
315 }
316
318 if (isEnd())
319 return false;
320
321 Position SavedPos = Pos;
322
323 consumeWhitespace();
325 const char *WordBegin = Pos.BufferPtr;
327 bool Error = false;
328 if (!isEnd()) {
329 const char C = peek();
330 if (C == OpenDelim) {
331 WordText.push_back(C);
332 consumeChar();
333 } else
335 }
336 char C = '\0';
337 while ( && !isEnd()) {
338 C = peek();
339 WordText.push_back(C);
340 consumeChar();
341 if (C == CloseDelim)
342 break;
343 }
344 if ( && C != CloseDelim)
346
348 Pos = SavedPos;
349 return false;
350 }
351
352 const unsigned Length = WordText.size();
353 char *TextPtr = Allocator.Allocate<char>(Length + 1);
354
355 memcpy(TextPtr, WordText.c_str(), Length + 1);
356 StringRef Text = StringRef(TextPtr, Length);
357
358 formTokenWithChars(Tok, Loc, WordBegin,
359 Pos.BufferPtr - WordBegin, Text);
360 return true;
361 }
362
363
365 if (isEnd())
366 return;
367
368 bool HavePartialTok = false;
369 Token PartialTok;
370 if (Pos.BufferPtr != Pos.BufferStart) {
371 formTokenWithChars(PartialTok, getSourceLocation(),
372 Pos.BufferPtr, Pos.BufferEnd - Pos.BufferPtr,
373 StringRef(Pos.BufferPtr,
374 Pos.BufferEnd - Pos.BufferPtr));
375 HavePartialTok = true;
376 Pos.CurToken++;
377 }
378
379 P.putBack(ArrayRef(Toks.begin() + Pos.CurToken, Toks.end()));
380 Pos.CurToken = Toks.size();
381
382 if (HavePartialTok)
383 P.putBack(PartialTok);
384 }
385};
386
387Parser::Parser(Lexer &L, Sema &S, llvm::BumpPtrAllocator &Allocator,
390 L(L), S(S), Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags),
391 Traits(Traits) {
392 consumeToken();
393}
394
398
399
401 S.actOnParamCommandDirectionArg(PC,
405
406 if (Retokenizer.lexWord(Arg))
407 S.actOnParamCommandParamNameArg(PC,
411}
412
416 if (Retokenizer.lexWord(Arg))
417 S.actOnTParamCommandParamNameArg(TPC,
421}
422
425 auto *Args = new (Allocator.Allocate<Comment::Argument>(NumArgs))
427 unsigned ParsedArgs = 0;
429 while (ParsedArgs < NumArgs && Retokenizer.lexWord(Arg)) {
432 ParsedArgs++;
433 }
434
435 return ArrayRef(Args, ParsedArgs);
436}
437
440 unsigned NumArgs) {
441 auto *Args = new (Allocator.Allocate<Comment::Argument>(NumArgs))
443 unsigned ParsedArgs = 0;
445
446 while (ParsedArgs < NumArgs && Retokenizer.lexType(Arg)) {
449 ParsedArgs++;
450 }
451
452 return ArrayRef(Args, ParsedArgs);
453}
454
457 unsigned NumArgs) {
458 assert(NumArgs > 0);
459 auto *Args = new (Allocator.Allocate<Comment::Argument>(NumArgs))
461 unsigned ParsedArgs = 0;
463
464 while (ParsedArgs < NumArgs && Retokenizer.lexParHeading(Arg)) {
467 ParsedArgs++;
468 }
469
470 return ArrayRef(Args, ParsedArgs);
471}
472
475
479 const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
483 PC = S.actOnParamCommandStart(Tok.getLocation(),
484 Tok.getEndLocation(),
485 Tok.getCommandID(),
486 CommandMarker);
488 TPC = S.actOnTParamCommandStart(Tok.getLocation(),
489 Tok.getEndLocation(),
490 Tok.getCommandID(),
491 CommandMarker);
492 } else {
493 BC = S.actOnBlockCommandStart(Tok.getLocation(),
494 Tok.getEndLocation(),
495 Tok.getCommandID(),
496 CommandMarker);
497 }
498 consumeToken();
499
500 if (isTokBlockCommand()) {
501
502
504 if (PC) {
505 S.actOnParamCommandFinish(PC, Paragraph);
506 return PC;
507 } else if (TPC) {
508 S.actOnTParamCommandFinish(TPC, Paragraph);
509 return TPC;
510 } else {
511 S.actOnBlockCommandFinish(BC, Paragraph);
512 return BC;
513 }
514 }
515
516 if (PC || TPC || Info->NumArgs > 0) {
517
518
520
521 if (PC)
523 else if (TPC)
526 S.actOnBlockCommandArgs(
529 S.actOnBlockCommandArgs(BC,
531 else
533
535 }
536
537
538
539 bool EmptyParagraph = false;
540 if (isTokBlockCommand())
541 EmptyParagraph = true;
543 Token PrevTok = Tok;
544 consumeToken();
545 EmptyParagraph = isTokBlockCommand();
546 putBack(PrevTok);
547 }
548
550 if (EmptyParagraph)
551 Paragraph = S.actOnParagraphComment({});
552 else {
554
555
557 }
558
559 if (PC) {
560 S.actOnParamCommandFinish(PC, Paragraph);
561 return PC;
562 } else if (TPC) {
563 S.actOnTParamCommandFinish(TPC, Paragraph);
564 return TPC;
565 } else {
566 S.actOnBlockCommandFinish(BC, Paragraph);
567 return BC;
568 }
569}
570
575 const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
576
577 const Token CommandTok = Tok;
578 consumeToken();
579
583
587
588 if (Args.size() < Info->NumArgs) {
590 diag::warn_doc_inline_command_not_enough_arguments)
594 }
595
597
598 return IC;
599}
600
604 S.actOnHTMLStartTagStart(Tok.getLocation(),
605 Tok.getHTMLTagStartName());
606 consumeToken();
607
609 while (true) {
610 switch (Tok.getKind()) {
612 Token Ident = Tok;
613 consumeToken();
617 continue;
618 }
619 Token Equals = Tok;
620 consumeToken();
622 Diag(Tok.getLocation(),
623 diag::warn_doc_html_start_tag_expected_quoted_string)
629 consumeToken();
630 continue;
631 }
635 Equals.getLocation(),
637 Tok.getEndLocation()),
638 Tok.getHTMLQuotedString()));
639 consumeToken();
640 continue;
641 }
642
644 S.actOnHTMLStartTagFinish(HST, S.copyArray(ArrayRef(Attrs)),
646 false);
647 consumeToken();
648 return HST;
649
651 S.actOnHTMLStartTagFinish(HST, S.copyArray(ArrayRef(Attrs)),
653 true);
654 consumeToken();
655 return HST;
656
659 Diag(Tok.getLocation(),
660 diag::warn_doc_html_start_tag_expected_ident_or_greater);
663 consumeToken();
667 continue;
668
669 S.actOnHTMLStartTagFinish(HST, S.copyArray(ArrayRef(Attrs)),
671 false);
672 return HST;
673
674 default:
675
676 S.actOnHTMLStartTagFinish(HST, S.copyArray(ArrayRef(Attrs)),
678 false);
679 bool StartLineInvalid;
680 const unsigned StartLine = SourceMgr.getPresumedLineNumber(
682 &StartLineInvalid);
683 bool EndLineInvalid;
684 const unsigned EndLine = SourceMgr.getPresumedLineNumber(
685 Tok.getLocation(),
686 &EndLineInvalid);
687 if (StartLineInvalid || EndLineInvalid || StartLine == EndLine)
688 Diag(Tok.getLocation(),
689 diag::warn_doc_html_start_tag_expected_ident_or_greater)
691 else {
692 Diag(Tok.getLocation(),
693 diag::warn_doc_html_start_tag_expected_ident_or_greater);
694 Diag(HST->getLocation(), diag::note_doc_html_tag_started_here)
696 }
697 return HST;
698 }
699 }
700}
701
704 Token TokEndTag = Tok;
705 consumeToken();
708 Loc = Tok.getLocation();
709 consumeToken();
710 }
711
712 return S.actOnHTMLEndTag(TokEndTag.getLocation(),
713 Loc,
715}
716
719
720 while (true) {
721 switch (Tok.getKind()) {
725 break;
726
728 Content.push_back(S.actOnUnknownCommand(Tok.getLocation(),
729 Tok.getEndLocation(),
730 Tok.getUnknownCommandName()));
731 consumeToken();
732 continue;
733
736 const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
738 if (Content.size() == 0)
740 break;
741 }
743 Diag(Tok.getLocation(),
744 diag::warn_verbatim_block_end_without_start)
746 << Info->Name
747 << SourceRange(Tok.getLocation(), Tok.getEndLocation());
748 consumeToken();
749 continue;
750 }
752 Content.push_back(S.actOnUnknownCommand(Tok.getLocation(),
753 Tok.getEndLocation(),
755 consumeToken();
756 continue;
757 }
760 continue;
761 }
762
764 consumeToken();
766 consumeToken();
767 break;
768 }
769
770
772 Token WhitespaceTok = Tok;
773 consumeToken();
775 consumeToken();
776 break;
777 }
778
779 putBack(WhitespaceTok);
780 }
781 if (Content.size() > 0)
782 Content.back()->addTrailingNewline();
783 continue;
784 }
785
786
789 continue;
790
793 continue;
794
796 Content.push_back(S.actOnText(Tok.getLocation(),
797 Tok.getEndLocation(),
798 Tok.getText()));
799 consumeToken();
800 continue;
801
810 llvm_unreachable("should not see this token");
811 }
812 break;
813 }
814
815 return S.actOnParagraphComment(S.copyArray(ArrayRef(Content)));
816}
817
820
822 S.actOnVerbatimBlockStart(Tok.getLocation(),
823 Tok.getVerbatimBlockID());
824 consumeToken();
825
826
827
829 consumeToken();
830
836 Line = S.actOnVerbatimBlockLine(Tok.getLocation(),
837 Tok.getVerbatimBlockText());
838 consumeToken();
840 consumeToken();
841 }
842 } else {
843
844 Line = S.actOnVerbatimBlockLine(Tok.getLocation(), "");
845 consumeToken();
846 }
847 Lines.push_back(Line);
848 }
849
851 const CommandInfo *Info = Traits.getCommandInfo(Tok.getVerbatimBlockID());
852 S.actOnVerbatimBlockFinish(VB, Tok.getLocation(), Info->Name,
853 S.copyArray(ArrayRef(Lines)));
854 consumeToken();
855 } else {
856
858 S.copyArray(ArrayRef(Lines)));
859 }
860
861 return VB;
862}
863
866
867 Token NameTok = Tok;
868 consumeToken();
869
871 StringRef Text;
872
873
875 TextBegin = Tok.getLocation();
876 Text = Tok.getVerbatimLineText();
877 } else {
880 }
881
884 TextBegin,
886 consumeToken();
887 return VL;
888}
889
891 switch (Tok.getKind()) {
899
902
905
916 llvm_unreachable("should not see this token");
917 }
918 llvm_unreachable("bogus token kind");
919}
920
922
924 consumeToken();
925
927 while (Tok.isNot(tok::eof)) {
929
930
932 consumeToken();
933 }
934 return S.actOnFullComment(S.copyArray(ArrayRef(Blocks)));
935}
936
937}
938}
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.
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',...
U cast(CodeGen::Address addr)