15188c4b9SDmitri Gribenko #include "clang/AST/CommentLexer.h"
25188c4b9SDmitri Gribenko #include "llvm/ADT/StringSwitch.h"
35188c4b9SDmitri Gribenko #include "llvm/Support/ErrorHandling.h"
45188c4b9SDmitri Gribenko 
55188c4b9SDmitri Gribenko namespace clang {
65188c4b9SDmitri Gribenko namespace comments {
75188c4b9SDmitri Gribenko 
85188c4b9SDmitri Gribenko void Token::dump(const Lexer &L, const SourceManager &SM) const {
95188c4b9SDmitri Gribenko   llvm::errs() << "comments::Token Kind=" << Kind << " ";
105188c4b9SDmitri Gribenko   Loc.dump(SM);
115188c4b9SDmitri Gribenko   llvm::errs() << " " << Length << " \"" << L.getSpelling(*this, SM) << "\"\n";
125188c4b9SDmitri Gribenko }
135188c4b9SDmitri Gribenko 
145188c4b9SDmitri Gribenko bool Lexer::isVerbatimBlockCommand(StringRef BeginName,
155188c4b9SDmitri Gribenko                                   StringRef &EndName) const {
165188c4b9SDmitri Gribenko   const char *Result = llvm::StringSwitch<const char *>(BeginName)
175188c4b9SDmitri Gribenko     .Case("code", "endcode")
185188c4b9SDmitri Gribenko     .Case("verbatim", "endverbatim")
195188c4b9SDmitri Gribenko     .Case("htmlonly", "endhtmlonly")
205188c4b9SDmitri Gribenko     .Case("latexonly", "endlatexonly")
215188c4b9SDmitri Gribenko     .Case("xmlonly", "endxmlonly")
225188c4b9SDmitri Gribenko     .Case("manonly", "endmanonly")
235188c4b9SDmitri Gribenko     .Case("rtfonly", "endrtfonly")
245188c4b9SDmitri Gribenko 
255188c4b9SDmitri Gribenko     .Case("dot", "enddot")
265188c4b9SDmitri Gribenko     .Case("msc", "endmsc")
275188c4b9SDmitri Gribenko 
285188c4b9SDmitri Gribenko     .Case("f$", "f$") // Inline LaTeX formula
295188c4b9SDmitri Gribenko     .Case("f[", "f]") // Displayed LaTeX formula
305188c4b9SDmitri Gribenko     .Case("f{", "f}") // LaTeX environment
315188c4b9SDmitri Gribenko 
325188c4b9SDmitri Gribenko     .Default(NULL);
335188c4b9SDmitri Gribenko 
345188c4b9SDmitri Gribenko   if (Result) {
355188c4b9SDmitri Gribenko     EndName = Result;
365188c4b9SDmitri Gribenko     return true;
375188c4b9SDmitri Gribenko   }
385188c4b9SDmitri Gribenko 
395188c4b9SDmitri Gribenko   for (VerbatimBlockCommandVector::const_iterator
405188c4b9SDmitri Gribenko            I = VerbatimBlockCommands.begin(),
415188c4b9SDmitri Gribenko            E = VerbatimBlockCommands.end();
425188c4b9SDmitri Gribenko        I != E; ++I)
435188c4b9SDmitri Gribenko     if (I->BeginName == BeginName) {
445188c4b9SDmitri Gribenko       EndName = I->EndName;
455188c4b9SDmitri Gribenko       return true;
465188c4b9SDmitri Gribenko     }
475188c4b9SDmitri Gribenko 
485188c4b9SDmitri Gribenko   return false;
495188c4b9SDmitri Gribenko }
505188c4b9SDmitri Gribenko 
515188c4b9SDmitri Gribenko bool Lexer::isVerbatimLineCommand(StringRef Name) const {
525188c4b9SDmitri Gribenko   bool Result = llvm::StringSwitch<bool>(Name)
535188c4b9SDmitri Gribenko   .Case("fn", true)
545188c4b9SDmitri Gribenko   .Case("var", true)
555188c4b9SDmitri Gribenko   .Case("property", true)
565188c4b9SDmitri Gribenko   .Case("typedef", true)
575188c4b9SDmitri Gribenko 
585188c4b9SDmitri Gribenko   .Case("overload", true)
595188c4b9SDmitri Gribenko 
605188c4b9SDmitri Gribenko   .Case("defgroup", true)
615188c4b9SDmitri Gribenko   .Case("ingroup", true)
625188c4b9SDmitri Gribenko   .Case("addtogroup", true)
635188c4b9SDmitri Gribenko   .Case("weakgroup", true)
645188c4b9SDmitri Gribenko   .Case("name", true)
655188c4b9SDmitri Gribenko 
665188c4b9SDmitri Gribenko   .Case("section", true)
675188c4b9SDmitri Gribenko   .Case("subsection", true)
685188c4b9SDmitri Gribenko   .Case("subsubsection", true)
695188c4b9SDmitri Gribenko   .Case("paragraph", true)
705188c4b9SDmitri Gribenko 
715188c4b9SDmitri Gribenko   .Case("mainpage", true)
725188c4b9SDmitri Gribenko   .Case("subpage", true)
735188c4b9SDmitri Gribenko   .Case("ref", true)
745188c4b9SDmitri Gribenko 
755188c4b9SDmitri Gribenko   .Default(false);
765188c4b9SDmitri Gribenko 
775188c4b9SDmitri Gribenko   if (Result)
785188c4b9SDmitri Gribenko     return true;
795188c4b9SDmitri Gribenko 
805188c4b9SDmitri Gribenko   for (VerbatimLineCommandVector::const_iterator
815188c4b9SDmitri Gribenko            I = VerbatimLineCommands.begin(),
825188c4b9SDmitri Gribenko            E = VerbatimLineCommands.end();
835188c4b9SDmitri Gribenko        I != E; ++I)
845188c4b9SDmitri Gribenko     if (I->Name == Name)
855188c4b9SDmitri Gribenko       return true;
865188c4b9SDmitri Gribenko 
875188c4b9SDmitri Gribenko   return false;
885188c4b9SDmitri Gribenko }
895188c4b9SDmitri Gribenko 
905188c4b9SDmitri Gribenko void Lexer::skipLineStartingDecorations() {
915188c4b9SDmitri Gribenko   // This function should be called only for C comments
925188c4b9SDmitri Gribenko   assert(CommentState == LCS_InsideCComment);
935188c4b9SDmitri Gribenko 
945188c4b9SDmitri Gribenko   if (BufferPtr == CommentEnd)
955188c4b9SDmitri Gribenko     return;
965188c4b9SDmitri Gribenko 
975188c4b9SDmitri Gribenko   switch (*BufferPtr) {
985188c4b9SDmitri Gribenko   case ' ':
995188c4b9SDmitri Gribenko   case '\t':
1005188c4b9SDmitri Gribenko   case '\f':
1015188c4b9SDmitri Gribenko   case '\v': {
1025188c4b9SDmitri Gribenko     const char *NewBufferPtr = BufferPtr;
1035188c4b9SDmitri Gribenko     NewBufferPtr++;
1045188c4b9SDmitri Gribenko     if (NewBufferPtr == CommentEnd)
1055188c4b9SDmitri Gribenko       return;
1065188c4b9SDmitri Gribenko 
1075188c4b9SDmitri Gribenko     char C = *NewBufferPtr;
1085188c4b9SDmitri Gribenko     while (C == ' ' || C == '\t' || C == '\f' || C == '\v') {
1095188c4b9SDmitri Gribenko       NewBufferPtr++;
1105188c4b9SDmitri Gribenko       if (NewBufferPtr == CommentEnd)
1115188c4b9SDmitri Gribenko         return;
1125188c4b9SDmitri Gribenko       C = *NewBufferPtr;
1135188c4b9SDmitri Gribenko     }
1145188c4b9SDmitri Gribenko     if (C == '*')
1155188c4b9SDmitri Gribenko       BufferPtr = NewBufferPtr + 1;
1165188c4b9SDmitri Gribenko     break;
1175188c4b9SDmitri Gribenko   }
1185188c4b9SDmitri Gribenko   case '*':
1195188c4b9SDmitri Gribenko     BufferPtr++;
1205188c4b9SDmitri Gribenko     break;
1215188c4b9SDmitri Gribenko   }
1225188c4b9SDmitri Gribenko }
1235188c4b9SDmitri Gribenko 
1245188c4b9SDmitri Gribenko namespace {
1255188c4b9SDmitri Gribenko const char *findNewline(const char *BufferPtr, const char *BufferEnd) {
1265188c4b9SDmitri Gribenko   for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
1275188c4b9SDmitri Gribenko     const char C = *BufferPtr;
1285188c4b9SDmitri Gribenko     if (C == '\n' || C == '\r')
1295188c4b9SDmitri Gribenko       return BufferPtr;
1305188c4b9SDmitri Gribenko   }
1315188c4b9SDmitri Gribenko   return BufferEnd;
1325188c4b9SDmitri Gribenko }
1335188c4b9SDmitri Gribenko 
1345188c4b9SDmitri Gribenko const char *skipNewline(const char *BufferPtr, const char *BufferEnd) {
1355188c4b9SDmitri Gribenko   if (BufferPtr == BufferEnd)
1365188c4b9SDmitri Gribenko     return BufferPtr;
1375188c4b9SDmitri Gribenko 
1385188c4b9SDmitri Gribenko   if (*BufferPtr == '\n')
1395188c4b9SDmitri Gribenko     BufferPtr++;
1405188c4b9SDmitri Gribenko   else {
1415188c4b9SDmitri Gribenko     assert(*BufferPtr == '\r');
1425188c4b9SDmitri Gribenko     BufferPtr++;
1435188c4b9SDmitri Gribenko     if (BufferPtr != BufferEnd && *BufferPtr == '\n')
1445188c4b9SDmitri Gribenko       BufferPtr++;
1455188c4b9SDmitri Gribenko   }
1465188c4b9SDmitri Gribenko   return BufferPtr;
1475188c4b9SDmitri Gribenko }
1485188c4b9SDmitri Gribenko 
1495188c4b9SDmitri Gribenko bool isHTMLIdentifierCharacter(char C) {
1505188c4b9SDmitri Gribenko   return (C >= 'a' && C <= 'z') ||
1515188c4b9SDmitri Gribenko          (C >= 'A' && C <= 'Z') ||
1525188c4b9SDmitri Gribenko          (C >= '0' && C <= '9');
1535188c4b9SDmitri Gribenko }
1545188c4b9SDmitri Gribenko 
1555188c4b9SDmitri Gribenko const char *skipHTMLIdentifier(const char *BufferPtr, const char *BufferEnd) {
1565188c4b9SDmitri Gribenko   for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
1575188c4b9SDmitri Gribenko     if (!isHTMLIdentifierCharacter(*BufferPtr))
1585188c4b9SDmitri Gribenko       return BufferPtr;
1595188c4b9SDmitri Gribenko   }
1605188c4b9SDmitri Gribenko   return BufferEnd;
1615188c4b9SDmitri Gribenko }
1625188c4b9SDmitri Gribenko 
1635188c4b9SDmitri Gribenko /// Skip HTML string quoted in single or double quotes.  Escaping quotes inside
1645188c4b9SDmitri Gribenko /// string allowed.
1655188c4b9SDmitri Gribenko ///
1665188c4b9SDmitri Gribenko /// Returns pointer to closing quote.
1675188c4b9SDmitri Gribenko const char *skipHTMLQuotedString(const char *BufferPtr, const char *BufferEnd)
1685188c4b9SDmitri Gribenko {
1695188c4b9SDmitri Gribenko   const char Quote = *BufferPtr;
1705188c4b9SDmitri Gribenko   assert(Quote == '\"' || Quote == '\'');
1715188c4b9SDmitri Gribenko 
1725188c4b9SDmitri Gribenko   BufferPtr++;
1735188c4b9SDmitri Gribenko   for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
1745188c4b9SDmitri Gribenko     const char C = *BufferPtr;
1755188c4b9SDmitri Gribenko     if (C == Quote && BufferPtr[-1] != '\\')
1765188c4b9SDmitri Gribenko       return BufferPtr;
1775188c4b9SDmitri Gribenko   }
1785188c4b9SDmitri Gribenko   return BufferEnd;
1795188c4b9SDmitri Gribenko }
1805188c4b9SDmitri Gribenko 
1815188c4b9SDmitri Gribenko bool isHorizontalWhitespace(char C) {
1825188c4b9SDmitri Gribenko   return C == ' ' || C == '\t' || C == '\f' || C == '\v';
1835188c4b9SDmitri Gribenko }
1845188c4b9SDmitri Gribenko 
1855188c4b9SDmitri Gribenko bool isWhitespace(char C) {
1865188c4b9SDmitri Gribenko   return C == ' ' || C == '\n' || C == '\r' ||
1875188c4b9SDmitri Gribenko          C == '\t' || C == '\f' || C == '\v';
1885188c4b9SDmitri Gribenko }
1895188c4b9SDmitri Gribenko 
1905188c4b9SDmitri Gribenko const char *skipWhitespace(const char *BufferPtr, const char *BufferEnd) {
1915188c4b9SDmitri Gribenko   for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
1925188c4b9SDmitri Gribenko     if (!isWhitespace(*BufferPtr))
1935188c4b9SDmitri Gribenko       return BufferPtr;
1945188c4b9SDmitri Gribenko   }
1955188c4b9SDmitri Gribenko   return BufferEnd;
1965188c4b9SDmitri Gribenko }
1975188c4b9SDmitri Gribenko 
1985188c4b9SDmitri Gribenko bool isCommandNameCharacter(char C) {
1995188c4b9SDmitri Gribenko   return (C >= 'a' && C <= 'z') ||
2005188c4b9SDmitri Gribenko          (C >= 'A' && C <= 'Z') ||
2015188c4b9SDmitri Gribenko          (C >= '0' && C <= '9');
2025188c4b9SDmitri Gribenko }
2035188c4b9SDmitri Gribenko 
2045188c4b9SDmitri Gribenko const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) {
2055188c4b9SDmitri Gribenko   for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
2065188c4b9SDmitri Gribenko     if (!isCommandNameCharacter(*BufferPtr))
2075188c4b9SDmitri Gribenko       return BufferPtr;
2085188c4b9SDmitri Gribenko   }
2095188c4b9SDmitri Gribenko   return BufferEnd;
2105188c4b9SDmitri Gribenko }
2115188c4b9SDmitri Gribenko 
2125188c4b9SDmitri Gribenko /// Return the one past end pointer for BCPL comments.
2135188c4b9SDmitri Gribenko /// Handles newlines escaped with backslash or trigraph for backslahs.
2145188c4b9SDmitri Gribenko const char *findBCPLCommentEnd(const char *BufferPtr, const char *BufferEnd) {
2155188c4b9SDmitri Gribenko   const char *CurPtr = BufferPtr;
2165188c4b9SDmitri Gribenko   while (CurPtr != BufferEnd) {
2175188c4b9SDmitri Gribenko     char C = *CurPtr;
2185188c4b9SDmitri Gribenko     while (C != '\n' && C != '\r') {
2195188c4b9SDmitri Gribenko       CurPtr++;
2205188c4b9SDmitri Gribenko       if (CurPtr == BufferEnd)
2215188c4b9SDmitri Gribenko         return BufferEnd;
2225188c4b9SDmitri Gribenko       C = *CurPtr;
2235188c4b9SDmitri Gribenko     }
2245188c4b9SDmitri Gribenko     // We found a newline, check if it is escaped.
2255188c4b9SDmitri Gribenko     const char *EscapePtr = CurPtr - 1;
2265188c4b9SDmitri Gribenko     while(isHorizontalWhitespace(*EscapePtr))
2275188c4b9SDmitri Gribenko       EscapePtr--;
2285188c4b9SDmitri Gribenko 
2295188c4b9SDmitri Gribenko     if (*EscapePtr == '\\' ||
2305188c4b9SDmitri Gribenko         (EscapePtr - 2 >= BufferPtr && EscapePtr[0] == '/' &&
2315188c4b9SDmitri Gribenko          EscapePtr[-1] == '?' && EscapePtr[-2] == '?')) {
2325188c4b9SDmitri Gribenko       // We found an escaped newline.
2335188c4b9SDmitri Gribenko       CurPtr = skipNewline(CurPtr, BufferEnd);
2345188c4b9SDmitri Gribenko     } else
2355188c4b9SDmitri Gribenko       return CurPtr; // Not an escaped newline.
2365188c4b9SDmitri Gribenko   }
2375188c4b9SDmitri Gribenko   return BufferEnd;
2385188c4b9SDmitri Gribenko }
2395188c4b9SDmitri Gribenko 
2405188c4b9SDmitri Gribenko /// Return the one past end pointer for C comments.
2415188c4b9SDmitri Gribenko /// Very dumb, does not handle escaped newlines or trigraphs.
2425188c4b9SDmitri Gribenko const char *findCCommentEnd(const char *BufferPtr, const char *BufferEnd) {
2435188c4b9SDmitri Gribenko   for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
2445188c4b9SDmitri Gribenko     if (*BufferPtr == '*') {
2455188c4b9SDmitri Gribenko       assert(BufferPtr + 1 != BufferEnd);
2465188c4b9SDmitri Gribenko       if (*(BufferPtr + 1) == '/')
2475188c4b9SDmitri Gribenko         return BufferPtr;
2485188c4b9SDmitri Gribenko     }
2495188c4b9SDmitri Gribenko   }
2505188c4b9SDmitri Gribenko   llvm_unreachable("buffer end hit before '*/' was seen");
2515188c4b9SDmitri Gribenko }
2525188c4b9SDmitri Gribenko } // unnamed namespace
2535188c4b9SDmitri Gribenko 
2545188c4b9SDmitri Gribenko void Lexer::lexCommentText(Token &T) {
2555188c4b9SDmitri Gribenko   assert(CommentState == LCS_InsideBCPLComment ||
2565188c4b9SDmitri Gribenko          CommentState == LCS_InsideCComment);
2575188c4b9SDmitri Gribenko 
2585188c4b9SDmitri Gribenko   switch (State) {
2595188c4b9SDmitri Gribenko   case LS_Normal:
2605188c4b9SDmitri Gribenko     break;
2615188c4b9SDmitri Gribenko   case LS_VerbatimBlockFirstLine:
2625188c4b9SDmitri Gribenko     lexVerbatimBlockFirstLine(T);
2635188c4b9SDmitri Gribenko     return;
2645188c4b9SDmitri Gribenko   case LS_VerbatimBlockBody:
2655188c4b9SDmitri Gribenko     lexVerbatimBlockBody(T);
2665188c4b9SDmitri Gribenko     return;
2671669f702SDmitri Gribenko   case LS_VerbatimLineText:
2681669f702SDmitri Gribenko     lexVerbatimLineText(T);
2691669f702SDmitri Gribenko     return;
2705188c4b9SDmitri Gribenko   case LS_HTMLOpenTag:
2715188c4b9SDmitri Gribenko     lexHTMLOpenTag(T);
2725188c4b9SDmitri Gribenko     return;
2735188c4b9SDmitri Gribenko   }
2745188c4b9SDmitri Gribenko 
2755188c4b9SDmitri Gribenko   assert(State == LS_Normal);
2765188c4b9SDmitri Gribenko 
2775188c4b9SDmitri Gribenko   const char *TokenPtr = BufferPtr;
2785188c4b9SDmitri Gribenko   assert(TokenPtr < CommentEnd);
2795188c4b9SDmitri Gribenko   while (TokenPtr != CommentEnd) {
2805188c4b9SDmitri Gribenko     switch(*TokenPtr) {
2815188c4b9SDmitri Gribenko       case '\\':
2825188c4b9SDmitri Gribenko       case '@': {
2835188c4b9SDmitri Gribenko         TokenPtr++;
2845188c4b9SDmitri Gribenko         if (TokenPtr == CommentEnd) {
28560ddd8a1SDmitri Gribenko           StringRef Text(BufferPtr, TokenPtr - BufferPtr);
2865188c4b9SDmitri Gribenko           formTokenWithChars(T, TokenPtr, tok::text);
28760ddd8a1SDmitri Gribenko           T.setText(Text);
2885188c4b9SDmitri Gribenko           return;
2895188c4b9SDmitri Gribenko         }
2905188c4b9SDmitri Gribenko         char C = *TokenPtr;
2915188c4b9SDmitri Gribenko         switch (C) {
2925188c4b9SDmitri Gribenko         default:
2935188c4b9SDmitri Gribenko           break;
2945188c4b9SDmitri Gribenko 
2955188c4b9SDmitri Gribenko         case '\\': case '@': case '&': case '$':
2965188c4b9SDmitri Gribenko         case '#':  case '<': case '>': case '%':
2975188c4b9SDmitri Gribenko         case '\"': case '.': case ':':
2985188c4b9SDmitri Gribenko           // This is one of \\ \@ \& \$ etc escape sequences.
2995188c4b9SDmitri Gribenko           TokenPtr++;
3005188c4b9SDmitri Gribenko           if (C == ':' && TokenPtr != CommentEnd && *TokenPtr == ':') {
3015188c4b9SDmitri Gribenko             // This is the \:: escape sequence.
3025188c4b9SDmitri Gribenko             TokenPtr++;
3035188c4b9SDmitri Gribenko           }
30460ddd8a1SDmitri Gribenko           StringRef UnescapedText(BufferPtr + 1, TokenPtr - (BufferPtr + 1));
3055188c4b9SDmitri Gribenko           formTokenWithChars(T, TokenPtr, tok::text);
30660ddd8a1SDmitri Gribenko           T.setText(UnescapedText);
3075188c4b9SDmitri Gribenko           return;
3085188c4b9SDmitri Gribenko         }
3095188c4b9SDmitri Gribenko 
3105188c4b9SDmitri Gribenko         // Don't make zero-length commands.
3115188c4b9SDmitri Gribenko         if (!isCommandNameCharacter(*TokenPtr)) {
31260ddd8a1SDmitri Gribenko           StringRef Text(BufferPtr, TokenPtr - BufferPtr);
3135188c4b9SDmitri Gribenko           formTokenWithChars(T, TokenPtr, tok::text);
31460ddd8a1SDmitri Gribenko           T.setText(Text);
3155188c4b9SDmitri Gribenko           return;
3165188c4b9SDmitri Gribenko         }
3175188c4b9SDmitri Gribenko 
3185188c4b9SDmitri Gribenko         TokenPtr = skipCommandName(TokenPtr, CommentEnd);
3195188c4b9SDmitri Gribenko         unsigned Length = TokenPtr - (BufferPtr + 1);
3205188c4b9SDmitri Gribenko 
3215188c4b9SDmitri Gribenko         // Hardcoded support for lexing LaTeX formula commands
3225188c4b9SDmitri Gribenko         // \f$ \f[ \f] \f{ \f} as a single command.
3235188c4b9SDmitri Gribenko         if (Length == 1 && TokenPtr[-1] == 'f' && TokenPtr != CommentEnd) {
3245188c4b9SDmitri Gribenko           C = *TokenPtr;
3255188c4b9SDmitri Gribenko           if (C == '$' || C == '[' || C == ']' || C == '{' || C == '}') {
3265188c4b9SDmitri Gribenko             TokenPtr++;
3275188c4b9SDmitri Gribenko             Length++;
3285188c4b9SDmitri Gribenko           }
3295188c4b9SDmitri Gribenko         }
3305188c4b9SDmitri Gribenko 
3315188c4b9SDmitri Gribenko         const StringRef CommandName(BufferPtr + 1, Length);
3325188c4b9SDmitri Gribenko         StringRef EndName;
3335188c4b9SDmitri Gribenko 
3345188c4b9SDmitri Gribenko         if (isVerbatimBlockCommand(CommandName, EndName)) {
3355188c4b9SDmitri Gribenko           setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, EndName);
3365188c4b9SDmitri Gribenko           return;
3375188c4b9SDmitri Gribenko         }
3385188c4b9SDmitri Gribenko         if (isVerbatimLineCommand(CommandName)) {
3391669f702SDmitri Gribenko           setupAndLexVerbatimLine(T, TokenPtr);
3405188c4b9SDmitri Gribenko           return;
3415188c4b9SDmitri Gribenko         }
3425188c4b9SDmitri Gribenko         formTokenWithChars(T, TokenPtr, tok::command);
3435188c4b9SDmitri Gribenko         T.setCommandName(CommandName);
3445188c4b9SDmitri Gribenko         return;
3455188c4b9SDmitri Gribenko       }
3465188c4b9SDmitri Gribenko 
3475188c4b9SDmitri Gribenko       case '<': {
3485188c4b9SDmitri Gribenko         TokenPtr++;
3495188c4b9SDmitri Gribenko         if (TokenPtr == CommentEnd) {
35060ddd8a1SDmitri Gribenko           StringRef Text(BufferPtr, TokenPtr - BufferPtr);
3515188c4b9SDmitri Gribenko           formTokenWithChars(T, TokenPtr, tok::text);
35260ddd8a1SDmitri Gribenko           T.setText(Text);
3535188c4b9SDmitri Gribenko           return;
3545188c4b9SDmitri Gribenko         }
3555188c4b9SDmitri Gribenko         const char C = *TokenPtr;
3565188c4b9SDmitri Gribenko         if (isHTMLIdentifierCharacter(C))
3575188c4b9SDmitri Gribenko           setupAndLexHTMLOpenTag(T);
3585188c4b9SDmitri Gribenko         else if (C == '/')
3595188c4b9SDmitri Gribenko           lexHTMLCloseTag(T);
360*632d58afSDmitri Gribenko         else {
361*632d58afSDmitri Gribenko           StringRef Text(BufferPtr, TokenPtr - BufferPtr);
362*632d58afSDmitri Gribenko           formTokenWithChars(T, TokenPtr, tok::text);
363*632d58afSDmitri Gribenko           T.setText(Text);
364*632d58afSDmitri Gribenko         }
3655188c4b9SDmitri Gribenko         return;
3665188c4b9SDmitri Gribenko       }
3675188c4b9SDmitri Gribenko 
3685188c4b9SDmitri Gribenko       case '\n':
3695188c4b9SDmitri Gribenko       case '\r':
3705188c4b9SDmitri Gribenko         TokenPtr = skipNewline(TokenPtr, CommentEnd);
3715188c4b9SDmitri Gribenko         formTokenWithChars(T, TokenPtr, tok::newline);
3725188c4b9SDmitri Gribenko 
3735188c4b9SDmitri Gribenko         if (CommentState == LCS_InsideCComment)
3745188c4b9SDmitri Gribenko           skipLineStartingDecorations();
3755188c4b9SDmitri Gribenko         return;
3765188c4b9SDmitri Gribenko 
3775188c4b9SDmitri Gribenko       default: {
3785188c4b9SDmitri Gribenko         while (true) {
3795188c4b9SDmitri Gribenko           TokenPtr++;
3805188c4b9SDmitri Gribenko           if (TokenPtr == CommentEnd)
3815188c4b9SDmitri Gribenko             break;
3825188c4b9SDmitri Gribenko           char C = *TokenPtr;
3835188c4b9SDmitri Gribenko           if(C == '\n' || C == '\r' ||
3845188c4b9SDmitri Gribenko              C == '\\' || C == '@' || C == '<')
3855188c4b9SDmitri Gribenko             break;
3865188c4b9SDmitri Gribenko         }
38760ddd8a1SDmitri Gribenko         StringRef Text(BufferPtr, TokenPtr - BufferPtr);
3885188c4b9SDmitri Gribenko         formTokenWithChars(T, TokenPtr, tok::text);
38960ddd8a1SDmitri Gribenko         T.setText(Text);
3905188c4b9SDmitri Gribenko         return;
3915188c4b9SDmitri Gribenko       }
3925188c4b9SDmitri Gribenko     }
3935188c4b9SDmitri Gribenko   }
3945188c4b9SDmitri Gribenko }
3955188c4b9SDmitri Gribenko 
3965188c4b9SDmitri Gribenko void Lexer::setupAndLexVerbatimBlock(Token &T,
3975188c4b9SDmitri Gribenko                                      const char *TextBegin,
3985188c4b9SDmitri Gribenko                                      char Marker, StringRef EndName) {
3995188c4b9SDmitri Gribenko   VerbatimBlockEndCommandName.clear();
4005188c4b9SDmitri Gribenko   VerbatimBlockEndCommandName.append(Marker == '\\' ? "\\" : "@");
4015188c4b9SDmitri Gribenko   VerbatimBlockEndCommandName.append(EndName);
4025188c4b9SDmitri Gribenko 
40360ddd8a1SDmitri Gribenko   StringRef Name(BufferPtr + 1, TextBegin - (BufferPtr + 1));
4045188c4b9SDmitri Gribenko   formTokenWithChars(T, TextBegin, tok::verbatim_block_begin);
40560ddd8a1SDmitri Gribenko   T.setVerbatimBlockName(Name);
4065188c4b9SDmitri Gribenko 
4075188c4b9SDmitri Gribenko   State = LS_VerbatimBlockFirstLine;
4085188c4b9SDmitri Gribenko }
4095188c4b9SDmitri Gribenko 
4105188c4b9SDmitri Gribenko void Lexer::lexVerbatimBlockFirstLine(Token &T) {
4115188c4b9SDmitri Gribenko   assert(BufferPtr < CommentEnd);
4125188c4b9SDmitri Gribenko 
4135188c4b9SDmitri Gribenko   // FIXME: It would be better to scan the text once, finding either the block
4145188c4b9SDmitri Gribenko   // end command or newline.
4155188c4b9SDmitri Gribenko   //
4165188c4b9SDmitri Gribenko   // Extract current line.
4175188c4b9SDmitri Gribenko   const char *Newline = findNewline(BufferPtr, CommentEnd);
4185188c4b9SDmitri Gribenko   StringRef Line(BufferPtr, Newline - BufferPtr);
4195188c4b9SDmitri Gribenko 
4205188c4b9SDmitri Gribenko   // Look for end command in current line.
4215188c4b9SDmitri Gribenko   size_t Pos = Line.find(VerbatimBlockEndCommandName);
4225188c4b9SDmitri Gribenko   const char *NextLine;
4235188c4b9SDmitri Gribenko   if (Pos == StringRef::npos) {
4245188c4b9SDmitri Gribenko     // Current line is completely verbatim.
4255188c4b9SDmitri Gribenko     NextLine = skipNewline(Newline, CommentEnd);
4265188c4b9SDmitri Gribenko   } else if (Pos == 0) {
4275188c4b9SDmitri Gribenko     // Current line contains just an end command.
4285188c4b9SDmitri Gribenko     const char *End = BufferPtr + VerbatimBlockEndCommandName.size();
42960ddd8a1SDmitri Gribenko     StringRef Name(BufferPtr + 1, End - (BufferPtr + 1));
4305188c4b9SDmitri Gribenko     formTokenWithChars(T, End, tok::verbatim_block_end);
43160ddd8a1SDmitri Gribenko     T.setVerbatimBlockName(Name);
4325188c4b9SDmitri Gribenko     State = LS_Normal;
4335188c4b9SDmitri Gribenko     return;
4345188c4b9SDmitri Gribenko   } else {
4355188c4b9SDmitri Gribenko     // There is some text, followed by end command.  Extract text first.
4365188c4b9SDmitri Gribenko     NextLine = BufferPtr + Pos;
4375188c4b9SDmitri Gribenko   }
4385188c4b9SDmitri Gribenko 
43960ddd8a1SDmitri Gribenko   StringRef Text(BufferPtr, NextLine - BufferPtr);
4405188c4b9SDmitri Gribenko   formTokenWithChars(T, NextLine, tok::verbatim_block_line);
44160ddd8a1SDmitri Gribenko   T.setVerbatimBlockText(Text);
4425188c4b9SDmitri Gribenko 
4435188c4b9SDmitri Gribenko   State = LS_VerbatimBlockBody;
4445188c4b9SDmitri Gribenko }
4455188c4b9SDmitri Gribenko 
4465188c4b9SDmitri Gribenko void Lexer::lexVerbatimBlockBody(Token &T) {
4475188c4b9SDmitri Gribenko   assert(State == LS_VerbatimBlockBody);
4485188c4b9SDmitri Gribenko 
4495188c4b9SDmitri Gribenko   if (CommentState == LCS_InsideCComment)
4505188c4b9SDmitri Gribenko     skipLineStartingDecorations();
4515188c4b9SDmitri Gribenko 
4525188c4b9SDmitri Gribenko   lexVerbatimBlockFirstLine(T);
4535188c4b9SDmitri Gribenko }
4545188c4b9SDmitri Gribenko 
4551669f702SDmitri Gribenko void Lexer::setupAndLexVerbatimLine(Token &T, const char *TextBegin) {
4561669f702SDmitri Gribenko   const StringRef Name(BufferPtr + 1, TextBegin - BufferPtr - 1);
4571669f702SDmitri Gribenko   formTokenWithChars(T, TextBegin, tok::verbatim_line_name);
4581669f702SDmitri Gribenko   T.setVerbatimLineName(Name);
4591669f702SDmitri Gribenko 
4601669f702SDmitri Gribenko   State = LS_VerbatimLineText;
4611669f702SDmitri Gribenko }
4621669f702SDmitri Gribenko 
4631669f702SDmitri Gribenko void Lexer::lexVerbatimLineText(Token &T) {
4641669f702SDmitri Gribenko   assert(State == LS_VerbatimLineText);
4651669f702SDmitri Gribenko 
4665188c4b9SDmitri Gribenko   // Extract current line.
4675188c4b9SDmitri Gribenko   const char *Newline = findNewline(BufferPtr, CommentEnd);
4681669f702SDmitri Gribenko   const StringRef Text(BufferPtr, Newline - BufferPtr);
4691669f702SDmitri Gribenko   formTokenWithChars(T, Newline, tok::verbatim_line_text);
4705188c4b9SDmitri Gribenko   T.setVerbatimLineText(Text);
4711669f702SDmitri Gribenko 
4721669f702SDmitri Gribenko   State = LS_Normal;
4735188c4b9SDmitri Gribenko }
4745188c4b9SDmitri Gribenko 
4755188c4b9SDmitri Gribenko void Lexer::setupAndLexHTMLOpenTag(Token &T) {
4765188c4b9SDmitri Gribenko   assert(BufferPtr[0] == '<' && isHTMLIdentifierCharacter(BufferPtr[1]));
4775188c4b9SDmitri Gribenko   const char *TagNameEnd = skipHTMLIdentifier(BufferPtr + 2, CommentEnd);
4785188c4b9SDmitri Gribenko 
47960ddd8a1SDmitri Gribenko   StringRef Name(BufferPtr + 1, TagNameEnd - (BufferPtr + 1));
4805188c4b9SDmitri Gribenko   formTokenWithChars(T, TagNameEnd, tok::html_tag_open);
48160ddd8a1SDmitri Gribenko   T.setHTMLTagOpenName(Name);
4825188c4b9SDmitri Gribenko 
4835188c4b9SDmitri Gribenko   BufferPtr = skipWhitespace(BufferPtr, CommentEnd);
4845188c4b9SDmitri Gribenko 
4855188c4b9SDmitri Gribenko   if (BufferPtr != CommentEnd && *BufferPtr == '>') {
4865188c4b9SDmitri Gribenko     BufferPtr++;
4875188c4b9SDmitri Gribenko     return;
4885188c4b9SDmitri Gribenko   }
4895188c4b9SDmitri Gribenko 
4905188c4b9SDmitri Gribenko   if (BufferPtr != CommentEnd && isHTMLIdentifierCharacter(*BufferPtr))
4915188c4b9SDmitri Gribenko     State = LS_HTMLOpenTag;
4925188c4b9SDmitri Gribenko }
4935188c4b9SDmitri Gribenko 
4945188c4b9SDmitri Gribenko void Lexer::lexHTMLOpenTag(Token &T) {
4955188c4b9SDmitri Gribenko   assert(State == LS_HTMLOpenTag);
4965188c4b9SDmitri Gribenko 
4975188c4b9SDmitri Gribenko   const char *TokenPtr = BufferPtr;
4985188c4b9SDmitri Gribenko   char C = *TokenPtr;
4995188c4b9SDmitri Gribenko   if (isHTMLIdentifierCharacter(C)) {
5005188c4b9SDmitri Gribenko     TokenPtr = skipHTMLIdentifier(TokenPtr, CommentEnd);
50160ddd8a1SDmitri Gribenko     StringRef Ident(BufferPtr, TokenPtr - BufferPtr);
5025188c4b9SDmitri Gribenko     formTokenWithChars(T, TokenPtr, tok::html_ident);
50360ddd8a1SDmitri Gribenko     T.setHTMLIdent(Ident);
5045188c4b9SDmitri Gribenko   } else {
5055188c4b9SDmitri Gribenko     switch (C) {
5065188c4b9SDmitri Gribenko     case '=':
5075188c4b9SDmitri Gribenko       TokenPtr++;
5085188c4b9SDmitri Gribenko       formTokenWithChars(T, TokenPtr, tok::html_equals);
5095188c4b9SDmitri Gribenko       break;
5105188c4b9SDmitri Gribenko     case '\"':
5115188c4b9SDmitri Gribenko     case '\'': {
5125188c4b9SDmitri Gribenko       const char *OpenQuote = TokenPtr;
5135188c4b9SDmitri Gribenko       TokenPtr = skipHTMLQuotedString(TokenPtr, CommentEnd);
5145188c4b9SDmitri Gribenko       const char *ClosingQuote = TokenPtr;
5155188c4b9SDmitri Gribenko       if (TokenPtr != CommentEnd) // Skip closing quote.
5165188c4b9SDmitri Gribenko         TokenPtr++;
5175188c4b9SDmitri Gribenko       formTokenWithChars(T, TokenPtr, tok::html_quoted_string);
5185188c4b9SDmitri Gribenko       T.setHTMLQuotedString(StringRef(OpenQuote + 1,
5195188c4b9SDmitri Gribenko                                       ClosingQuote - (OpenQuote + 1)));
5205188c4b9SDmitri Gribenko       break;
5215188c4b9SDmitri Gribenko     }
5225188c4b9SDmitri Gribenko     case '>':
5235188c4b9SDmitri Gribenko       TokenPtr++;
5245188c4b9SDmitri Gribenko       formTokenWithChars(T, TokenPtr, tok::html_greater);
5255188c4b9SDmitri Gribenko       break;
5265188c4b9SDmitri Gribenko     }
5275188c4b9SDmitri Gribenko   }
5285188c4b9SDmitri Gribenko 
5295188c4b9SDmitri Gribenko   // Now look ahead and return to normal state if we don't see any HTML tokens
5305188c4b9SDmitri Gribenko   // ahead.
5315188c4b9SDmitri Gribenko   BufferPtr = skipWhitespace(BufferPtr, CommentEnd);
5325188c4b9SDmitri Gribenko   if (BufferPtr == CommentEnd) {
5335188c4b9SDmitri Gribenko     State = LS_Normal;
5345188c4b9SDmitri Gribenko     return;
5355188c4b9SDmitri Gribenko   }
5365188c4b9SDmitri Gribenko 
5375188c4b9SDmitri Gribenko   C = *BufferPtr;
5385188c4b9SDmitri Gribenko   if (!isHTMLIdentifierCharacter(C) &&
5395188c4b9SDmitri Gribenko       C != '=' && C != '\"' && C != '\'' && C != '>') {
5405188c4b9SDmitri Gribenko     State = LS_Normal;
5415188c4b9SDmitri Gribenko     return;
5425188c4b9SDmitri Gribenko   }
5435188c4b9SDmitri Gribenko }
5445188c4b9SDmitri Gribenko 
5455188c4b9SDmitri Gribenko void Lexer::lexHTMLCloseTag(Token &T) {
5465188c4b9SDmitri Gribenko   assert(BufferPtr[0] == '<' && BufferPtr[1] == '/');
5475188c4b9SDmitri Gribenko 
5485188c4b9SDmitri Gribenko   const char *TagNameBegin = skipWhitespace(BufferPtr + 2, CommentEnd);
5495188c4b9SDmitri Gribenko   const char *TagNameEnd = skipHTMLIdentifier(TagNameBegin, CommentEnd);
5505188c4b9SDmitri Gribenko 
5515188c4b9SDmitri Gribenko   const char *End = skipWhitespace(TagNameEnd, CommentEnd);
5525188c4b9SDmitri Gribenko   if (End != CommentEnd && *End == '>')
5535188c4b9SDmitri Gribenko     End++;
5545188c4b9SDmitri Gribenko 
5555188c4b9SDmitri Gribenko   formTokenWithChars(T, End, tok::html_tag_close);
5565188c4b9SDmitri Gribenko   T.setHTMLTagCloseName(StringRef(TagNameBegin, TagNameEnd - TagNameBegin));
5575188c4b9SDmitri Gribenko }
5585188c4b9SDmitri Gribenko 
5595188c4b9SDmitri Gribenko Lexer::Lexer(SourceLocation FileLoc, const CommentOptions &CommOpts,
5605188c4b9SDmitri Gribenko              const char *BufferStart, const char *BufferEnd):
5615188c4b9SDmitri Gribenko     BufferStart(BufferStart), BufferEnd(BufferEnd),
5625188c4b9SDmitri Gribenko     FileLoc(FileLoc), CommOpts(CommOpts), BufferPtr(BufferStart),
5635188c4b9SDmitri Gribenko     CommentState(LCS_BeforeComment), State(LS_Normal) {
5645188c4b9SDmitri Gribenko }
5655188c4b9SDmitri Gribenko 
5665188c4b9SDmitri Gribenko void Lexer::lex(Token &T) {
5675188c4b9SDmitri Gribenko again:
5685188c4b9SDmitri Gribenko   switch (CommentState) {
5695188c4b9SDmitri Gribenko   case LCS_BeforeComment:
5705188c4b9SDmitri Gribenko     if (BufferPtr == BufferEnd) {
5715188c4b9SDmitri Gribenko       formTokenWithChars(T, BufferPtr, tok::eof);
5725188c4b9SDmitri Gribenko       return;
5735188c4b9SDmitri Gribenko     }
5745188c4b9SDmitri Gribenko 
5755188c4b9SDmitri Gribenko     assert(*BufferPtr == '/');
5765188c4b9SDmitri Gribenko     BufferPtr++; // Skip first slash.
5775188c4b9SDmitri Gribenko     switch(*BufferPtr) {
5785188c4b9SDmitri Gribenko     case '/': { // BCPL comment.
5795188c4b9SDmitri Gribenko       BufferPtr++; // Skip second slash.
5805188c4b9SDmitri Gribenko 
5815188c4b9SDmitri Gribenko       if (BufferPtr != BufferEnd) {
5825188c4b9SDmitri Gribenko         // Skip Doxygen magic marker, if it is present.
5835188c4b9SDmitri Gribenko         // It might be missing because of a typo //< or /*<, or because we
5845188c4b9SDmitri Gribenko         // merged this non-Doxygen comment into a bunch of Doxygen comments
5855188c4b9SDmitri Gribenko         // around it: /** ... */ /* ... */ /** ... */
5865188c4b9SDmitri Gribenko         const char C = *BufferPtr;
5875188c4b9SDmitri Gribenko         if (C == '/' || C == '!')
5885188c4b9SDmitri Gribenko           BufferPtr++;
5895188c4b9SDmitri Gribenko       }
5905188c4b9SDmitri Gribenko 
5915188c4b9SDmitri Gribenko       // Skip less-than symbol that marks trailing comments.
5925188c4b9SDmitri Gribenko       // Skip it even if the comment is not a Doxygen one, because //< and /*<
5935188c4b9SDmitri Gribenko       // are frequent typos.
5945188c4b9SDmitri Gribenko       if (BufferPtr != BufferEnd && *BufferPtr == '<')
5955188c4b9SDmitri Gribenko         BufferPtr++;
5965188c4b9SDmitri Gribenko 
5975188c4b9SDmitri Gribenko       CommentState = LCS_InsideBCPLComment;
5985188c4b9SDmitri Gribenko       State = LS_Normal;
5995188c4b9SDmitri Gribenko       CommentEnd = findBCPLCommentEnd(BufferPtr, BufferEnd);
6005188c4b9SDmitri Gribenko       goto again;
6015188c4b9SDmitri Gribenko     }
6025188c4b9SDmitri Gribenko     case '*': { // C comment.
6035188c4b9SDmitri Gribenko       BufferPtr++; // Skip star.
6045188c4b9SDmitri Gribenko 
6055188c4b9SDmitri Gribenko       // Skip Doxygen magic marker.
6065188c4b9SDmitri Gribenko       const char C = *BufferPtr;
6075188c4b9SDmitri Gribenko       if ((C == '*' && *(BufferPtr + 1) != '/') || C == '!')
6085188c4b9SDmitri Gribenko         BufferPtr++;
6095188c4b9SDmitri Gribenko 
6105188c4b9SDmitri Gribenko       // Skip less-than symbol that marks trailing comments.
6115188c4b9SDmitri Gribenko       if (BufferPtr != BufferEnd && *BufferPtr == '<')
6125188c4b9SDmitri Gribenko         BufferPtr++;
6135188c4b9SDmitri Gribenko 
6145188c4b9SDmitri Gribenko       CommentState = LCS_InsideCComment;
6155188c4b9SDmitri Gribenko       State = LS_Normal;
6165188c4b9SDmitri Gribenko       CommentEnd = findCCommentEnd(BufferPtr, BufferEnd);
6175188c4b9SDmitri Gribenko       goto again;
6185188c4b9SDmitri Gribenko     }
6195188c4b9SDmitri Gribenko     default:
6205188c4b9SDmitri Gribenko       llvm_unreachable("second character of comment should be '/' or '*'");
6215188c4b9SDmitri Gribenko     }
6225188c4b9SDmitri Gribenko 
6235188c4b9SDmitri Gribenko   case LCS_BetweenComments: {
6245188c4b9SDmitri Gribenko     // Consecutive comments are extracted only if there is only whitespace
6255188c4b9SDmitri Gribenko     // between them.  So we can search for the start of the next comment.
6265188c4b9SDmitri Gribenko     const char *EndWhitespace = BufferPtr;
6275188c4b9SDmitri Gribenko     while(EndWhitespace != BufferEnd && *EndWhitespace != '/')
6285188c4b9SDmitri Gribenko       EndWhitespace++;
6295188c4b9SDmitri Gribenko 
6305188c4b9SDmitri Gribenko     // Turn any whitespace between comments (and there is only whitespace
6315188c4b9SDmitri Gribenko     // between them) into a newline.  We have two newlines between comments
6325188c4b9SDmitri Gribenko     // in total (first one was synthesized after a comment).
6335188c4b9SDmitri Gribenko     formTokenWithChars(T, EndWhitespace, tok::newline);
6345188c4b9SDmitri Gribenko 
6355188c4b9SDmitri Gribenko     CommentState = LCS_BeforeComment;
6365188c4b9SDmitri Gribenko     break;
6375188c4b9SDmitri Gribenko   }
6385188c4b9SDmitri Gribenko 
6395188c4b9SDmitri Gribenko   case LCS_InsideBCPLComment:
6405188c4b9SDmitri Gribenko   case LCS_InsideCComment:
6415188c4b9SDmitri Gribenko     if (BufferPtr != CommentEnd) {
6425188c4b9SDmitri Gribenko       lexCommentText(T);
6435188c4b9SDmitri Gribenko       break;
6445188c4b9SDmitri Gribenko     } else {
6455188c4b9SDmitri Gribenko       // Skip C comment closing sequence.
6465188c4b9SDmitri Gribenko       if (CommentState == LCS_InsideCComment) {
6475188c4b9SDmitri Gribenko         assert(BufferPtr[0] == '*' && BufferPtr[1] == '/');
6485188c4b9SDmitri Gribenko         BufferPtr += 2;
6495188c4b9SDmitri Gribenko         assert(BufferPtr <= BufferEnd);
6505188c4b9SDmitri Gribenko 
6515188c4b9SDmitri Gribenko         // Synthenize newline just after the C comment, regardless if there is
6525188c4b9SDmitri Gribenko         // actually a newline.
6535188c4b9SDmitri Gribenko         formTokenWithChars(T, BufferPtr, tok::newline);
6545188c4b9SDmitri Gribenko 
6555188c4b9SDmitri Gribenko         CommentState = LCS_BetweenComments;
6565188c4b9SDmitri Gribenko         break;
6575188c4b9SDmitri Gribenko       } else {
6585188c4b9SDmitri Gribenko         // Don't synthesized a newline after BCPL comment.
6595188c4b9SDmitri Gribenko         CommentState = LCS_BetweenComments;
6605188c4b9SDmitri Gribenko         goto again;
6615188c4b9SDmitri Gribenko       }
6625188c4b9SDmitri Gribenko     }
6635188c4b9SDmitri Gribenko   }
6645188c4b9SDmitri Gribenko }
6655188c4b9SDmitri Gribenko 
6665188c4b9SDmitri Gribenko StringRef Lexer::getSpelling(const Token &Tok,
6675188c4b9SDmitri Gribenko                              const SourceManager &SourceMgr,
6685188c4b9SDmitri Gribenko                              bool *Invalid) const {
6695188c4b9SDmitri Gribenko   SourceLocation Loc = Tok.getLocation();
6705188c4b9SDmitri Gribenko   std::pair<FileID, unsigned> LocInfo = SourceMgr.getDecomposedLoc(Loc);
6715188c4b9SDmitri Gribenko 
6725188c4b9SDmitri Gribenko   bool InvalidTemp = false;
6735188c4b9SDmitri Gribenko   StringRef File = SourceMgr.getBufferData(LocInfo.first, &InvalidTemp);
6745188c4b9SDmitri Gribenko   if (InvalidTemp) {
6755188c4b9SDmitri Gribenko     *Invalid = true;
6765188c4b9SDmitri Gribenko     return StringRef();
6775188c4b9SDmitri Gribenko   }
6785188c4b9SDmitri Gribenko 
6795188c4b9SDmitri Gribenko   const char *Begin = File.data() + LocInfo.second;
6805188c4b9SDmitri Gribenko   return StringRef(Begin, Tok.getLength());
6815188c4b9SDmitri Gribenko }
6825188c4b9SDmitri Gribenko 
6835188c4b9SDmitri Gribenko void Lexer::addVerbatimBlockCommand(StringRef BeginName, StringRef EndName) {
6845188c4b9SDmitri Gribenko   VerbatimBlockCommand VBC;
6855188c4b9SDmitri Gribenko   VBC.BeginName = BeginName;
6865188c4b9SDmitri Gribenko   VBC.EndName = EndName;
6875188c4b9SDmitri Gribenko   VerbatimBlockCommands.push_back(VBC);
6885188c4b9SDmitri Gribenko }
6895188c4b9SDmitri Gribenko 
6905188c4b9SDmitri Gribenko void Lexer::addVerbatimLineCommand(StringRef Name) {
6915188c4b9SDmitri Gribenko   VerbatimLineCommand VLC;
6925188c4b9SDmitri Gribenko   VLC.Name = Name;
6935188c4b9SDmitri Gribenko   VerbatimLineCommands.push_back(VLC);
6945188c4b9SDmitri Gribenko }
6955188c4b9SDmitri Gribenko 
6965188c4b9SDmitri Gribenko } // end namespace comments
6975188c4b9SDmitri Gribenko } // end namespace clang
6985188c4b9SDmitri Gribenko 
699