24 #include "llvm/ADT/STLExtras.h" 25 #include "llvm/ADT/SmallString.h" 26 #include "llvm/ADT/StringRef.h" 27 #include "llvm/Support/ErrorHandling.h" 28 #include "llvm/Support/raw_ostream.h" 30 using namespace clang;
36 OS <<
"#define " << II.
getName();
42 for (; AI+1 != E; ++AI) {
43 OS << (*AI)->getName();
48 if ((*AI)->getName() ==
"__VA_ARGS__")
51 OS << (*AI)->getName();
66 for (
const auto &T : MI.
tokens()) {
67 if (T.hasLeadingSpace())
79 class PrintPPOutputPPCallbacks :
public PPCallbacks {
88 bool EmittedTokensOnThisLine;
89 bool EmittedDirectiveOnThisLine;
93 bool DisableLineMarkers;
95 bool DumpIncludeDirectives;
96 bool UseLineDirectives;
97 bool IsFirstFileEntered;
99 PrintPPOutputPPCallbacks(
Preprocessor &pp, raw_ostream &os,
bool lineMarkers,
100 bool defines,
bool DumpIncludeDirectives,
101 bool UseLineDirectives)
103 DisableLineMarkers(lineMarkers), DumpDefines(defines),
104 DumpIncludeDirectives(DumpIncludeDirectives),
105 UseLineDirectives(UseLineDirectives) {
107 CurFilename +=
"<uninit>";
108 EmittedTokensOnThisLine =
false;
109 EmittedDirectiveOnThisLine =
false;
112 IsFirstFileEntered =
false;
115 void setEmittedTokensOnThisLine() { EmittedTokensOnThisLine =
true; }
116 bool hasEmittedTokensOnThisLine()
const {
return EmittedTokensOnThisLine; }
118 void setEmittedDirectiveOnThisLine() { EmittedDirectiveOnThisLine =
true; }
119 bool hasEmittedDirectiveOnThisLine()
const {
120 return EmittedDirectiveOnThisLine;
123 bool startNewLineIfNeeded(
bool ShouldUpdateCurrentLine =
true);
129 StringRef FileName,
bool IsAngled,
131 StringRef SearchPath, StringRef RelativePath,
136 PragmaMessageKind
Kind, StringRef Str)
override;
137 void PragmaDebug(
SourceLocation Loc, StringRef DebugType)
override;
138 void PragmaDiagnosticPush(
SourceLocation Loc, StringRef Namespace)
override;
139 void PragmaDiagnosticPop(
SourceLocation Loc, StringRef Namespace)
override;
146 void PragmaExecCharsetPush(
SourceLocation Loc, StringRef Str)
override;
151 bool HandleFirstTokOnLine(
Token &
Tok);
162 bool MoveToLine(
unsigned LineNo);
164 bool AvoidConcat(
const Token &PrevPrevTok,
const Token &PrevTok,
166 return ConcatInfo.
AvoidConcat(PrevPrevTok, PrevTok, Tok);
168 void WriteLineInfo(
unsigned LineNo,
const char *Extra=
nullptr,
169 unsigned ExtraLen=0);
170 bool LineMarkersAreDisabled()
const {
return DisableLineMarkers; }
171 void HandleNewlinesInToken(
const char *TokStr,
unsigned Len);
174 void MacroDefined(
const Token &MacroNameTok,
178 void MacroUndefined(
const Token &MacroNameTok,
182 void BeginModule(
const Module *M);
183 void EndModule(
const Module *M);
187 void PrintPPOutputPPCallbacks::WriteLineInfo(
unsigned LineNo,
190 startNewLineIfNeeded(
false);
193 if (UseLineDirectives) {
194 OS <<
"#line" <<
' ' << LineNo <<
' ' <<
'"';
195 OS.write_escaped(CurFilename);
198 OS <<
'#' <<
' ' << LineNo <<
' ' <<
'"';
199 OS.write_escaped(CurFilename);
203 OS.write(Extra, ExtraLen);
217 bool PrintPPOutputPPCallbacks::MoveToLine(
unsigned LineNo) {
220 if (LineNo-CurLine <= 8) {
221 if (LineNo-CurLine == 1)
223 else if (LineNo == CurLine)
226 const char *NewLines =
"\n\n\n\n\n\n\n\n";
227 OS.write(NewLines, LineNo-CurLine);
229 }
else if (!DisableLineMarkers) {
231 WriteLineInfo(LineNo,
nullptr, 0);
235 startNewLineIfNeeded(
false);
243 PrintPPOutputPPCallbacks::startNewLineIfNeeded(
bool ShouldUpdateCurrentLine) {
244 if (EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) {
246 EmittedTokensOnThisLine =
false;
247 EmittedDirectiveOnThisLine =
false;
248 if (ShouldUpdateCurrentLine)
260 FileChangeReason Reason,
276 MoveToLine(IncludeLoc);
290 FileType = NewFileType;
292 if (DisableLineMarkers) {
293 startNewLineIfNeeded(
false);
298 WriteLineInfo(CurLine);
307 IsFirstFileEntered =
true;
313 WriteLineInfo(CurLine,
" 1", 2);
316 WriteLineInfo(CurLine,
" 2", 2);
320 WriteLineInfo(CurLine);
325 void PrintPPOutputPPCallbacks::InclusionDirective(
327 const Token &IncludeTok,
332 StringRef SearchPath,
333 StringRef RelativePath,
338 if (DumpIncludeDirectives) {
339 startNewLineIfNeeded();
341 const std::string TokenText = PP.getSpelling(IncludeTok);
342 assert(!TokenText.empty());
343 OS <<
"#" << TokenText <<
" " 344 << (IsAngled ?
'<' :
'"') << FileName << (IsAngled ?
'>' :
'"')
345 <<
" /* clang -E -dI */";
346 setEmittedDirectiveOnThisLine();
347 startNewLineIfNeeded();
356 startNewLineIfNeeded();
359 <<
" /* clang -E: implicit import for " 360 <<
"#" << PP.getSpelling(IncludeTok) <<
" " 361 << (IsAngled ?
'<' :
'"') << FileName << (IsAngled ?
'>' :
'"')
365 EmittedTokensOnThisLine =
true;
366 startNewLineIfNeeded();
378 llvm_unreachable(
"unknown include directive kind");
385 void PrintPPOutputPPCallbacks::BeginModule(
const Module *M) {
386 startNewLineIfNeeded();
388 setEmittedDirectiveOnThisLine();
392 void PrintPPOutputPPCallbacks::EndModule(
const Module *M) {
393 startNewLineIfNeeded();
395 setEmittedDirectiveOnThisLine();
400 void PrintPPOutputPPCallbacks::Ident(
SourceLocation Loc, StringRef S) {
403 OS.write(
"#ident ", strlen(
"#ident "));
404 OS.write(S.begin(), S.size());
405 EmittedTokensOnThisLine =
true;
409 void PrintPPOutputPPCallbacks::MacroDefined(
const Token &MacroNameTok,
419 setEmittedDirectiveOnThisLine();
422 void PrintPPOutputPPCallbacks::MacroUndefined(
const Token &MacroNameTok,
426 if (!DumpDefines)
return;
430 setEmittedDirectiveOnThisLine();
434 for (
unsigned char Char : Str) {
435 if (
isPrintable(Char) && Char !=
'\\' && Char !=
'"')
439 << (char)(
'0' + ((Char >> 6) & 7))
440 << (char)(
'0' + ((Char >> 3) & 7))
441 << (char)(
'0' + ((Char >> 0) & 7));
447 PragmaMessageKind
Kind,
449 startNewLineIfNeeded();
452 if (!Namespace.empty())
453 OS << Namespace <<
' ';
468 if (
Kind == PMK_Message)
470 setEmittedDirectiveOnThisLine();
474 StringRef DebugType) {
475 startNewLineIfNeeded();
478 OS <<
"#pragma clang __debug ";
481 setEmittedDirectiveOnThisLine();
484 void PrintPPOutputPPCallbacks::
486 startNewLineIfNeeded();
488 OS <<
"#pragma " << Namespace <<
" diagnostic push";
489 setEmittedDirectiveOnThisLine();
492 void PrintPPOutputPPCallbacks::
494 startNewLineIfNeeded();
496 OS <<
"#pragma " << Namespace <<
" diagnostic pop";
497 setEmittedDirectiveOnThisLine();
500 void PrintPPOutputPPCallbacks::PragmaDiagnostic(
SourceLocation Loc,
504 startNewLineIfNeeded();
506 OS <<
"#pragma " << Namespace <<
" diagnostic ";
524 OS <<
" \"" << Str <<
'"';
525 setEmittedDirectiveOnThisLine();
529 StringRef WarningSpec,
531 startNewLineIfNeeded();
533 OS <<
"#pragma warning(" << WarningSpec <<
':';
537 setEmittedDirectiveOnThisLine();
540 void PrintPPOutputPPCallbacks::PragmaWarningPush(
SourceLocation Loc,
542 startNewLineIfNeeded();
544 OS <<
"#pragma warning(push";
548 setEmittedDirectiveOnThisLine();
551 void PrintPPOutputPPCallbacks::PragmaWarningPop(
SourceLocation Loc) {
552 startNewLineIfNeeded();
554 OS <<
"#pragma warning(pop)";
555 setEmittedDirectiveOnThisLine();
558 void PrintPPOutputPPCallbacks::PragmaExecCharsetPush(
SourceLocation Loc,
560 startNewLineIfNeeded();
562 OS <<
"#pragma character_execution_set(push";
566 setEmittedDirectiveOnThisLine();
569 void PrintPPOutputPPCallbacks::PragmaExecCharsetPop(
SourceLocation Loc) {
570 startNewLineIfNeeded();
572 OS <<
"#pragma character_execution_set(pop)";
573 setEmittedDirectiveOnThisLine();
576 void PrintPPOutputPPCallbacks::
578 startNewLineIfNeeded();
580 OS <<
"#pragma clang assume_nonnull begin";
581 setEmittedDirectiveOnThisLine();
584 void PrintPPOutputPPCallbacks::
586 startNewLineIfNeeded();
588 OS <<
"#pragma clang assume_nonnull end";
589 setEmittedDirectiveOnThisLine();
597 bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(
Token &
Tok) {
620 if (ColNo <= 1 && Tok.
is(tok::hash))
624 for (; ColNo > 1; --ColNo)
630 void PrintPPOutputPPCallbacks::HandleNewlinesInToken(
const char *TokStr,
632 unsigned NumNewlines = 0;
633 for (; Len; --Len, ++TokStr) {
634 if (*TokStr !=
'\n' &&
642 (TokStr[1] ==
'\n' || TokStr[1] ==
'\r') &&
643 TokStr[0] != TokStr[1]) {
649 if (NumNewlines == 0)
return;
651 CurLine += NumNewlines;
658 PrintPPOutputPPCallbacks *Callbacks;
661 bool ShouldExpandTokens;
663 UnknownPragmaHandler(
const char *prefix, PrintPPOutputPPCallbacks *callbacks,
664 bool RequireTokenExpansion)
665 : Prefix(prefix), Callbacks(callbacks),
666 ShouldExpandTokens(RequireTokenExpansion) {}
668 Token &PragmaTok)
override {
671 Callbacks->startNewLineIfNeeded();
673 Callbacks->OS.write(Prefix, strlen(Prefix));
675 if (ShouldExpandTokens) {
678 auto Toks = std::make_unique<Token[]>(1);
680 PP.EnterTokenStream(std::move(Toks), 1,
691 while (PragmaTok.
isNot(tok::eod)) {
693 Callbacks->AvoidConcat(PrevPrevToken, PrevToken, PragmaTok))
694 Callbacks->OS <<
' ';
696 Callbacks->OS.write(&TokSpell[0], TokSpell.size());
698 PrevPrevToken = PrevToken;
699 PrevToken = PragmaTok;
701 if (ShouldExpandTokens)
706 Callbacks->setEmittedDirectiveOnThisLine();
713 PrintPPOutputPPCallbacks *Callbacks,
715 bool DropComments = PP.
getLangOpts().TraditionalCPP &&
719 Token PrevPrevTok, PrevTok;
723 if (Callbacks->hasEmittedDirectiveOnThisLine()) {
724 Callbacks->startNewLineIfNeeded();
734 (Callbacks->hasEmittedTokensOnThisLine() &&
736 Callbacks->AvoidConcat(PrevPrevTok, PrevTok, Tok))) {
740 if (DropComments && Tok.
is(tok::comment)) {
746 }
else if (Tok.
is(tok::eod)) {
752 }
else if (Tok.
is(tok::annot_module_include)) {
757 }
else if (Tok.
is(tok::annot_module_begin)) {
764 Callbacks->BeginModule(
768 }
else if (Tok.
is(tok::annot_module_end)) {
769 Callbacks->EndModule(
773 }
else if (Tok.
is(tok::annot_header_unit)) {
780 OS.write(Name.data(), Name.size());
781 Callbacks->HandleNewlinesInToken(Name.data(), Name.size());
792 }
else if (Tok.
getLength() < llvm::array_lengthof(Buffer)) {
793 const char *TokPtr = Buffer;
795 OS.write(TokPtr, Len);
799 if (Tok.
getKind() == tok::comment || Tok.
getKind() == tok::unknown)
800 Callbacks->HandleNewlinesInToken(TokPtr, Len);
803 OS.write(S.data(), S.size());
807 if (Tok.
getKind() == tok::comment || Tok.
getKind() == tok::unknown)
808 Callbacks->HandleNewlinesInToken(S.data(), S.size());
810 Callbacks->setEmittedTokensOnThisLine();
814 PrevPrevTok = PrevTok;
822 return LHS->first->getName().compare(RHS->first->getName());
840 auto *MD = I->second.getLatest();
841 if (MD && MD->isDefined())
844 llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(),
MacroIDCompare);
846 for (
unsigned i = 0, e = MacrosByID.size(); i != e; ++i) {
862 assert(Opts.
ShowMacros &&
"Not yet implemented!");
871 PrintPPOutputPPCallbacks *Callbacks =
new PrintPPOutputPPCallbacks(
878 std::unique_ptr<UnknownPragmaHandler> MicrosoftExtHandler(
879 new UnknownPragmaHandler(
880 "#pragma", Callbacks,
883 std::unique_ptr<UnknownPragmaHandler> GCCHandler(
new UnknownPragmaHandler(
884 "#pragma GCC", Callbacks,
887 std::unique_ptr<UnknownPragmaHandler> ClangHandler(
new UnknownPragmaHandler(
888 "#pragma clang", Callbacks,
900 std::unique_ptr<UnknownPragmaHandler> OpenMPHandler(
901 new UnknownPragmaHandler(
"#pragma omp", Callbacks,
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, Preprocessor &PP, raw_ostream &OS)
PrintMacroDefinition - Print a macro definition in a form that will be properly accepted back as a de...
param_iterator param_begin() const
std::pair< const IdentifierInfo *, MacroInfo * > id_macro_pair
void AddPragmaHandler(StringRef Namespace, PragmaHandler *Handler)
Add the specified pragma handler to this preprocessor.
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)) {...
Defines the SourceManager interface.
TokenConcatenation class, which answers the question of "Is it safe to emit two tokens without a whit...
Defines the clang::MacroInfo and clang::MacroDirective classes.
A description of the current definition of a macro.
void IgnorePragmas()
Install empty handlers for all pragmas (making them ignored).
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing)...
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
This interface provides a way to observe the actions of the preprocessor as it does its thing...
bool isAnnotation() const
Return true if this is any of tok::annot_* kind tokens.
tokens_iterator tokens_begin() const
tok::TokenKind getKind() const
bool isLiteral() const
Return true if this is a "literal", like a numeric constant, string, etc.
One of these records is kept for each identifier that is lexed.
Token - This structure provides full information about a lexed token.
void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments)
Control whether the preprocessor retains comments in output.
const LangOptions & getLangOpts() const
Describes a module or submodule.
param_iterator param_end() const
std::string getFullModuleName(bool AllowStringLiterals=false) const
Retrieve the full name of this module, including the path from its top-level module.
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 ...
macro_iterator macro_begin(bool IncludeExternalMacros=true) const
Defines the Diagnostic-related interfaces.
Present this diagnostic as an error.
macro_iterator macro_end(bool IncludeExternalMacros=true) const
void LexUnexpandedToken(Token &Result)
Just like Lex, but disables macro expansion of identifier tokens.
IdentifierInfo *const * param_iterator
Parameters - The list of parameters for a function-like macro.
PreprocessorOutputOptions - Options for controlling the C preprocessor output (e.g., -E).
void DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, const PreprocessorOutputOptions &Opts)
DoPrintPreprocessedInput - Implement -E mode.
static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS)
Represents a character-granular source range.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
static void outputPrintable(raw_ostream &OS, StringRef Str)
unsigned getLine() const
Return the presumed line number of this location.
void EnterMainSourceFile()
Enter the specified FileID as the main source file, which implicitly adds the builtin defines etc...
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file. ...
Defines the clang::Preprocessor interface.
void RemovePragmaHandler(StringRef Namespace, PragmaHandler *Handler)
Remove the specific pragma handler from this preprocessor.
bool getCommentRetentionState() const
unsigned ShowMacros
Print macro definitions.
Record the location of an inclusion directive, such as an #include or #import statement.
Represents an unpacked "presumed" location which can be presented to the user.
SourceManager & getSourceManager() const
const char * getFilename() const
Return the presumed filename of this location.
unsigned ShowIncludeDirectives
Print includes, imports etc. within preprocessed output.
Encapsulates changes to the "macros namespace" (the location where the macro name became active...
static int MacroIDCompare(const id_macro_pair *LHS, const id_macro_pair *RHS)
Encodes a location in the source.
IdentifierInfo * getIdentifierInfo() const
Cached information about one file (either on disk or in the virtual file system). ...
void Lex(Token &Result)
Lex the next token for this preprocessor.
bool isAtStartOfLine() const
isAtStartOfLine - Return true if this token is at the start of a line.
unsigned UseLineDirectives
Use #line instead of GCC-style # N.
LLVM_READONLY bool isPrintable(unsigned char c)
Return true if this character is an ASCII printable character; that is, a character that should take ...
const MacroInfo * getMacroInfo() const
unsigned ShowComments
Show comments.
StringRef getName() const
Return the actual identifier string.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool isNot(tok::TokenKind K) const
unsigned getExpansionColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
bool isFunctionLike() const
Present this diagnostic as a remark.
PragmaHandler - Instances of this interface defined to handle the various pragmas that the language f...
tok::PPKeywordKind getPPKeywordID() const
Return the preprocessor keyword ID for this identifier.
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.
unsigned getLength() const
Encapsulates the data about a macro definition (e.g.
const char * getLiteralData() const
getLiteralData - For a literal token (numeric constant, string, etc), this returns a pointer to the s...
SourceLocation getDefinitionLoc() const
Return the location that the macro was defined at.
bool AvoidConcat(const Token &PrevPrevTok, const Token &PrevTok, const Token &Tok) const
AvoidConcat - If printing PrevTok immediately followed by Tok would cause the two individual tokens t...
bool tokens_empty() const
Defines the PPCallbacks interface.
unsigned ShowMacroComments
Show comments, even in macros.
ArrayRef< Token > tokens() const
Do not present this diagnostic, ignore it.
bool isBuiltinMacro() const
Return true if this macro requires processing before expansion.
unsigned ShowLineMarkers
Show #line markers.
bool needsCleaning() const
Return true if this token has trigraphs or escaped newlines in it.
bool isGNUVarargs() const
MacroMap::const_iterator macro_iterator
unsigned ShowCPP
Print normal preprocessed output.
MacroInfo * getMacroInfo() const
Get the MacroInfo that should be used for this definition.
Present this diagnostic as a fatal error.
Describes how and where the pragma was introduced.
Present this diagnostic as a warning.
SourceLocation getIncludeLoc() const
Return the presumed include location of this location.
void * getAnnotationValue() const
bool hasLeadingSpace() const
Return true if this token has whitespace before it.
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
This class handles loading and caching of source files into memory.
void startToken()
Reset all flags to cleared.
static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, PrintPPOutputPPCallbacks *Callbacks, raw_ostream &OS)
Engages in a tight little dance with the lexer to efficiently preprocess tokens.