23#include "llvm/ADT/ScopeExit.h"
24#include "llvm/ADT/SmallString.h"
25#include "llvm/ADT/StringMap.h"
26#include "llvm/ADT/StringSwitch.h"
35struct DirectiveWithTokens {
40 : Kind(Kind), NumTokens(NumTokens) {}
43enum class CXX20ModuleDirectiveKind {
46 NamedModuleDeclaration,
50static CXX20ModuleDirectiveKind scanFirstCXX20ModuleDirective(StringRef Source);
72 Scanner(StringRef Input,
73 SmallVectorImpl<dependency_directives_scan::Token> &Tokens,
74 DiagnosticsEngine *Diags, SourceLocation InputSourceLoc)
75 : Input(Input), Tokens(Tokens), Diags(Diags),
76 InputSourceLoc(InputSourceLoc), LangOpts(getLangOptsForDepScanning()),
77 TheLexer(InputSourceLoc, LangOpts, Input.begin(), Input.begin(),
80 static LangOptions getLangOptsForDepScanning() {
84 LangOpts.LineComment =
true;
85 LangOpts.RawStringLiterals =
true;
86 LangOpts.AllowLiteralDigitSeparator =
true;
94 bool scan(SmallVectorImpl<Directive> &Directives);
96 friend CXX20ModuleDirectiveKind
97 scanFirstCXX20ModuleDirective(StringRef Source);
102 [[nodiscard]] dependency_directives_scan::Token &
103 lexToken(
const char *&
First,
const char *
const End);
105 [[nodiscard]] dependency_directives_scan::Token &
106 lexIncludeFilename(
const char *&
First,
const char *
const End);
108 void skipLine(
const char *&
First,
const char *
const End);
109 void skipDirective(StringRef Name,
const char *&
First,
const char *
const End);
113 StringRef cleanStringIfNeeded(
const dependency_directives_scan::Token &
Tok);
120 [[nodiscard]] std::optional<StringRef>
121 tryLexIdentifierOrSkipLine(
const char *&
First,
const char *
const End);
124 [[nodiscard]] StringRef lexIdentifier(
const char *&
First,
125 const char *
const End);
132 [[nodiscard]]
bool isNextIdentifierOrSkipLine(StringRef Id,
134 const char *
const End);
142 const char *
const End);
149 [[nodiscard]] std::optional<StringRef>
150 tryLexStringLiteralOrSkipLine(
const char *&
First,
const char *
const End);
152 [[nodiscard]]
bool scanImpl(
const char *
First,
const char *
const End);
153 [[nodiscard]]
bool lexPPLine(
const char *&
First,
const char *
const End);
154 [[nodiscard]]
bool lexAt(
const char *&
First,
const char *
const End);
155 [[nodiscard]]
bool lexModule(
const char *&
First,
const char *
const End);
156 [[nodiscard]]
bool lexPragma(
const char *&
First,
const char *
const End);
157 [[nodiscard]]
bool lex_Pragma(
const char *&
First,
const char *
const End);
158 [[nodiscard]]
bool lexEndif(
const char *&
First,
const char *
const End);
160 const char *
const End);
161 [[nodiscard]]
bool lexModuleDirectiveBody(
DirectiveKind Kind,
163 const char *
const End);
164 void lexPPDirectiveBody(
const char *&
First,
const char *
const End);
167 Tokens.append(CurDirToks);
168 DirsWithToks.emplace_back(Kind, CurDirToks.size());
170 return DirsWithToks.back();
172 void popDirective() {
173 Tokens.pop_back_n(DirsWithToks.pop_back_val().NumTokens);
176 return DirsWithToks.empty() ?
pp_none : DirsWithToks.back().Kind;
179 unsigned getOffsetAt(
const char *CurPtr)
const {
180 return CurPtr - Input.data();
185 bool reportError(
const char *CurPtr,
unsigned Err);
187 bool ScanningPreprocessedModuleFile =
false;
188 StringMap<char> SplitIds;
190 SmallVectorImpl<dependency_directives_scan::Token> &Tokens;
191 DiagnosticsEngine *Diags;
192 SourceLocation InputSourceLoc;
194 const char *LastTokenPtr =
nullptr;
198 SmallVector<dependency_directives_scan::Token, 32> CurDirToks;
202 SmallVector<DirectiveWithTokens, 64> DirsWithToks;
203 LangOptions LangOpts;
209bool Scanner::reportError(
const char *CurPtr,
unsigned Err) {
212 assert(CurPtr >= Input.data() &&
"invalid buffer ptr");
224 assert(Current >
First);
228 if (Current >
First && *(Current - 1) ==
'\\') {
232 if (EscapeSize > 0) {
235 Current -= (1 + EscapeSize);
247 const char *Current) {
248 assert(
First <= Current);
251 if (*Current !=
'"' ||
First == Current)
257 if (
First == Current ||
262 if (*Current ==
'u' || *Current ==
'U' || *Current ==
'L')
263 return First == Current ||
267 if (*Current !=
'8' ||
First == Current ||
270 return First == Current ||
275 assert(
First[0] ==
'"');
297 while (
Last != End &&
size_t(
Last -
First) < Terminator.size() &&
306 if (
size_t(
Last -
First) < Terminator.size())
316static unsigned isEOL(
const char *
First,
const char *
const End) {
327 const char Terminator = *
First ==
'<' ?
'>' : *
First;
342 const char *FirstAfterBackslashPastSpace =
First;
344 if (
unsigned NLSize =
isEOL(FirstAfterBackslashPastSpace, End)) {
347 First = FirstAfterBackslashPastSpace + NLSize - 1;
360 assert(Len &&
"expected newline");
374 char LastNonWhitespace =
' ';
377 LastNonWhitespace = *
First;
383 if (LastNonWhitespace !=
'\\')
399 if (End -
First < 4) {
413 const char *
const Cur,
414 const char *
const End) {
415 assert(*Cur ==
'\'' &&
"expected quotation character");
423 char Prev = *(Cur - 1);
424 if (Prev ==
'L' || Prev ==
'U' || Prev ==
'u')
426 if (Prev ==
'8' && (Cur - 1 != Start) && *(Cur - 2) ==
'u')
434void Scanner::skipLine(
const char *&
First,
const char *
const End) {
436 assert(
First <= End);
444 const char *Start =
First;
447 char LastNonWhitespace =
' ';
452 LastTokenPtr =
First;
470 LastTokenPtr =
First;
472 LastNonWhitespace = *
First;
477 if (
First[1] ==
'/') {
483 if (
First[1] !=
'*') {
484 LastTokenPtr =
First;
486 LastNonWhitespace = *
First;
500 if (LastNonWhitespace !=
'\\')
505void Scanner::skipDirective(StringRef Name,
const char *&
First,
506 const char *
const End) {
507 if (llvm::StringSwitch<bool>(Name)
508 .Case(
"warning",
true)
514 skipLine(
First, End);
519 assert(
First <= End);
525 if (*
First ==
'\\') {
526 const char *Ptr =
First + 1;
542 if (
First[1] ==
'/') {
557 const char *
const End) {
558 assert(Kind == DirectiveKind::cxx_export_import_decl ||
559 Kind == DirectiveKind::cxx_export_module_decl ||
560 Kind == DirectiveKind::cxx_import_decl ||
561 Kind == DirectiveKind::cxx_module_decl ||
562 Kind == DirectiveKind::decl_at_import);
564 const char *DirectiveLoc = Input.data() + CurDirToks.front().Offset;
568 const dependency_directives_scan::Token &
Tok = lexToken(
First, End);
571 CurDirToks.pop_back();
578 diag::err_dep_source_scanner_missing_semi_after_at_import);
579 if (
Tok.
is(tok::semi))
583 bool IsCXXModules =
Kind == DirectiveKind::cxx_export_import_decl ||
584 Kind == DirectiveKind::cxx_export_module_decl ||
585 Kind == DirectiveKind::cxx_import_decl ||
586 Kind == DirectiveKind::cxx_module_decl;
588 lexPPDirectiveBody(
First, End);
593 const auto &
Tok = lexToken(
First, End);
597 return reportError(DirectiveLoc,
598 diag::err_dep_source_scanner_unexpected_tokens_at_import);
601dependency_directives_scan::Token &Scanner::lexToken(
const char *&
First,
602 const char *
const End) {
606 assert(
First <= End);
609 CurDirToks.emplace_back(Offset,
Tok.getLength(),
Tok.getKind(),
611 return CurDirToks.back();
614dependency_directives_scan::Token &
615Scanner::lexIncludeFilename(
const char *&
First,
const char *
const End) {
619 assert(
First <= End);
622 CurDirToks.emplace_back(Offset,
Tok.getLength(),
Tok.getKind(),
624 return CurDirToks.back();
627void Scanner::lexPPDirectiveBody(
const char *&
First,
const char *
const End) {
629 const dependency_directives_scan::Token &
Tok = lexToken(
First, End);
636Scanner::cleanStringIfNeeded(
const dependency_directives_scan::Token &
Tok) {
638 if (LLVM_LIKELY(!NeedsCleaning))
641 SmallString<64> Spelling;
647 unsigned SpellingLength = 0;
648 const char *BufPtr = Input.begin() +
Tok.
Offset;
649 const char *AfterIdent = Input.begin() +
Tok.
getEnd();
650 while (BufPtr < AfterIdent) {
652 Spelling[SpellingLength++] = Char;
656 return SplitIds.try_emplace(StringRef(Spelling.begin(), SpellingLength), 0)
660std::optional<StringRef>
661Scanner::tryLexIdentifierOrSkipLine(
const char *&
First,
const char *
const End) {
662 const dependency_directives_scan::Token &
Tok = lexToken(
First, End);
663 if (
Tok.
isNot(tok::raw_identifier)) {
664 if (!
Tok.
is(tok::eod))
665 skipLine(
First, End);
669 return cleanStringIfNeeded(
Tok);
672StringRef Scanner::lexIdentifier(
const char *&
First,
const char *
const End) {
673 std::optional<StringRef> Id = tryLexIdentifierOrSkipLine(
First, End);
674 assert(Id &&
"expected identifier token");
678bool Scanner::isNextIdentifierOrSkipLine(StringRef Id,
const char *&
First,
679 const char *
const End) {
680 if (std::optional<StringRef> FoundId =
681 tryLexIdentifierOrSkipLine(
First, End)) {
684 skipLine(
First, End);
690 const char *
const End) {
691 const dependency_directives_scan::Token &
Tok = lexToken(
First, End);
694 skipLine(
First, End);
698std::optional<StringRef>
699Scanner::tryLexStringLiteralOrSkipLine(
const char *&
First,
700 const char *
const End) {
701 const dependency_directives_scan::Token &
Tok = lexToken(
First, End);
703 if (!
Tok.
is(tok::eod))
704 skipLine(
First, End);
708 return cleanStringIfNeeded(
Tok);
711bool Scanner::lexAt(
const char *&
First,
const char *
const End) {
715 const dependency_directives_scan::Token &AtTok = lexToken(
First, End);
716 assert(AtTok.
is(tok::at));
719 if (!isNextIdentifierOrSkipLine(
"import",
First, End))
724bool Scanner::lexModule(
const char *&
First,
const char *
const End) {
725 StringRef Id = lexIdentifier(
First, End);
727 if (Id ==
"export") {
729 std::optional<StringRef> NextId = tryLexIdentifierOrSkipLine(
First, End);
736 ScanningPreprocessedModuleFile ?
"__preprocessed_module" :
"module";
738 ScanningPreprocessedModuleFile ?
"__preprocessed_import" :
"import";
740 if (Id !=
Module && Id != Import) {
741 skipLine(
First, End);
754 skipLine(
First, End);
761 skipLine(
First, End);
765 (void)lexToken(
First, End);
766 if (!tryLexIdentifierOrSkipLine(
First, End))
772 if (Id ==
Module && !Export)
774 skipLine(
First, End);
782 skipLine(
First, End);
787 TheLexer.
seek(getOffsetAt(
First),
false);
795 return lexModuleDirectiveBody(Kind,
First, End);
798bool Scanner::lex_Pragma(
const char *&
First,
const char *
const End) {
799 if (!isNextTokenOrSkipLine(tok::l_paren,
First, End))
802 std::optional<StringRef> Str = tryLexStringLiteralOrSkipLine(
First, End);
804 if (!Str || !isNextTokenOrSkipLine(tok::r_paren,
First, End))
807 SmallString<64> Buffer(*Str);
813 SmallVector<dependency_directives_scan::Token> DiscardTokens;
814 const char *Begin = Buffer.c_str();
815 Scanner PragmaScanner{StringRef(Begin, Buffer.size()), DiscardTokens, Diags,
819 if (PragmaScanner.lexPragma(Begin, Buffer.end()))
824 skipLine(
First, End);
828 assert(Begin == Buffer.end());
833bool Scanner::lexPragma(
const char *&
First,
const char *
const End) {
834 std::optional<StringRef> FoundId = tryLexIdentifierOrSkipLine(
First, End);
838 StringRef Id = *FoundId;
839 auto Kind = llvm::StringSwitch<DirectiveKind>(Id)
846 lexPPDirectiveBody(
First, End);
852 skipLine(
First, End);
856 FoundId = tryLexIdentifierOrSkipLine(
First, End);
862 if (Id ==
"system_header") {
863 lexPPDirectiveBody(
First, End);
868 if (Id !=
"module") {
869 skipLine(
First, End);
874 if (!isNextIdentifierOrSkipLine(
"import",
First, End))
878 lexPPDirectiveBody(
First, End);
883bool Scanner::lexEndif(
const char *&
First,
const char *
const End) {
896 skipLine(
First, End);
904 const char *
const End) {
905 lexPPDirectiveBody(
First, End);
925 assert(
First <= End);
928 return Str.starts_with(
936bool Scanner::lexPPLine(
const char *&
First,
const char *
const End) {
937 assert(
First != End);
940 assert(
First <= End);
945 skipLine(
First, End);
946 assert(
First <= End);
950 LastTokenPtr =
First;
954 llvm::scope_exit ScEx1([&]() {
960 bool IsPreprocessedModule =
962 if (*
First ==
'_' && !IsPreprocessedModule) {
963 if (isNextIdentifierOrSkipLine(
"_Pragma",
First, End))
964 return lex_Pragma(
First, End);
971 llvm::scope_exit ScEx2(
975 return lexAt(
First, End);
978 if (*
First ==
'i' || *
First ==
'e' || *
First ==
'm' || IsPreprocessedModule)
979 return lexModule(
First, End);
982 const dependency_directives_scan::Token &HashTok = lexToken(
First, End);
983 if (HashTok.
is(tok::hashhash)) {
987 skipLine(
First, End);
988 assert(
First <= End);
991 assert(HashTok.
is(tok::hash));
994 std::optional<StringRef> FoundId = tryLexIdentifierOrSkipLine(
First, End);
998 StringRef Id = *FoundId;
1001 return lexPragma(
First, End);
1003 auto Kind = llvm::StringSwitch<DirectiveKind>(Id)
1020 skipDirective(Id,
First, End);
1025 return lexEndif(
First, End);
1033 if (lexIncludeFilename(
First, End).
is(tok::eod)) {
1042 return lexDefault(Kind,
First, End);
1051bool Scanner::scanImpl(
const char *
First,
const char *
const End) {
1053 while (
First != End)
1054 if (lexPPLine(
First, End))
1059bool Scanner::scan(SmallVectorImpl<Directive> &Directives) {
1061 bool Error = scanImpl(Input.begin(), Input.end());
1066 (Tokens.empty() || LastTokenPtr > Input.begin() + Tokens.back().Offset))
1071 ArrayRef<dependency_directives_scan::Token> RemainingTokens = Tokens;
1072 for (
const DirectiveWithTokens &DirWithToks : DirsWithToks) {
1073 assert(RemainingTokens.size() >= DirWithToks.NumTokens);
1074 Directives.emplace_back(DirWithToks.Kind,
1075 RemainingTokens.take_front(DirWithToks.NumTokens));
1076 RemainingTokens = RemainingTokens.drop_front(DirWithToks.NumTokens);
1078 assert(RemainingTokens.empty());
1087 return Scanner(Input, Tokens, Diags, InputSourceLoc).scan(Directives);
1093 llvm::raw_ostream &OS) {
1099 return !
Tok.isOneOf(tok::l_paren, tok::r_paren, tok::l_square,
1101 if (Prev.
Kind == tok::raw_identifier &&
1102 Tok.isOneOf(tok::hash, tok::numeric_constant, tok::string_literal,
1103 tok::char_constant, tok::header_name))
1105 if (Prev.
Kind == tok::r_paren &&
1106 Tok.isOneOf(tok::raw_identifier, tok::hash, tok::string_literal,
1107 tok::char_constant, tok::unknown))
1109 if (Prev.
Kind == tok::comma &&
1110 Tok.isOneOf(tok::l_paren, tok::string_literal, tok::less))
1115 constexpr unsigned FirstBodyIdx = 3;
1116 return Kind ==
pp_define && TokIdx == FirstBodyIdx &&
1117 Prev.
is(tok::raw_identifier) &&
Tok.is(tok::l_paren) &&
1125 OS <<
";/*TokBeforeEOF*/";
1127 unsigned TokIdx = 0;
1133 OS << Source.slice(
Tok.Offset,
Tok.getEnd());
1139 const char *
const End) {
1140 assert(
First <= End);
1141 while (
First != End) {
1142 if (*
First ==
'#') {
1157static CXX20ModuleDirectiveKind
1158scanFirstCXX20ModuleDirective(StringRef Source) {
1159 const char *
First = Source.begin();
1160 const char *
const End = Source.end();
1163 return CXX20ModuleDirectiveKind::None;
1168 return CXX20ModuleDirectiveKind::None;
1170 llvm::SmallVector<dependency_directives_scan::Token> Tokens;
1171 Scanner S(StringRef(
First, End -
First), Tokens,
nullptr, SourceLocation());
1172 S.TheLexer.setParsingPreprocessorDirective(
true);
1173 if (S.lexModule(
First, End) || S.DirsWithToks.empty())
1174 return CXX20ModuleDirectiveKind::None;
1176 assert(S.DirsWithToks.size() == 1);
1177 const DirectiveWithTokens &
Directive = S.DirsWithToks.front();
1181 return Tokens[1].is(tok::semi)
1182 ? CXX20ModuleDirectiveKind::GlobalModuleFragment
1183 : CXX20ModuleDirectiveKind::NamedModuleDeclaration;
1185 return CXX20ModuleDirectiveKind::NamedModuleDeclaration;
1188 return CXX20ModuleDirectiveKind::ImportDeclaration;
1190 llvm_unreachable(
"unexpected C++20 module directive kind");
1197 return scanFirstCXX20ModuleDirective(Source) !=
1198 CXX20ModuleDirectiveKind::None;
1202 switch (scanFirstCXX20ModuleDirective(Source)) {
1203 case CXX20ModuleDirectiveKind::GlobalModuleFragment:
1205 case CXX20ModuleDirectiveKind::NamedModuleDeclaration:
1207 case CXX20ModuleDirectiveKind::None:
1208 case CXX20ModuleDirectiveKind::ImportDeclaration:
1211 llvm_unreachable(
"unexpected C++20 module directive kind");
1215 const char *
First = Source.begin();
1216 const char *
const End = Source.end();
1224 while (
First != End) {
1225 if (*
First ==
'#') {
1228 }
else if (*
First ==
'e') {
1229 S.TheLexer.
seek(S.getOffsetAt(
First),
true);
1230 StringRef Id = S.lexIdentifier(
First, End);
1231 if (Id ==
"export") {
1232 std::optional<StringRef> NextId =
1233 S.tryLexIdentifierOrSkipLine(
First, End);
1238 if (Id ==
"__preprocessed_module" || Id ==
"__preprocessed_import")
Defines the Diagnostic-related interfaces.
static void skipBlockComment(const char *&First, const char *const End)
static void skipRawString(const char *&First, const char *const End)
static void skipString(const char *&First, const char *const End)
static bool isStartOfRelevantLine(char First)
static bool isStartWithPreprocessedModuleDirective(const char *First, const char *End)
static bool isRawStringLiteral(const char *First, const char *Current)
static void skipUntilMaybeCXX20ModuleDirective(const char *&First, const char *const End)
static void skipOverSpaces(const char *&First, const char *const End)
static unsigned isEOL(const char *First, const char *const End)
static char previousChar(const char *First, const char *&Current)
static void skipToNewlineRaw(const char *&First, const char *const End)
static unsigned skipNewline(const char *&First, const char *End)
static void skipUTF8ByteOrderMark(const char *&First, const char *const End)
static void skipLineComment(const char *&First, const char *const End)
static bool isQuoteCppDigitSeparator(const char *const Start, const char *const Cur, const char *const End)
This is the interface for scanning header and source files to get the minimum necessary preprocessor ...
static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length)
Skip over whitespace in the string, starting at the given index.
VerifyDiagnosticConsumer::Directive Directive
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
static unsigned getEscapedNewLineSize(const char *P)
getEscapedNewLineSize - Return the size of the specified escaped newline, or 0 if it is not an escape...
void seek(unsigned Offset, bool IsAtStartOfLine)
Set the lexer's buffer pointer to Offset.
unsigned getCurrentBufferOffset()
Returns the current lexing offset.
static SizedChar getCharAndSizeNoWarn(const char *Ptr, const LangOptions &LangOpts)
getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever emit a warning.
void setParsingPreprocessorDirective(bool f)
Inform the lexer whether or not we are currently lexing a preprocessor directive.
void LexIncludeFilename(Token &FilenameTok)
Lex a token, producing a header-name token if possible.
Encodes a location in the source.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
DirectiveKind
Represents the kind of preprocessor directive or a module declaration that is tracked by the scanner ...
@ tokens_present_before_eof
Indicates that there are tokens present between the last scanned directive and eof.
@ pp_pragma_system_header
@ pp_pragma_include_alias
bool isStringLiteral(TokenKind K)
Return true if this is a C or C++ string-literal (or C++11 user-defined-string-literal) token.
const char * getPPKeywordSpelling(PPKeywordKind Kind) LLVM_READNONE
Returns the spelling of preprocessor keywords, such as "else".
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
Top level wrappers for InstallAPI frontend operations.
LLVM_READONLY bool isVerticalWhitespace(unsigned char c)
Returns true if this character is vertical ASCII whitespace: '\n', '\r'.
LLVM_READONLY bool isAsciiIdentifierContinue(unsigned char c)
void printDependencyDirectivesAsSource(StringRef Source, ArrayRef< dependency_directives_scan::Directive > Directives, llvm::raw_ostream &OS)
Print the previously scanned dependency directives as minimized source text.
bool scanInputForCXX20ModulesUsage(StringRef Source)
Scan an input source buffer for C++20 named module usage.
bool isPreprocessedModuleFile(StringRef Source)
Scan an input source buffer, and check whether the input source is a preprocessed output.
LLVM_READONLY bool isHorizontalWhitespace(unsigned char c)
Returns true if this character is horizontal ASCII whitespace: ' ', '\t', '\f', '\v'.
bool scanSourceForDependencyDirectives(StringRef Input, SmallVectorImpl< dependency_directives_scan::Token > &Tokens, SmallVectorImpl< dependency_directives_scan::Directive > &Directives, DiagnosticsEngine *Diags=nullptr, SourceLocation InputSourceLoc=SourceLocation())
Scan the input for the preprocessor directives that might have an effect on the dependencies for a co...
@ Module
Module linkage, which indicates that the entity can be referred to from other translation units withi...
@ Default
Set to the current date and time.
ModuleUnitKind
Describes how a source input starts a C++20 module unit.
@ HasGlobalModuleFragment
@ NamedModuleWithoutGlobalModuleFragment
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...
LLVM_READONLY bool isPreprocessingNumberBody(unsigned char c)
Return true if this is the body character of a C preprocessing number, which is [a-zA-Z0-9_.
void prepare_PragmaString(SmallVectorImpl< char > &StrVal)
Destringize a _Pragma("") string according to C11 6.10.9.1: "The string literal is destringized by de...
ModuleUnitKind scanInputForCXX20ModuleUnit(StringRef Source)
Scan an input source buffer to determine whether it starts a C++20 module unit, and whether that modu...
Diagnostic wrappers for TextAPI types for error reporting.
Represents a directive that's lexed as part of the dependency directives scanning.
DirectiveKind Kind
The kind of token.
Token lexed as part of dependency directive scanning.
bool isNot(tok::TokenKind K) const
unsigned Offset
Offset into the original source input.
bool is(tok::TokenKind K) const
bool isOneOf(Ts... Ks) const