clang: lib/AST/CommentLexer.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
13#include "llvm/ADT/StringExtras.h"
14#include "llvm/ADT/StringSwitch.h"
15#include "llvm/Support/ConvertUTF.h"
16#include "llvm/Support/ErrorHandling.h"
17
19namespace comments {
20
22 llvm::errs() << "comments::Token Kind=" << Kind << " ";
23 Loc.print(llvm::errs(), SM);
24 llvm::errs() << " " << Length << " \"" << L.getSpelling(*this, SM) << "\"\n";
25}
26
29}
30
33}
34
37}
38
40 llvm::BumpPtrAllocator &Allocator,
41 unsigned CodePoint) {
42 char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT);
43 char *ResolvedPtr = Resolved;
44 if (llvm::ConvertCodePointToUTF8(CodePoint, ResolvedPtr))
45 return StringRef(Resolved, ResolvedPtr - Resolved);
46 else
47 return StringRef();
48}
49
50namespace {
51
52#include "clang/AST/CommentHTMLTags.inc"
53#include "clang/AST/CommentHTMLNamedCharacterReferences.inc"
54
55}
56
57StringRef Lexer::resolveHTMLNamedCharacterReference(StringRef Name) const {
58
59 return llvm::StringSwitch(Name)
60 .Case("amp", "&")
61 .Case("lt", "<")
62 .Case("gt", ">")
63 .Case("quot", "\"")
64 .Case("apos", "\'")
65
66 .Default(translateHTMLNamedCharacterReferenceToUTF8(Name));
67}
68
69StringRef Lexer::resolveHTMLDecimalCharacterReference(StringRef Name) const {
70 unsigned CodePoint = 0;
71 for (unsigned i = 0, e = Name.size(); i != e; ++i) {
73 CodePoint *= 10;
74 CodePoint += Name[i] - '0';
75 }
77}
78
79StringRef Lexer::resolveHTMLHexCharacterReference(StringRef Name) const {
80 unsigned CodePoint = 0;
81 for (unsigned i = 0, e = Name.size(); i != e; ++i) {
82 CodePoint *= 16;
83 const char C = Name[i];
85 CodePoint += llvm::hexDigitValue(C);
86 }
88}
89
90void Lexer::skipLineStartingDecorations() {
91
92 assert(CommentState == LCS_InsideCComment);
93
94 if (BufferPtr == CommentEnd)
95 return;
96
97 const char *NewBufferPtr = BufferPtr;
99 if (++NewBufferPtr == CommentEnd)
100 return;
101 if (*NewBufferPtr == '*')
102 BufferPtr = NewBufferPtr + 1;
103}
104
105namespace {
106
107const char *findNewline(const char *BufferPtr, const char *BufferEnd) {
108 for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
110 return BufferPtr;
111 }
112 return BufferEnd;
113}
114
115const char *skipNewline(const char *BufferPtr, const char *BufferEnd) {
116 if (BufferPtr == BufferEnd)
117 return BufferPtr;
118
119 if (*BufferPtr == '\n')
120 BufferPtr++;
121 else {
122 assert(*BufferPtr == '\r');
123 BufferPtr++;
124 if (BufferPtr != BufferEnd && *BufferPtr == '\n')
125 BufferPtr++;
126 }
127 return BufferPtr;
128}
129
130const char *skipNamedCharacterReference(const char *BufferPtr,
131 const char *BufferEnd) {
132 for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
134 return BufferPtr;
135 }
136 return BufferEnd;
137}
138
139const char *skipDecimalCharacterReference(const char *BufferPtr,
140 const char *BufferEnd) {
141 for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
143 return BufferPtr;
144 }
145 return BufferEnd;
146}
147
148const char *skipHexCharacterReference(const char *BufferPtr,
149 const char *BufferEnd) {
150 for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
152 return BufferPtr;
153 }
154 return BufferEnd;
155}
156
157bool isHTMLIdentifierStartingCharacter(char C) {
159}
160
161bool isHTMLIdentifierCharacter(char C) {
163}
164
165const char *skipHTMLIdentifier(const char *BufferPtr, const char *BufferEnd) {
166 for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
167 if (!isHTMLIdentifierCharacter(*BufferPtr))
168 return BufferPtr;
169 }
170 return BufferEnd;
171}
172
173
174
175
176
177const char *skipHTMLQuotedString(const char *BufferPtr, const char *BufferEnd)
178{
179 const char Quote = *BufferPtr;
180 assert(Quote == '\"' || Quote == '\'');
181
182 BufferPtr++;
183 for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
184 const char C = *BufferPtr;
185 if (C == Quote && BufferPtr[-1] != '\\')
186 return BufferPtr;
187 }
188 return BufferEnd;
189}
190
191const char *skipWhitespace(const char *BufferPtr, const char *BufferEnd) {
192 for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
194 return BufferPtr;
195 }
196 return BufferEnd;
197}
198
199bool isWhitespace(const char *BufferPtr, const char *BufferEnd) {
200 return skipWhitespace(BufferPtr, BufferEnd) == BufferEnd;
201}
202
203bool isCommandNameStartCharacter(char C) {
205}
206
207bool isCommandNameCharacter(char C) {
209}
210
211const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) {
212 for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
213 if (!isCommandNameCharacter(*BufferPtr))
214 return BufferPtr;
215 }
216 return BufferEnd;
217}
218
219
220
221const char *findBCPLCommentEnd(const char *BufferPtr, const char *BufferEnd) {
222 const char *CurPtr = BufferPtr;
223 while (CurPtr != BufferEnd) {
225 CurPtr++;
226 if (CurPtr == BufferEnd)
227 return BufferEnd;
228 }
229
230 const char *EscapePtr = CurPtr - 1;
232 EscapePtr--;
233
234 if (*EscapePtr == '\\' ||
235 (EscapePtr - 2 >= BufferPtr && EscapePtr[0] == '/' &&
236 EscapePtr[-1] == '?' && EscapePtr[-2] == '?')) {
237
239 } else
240 return CurPtr;
241 }
242 return BufferEnd;
243}
244
245
246
247const char *findCCommentEnd(const char *BufferPtr, const char *BufferEnd) {
248 for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
249 if (*BufferPtr == '*') {
250 assert(BufferPtr + 1 != BufferEnd);
251 if (*(BufferPtr + 1) == '/')
252 return BufferPtr;
253 }
254 }
255 llvm_unreachable("buffer end hit before '*/' was seen");
256}
257
258}
259
260void Lexer::formTokenWithChars(Token &Result, const char *TokEnd,
262 const unsigned TokLen = TokEnd - BufferPtr;
263 Result.setLocation(getSourceLocation(BufferPtr));
265 Result.setLength(TokLen);
266#ifndef NDEBUG
267 Result.TextPtr = "";
269#endif
270 BufferPtr = TokEnd;
271}
272
273const char *Lexer::skipTextToken() {
274 const char *TokenPtr = BufferPtr;
275 assert(TokenPtr < CommentEnd);
276 StringRef TokStartSymbols = ParseCommands ? "\n\r\\@\"&<" : "\n\r";
277
278again:
279 size_t End =
280 StringRef(TokenPtr, CommentEnd - TokenPtr).find_first_of(TokStartSymbols);
281 if (End == StringRef::npos)
282 return CommentEnd;
283
284
285
286 if (*(TokenPtr + End) == '\"') {
287 TokenPtr += End + 1;
288 End = StringRef(TokenPtr, CommentEnd - TokenPtr).find_first_of("\n\r\"");
289 if (End != StringRef::npos && *(TokenPtr + End) == '\"')
290 TokenPtr += End + 1;
291 goto again;
292 }
293 return TokenPtr + End;
294}
295
296void Lexer::lexCommentText(Token &T) {
297 assert(CommentState == LCS_InsideBCPLComment ||
298 CommentState == LCS_InsideCComment);
299
300
301 auto HandleNonCommandToken = [&]() -> void {
302 assert(State == LS_Normal);
303
304 const char *TokenPtr = BufferPtr;
305 assert(TokenPtr < CommentEnd);
306 switch (*TokenPtr) {
307 case '\n':
308 case '\r':
309 TokenPtr = skipNewline(TokenPtr, CommentEnd);
311
312 if (CommentState == LCS_InsideCComment)
313 skipLineStartingDecorations();
314 return;
315
316 default:
317 return formTextToken(T, skipTextToken());
318 }
319 };
320
321 if (!ParseCommands)
322 return HandleNonCommandToken();
323
324 switch (State) {
325 case LS_Normal:
326 break;
327 case LS_VerbatimBlockFirstLine:
328 lexVerbatimBlockFirstLine(T);
329 return;
330 case LS_VerbatimBlockBody:
331 lexVerbatimBlockBody(T);
332 return;
333 case LS_VerbatimLineText:
334 lexVerbatimLineText(T);
335 return;
336 case LS_HTMLStartTag:
337 lexHTMLStartTag(T);
338 return;
339 case LS_HTMLEndTag:
340 lexHTMLEndTag(T);
341 return;
342 }
343
344 assert(State == LS_Normal);
345 const char *TokenPtr = BufferPtr;
346 assert(TokenPtr < CommentEnd);
347 switch(*TokenPtr) {
348 case '\\':
349 case '@': {
350
351
352
355 TokenPtr++;
356 if (TokenPtr == CommentEnd) {
357 formTextToken(T, TokenPtr);
358 return;
359 }
360 char C = *TokenPtr;
361 switch (C) {
362 default:
363 break;
364
365 case '\\': case '@': case '&': case '$':
366 case '#': case '<': case '>': case '%':
367 case '\"': case '.': case ':':
368
369 TokenPtr++;
370 if (C == ':' && TokenPtr != CommentEnd && *TokenPtr == ':') {
371
372 TokenPtr++;
373 }
374 StringRef UnescapedText(BufferPtr + 1, TokenPtr - (BufferPtr + 1));
375 formTokenWithChars(T, TokenPtr, tok::text);
376 T.setText(UnescapedText);
377 return;
378 }
379
380
381 if (!isCommandNameStartCharacter(*TokenPtr)) {
382 formTextToken(T, TokenPtr);
383 return;
384 }
385
386 TokenPtr = skipCommandName(TokenPtr, CommentEnd);
387 unsigned Length = TokenPtr - (BufferPtr + 1);
388
389
390
391 if (Length == 1 && TokenPtr[-1] == 'f' && TokenPtr != CommentEnd) {
392 C = *TokenPtr;
393 if (C == '$' || C == '(' || C == ')' || C == '[' || C == ']' ||
395 TokenPtr++;
396 Length++;
397 }
398 }
399
400 StringRef CommandName(BufferPtr + 1, Length);
401
403 if (!Info) {
405 StringRef CorrectedName = Info->Name;
406 SourceLocation Loc = getSourceLocation(BufferPtr);
407 SourceLocation EndLoc = getSourceLocation(TokenPtr);
408 SourceRange FullRange = SourceRange(Loc, EndLoc);
409 SourceRange CommandRange(Loc.getLocWithOffset(1), EndLoc);
410 Diag(Loc, diag::warn_correct_comment_command_name)
411 << FullRange << CommandName << CorrectedName
413 } else {
415 T.setUnknownCommandName(CommandName);
416 Diag(T.getLocation(), diag::warn_unknown_comment_command_name)
417 << SourceRange(T.getLocation(), T.getEndLocation());
418 return;
419 }
420 }
421 if (Info->IsVerbatimBlockCommand) {
422 setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info);
423 return;
424 }
425 if (Info->IsVerbatimLineCommand) {
426 setupAndLexVerbatimLine(T, TokenPtr, Info);
427 return;
428 }
429 formTokenWithChars(T, TokenPtr, CommandKind);
430 T.setCommandID(Info->getID());
431 return;
432 }
433
434 case '&':
435 lexHTMLCharacterReference(T);
436 return;
437
438 case '<': {
439 TokenPtr++;
440 if (TokenPtr == CommentEnd) {
441 formTextToken(T, TokenPtr);
442 return;
443 }
444 const char C = *TokenPtr;
445 if (isHTMLIdentifierStartingCharacter(C))
446 setupAndLexHTMLStartTag(T);
447 else if (C == '/')
448 setupAndLexHTMLEndTag(T);
449 else
450 formTextToken(T, TokenPtr);
451 return;
452 }
453
454 default:
455 return HandleNonCommandToken();
456 }
457}
458
459void Lexer::setupAndLexVerbatimBlock(Token &T,
460 const char *TextBegin,
461 char Marker, const CommandInfo *Info) {
462 assert(Info->IsVerbatimBlockCommand);
463
464 VerbatimBlockEndCommandName.clear();
465 VerbatimBlockEndCommandName.append(Marker == '\\' ? "\\" : "@");
466 VerbatimBlockEndCommandName.append(Info->EndCommandName);
467
469 T.setVerbatimBlockID(Info->getID());
470
471
472
473
474 if (BufferPtr != CommentEnd &&
476 BufferPtr = skipNewline(BufferPtr, CommentEnd);
477 State = LS_VerbatimBlockBody;
478 return;
479 }
480
481 State = LS_VerbatimBlockFirstLine;
482}
483
484void Lexer::lexVerbatimBlockFirstLine(Token &T) {
485again:
486 assert(BufferPtr < CommentEnd);
487
488
489
490
491
492 const char *Newline = findNewline(BufferPtr, CommentEnd);
493 StringRef Line(BufferPtr, Newline - BufferPtr);
494
495
496 size_t Pos = Line.find(VerbatimBlockEndCommandName);
497 const char *TextEnd;
498 const char *NextLine;
499 if (Pos == StringRef::npos) {
500
501 TextEnd = Newline;
502 NextLine = skipNewline(Newline, CommentEnd);
503 } else if (Pos == 0) {
504
505 const char *End = BufferPtr + VerbatimBlockEndCommandName.size();
506 StringRef Name(BufferPtr + 1, End - (BufferPtr + 1));
509 State = LS_Normal;
510 return;
511 } else {
512
513 TextEnd = BufferPtr + Pos;
514 NextLine = TextEnd;
515
517 BufferPtr = TextEnd;
518 goto again;
519 }
520 }
521
522 StringRef Text(BufferPtr, TextEnd - BufferPtr);
524 T.setVerbatimBlockText(Text);
525
526 State = LS_VerbatimBlockBody;
527}
528
529void Lexer::lexVerbatimBlockBody(Token &T) {
530 assert(State == LS_VerbatimBlockBody);
531
532 if (CommentState == LCS_InsideCComment)
533 skipLineStartingDecorations();
534
535 if (BufferPtr == CommentEnd) {
537 T.setVerbatimBlockText("");
538 return;
539 }
540
541 lexVerbatimBlockFirstLine(T);
542}
543
544void Lexer::setupAndLexVerbatimLine(Token &T, const char *TextBegin,
545 const CommandInfo *Info) {
546 assert(Info->IsVerbatimLineCommand);
548 T.setVerbatimLineID(Info->getID());
549
550 State = LS_VerbatimLineText;
551}
552
553void Lexer::lexVerbatimLineText(Token &T) {
554 assert(State == LS_VerbatimLineText);
555
556
557 const char *Newline = findNewline(BufferPtr, CommentEnd);
558 StringRef Text(BufferPtr, Newline - BufferPtr);
560 T.setVerbatimLineText(Text);
561
562 State = LS_Normal;
563}
564
565void Lexer::lexHTMLCharacterReference(Token &T) {
566 const char *TokenPtr = BufferPtr;
567 assert(*TokenPtr == '&');
568 TokenPtr++;
569 if (TokenPtr == CommentEnd) {
570 formTextToken(T, TokenPtr);
571 return;
572 }
573 const char *NamePtr;
575 bool isDecimal = false;
576 char C = *TokenPtr;
578 NamePtr = TokenPtr;
579 TokenPtr = skipNamedCharacterReference(TokenPtr, CommentEnd);
581 } else if (C == '#') {
582 TokenPtr++;
583 if (TokenPtr == CommentEnd) {
584 formTextToken(T, TokenPtr);
585 return;
586 }
587 C = *TokenPtr;
589 NamePtr = TokenPtr;
590 TokenPtr = skipDecimalCharacterReference(TokenPtr, CommentEnd);
591 isDecimal = true;
592 } else if (C == 'x' || C == 'X') {
593 TokenPtr++;
594 NamePtr = TokenPtr;
595 TokenPtr = skipHexCharacterReference(TokenPtr, CommentEnd);
596 } else {
597 formTextToken(T, TokenPtr);
598 return;
599 }
600 } else {
601 formTextToken(T, TokenPtr);
602 return;
603 }
604 if (NamePtr == TokenPtr || TokenPtr == CommentEnd ||
605 *TokenPtr != ';') {
606 formTextToken(T, TokenPtr);
607 return;
608 }
609 StringRef Name(NamePtr, TokenPtr - NamePtr);
610 TokenPtr++;
611 StringRef Resolved;
613 Resolved = resolveHTMLNamedCharacterReference(Name);
614 else if (isDecimal)
615 Resolved = resolveHTMLDecimalCharacterReference(Name);
616 else
617 Resolved = resolveHTMLHexCharacterReference(Name);
618
619 if (Resolved.empty()) {
620 formTextToken(T, TokenPtr);
621 return;
622 }
623 formTokenWithChars(T, TokenPtr, tok::text);
624 T.setText(Resolved);
625}
626
627void Lexer::setupAndLexHTMLStartTag(Token &T) {
628 assert(BufferPtr[0] == '<' &&
629 isHTMLIdentifierStartingCharacter(BufferPtr[1]));
630 const char *TagNameEnd = skipHTMLIdentifier(BufferPtr + 2, CommentEnd);
631 StringRef Name(BufferPtr + 1, TagNameEnd - (BufferPtr + 1));
632 if (!isHTMLTagName(Name)) {
633 formTextToken(T, TagNameEnd);
634 return;
635 }
636
638 T.setHTMLTagStartName(Name);
639
641
642 const char C = *BufferPtr;
643 if (BufferPtr != CommentEnd &&
644 (C == '>' || C == '/' || isHTMLIdentifierStartingCharacter(C)))
645 State = LS_HTMLStartTag;
646}
647
648void Lexer::lexHTMLStartTag(Token &T) {
649 assert(State == LS_HTMLStartTag);
650
651 const char *TokenPtr = BufferPtr;
652 char C = *TokenPtr;
653 if (isHTMLIdentifierCharacter(C)) {
654 TokenPtr = skipHTMLIdentifier(TokenPtr, CommentEnd);
655 StringRef Ident(BufferPtr, TokenPtr - BufferPtr);
657 T.setHTMLIdent(Ident);
658 } else {
659 switch (C) {
660 case '=':
661 TokenPtr++;
663 break;
664 case '\"':
665 case '\'': {
666 const char *OpenQuote = TokenPtr;
667 TokenPtr = skipHTMLQuotedString(TokenPtr, CommentEnd);
668 const char *ClosingQuote = TokenPtr;
669 if (TokenPtr != CommentEnd)
670 TokenPtr++;
672 T.setHTMLQuotedString(StringRef(OpenQuote + 1,
673 ClosingQuote - (OpenQuote + 1)));
674 break;
675 }
676 case '>':
677 TokenPtr++;
679 State = LS_Normal;
680 return;
681 case '/':
682 TokenPtr++;
683 if (TokenPtr != CommentEnd && *TokenPtr == '>') {
684 TokenPtr++;
686 } else
687 formTextToken(T, TokenPtr);
688
689 State = LS_Normal;
690 return;
691 }
692 }
693
694
695
697 if (BufferPtr == CommentEnd) {
698 State = LS_Normal;
699 return;
700 }
701
702 C = *BufferPtr;
703 if (!isHTMLIdentifierStartingCharacter(C) &&
704 C != '=' && C != '\"' && C != '\'' && C != '>' && C != '/') {
705 State = LS_Normal;
706 return;
707 }
708}
709
710void Lexer::setupAndLexHTMLEndTag(Token &T) {
711 assert(BufferPtr[0] == '<' && BufferPtr[1] == '/');
712
713 const char *TagNameBegin = skipWhitespace(BufferPtr + 2, CommentEnd);
714 const char *TagNameEnd = skipHTMLIdentifier(TagNameBegin, CommentEnd);
715 StringRef Name(TagNameBegin, TagNameEnd - TagNameBegin);
716 if (!isHTMLTagName(Name)) {
717 formTextToken(T, TagNameEnd);
718 return;
719 }
720
721 const char *End = skipWhitespace(TagNameEnd, CommentEnd);
722
724 T.setHTMLTagEndName(Name);
725
726 if (BufferPtr != CommentEnd && *BufferPtr == '>')
727 State = LS_HTMLEndTag;
728}
729
730void Lexer::lexHTMLEndTag(Token &T) {
731 assert(BufferPtr != CommentEnd && *BufferPtr == '>');
732
734 State = LS_Normal;
735}
736
739 const char *BufferStart, const char *BufferEnd, bool ParseCommands)
740 : Allocator(Allocator), Diags(Diags), Traits(Traits),
741 BufferStart(BufferStart), BufferEnd(BufferEnd), BufferPtr(BufferStart),
742 FileLoc(FileLoc), ParseCommands(ParseCommands),
743 CommentState(LCS_BeforeComment), State(LS_Normal) {}
744
746again:
747 switch (CommentState) {
748 case LCS_BeforeComment:
749 if (BufferPtr == BufferEnd) {
750 formTokenWithChars(T, BufferPtr, tok::eof);
751 return;
752 }
753
754 assert(*BufferPtr == '/');
755 BufferPtr++;
756 switch(*BufferPtr) {
757 case '/': {
758 BufferPtr++;
759
760 if (BufferPtr != BufferEnd) {
761
762
763
764
765 const char C = *BufferPtr;
767 BufferPtr++;
768 }
769
770
771
772
773 if (BufferPtr != BufferEnd && *BufferPtr == '<')
774 BufferPtr++;
775
776 CommentState = LCS_InsideBCPLComment;
777 if (State != LS_VerbatimBlockBody && State != LS_VerbatimBlockFirstLine)
778 State = LS_Normal;
779 CommentEnd = findBCPLCommentEnd(BufferPtr, BufferEnd);
780 goto again;
781 }
782 case '*': {
783 BufferPtr++;
784
785
786 const char C = *BufferPtr;
787 if ((C == '*' && *(BufferPtr + 1) != '/') || C == '!')
788 BufferPtr++;
789
790
791 if (BufferPtr != BufferEnd && *BufferPtr == '<')
792 BufferPtr++;
793
794 CommentState = LCS_InsideCComment;
795 State = LS_Normal;
796 CommentEnd = findCCommentEnd(BufferPtr, BufferEnd);
797 goto again;
798 }
799 default:
800 llvm_unreachable("second character of comment should be '/' or '*'");
801 }
802
803 case LCS_BetweenComments: {
804
805
806 const char *EndWhitespace = BufferPtr;
807 while(EndWhitespace != BufferEnd && *EndWhitespace != '/')
808 EndWhitespace++;
809
810
811
812
813
814 formTokenWithChars(T, EndWhitespace, tok::newline);
815
816 CommentState = LCS_BeforeComment;
817 break;
818 }
819
820 case LCS_InsideBCPLComment:
821 case LCS_InsideCComment:
822 if (BufferPtr != CommentEnd) {
823 lexCommentText(T);
824 break;
825 } else {
826
827 if (CommentState == LCS_InsideCComment) {
828 assert(BufferPtr[0] == '*' && BufferPtr[1] == '/');
829 BufferPtr += 2;
830 assert(BufferPtr <= BufferEnd);
831
832
833
835
836 CommentState = LCS_BetweenComments;
837 break;
838 } else {
839
840 CommentState = LCS_BetweenComments;
841 goto again;
842 }
843 }
844 }
845}
846
851
852 bool InvalidTemp = false;
853 StringRef File = SourceMgr.getBufferData(LocInfo.first, &InvalidTemp);
854 if (InvalidTemp)
855 return StringRef();
856
857 const char *Begin = File.data() + LocInfo.second;
859}
860
861}
862}
enum clang::sema::@1727::IndirectLocalPathEntry::EntryKind Kind
static bool isNamed(const NamedDecl *ND, const char(&Str)[Len])
static unsigned skipNewline(const char *&First, const char *End)
static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length)
Skip over whitespace in the string, starting at the given index.
Concrete class used by the front-end to report problems and issues.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
Encodes a location in the source.
void print(raw_ostream &OS, const SourceManager &SM) const
This class handles loading and caching of source files into memory.
StringRef getBufferData(FileID FID, bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
The JSON file list parser is used to communicate input to InstallAPI.
LLVM_READONLY bool isVerticalWhitespace(unsigned char c)
Returns true if this character is vertical ASCII whitespace: '\n', '\r'.
LLVM_READONLY bool isLetter(unsigned char c)
Return true if this character is an ASCII letter: [a-zA-Z].
LLVM_READONLY bool isAlphanumeric(unsigned char c)
Return true if this character is an ASCII letter or digit: [a-zA-Z0-9].
LLVM_READONLY bool isHorizontalWhitespace(unsigned char c)
Returns true if this character is horizontal ASCII whitespace: ' ', '\t', '\f', '\v'.
@ Result
The result type of a method or function.
LLVM_READONLY bool isDigit(unsigned char c)
Return true if this character is an ASCII digit: [0-9].
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...
LLVM_READONLY bool isHexDigit(unsigned char c)
Return true if this character is an ASCII hex digit: [0-9a-fA-F].
const FunctionProtoType * T