25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/ADT/SmallString.h"
27 #include "llvm/ADT/StringRef.h"
28 #include "llvm/Support/ErrorHandling.h"
29 #include "llvm/Support/raw_ostream.h"
31 using namespace clang;
37 OS <<
"#define " << II.
getName();
43 for (; AI+1 != E; ++AI) {
44 OS << (*AI)->getName();
49 if ((*AI)->getName() ==
"__VA_ARGS__")
52 OS << (*AI)->getName();
67 for (
const auto &T : MI.
tokens()) {
68 if (T.hasLeadingSpace())
80 class PrintPPOutputPPCallbacks :
public PPCallbacks {
89 bool EmittedTokensOnThisLine;
90 bool EmittedDirectiveOnThisLine;
94 bool DisableLineMarkers;
96 bool UseLineDirectives;
97 bool IsFirstFileEntered;
99 PrintPPOutputPPCallbacks(
Preprocessor &pp, raw_ostream &os,
bool lineMarkers,
100 bool defines,
bool UseLineDirectives)
101 : PP(pp),
SM(PP.getSourceManager()), ConcatInfo(PP), OS(os),
102 DisableLineMarkers(lineMarkers), DumpDefines(defines),
103 UseLineDirectives(UseLineDirectives) {
105 CurFilename +=
"<uninit>";
106 EmittedTokensOnThisLine =
false;
107 EmittedDirectiveOnThisLine =
false;
110 IsFirstFileEntered =
false;
113 void setEmittedTokensOnThisLine() { EmittedTokensOnThisLine =
true; }
114 bool hasEmittedTokensOnThisLine()
const {
return EmittedTokensOnThisLine; }
116 void setEmittedDirectiveOnThisLine() { EmittedDirectiveOnThisLine =
true; }
117 bool hasEmittedDirectiveOnThisLine()
const {
118 return EmittedDirectiveOnThisLine;
121 bool startNewLineIfNeeded(
bool ShouldUpdateCurrentLine =
true);
127 StringRef FileName,
bool IsAngled,
129 StringRef SearchPath, StringRef RelativePath,
130 const Module *Imported)
override;
133 PragmaMessageKind
Kind, StringRef Str)
override;
134 void PragmaDebug(
SourceLocation Loc, StringRef DebugType)
override;
135 void PragmaDiagnosticPush(
SourceLocation Loc, StringRef Namespace)
override;
136 void PragmaDiagnosticPop(
SourceLocation Loc, StringRef Namespace)
override;
144 bool HandleFirstTokOnLine(
Token &Tok);
155 bool MoveToLine(
unsigned LineNo);
157 bool AvoidConcat(
const Token &PrevPrevTok,
const Token &PrevTok,
159 return ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok);
161 void WriteLineInfo(
unsigned LineNo,
const char *Extra=
nullptr,
162 unsigned ExtraLen=0);
163 bool LineMarkersAreDisabled()
const {
return DisableLineMarkers; }
164 void HandleNewlinesInToken(
const char *TokStr,
unsigned Len);
167 void MacroDefined(
const Token &MacroNameTok,
171 void MacroUndefined(
const Token &MacroNameTok,
176 void PrintPPOutputPPCallbacks::WriteLineInfo(
unsigned LineNo,
179 startNewLineIfNeeded(
false);
182 if (UseLineDirectives) {
183 OS <<
"#line" <<
' ' << LineNo <<
' ' <<
'"';
184 OS.write_escaped(CurFilename);
187 OS <<
'#' <<
' ' << LineNo <<
' ' <<
'"';
188 OS.write_escaped(CurFilename);
192 OS.write(Extra, ExtraLen);
206 bool PrintPPOutputPPCallbacks::MoveToLine(
unsigned LineNo) {
209 if (LineNo-CurLine <= 8) {
210 if (LineNo-CurLine == 1)
212 else if (LineNo == CurLine)
215 const char *NewLines =
"\n\n\n\n\n\n\n\n";
216 OS.write(NewLines, LineNo-CurLine);
218 }
else if (!DisableLineMarkers) {
220 WriteLineInfo(LineNo,
nullptr, 0);
224 startNewLineIfNeeded(
false);
232 PrintPPOutputPPCallbacks::startNewLineIfNeeded(
bool ShouldUpdateCurrentLine) {
233 if (EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) {
235 EmittedTokensOnThisLine =
false;
236 EmittedDirectiveOnThisLine =
false;
237 if (ShouldUpdateCurrentLine)
249 FileChangeReason Reason,
265 MoveToLine(IncludeLoc);
279 FileType = NewFileType;
281 if (DisableLineMarkers) {
282 startNewLineIfNeeded(
false);
287 WriteLineInfo(CurLine);
296 IsFirstFileEntered =
true;
302 WriteLineInfo(CurLine,
" 1", 2);
305 WriteLineInfo(CurLine,
" 2", 2);
309 WriteLineInfo(CurLine);
314 void PrintPPOutputPPCallbacks::InclusionDirective(
SourceLocation HashLoc,
315 const Token &IncludeTok,
320 StringRef SearchPath,
321 StringRef RelativePath,
327 startNewLineIfNeeded();
330 <<
" /* clang -E: implicit import for \"" << File->
getName() <<
"\" */";
333 EmittedTokensOnThisLine =
true;
334 startNewLineIfNeeded();
340 void PrintPPOutputPPCallbacks::Ident(
SourceLocation Loc, StringRef
S) {
343 OS.write(
"#ident ", strlen(
"#ident "));
344 OS.write(S.begin(), S.size());
345 EmittedTokensOnThisLine =
true;
349 void PrintPPOutputPPCallbacks::MacroDefined(
const Token &MacroNameTok,
359 setEmittedDirectiveOnThisLine();
362 void PrintPPOutputPPCallbacks::MacroUndefined(
const Token &MacroNameTok,
365 if (!DumpDefines)
return;
369 setEmittedDirectiveOnThisLine();
373 const std::string &Str) {
374 for (
unsigned i = 0, e = Str.size(); i != e; ++i) {
375 unsigned char Char = Str[i];
376 if (
isPrintable(Char) && Char !=
'\\' && Char !=
'"')
380 << (char)(
'0'+ ((Char >> 6) & 7))
381 << (char)(
'0'+ ((Char >> 3) & 7))
382 << (char)(
'0'+ ((Char >> 0) & 7));
388 PragmaMessageKind
Kind,
390 startNewLineIfNeeded();
393 if (!Namespace.empty())
394 OS << Namespace <<
' ';
409 if (Kind == PMK_Message)
411 setEmittedDirectiveOnThisLine();
415 StringRef DebugType) {
416 startNewLineIfNeeded();
419 OS <<
"#pragma clang __debug ";
422 setEmittedDirectiveOnThisLine();
425 void PrintPPOutputPPCallbacks::
427 startNewLineIfNeeded();
429 OS <<
"#pragma " << Namespace <<
" diagnostic push";
430 setEmittedDirectiveOnThisLine();
433 void PrintPPOutputPPCallbacks::
435 startNewLineIfNeeded();
437 OS <<
"#pragma " << Namespace <<
" diagnostic pop";
438 setEmittedDirectiveOnThisLine();
441 void PrintPPOutputPPCallbacks::PragmaDiagnostic(
SourceLocation Loc,
445 startNewLineIfNeeded();
447 OS <<
"#pragma " << Namespace <<
" diagnostic ";
465 OS <<
" \"" << Str <<
'"';
466 setEmittedDirectiveOnThisLine();
470 StringRef WarningSpec,
472 startNewLineIfNeeded();
474 OS <<
"#pragma warning(" << WarningSpec <<
':';
478 setEmittedDirectiveOnThisLine();
481 void PrintPPOutputPPCallbacks::PragmaWarningPush(
SourceLocation Loc,
483 startNewLineIfNeeded();
485 OS <<
"#pragma warning(push";
489 setEmittedDirectiveOnThisLine();
492 void PrintPPOutputPPCallbacks::PragmaWarningPop(
SourceLocation Loc) {
493 startNewLineIfNeeded();
495 OS <<
"#pragma warning(pop)";
496 setEmittedDirectiveOnThisLine();
504 bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(
Token &Tok) {
527 if (ColNo <= 1 && Tok.
is(tok::hash))
531 for (; ColNo > 1; --ColNo)
537 void PrintPPOutputPPCallbacks::HandleNewlinesInToken(
const char *TokStr,
539 unsigned NumNewlines = 0;
540 for (; Len; --Len, ++TokStr) {
541 if (*TokStr !=
'\n' &&
549 (TokStr[1] ==
'\n' || TokStr[1] ==
'\r') &&
550 TokStr[0] != TokStr[1])
554 if (NumNewlines == 0)
return;
556 CurLine += NumNewlines;
563 PrintPPOutputPPCallbacks *Callbacks;
566 bool ShouldExpandTokens;
568 UnknownPragmaHandler(
const char *prefix, PrintPPOutputPPCallbacks *callbacks,
569 bool RequireTokenExpansion)
570 : Prefix(prefix), Callbacks(callbacks),
571 ShouldExpandTokens(RequireTokenExpansion) {}
573 Token &PragmaTok)
override {
576 Callbacks->startNewLineIfNeeded();
578 Callbacks->OS.write(Prefix, strlen(Prefix));
586 while (PragmaTok.
isNot(tok::eod)) {
588 Callbacks->AvoidConcat(PrevPrevToken, PrevToken, PragmaTok))
589 Callbacks->OS <<
' ';
591 Callbacks->OS.write(&TokSpell[0], TokSpell.size());
593 PrevPrevToken = PrevToken;
594 PrevToken = PragmaTok;
596 if (ShouldExpandTokens)
601 Callbacks->setEmittedDirectiveOnThisLine();
608 PrintPPOutputPPCallbacks *Callbacks,
610 bool DropComments = PP.
getLangOpts().TraditionalCPP &&
614 Token PrevPrevTok, PrevTok;
618 if (Callbacks->hasEmittedDirectiveOnThisLine()) {
619 Callbacks->startNewLineIfNeeded();
629 (Callbacks->hasEmittedTokensOnThisLine() &&
631 Callbacks->AvoidConcat(PrevPrevTok, PrevTok, Tok))) {
635 if (DropComments && Tok.
is(tok::comment)) {
641 }
else if (Tok.
is(tok::annot_module_include) ||
642 Tok.
is(tok::annot_module_begin) ||
643 Tok.
is(tok::annot_module_end)) {
654 const char *TokPtr = Buffer;
656 OS.write(TokPtr, Len);
660 if (Tok.
getKind() == tok::comment || Tok.
getKind() == tok::unknown)
661 Callbacks->HandleNewlinesInToken(TokPtr, Len);
664 OS.write(&S[0], S.size());
668 if (Tok.
getKind() == tok::comment || Tok.
getKind() == tok::unknown)
669 Callbacks->HandleNewlinesInToken(&S[0], S.size());
671 Callbacks->setEmittedTokensOnThisLine();
675 PrevPrevTok = PrevTok;
683 return LHS->first->getName().compare(RHS->first->getName());
701 auto *MD = I->second.getLatest();
702 if (MD && MD->isDefined())
705 llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(),
MacroIDCompare);
707 for (
unsigned i = 0, e = MacrosByID.size(); i != e; ++i) {
723 assert(Opts.
ShowMacros &&
"Not yet implemented!");
732 PrintPPOutputPPCallbacks *Callbacks =
new PrintPPOutputPPCallbacks(
738 "#pragma", Callbacks,
741 "GCC",
new UnknownPragmaHandler(
742 "#pragma GCC", Callbacks,
745 "clang",
new UnknownPragmaHandler(
746 "#pragma clang", Callbacks,
755 new UnknownPragmaHandler(
"#pragma omp", Callbacks,
bool isAtStartOfLine() const
SourceManager & getSourceManager() const
static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, Preprocessor &PP, raw_ostream &OS)
std::pair< const IdentifierInfo *, MacroInfo * > id_macro_pair
void AddPragmaHandler(StringRef Namespace, PragmaHandler *Handler)
Add the specified pragma handler to this preprocessor.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
Defines the SourceManager interface.
Defines the clang::MacroInfo and clang::MacroDirective classes.
bool hasLeadingSpace() const
Return true if this token has whitespace before it.
A description of the current definition of a macro.
macro_iterator macro_begin(bool IncludeExternalMacros=true) const
bool needsCleaning() const
Return true if this token has trigraphs or escaped newlines in it.
MacroMap::const_iterator macro_iterator
void IgnorePragmas()
Install empty handlers for all pragmas (making them ignored).
SourceLocation getDefinitionLoc() const
Return the location that the macro was defined at.
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...
StringRef getSpelling(SourceLocation loc, SmallVectorImpl< char > &buffer, bool *invalid=nullptr) const
std::string getFullModuleName() const
Retrieve the full name of this module, including the path from its top-level module.
const LangOptions & getLangOpts() const
void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments)
Control whether the preprocessor retains comments in output.
bool tokens_empty() const
Describes a module or submodule.
MacroInfo * getMacroInfo() const
Get the MacroInfo that should be used for this definition.
unsigned getExpansionColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
static void outputPrintable(llvm::raw_ostream &OS, const std::string &Str)
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
bool getCommentRetentionState() const
tokens_iterator tokens_begin() const
Present this diagnostic as an error.
tok::TokenKind getKind() const
unsigned getLine() const
Return the presumed line number of this location.
PragmaIntroducerKind
Describes how the pragma was introduced, e.g., with #pragma, _Pragma, or __pragma.
SourceLocation getIncludeLoc() const
Return the presumed include location of this location.
ArrayRef< Token > tokens() const
void LexUnexpandedToken(Token &Result)
Just like Lex, but disables macro expansion of identifier tokens.
void DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, const PreprocessorOutputOptions &Opts)
DoPrintPreprocessedInput - Implement -E mode.
IdentifierInfo *const * arg_iterator
static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS)
StringRef getName() const
Return the actual identifier string.
Represents a character-granular source range.
void EnterMainSourceFile()
Enter the specified FileID as the main source file, which implicitly adds the builtin defines etc...
Defines the clang::Preprocessor interface.
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file. ...
bool isNot(tok::TokenKind K) 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.
arg_iterator arg_end() const
const char * getLiteralData() const
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)
const char * getFilename() const
Return the presumed filename of this location.
const char * getName() const
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
bool isValid() const
Return true if this is a valid SourceLocation object.
macro_iterator macro_end(bool IncludeExternalMacros=true) 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.
unsigned UseLineDirectives
Use #line instead of GCC-style # N.
bool is(tok::TokenKind K) const
unsigned ShowComments
Show comments.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
static LLVM_READONLY bool isPrintable(unsigned char c)
Present this diagnostic as a remark.
bool isGNUVarargs() const
const MacroInfo * getMacroInfo() const
Defines the Diagnostic-related interfaces.
bool isLiteral() const
Return true if this is a "literal", like a numeric constant, string, etc.
bool isFunctionLike() const
Encapsulates the data about a macro definition (e.g. its tokens).
bool isBuiltinMacro() const
Return true if this macro requires processing before expansion.
Defines the PPCallbacks interface.
unsigned ShowMacroComments
Show comments, even in macros.
Do not present this diagnostic, ignore it.
unsigned ShowLineMarkers
Show #line markers.
unsigned ShowCPP
Print normal preprocessed output.
unsigned getLength() const
Present this diagnostic as a fatal error.
arg_iterator arg_begin() const
Present this diagnostic as a warning.
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.
IdentifierInfo * getIdentifierInfo() const
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.