27#include "llvm/ADT/ArrayRef.h"
28#include "llvm/ADT/STLExtras.h"
29#include "llvm/ADT/SmallString.h"
30#include "llvm/ADT/SmallVector.h"
31#include "llvm/ADT/iterator_range.h"
54 NextTokGetsSpace =
false;
57 DisableMacroExpansion =
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());
77 MacroExpansionStart =
SM.createExpansionLoc(MacroDefStart,
86 ExpandFunctionArguments();
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;
126void TokenLexer::destroy() {
136 if (ActualArgs) ActualArgs->
destroy(PP);
139bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
143 if (!
Macro->isVariadic() || MacroArgNo !=
Macro->getNumParams()-1)
149 if (!HasPasteOperator && !PP.
getLangOpts().MSVCCompat)
158 &&
Macro->getNumParams() < 2)
162 if (ResultToks.empty() || !ResultToks.back().is(tok::comma))
166 if (HasPasteOperator)
167 PP.
Diag(ResultToks.back().getLocation(), diag::ext_paste_comma);
170 ResultToks.pop_back();
172 if (!ResultToks.empty()) {
177 if (ResultToks.back().is(tok::hashhash))
178 ResultToks.pop_back();
185 NextTokGetsSpace =
false;
189void TokenLexer::stringifyVAOPTContents(
193 const unsigned int NumVAOptTokens = ResultToks.size() - NumToksPriorToVAOpt;
194 Token *
const VAOPTTokens =
195 NumVAOptTokens ? &ResultToks[NumToksPriorToVAOpt] :
nullptr;
202 for (
unsigned int CurTokenIdx = 0; CurTokenIdx != NumVAOptTokens;
204 if (VAOPTTokens[CurTokenIdx].is(tok::hashhash)) {
205 assert(CurTokenIdx != 0 &&
206 "Can not have __VAOPT__ contents begin with a ##");
207 Token &LHS = VAOPTTokens[CurTokenIdx - 1];
211 ConcatenatedVAOPTResultToks.back() = LHS;
212 if (CurTokenIdx == NumVAOptTokens)
215 ConcatenatedVAOPTResultToks.push_back(VAOPTTokens[CurTokenIdx]);
218 ConcatenatedVAOPTResultToks.push_back(VCtx.
getEOFTok());
227 getExpansionLocForMacroDefLoc(VAOPTClosingParenLoc);
231 ExpansionLocStartWithinMacro, ExpansionLocEndWithinMacro);
238 ResultToks.resize(NumToksPriorToVAOpt + 1);
239 ResultToks.back() = StringifiedVAOPT;
244void TokenLexer::ExpandFunctionArguments() {
250 bool MadeChange =
false;
252 std::optional<bool> CalledWithVariadicArguments;
256 for (
unsigned I = 0,
E = NumTokens; I !=
E; ++I) {
257 const Token &CurTok = Tokens[I];
264 if (I != 0 && !Tokens[I-1].is(tok::hashhash) && CurTok.
hasLeadingSpace())
265 NextTokGetsSpace =
true;
269 assert(Tokens[I + 1].is(tok::l_paren) &&
270 "__VA_OPT__ must be followed by '('");
292 if (Tokens[I].is(tok::l_paren))
300 if (!CalledWithVariadicArguments) {
301 CalledWithVariadicArguments =
304 if (!*CalledWithVariadicArguments) {
324 stringifyVAOPTContents(ResultToks, VCtx,
325 Tokens[I].getLocation());
334 if (ResultToks.size() && ResultToks.back().is(tok::hashhash)) {
335 ResultToks.pop_back();
336 }
else if ((I + 1 !=
E) && Tokens[I + 1].is(tok::hashhash)) {
349 "no token paste before __VA_OPT__");
350 ResultToks.erase(ResultToks.begin() +
356 Tokens[I + 1].is(tok::hashhash)) {
371 if (CurTok.
isOneOf(tok::hash, tok::hashat)) {
372 int ArgNo =
Macro->getParameterNum(Tokens[I+1].getIdentifierInfo());
373 assert((ArgNo != -1 || VCtx.
isVAOptToken(Tokens[I + 1])) &&
374 "Token following # is not an argument or __VA_OPT__!");
379 CurTok.
is(tok::hashat));
384 getExpansionLocForMacroDefLoc(CurTok.
getLocation());
386 getExpansionLocForMacroDefLoc(Tokens[I+1].getLocation());
388 bool Charify = CurTok.
is(tok::hashat);
391 UnexpArg, PP, Charify, ExpansionLocStart, ExpansionLocEnd);
396 if (NextTokGetsSpace)
399 ResultToks.push_back(Res);
402 NextTokGetsSpace =
false;
407 bool NonEmptyPasteBefore =
408 !ResultToks.empty() && ResultToks.back().is(tok::hashhash);
409 bool PasteBefore = I != 0 && Tokens[I-1].
is(tok::hashhash);
410 bool PasteAfter = I+1 !=
E && Tokens[I+1].
is(tok::hashhash);
411 bool RParenAfter = I+1 !=
E && Tokens[I+1].
is(tok::r_paren);
413 assert((!NonEmptyPasteBefore || PasteBefore || VCtx.
isInVAOpt()) &&
414 "unexpected ## in ResultToks");
419 int ArgNo = II ?
Macro->getParameterNum(II) : -1;
422 ResultToks.push_back(CurTok);
424 if (NextTokGetsSpace) {
426 NextTokGetsSpace =
false;
427 }
else if (PasteBefore && !NonEmptyPasteBefore)
442 MaybeRemoveCommaBeforeVaArgs(ResultToks,
450 if (!PasteBefore && !PasteAfter) {
451 const Token *ResultArgToks;
459 ResultArgToks = ArgTok;
462 if (ResultArgToks->
isNot(tok::eof)) {
463 size_t FirstResult = ResultToks.size();
465 ResultToks.append(ResultArgToks, ResultArgToks+NumToks);
472 ResultToks.back().is(tok::comma))
477 for (
Token &Tok : llvm::drop_begin(ResultToks, FirstResult))
478 if (Tok.is(tok::hashhash))
479 Tok.setKind(tok::unknown);
483 ResultToks.begin()+FirstResult,
493 NextTokGetsSpace =
false;
498 if (NonEmptyPasteBefore) {
501 assert(VCtx.
isInVAOpt() &&
"should only happen inside a __VA_OPT__");
503 }
else if (RParenAfter)
514 bool VaArgsPseudoPaste =
false;
519 if (NonEmptyPasteBefore && ResultToks.size() >= 2 &&
520 ResultToks[ResultToks.size()-2].is(tok::comma) &&
521 (
unsigned)ArgNo ==
Macro->getNumParams()-1 &&
522 Macro->isVariadic()) {
523 VaArgsPseudoPaste =
true;
525 PP.
Diag(ResultToks.pop_back_val().getLocation(), diag::ext_paste_comma);
528 ResultToks.append(ArgToks, ArgToks+NumToks);
532 for (
Token &Tok : llvm::make_range(ResultToks.end() - NumToks,
534 if (Tok.is(tok::hashhash))
535 Tok.setKind(tok::unknown);
538 if (ExpandLocStart.
isValid()) {
540 ResultToks.end()-NumToks, ResultToks.end());
547 if (!VaArgsPseudoPaste) {
550 ResultToks[ResultToks.size() - NumToks].setFlagValue(
554 NextTokGetsSpace =
false;
569 if (RParenAfter && !NonEmptyPasteBefore)
576 if (NonEmptyPasteBefore) {
577 assert(ResultToks.back().is(tok::hashhash));
584 ResultToks.pop_back();
594 MaybeRemoveCommaBeforeVaArgs(ResultToks,
601 assert(!OwnsTokens &&
"This would leak if we already own the token list");
603 NumTokens = ResultToks.size();
606 Tokens = PP.cacheMacroExpandedTokens(
this, ResultToks);
615 const Token &SecondTok) {
616 return FirstTok.
is(tok::identifier) &&
627 if (Macro) Macro->EnableMacro();
632 if (CurTokenIdx == 0)
641 bool isFirstToken = CurTokenIdx == 0;
644 Tok = Tokens[CurTokenIdx++];
648 bool TokenIsFromPaste =
false;
652 if (!isAtEnd() && Macro &&
653 (Tokens[CurTokenIdx].is(tok::hashhash) ||
661 if (pasteTokens(Tok))
664 TokenIsFromPaste =
true;
672 if (ExpandLocStart.
isValid() &&
674 SM.isBeforeInSLocAddrSpace(Tok.
getLocation(), MacroStartSLocOffset)) {
676 if (Tok.
is(tok::comment)) {
682 instLoc = getExpansionLocForMacroDefLoc(Tok.
getLocation());
699 AtStartOfLine =
false;
700 HasLeadingSpace =
false;
724bool TokenLexer::pasteTokens(
Token &Tok) {
725 return pasteTokens(Tok,
llvm::ArrayRef(Tokens, NumTokens), CurTokenIdx);
733 unsigned int &CurIdx) {
734 assert(CurIdx > 0 &&
"## can not be the first token within tokens");
735 assert((TokenStream[CurIdx].is(tok::hashhash) ||
738 "Token at this Index must be ## or part of the MSVC 'L "
739 "#macro-arg' pasting pair");
744 if (PP.
getLangOpts().MicrosoftExt && (CurIdx >= 2) &&
745 TokenStream[CurIdx - 2].is(tok::hashhash))
749 const char *ResultTokStrPtr =
nullptr;
753 auto IsAtEnd = [&TokenStream, &CurIdx] {
754 return TokenStream.size() == CurIdx;
759 PasteOpLoc = TokenStream[CurIdx].getLocation();
760 if (TokenStream[CurIdx].is(tok::hashhash))
762 assert(!IsAtEnd() &&
"No token on the RHS of a paste operator!");
765 const Token &RHS = TokenStream[CurIdx];
772 const char *BufPtr = &Buffer[0];
775 if (BufPtr != &Buffer[0])
776 memcpy(&Buffer[0], BufPtr, LHSLen);
780 BufPtr = Buffer.data() + LHSLen;
784 if (RHSLen && BufPtr != &Buffer[LHSLen])
786 memcpy(&Buffer[LHSLen], BufPtr, RHSLen);
789 Buffer.resize(LHSLen+RHSLen);
798 ResultTokTmp.
setKind(tok::string_literal);
811 Result.setKind(tok::raw_identifier);
812 Result.setRawIdentifierData(ResultTokStrPtr);
813 Result.setLocation(ResultTokLoc);
814 Result.setLength(LHSLen+RHSLen);
819 "Should be a raw location into scratch buffer");
824 const char *ScratchBufStart
833 ResultTokStrPtr, ResultTokStrPtr+LHSLen+RHSLen);
853 SM.createExpansionLoc(PasteOpLoc, ExpandLocStart, ExpandLocEnd, 2);
857 if (PP.
getLangOpts().MicrosoftExt && LHSTok.
is(tok::slash) &&
858 RHS.
is(tok::slash)) {
859 HandleMicrosoftCommentPaste(LHSTok,
Loc);
869 : diag::err_pp_bad_paste)
879 if (
Result.is(tok::hashhash))
880 Result.setKind(tok::unknown);
890 }
while (!IsAtEnd() && TokenStream[CurIdx].is(tok::hashhash));
901 StartLoc = getExpansionLocForMacroDefLoc(StartLoc);
903 EndLoc = getExpansionLocForMacroDefLoc(EndLoc);
904 FileID MacroFID =
SM.getFileID(MacroExpansionStart);
905 while (
SM.getFileID(StartLoc) != MacroFID)
906 StartLoc =
SM.getImmediateExpansionRange(StartLoc).getBegin();
907 while (
SM.getFileID(EndLoc) != MacroFID)
908 EndLoc =
SM.getImmediateExpansionRange(EndLoc).getEnd();
916 if (LHSTok.
is(tok::raw_identifier)) {
931 return Tokens[CurTokenIdx].
is(tok::l_paren);
937 return Tokens[NumTokens-1].
is(tok::eod) && !isAtEnd();
946 PP.
Diag(OpLoc, diag::ext_comment_paste_microsoft);
953 assert(Macro &&
"Token streams can't paste comments");
954 Macro->EnableMacro();
964TokenLexer::getExpansionLocForMacroDefLoc(
SourceLocation loc)
const {
965 assert(ExpandLocStart.
isValid() && MacroExpansionStart.
isValid() &&
966 "Not appropriate for token streams");
970 assert(
SM.isInSLocAddrSpace(loc, MacroDefStart, MacroDefLength) &&
971 "Expected loc to come from the macro definition");
974 SM.isInSLocAddrSpace(loc, MacroDefStart, MacroDefLength, &relativeOffset);
989 Token *&begin_tokens,
990 Token * end_tokens) {
991 assert(begin_tokens + 1 < end_tokens);
1003 return Distance <= MaxDistance;
1012 Partition =
All.take_while([&](
const Token &
T) {
1013 return T.getLocation().isFileID() && NearLast(
T.getLocation());
1018 FileID BeginFID =
SM.getFileID(BeginLoc);
1020 SM.getComposedLoc(BeginFID,
SM.getFileIDSize(BeginFID));
1021 Partition =
All.take_while([&](
const Token &
T) {
1030 return T.getLocation() >= BeginLoc &&
T.getLocation() <= Limit
1031 && NearLast(
T.getLocation());
1034 assert(!Partition.empty());
1039 Partition.back().getEndLoc().getRawEncoding() -
1040 Partition.front().getLocation().getRawEncoding();
1043 SM.createMacroArgExpansionLoc(BeginLoc, ExpandLoc, FullLength);
1045#ifdef EXPENSIVE_CHECKS
1046 assert(llvm::all_of(Partition.drop_front(),
1047 [&
SM, ID =
SM.getFileID(Partition.front().getLocation())](
1049 return ID == SM.getFileID(T.getLocation());
1051 "Must have the same FIleID!");
1055 for (
Token&
T : Partition) {
1060 begin_tokens = &Partition.back() + 1;
1068void TokenLexer::updateLocForMacroArgTokens(
SourceLocation ArgIdSpellLoc,
1069 Token *begin_tokens,
1070 Token *end_tokens) {
1074 getExpansionLocForMacroDefLoc(ArgIdSpellLoc);
1076 while (begin_tokens < end_tokens) {
1078 if (end_tokens - begin_tokens == 1) {
1079 Token &Tok = *begin_tokens;
1090void TokenLexer::PropagateLineStartLeadingSpaceInfo(
Token &
Result) {
1091 AtStartOfLine =
Result.isAtStartOfLine();
1092 HasLeadingSpace =
Result.hasLeadingSpace();
Defines the Diagnostic-related interfaces.
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
Defines the clang::LangOptions interface.
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 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...
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.
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens.
MacroArgs - An instance of this class captures information about the formal arguments specified to a ...
const Token * getUnexpArgument(unsigned Arg) const
getUnexpArgument - Return a pointer to the first token of the unexpanded token list for the specified...
const std::vector< Token > & getPreExpArgument(unsigned Arg, Preprocessor &PP)
getPreExpArgument - Return the pre-expanded form of the specified argument.
static unsigned getArgLength(const Token *ArgPtr)
getArgLength - Given a pointer to an expanded or unexpanded argument, return the number of tokens,...
bool ArgNeedsPreexpansion(const Token *ArgTok, Preprocessor &PP) const
ArgNeedsPreexpansion - If we can prove that the argument won't be affected by pre-expansion,...
bool invokedWithVariadicArgument(const MacroInfo *const MI, Preprocessor &PP)
Returns true if the macro was defined with a variadic (ellipsis) parameter AND was invoked with at le...
bool isVarargsElidedUse() const
isVarargsElidedUse - Return true if this is a C99 style varargs macro invocation and there was no arg...
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.
bool isFunctionLike() const
const_tokens_iterator tokens_begin() const
const_tokens_iterator tokens_end() const
unsigned getNumParams() const
unsigned getDefinitionLength(const SourceManager &SM) const
Get length in characters of the macro definition.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
void CreateString(StringRef Str, Token &Tok, SourceLocation ExpansionLocStart=SourceLocation(), SourceLocation ExpansionLocEnd=SourceLocation())
Plop the specified string into a scratch buffer and set the specified token's location and length to ...
IdentifierInfo * LookUpIdentifierInfo(Token &Identifier) const
Given a tok::raw_identifier token, look up the identifier information for the token and install it in...
bool HandleEndOfTokenLexer(Token &Result)
Callback invoked when the current TokenLexer hits the end of its token stream.
void HandlePoisonedIdentifier(Token &Identifier)
Display reason for poisoned identifier.
bool HandleIdentifier(Token &Identifier)
Callback invoked when the lexer reads an identifier and has filled in the tokens IdentifierInfo membe...
void IncrementPasteCounter(bool isFast)
Increment the counters for the number of token paste operations performed.
SourceManager & getSourceManager() const
StringRef getSpelling(SourceLocation loc, SmallVectorImpl< char > &buffer, bool *invalid=nullptr) const
Return the 'spelling' of the token at the given location; does not go up to the spelling location or ...
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.
unsigned isNextTokenLParen() const
If the next token lexed will pop this macro off the expansion stack, return 2.
bool Lex(Token &Tok)
Lex and return a token from this macro stream.
void Init(Token &Tok, SourceLocation ELEnd, MacroInfo *MI, MacroArgs *Actuals)
Initialize this TokenLexer to expand from the specified macro with the specified argument information...
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...
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 hasLeadingSpace() const
Return true if this token has whitespace before it.
void setLocation(SourceLocation L)
bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const
bool isNot(tok::TokenKind K) const
bool isAnnotation() const
Return true if this is any of tok::annot_* kind tokens.
bool stringifiedInMacro() const
Returns true if this token is formed by macro by stringizing or charizing operator.
void startToken()
Reset all flags to cleared.
void setFlagValue(TokenFlags Flag, bool Val)
Set a flag to either true or false.
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.
const FunctionProtoType * T