27#include "llvm/ADT/ArrayRef.h"
28#include "llvm/ADT/STLExtras.h"
29#include "llvm/ADT/SmallVector.h"
30#include "llvm/ADT/iterator_range.h"
49 ExpandLocStart =
Tok.getLocation();
51 AtStartOfLine =
Tok.isAtStartOfLine();
52 HasLeadingSpace =
Tok.hasLeadingSpace();
53 NextTokGetsSpace =
false;
54 Tokens = &*Macro->tokens_begin();
56 DisableMacroExpansion =
false;
58 NumTokens = Macro->tokens_end()-Macro->tokens_begin();
60 LexingCXXModuleDirective =
false;
63 MacroStartSLocOffset =
SM.getNextLocalOffset();
66 assert(Tokens[0].getLocation().isValid());
67 assert((Tokens[0].getLocation().isFileID() || Tokens[0].
is(tok::comment)) &&
68 "Macro defined in macro?");
69 assert(ExpandLocStart.isValid());
75 MacroDefStart =
SM.getExpansionLoc(Tokens[0].getLocation());
76 MacroDefLength = Macro->getDefinitionLength(
SM);
77 MacroExpansionStart =
SM.createExpansionLoc(MacroDefStart,
85 if (Macro->isFunctionLike() && Macro->getNumParams())
86 ExpandFunctionArguments();
91 Macro->DisableMacro();
97 bool disableMacroExpansion,
bool ownsTokens,
99 assert(!isReinject || disableMacroExpansion);
105 ActualArgs =
nullptr;
107 OwnsTokens = ownsTokens;
108 DisableMacroExpansion = disableMacroExpansion;
109 IsReinject = isReinject;
113 AtStartOfLine =
false;
114 HasLeadingSpace =
false;
115 NextTokGetsSpace =
false;
117 LexingCXXModuleDirective =
false;
127void TokenLexer::destroy() {
137 if (ActualArgs) ActualArgs->
destroy(PP);
141 return LangOpts.C23 || LangOpts.CPlusPlus20;
144bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
148 if (!Macro->isVariadic() || MacroArgNo != Macro->getNumParams()-1)
154 if (!HasPasteOperator && !PP.getLangOpts().MSVCCompat)
162 if (PP.getLangOpts().C99 && !PP.getLangOpts().GNUMode
163 && Macro->getNumParams() < 2)
167 if (ResultToks.empty() || !ResultToks.back().is(tok::comma))
171 if (HasPasteOperator) {
172 PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma)
177 ResultToks.pop_back();
179 if (!ResultToks.empty()) {
184 if (ResultToks.back().is(tok::hashhash))
185 ResultToks.pop_back();
192 NextTokGetsSpace =
false;
196void TokenLexer::stringifyVAOPTContents(
200 const unsigned int NumVAOptTokens = ResultToks.size() - NumToksPriorToVAOpt;
201 Token *
const VAOPTTokens =
202 NumVAOptTokens ? &ResultToks[NumToksPriorToVAOpt] :
nullptr;
204 SmallVector<Token, 64> ConcatenatedVAOPTResultToks;
209 for (
unsigned int CurTokenIdx = 0; CurTokenIdx != NumVAOptTokens;
211 if (VAOPTTokens[CurTokenIdx].
is(tok::hashhash)) {
212 assert(CurTokenIdx != 0 &&
213 "Can not have __VAOPT__ contents begin with a ##");
214 Token &LHS = VAOPTTokens[CurTokenIdx - 1];
215 pasteTokens(LHS, llvm::ArrayRef(VAOPTTokens, NumVAOptTokens),
218 ConcatenatedVAOPTResultToks.back() = LHS;
219 if (CurTokenIdx == NumVAOptTokens)
222 ConcatenatedVAOPTResultToks.push_back(VAOPTTokens[CurTokenIdx]);
225 ConcatenatedVAOPTResultToks.push_back(VCtx.
getEOFTok());
231 const SourceLocation ExpansionLocStartWithinMacro =
233 const SourceLocation ExpansionLocEndWithinMacro =
234 getExpansionLocForMacroDefLoc(VAOPTClosingParenLoc);
238 ExpansionLocStartWithinMacro, ExpansionLocEndWithinMacro);
245 ResultToks.resize(NumToksPriorToVAOpt + 1);
246 ResultToks.back() = StringifiedVAOPT;
251void TokenLexer::ExpandFunctionArguments() {
252 SmallVector<Token, 128> ResultToks;
257 bool MadeChange =
false;
259 std::optional<bool> CalledWithVariadicArguments;
261 VAOptExpansionContext VCtx(PP);
263 for (
unsigned I = 0, E = NumTokens; I != E; ++I) {
264 const Token &CurTok = Tokens[I];
272 NextTokGetsSpace =
true;
276 assert(Tokens[I + 1].
is(tok::l_paren) &&
277 "__VA_OPT__ must be followed by '('");
299 if (Tokens[I].
is(tok::l_paren))
307 if (!CalledWithVariadicArguments) {
308 CalledWithVariadicArguments =
309 ActualArgs->invokedWithVariadicArgument(Macro, PP);
311 if (!*CalledWithVariadicArguments) {
331 stringifyVAOPTContents(ResultToks, VCtx,
332 Tokens[I].getLocation());
341 if (ResultToks.size() && ResultToks.back().is(tok::hashhash)) {
342 ResultToks.pop_back();
343 }
else if ((I + 1 != E) && Tokens[I + 1].
is(tok::hashhash)) {
356 "no token paste before __VA_OPT__");
357 ResultToks.erase(ResultToks.begin() +
363 Tokens[I + 1].is(tok::hashhash)) {
378 if (CurTok.
isOneOf(tok::hash, tok::hashat)) {
379 int ArgNo = Macro->getParameterNum(Tokens[I+1].getIdentifierInfo());
380 assert((ArgNo != -1 || VCtx.
isVAOptToken(Tokens[I + 1])) &&
381 "Token following # is not an argument or __VA_OPT__!");
386 CurTok.
is(tok::hashat));
390 SourceLocation ExpansionLocStart =
391 getExpansionLocForMacroDefLoc(CurTok.
getLocation());
392 SourceLocation ExpansionLocEnd =
393 getExpansionLocForMacroDefLoc(Tokens[I+1].getLocation());
395 bool Charify = CurTok.
is(tok::hashat);
396 const Token *UnexpArg = ActualArgs->getUnexpArgument(ArgNo);
398 UnexpArg, PP, Charify, ExpansionLocStart, ExpansionLocEnd);
403 if (NextTokGetsSpace)
406 ResultToks.push_back(Res);
409 NextTokGetsSpace =
false;
414 bool NonEmptyPasteBefore =
415 !ResultToks.empty() && ResultToks.back().is(tok::hashhash);
416 bool PasteBefore = I != 0 && Tokens[I-1].is(tok::hashhash);
417 bool PasteAfter = I+1 != E && Tokens[I+1].is(tok::hashhash);
418 bool RParenAfter = I+1 != E && Tokens[I+1].is(tok::r_paren);
420 assert((!NonEmptyPasteBefore || PasteBefore || VCtx.
isInVAOpt()) &&
421 "unexpected ## in ResultToks");
426 int ArgNo = II ? Macro->getParameterNum(II) : -1;
429 ResultToks.push_back(CurTok);
431 if (NextTokGetsSpace) {
433 NextTokGetsSpace =
false;
434 }
else if (PasteBefore && !NonEmptyPasteBefore)
448 if (!PasteBefore && ActualArgs->isVarargsElidedUse() &&
449 MaybeRemoveCommaBeforeVaArgs(ResultToks,
457 if (!PasteBefore && !PasteAfter) {
458 const Token *ResultArgToks;
462 const Token *ArgTok = ActualArgs->getUnexpArgument(ArgNo);
463 if (ActualArgs->ArgNeedsPreexpansion(ArgTok, PP))
464 ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, PP)[0];
466 ResultArgToks = ArgTok;
469 if (ResultArgToks->
isNot(tok::eof)) {
470 size_t FirstResult = ResultToks.size();
472 ResultToks.append(ResultArgToks, ResultArgToks+NumToks);
478 if (PP.getLangOpts().MSVCCompat && NumToks == 1 &&
479 ResultToks.back().is(tok::comma))
484 for (Token &
Tok : llvm::drop_begin(ResultToks, FirstResult))
485 if (
Tok.
is(tok::hashhash))
488 if(ExpandLocStart.isValid()) {
490 ResultToks.begin()+FirstResult,
500 NextTokGetsSpace =
false;
505 if (NonEmptyPasteBefore) {
508 assert(VCtx.
isInVAOpt() &&
"should only happen inside a __VA_OPT__");
510 }
else if (RParenAfter)
518 const Token *ArgToks = ActualArgs->getUnexpArgument(ArgNo);
521 bool VaArgsPseudoPaste =
false;
526 if (NonEmptyPasteBefore && ResultToks.size() >= 2 &&
527 ResultToks[ResultToks.size()-2].is(tok::comma) &&
528 (
unsigned)ArgNo == Macro->getNumParams()-1 &&
529 Macro->isVariadic()) {
530 VaArgsPseudoPaste =
true;
533 auto Diag = PP.Diag(ResultToks.pop_back_val().getLocation(),
534 diag::ext_paste_comma)
538 SourceRange(ResultToks.back().getLocation(),
540 " __VA_OPT__(,) __VA_ARGS__");
544 ResultToks.append(ArgToks, ArgToks+NumToks);
548 for (Token &
Tok : llvm::make_range(ResultToks.end() - NumToks,
550 if (
Tok.
is(tok::hashhash))
554 if (ExpandLocStart.isValid()) {
556 ResultToks.end()-NumToks, ResultToks.end());
563 if (!VaArgsPseudoPaste) {
566 ResultToks[ResultToks.size() - NumToks].setFlagValue(
570 NextTokGetsSpace =
false;
585 if (RParenAfter && !NonEmptyPasteBefore)
592 if (NonEmptyPasteBefore) {
593 assert(ResultToks.back().is(tok::hashhash));
600 ResultToks.pop_back();
609 if (ActualArgs->isVarargsElidedUse())
610 MaybeRemoveCommaBeforeVaArgs(ResultToks,
617 assert(!OwnsTokens &&
"This would leak if we already own the token list");
619 NumTokens = ResultToks.size();
622 Tokens = PP.cacheMacroExpandedTokens(
this, ResultToks);
631 const Token &SecondTok) {
632 return FirstTok.
is(tok::identifier) &&
643 if (Macro) Macro->EnableMacro();
653 AtStartOfLine =
true;
660 if (CurTokenIdx == 0)
662 return PP.HandleEndOfTokenLexer(
Tok);
669 bool isFirstToken = CurTokenIdx == 0;
672 Tok = Tokens[CurTokenIdx++];
676 bool TokenIsFromPaste =
false;
680 if (!isAtEnd() && Macro &&
681 (Tokens[CurTokenIdx].
is(tok::hashhash) ||
685 (PP.getLangOpts().MSVCCompat &&
689 if (pasteTokens(
Tok))
692 TokenIsFromPaste =
true;
700 if (ExpandLocStart.isValid() &&
702 SM.isBeforeInSLocAddrSpace(
Tok.getLocation(), MacroStartSLocOffset)) {
704 if (
Tok.is(tok::comment)) {
705 instLoc =
SM.createExpansionLoc(
Tok.getLocation(),
710 instLoc = getExpansionLocForMacroDefLoc(
Tok.getLocation());
713 Tok.setLocation(instLoc);
727 AtStartOfLine =
false;
728 HasLeadingSpace =
false;
731 if (!
Tok.isAnnotation() &&
Tok.getIdentifierInfo() !=
nullptr &&
732 (!PP.getLangOpts().CPlusPlusModules ||
733 !
Tok.isModuleContextualKeyword())) {
743 PP.HandlePoisonedIdentifier(
Tok);
747 return PP.HandleIdentifier(
Tok);
754bool TokenLexer::pasteTokens(
Token &
Tok) {
763 unsigned int &CurIdx) {
764 assert(CurIdx > 0 &&
"## can not be the first token within tokens");
765 assert((TokenStream[CurIdx].
is(tok::hashhash) ||
768 "Token at this Index must be ## or part of the MSVC 'L "
769 "#macro-arg' pasting pair");
774 if (PP.
getLangOpts().MicrosoftExt && (CurIdx >= 2) &&
775 TokenStream[CurIdx - 2].is(tok::hashhash))
779 const char *ResultTokStrPtr =
nullptr;
782 bool HasUCNs =
false;
784 auto IsAtEnd = [&TokenStream, &CurIdx] {
785 return TokenStream.size() == CurIdx;
790 PasteOpLoc = TokenStream[CurIdx].getLocation();
791 if (TokenStream[CurIdx].
is(tok::hashhash))
793 assert(!IsAtEnd() &&
"No token on the RHS of a paste operator!");
796 const Token &RHS = TokenStream[CurIdx];
803 const char *BufPtr = &Buffer[0];
805 unsigned LHSLen = PP.getSpelling(LHSTok, BufPtr, &
Invalid);
806 if (BufPtr != &Buffer[0])
807 memcpy(&Buffer[0], BufPtr, LHSLen);
811 BufPtr = Buffer.data() + LHSLen;
812 unsigned RHSLen = PP.getSpelling(RHS, BufPtr, &
Invalid);
815 if (RHSLen && BufPtr != &Buffer[LHSLen])
817 memcpy(&Buffer[LHSLen], BufPtr, RHSLen);
820 Buffer.resize(LHSLen+RHSLen);
829 ResultTokTmp.
setKind(tok::string_literal);
830 PP.CreateString(Buffer, ResultTokTmp);
831 SourceLocation ResultTokLoc = ResultTokTmp.
getLocation();
840 PP.IncrementPasteCounter(
true);
842 Result.setKind(tok::raw_identifier);
843 Result.setRawIdentifierData(ResultTokStrPtr);
844 Result.setLocation(ResultTokLoc);
845 Result.setLength(LHSLen+RHSLen);
847 PP.IncrementPasteCounter(
false);
850 "Should be a raw location into scratch buffer");
851 SourceManager &SourceMgr = PP.getSourceManager();
852 FileID LocFileID = SourceMgr.
getFileID(ResultTokLoc);
855 const char *ScratchBufStart
863 PP.getLangOpts(), ScratchBufStart,
864 ResultTokStrPtr, ResultTokStrPtr+LHSLen+RHSLen);
882 SourceManager &
SM = PP.getSourceManager();
884 SM.createExpansionLoc(PasteOpLoc, ExpandLocStart, ExpandLocEnd, 2);
888 if (PP.getLangOpts().MicrosoftExt && LHSTok.
is(tok::slash) &&
889 RHS.
is(tok::slash)) {
890 HandleMicrosoftCommentPaste(LHSTok, Loc);
895 if (!PP.getLangOpts().AsmPreprocessor) {
899 PP.Diag(Loc, PP.getLangOpts().MicrosoftExt ? diag::ext_pp_bad_paste_ms
900 : diag::err_pp_bad_paste)
910 if (
Result.is(tok::hashhash))
911 Result.setKind(tok::unknown);
924 }
while (!IsAtEnd() && TokenStream[CurIdx].
is(tok::hashhash));
926 SourceLocation EndLoc = TokenStream[CurIdx - 1].getLocation();
933 SourceManager &
SM = PP.getSourceManager();
935 StartLoc = getExpansionLocForMacroDefLoc(StartLoc);
937 EndLoc = getExpansionLocForMacroDefLoc(EndLoc);
938 FileID MacroFID =
SM.getFileID(MacroExpansionStart);
939 while (
SM.getFileID(StartLoc) != MacroFID)
940 StartLoc =
SM.getImmediateExpansionRange(StartLoc).getBegin();
941 while (
SM.getFileID(EndLoc) != MacroFID)
942 EndLoc =
SM.getImmediateExpansionRange(EndLoc).getEnd();
950 if (LHSTok.
is(tok::raw_identifier)) {
960 PP.LookUpIdentifierInfo(LHSTok);
972 return Tokens[CurTokenIdx];
978 return Tokens[NumTokens-1].is(tok::eod) && !isAtEnd();
984 LexingCXXModuleDirective = Val;
990 return LexingCXXModuleDirective;
999 PP.
Diag(OpLoc, diag::ext_comment_paste_microsoft);
1006 assert(
Macro &&
"Token streams can't paste comments");
1007 Macro->EnableMacro();
1017TokenLexer::getExpansionLocForMacroDefLoc(
SourceLocation loc)
const {
1018 assert(ExpandLocStart.
isValid() && MacroExpansionStart.
isValid() &&
1019 "Not appropriate for token streams");
1023 assert(
SM.isInSLocAddrSpace(loc, MacroDefStart, MacroDefLength) &&
1024 "Expected loc to come from the macro definition");
1027 SM.isInSLocAddrSpace(loc, MacroDefStart, MacroDefLength, &relativeOffset);
1042 Token *&begin_tokens,
1043 Token * end_tokens) {
1044 assert(begin_tokens + 1 < end_tokens);
1056 return Distance <= MaxDistance;
1065 Partition =
All.take_while([&](
const Token &T) {
1066 return T.getLocation().isFileID() && NearLast(T.getLocation());
1071 FileID BeginFID =
SM.getFileID(BeginLoc);
1073 SM.getComposedLoc(BeginFID,
SM.getFileIDSize(BeginFID));
1074 Partition =
All.take_while([&](
const Token &T) {
1083 return T.getLocation() >= BeginLoc && T.getLocation() <= Limit
1084 && NearLast(T.getLocation());
1087 assert(!Partition.empty());
1092 Partition.back().getEndLoc().getRawEncoding() -
1093 Partition.front().getLocation().getRawEncoding();
1096 SM.createMacroArgExpansionLoc(BeginLoc, ExpandLoc, FullLength);
1098#ifdef EXPENSIVE_CHECKS
1099 assert(llvm::all_of(Partition.drop_front(),
1100 [&
SM, ID =
SM.getFileID(Partition.front().getLocation())](
1102 return ID == SM.getFileID(T.getLocation());
1104 "Must have the same FIleID!");
1108 for (
Token& T : Partition) {
1113 begin_tokens = &Partition.back() + 1;
1121void TokenLexer::updateLocForMacroArgTokens(
SourceLocation ArgIdSpellLoc,
1122 Token *begin_tokens,
1123 Token *end_tokens) {
1124 SourceManager &
SM = PP.getSourceManager();
1126 SourceLocation ExpandLoc =
1127 getExpansionLocForMacroDefLoc(ArgIdSpellLoc);
1129 while (begin_tokens < end_tokens) {
1131 if (end_tokens - begin_tokens == 1) {
1132 Token &
Tok = *begin_tokens;
1143void TokenLexer::PropagateLineStartLeadingSpaceInfo(
Token &
Result) {
1144 AtStartOfLine =
Result.isAtStartOfLine();
1145 HasLeadingSpace =
Result.hasLeadingSpace();
Defines the Diagnostic-related interfaces.
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
Defines the clang::LangOptions interface.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
Defines the clang::MacroInfo and clang::MacroDirective classes.
Defines the clang::Preprocessor interface.
Defines the clang::SourceLocation class and associated facilities.
static bool isInvalid(LocType Loc, bool *Invalid)
Defines the SourceManager interface.
Defines the clang::TokenKind enum and support functions.
static bool isWideStringLiteralFromMacro(const Token &FirstTok, const Token &SecondTok)
Checks if two tokens form wide string literal.
static bool hasVaOptSupport(const LangOptions &LangOpts)
static void updateConsecutiveMacroArgTokens(SourceManager &SM, SourceLocation ExpandLoc, Token *&begin_tokens, Token *end_tokens)
Finds the tokens that are consecutive (from the same FileID) creates a single SLocEntry,...
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
One of these records is kept for each identifier that is lexed.
bool isHandleIdentifierCase() const
Return true if the Preprocessor::HandleIdentifier must be called on a token of this identifier.
tok::TokenKind getTokenID() const
If this is a source-language token (e.g.
bool isPoisoned() const
Return true if this token has been poisoned.
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
MacroArgs - An instance of this class captures information about the formal arguments specified to a ...
static unsigned getArgLength(const Token *ArgPtr)
getArgLength - Given a pointer to an expanded or unexpanded argument, return the number of tokens,...
static Token StringifyArgument(const Token *ArgToks, Preprocessor &PP, bool Charify, SourceLocation ExpansionLocStart, SourceLocation ExpansionLocEnd)
StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of tokens into the literal string...
void destroy(Preprocessor &PP)
destroy - Destroy and deallocate the memory for this object.
Encapsulates the data about a macro definition (e.g.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
SourceManager & getSourceManager() const
const LangOptions & getLangOpts() const
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const
Forwarding function for diagnostics.
void HandleMicrosoftCommentPaste(Token &Tok)
When the macro expander pastes together a comment (/##/) in Microsoft mode, this method handles updat...
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
UIntTy getRawEncoding() const
When a SourceLocation itself cannot be used, this returns an (opaque) 32-bit integer encoding for it.
This class handles loading and caching of source files into memory.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
StringRef getBufferData(FileID FID, bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file.
bool isParsingPreprocessorDirective() const
isParsingPreprocessorDirective - Return true if we are in the middle of a preprocessor directive.
bool isLexingCXXModuleDirective() const
isLexingCXXModuleDirective - Return true if we are lexing a C++ module or import directive.
bool Lex(Token &Tok)
Lex and return a token from this macro stream.
std::optional< Token > peekNextPPToken() const
If TokenLexer::isAtEnd returns true(the next token lexed will pop thismacro off the expansion stack),...
void Init(Token &Tok, SourceLocation ELEnd, MacroInfo *MI, MacroArgs *Actuals)
Initialize this TokenLexer to expand from the specified macro with the specified argument information...
void setLexingCXXModuleDirective(bool Val=true)
setLexingCXXModuleDirective - This is set to true if this TokenLexer is created when handling a C++ m...
Token - This structure provides full information about a lexed token.
IdentifierInfo * getIdentifierInfo() const
bool isAnyIdentifier() const
Return true if this is a raw identifier (when lexing in raw mode) or a non-keyword identifier (when l...
bool hasUCN() const
Returns true if this token contains a universal character name.
void clearFlag(TokenFlags Flag)
Unset the specified flag.
bool isLiteral() const
Return true if this is a "literal", like a numeric constant, string, etc.
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
unsigned getLength() const
void setKind(tok::TokenKind K)
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {....
bool isAtStartOfLine() const
isAtStartOfLine - Return true if this token is at the start of a line.
bool isOneOf(Ts... Ks) const
bool hasLeadingSpace() const
Return true if this token has whitespace before it.
void setLocation(SourceLocation L)
bool isNot(tok::TokenKind K) const
bool stringifiedInMacro() const
Returns true if this token is formed by macro by stringizing or charizing operator.
void startToken()
Reset all flags to cleared.
const char * getLiteralData() const
getLiteralData - For a literal token (numeric constant, string, etc), this returns a pointer to the s...
void setFlag(TokenFlags Flag)
Set the specified flag.
A class for tracking whether we're inside a VA_OPT during a traversal of the tokens of a macro during...
void hasPlaceholderAfterHashhashAtStart()
bool isInVAOpt() const
Returns true if we have seen the VA_OPT and '(' but before having seen the matching ')'.
bool isVAOptToken(const Token &T) const
void sawHashOrHashAtBefore(const bool HasLeadingSpace, const bool IsHashAt)
SourceLocation getVAOptLoc() const
unsigned int getNumberOfTokensPriorToVAOpt() const
bool getLeadingSpaceForStringifiedToken() const
bool hasStringifyOrCharifyBefore() const
bool hasCharifyBefore() const
void sawOpeningParen(SourceLocation LParenLoc)
Call this function each time an lparen is seen.
void hasPlaceholderBeforeRParen()
const Token & getEOFTok() const
bool sawClosingParen()
Call this function each time an rparen is seen.
bool beginsWithPlaceholder() const
bool endsWithPlaceholder() const
void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc, const unsigned int NumPriorTokens)
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.