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 DumpIncludeDirectives;
97 bool UseLineDirectives;
98 bool IsFirstFileEntered;
100 PrintPPOutputPPCallbacks(
Preprocessor &pp, raw_ostream &os,
bool lineMarkers,
101 bool defines,
bool DumpIncludeDirectives,
102 bool UseLineDirectives)
103 : PP(pp),
SM(PP.getSourceManager()), ConcatInfo(PP), OS(os),
104 DisableLineMarkers(lineMarkers), DumpDefines(defines),
105 DumpIncludeDirectives(DumpIncludeDirectives),
106 UseLineDirectives(UseLineDirectives) {
108 CurFilename +=
"<uninit>";
109 EmittedTokensOnThisLine =
false;
110 EmittedDirectiveOnThisLine =
false;
113 IsFirstFileEntered =
false;
116 void setEmittedTokensOnThisLine() { EmittedTokensOnThisLine =
true; }
117 bool hasEmittedTokensOnThisLine()
const {
return EmittedTokensOnThisLine; }
119 void setEmittedDirectiveOnThisLine() { EmittedDirectiveOnThisLine =
true; }
120 bool hasEmittedDirectiveOnThisLine()
const {
121 return EmittedDirectiveOnThisLine;
124 bool startNewLineIfNeeded(
bool ShouldUpdateCurrentLine =
true);
132 StringRef SearchPath, StringRef RelativePath,
133 const Module *Imported)
override;
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;
147 bool HandleFirstTokOnLine(
Token &Tok);
158 bool MoveToLine(
unsigned LineNo);
160 bool AvoidConcat(
const Token &PrevPrevTok,
const Token &PrevTok,
162 return ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok);
164 void WriteLineInfo(
unsigned LineNo,
const char *Extra=
nullptr,
165 unsigned ExtraLen=0);
166 bool LineMarkersAreDisabled()
const {
return DisableLineMarkers; }
167 void HandleNewlinesInToken(
const char *TokStr,
unsigned Len);
170 void MacroDefined(
const Token &MacroNameTok,
174 void MacroUndefined(
const Token &MacroNameTok,
178 void BeginModule(
const Module *M);
179 void EndModule(
const Module *M);
183 void PrintPPOutputPPCallbacks::WriteLineInfo(
unsigned LineNo,
186 startNewLineIfNeeded(
false);
189 if (UseLineDirectives) {
190 OS <<
"#line" <<
' ' << LineNo <<
' ' <<
'"';
191 OS.write_escaped(CurFilename);
194 OS <<
'#' <<
' ' << LineNo <<
' ' <<
'"';
195 OS.write_escaped(CurFilename);
199 OS.write(Extra, ExtraLen);
213 bool PrintPPOutputPPCallbacks::MoveToLine(
unsigned LineNo) {
216 if (LineNo-CurLine <= 8) {
217 if (LineNo-CurLine == 1)
219 else if (LineNo == CurLine)
222 const char *NewLines =
"\n\n\n\n\n\n\n\n";
223 OS.write(NewLines, LineNo-CurLine);
225 }
else if (!DisableLineMarkers) {
227 WriteLineInfo(LineNo,
nullptr, 0);
231 startNewLineIfNeeded(
false);
239 PrintPPOutputPPCallbacks::startNewLineIfNeeded(
bool ShouldUpdateCurrentLine) {
240 if (EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) {
242 EmittedTokensOnThisLine =
false;
243 EmittedDirectiveOnThisLine =
false;
244 if (ShouldUpdateCurrentLine)
256 FileChangeReason Reason,
272 MoveToLine(IncludeLoc);
286 FileType = NewFileType;
288 if (DisableLineMarkers) {
289 startNewLineIfNeeded(
false);
294 WriteLineInfo(CurLine);
303 IsFirstFileEntered =
true;
309 WriteLineInfo(CurLine,
" 1", 2);
312 WriteLineInfo(CurLine,
" 2", 2);
316 WriteLineInfo(CurLine);
321 void PrintPPOutputPPCallbacks::InclusionDirective(
SourceLocation HashLoc,
322 const Token &IncludeTok,
327 StringRef SearchPath,
328 StringRef RelativePath,
332 if (DumpIncludeDirectives) {
333 startNewLineIfNeeded();
335 const std::string TokenText = PP.getSpelling(IncludeTok);
336 assert(!TokenText.empty());
337 OS <<
"#" << TokenText <<
" "
338 << (IsAngled ?
'<' :
'"') << FileName << (IsAngled ?
'>' :
'"')
339 <<
" /* clang -E -dI */";
340 setEmittedDirectiveOnThisLine();
341 startNewLineIfNeeded();
347 case tok::pp_include:
349 case tok::pp_include_next:
350 startNewLineIfNeeded();
353 <<
" /* clang -E: implicit import for "
354 <<
"#" << PP.getSpelling(IncludeTok) <<
" "
355 << (IsAngled ?
'<' :
'"') << FileName << (IsAngled ?
'>' :
'"')
359 EmittedTokensOnThisLine =
true;
360 startNewLineIfNeeded();
363 case tok::pp___include_macros:
372 llvm_unreachable(
"unknown include directive kind");
379 void PrintPPOutputPPCallbacks::BeginModule(
const Module *M) {
380 startNewLineIfNeeded();
382 setEmittedDirectiveOnThisLine();
386 void PrintPPOutputPPCallbacks::EndModule(
const Module *M) {
387 startNewLineIfNeeded();
389 setEmittedDirectiveOnThisLine();
394 void PrintPPOutputPPCallbacks::Ident(
SourceLocation Loc, StringRef
S) {
397 OS.write(
"#ident ", strlen(
"#ident "));
398 OS.write(S.begin(), S.size());
399 EmittedTokensOnThisLine =
true;
403 void PrintPPOutputPPCallbacks::MacroDefined(
const Token &MacroNameTok,
413 setEmittedDirectiveOnThisLine();
416 void PrintPPOutputPPCallbacks::MacroUndefined(
const Token &MacroNameTok,
420 if (!DumpDefines)
return;
424 setEmittedDirectiveOnThisLine();
428 for (
unsigned char Char : Str) {
429 if (
isPrintable(Char) && Char !=
'\\' && Char !=
'"')
433 << (char)(
'0' + ((Char >> 6) & 7))
434 << (char)(
'0' + ((Char >> 3) & 7))
435 << (char)(
'0' + ((Char >> 0) & 7));
441 PragmaMessageKind
Kind,
443 startNewLineIfNeeded();
446 if (!Namespace.empty())
447 OS << Namespace <<
' ';
462 if (Kind == PMK_Message)
464 setEmittedDirectiveOnThisLine();
468 StringRef DebugType) {
469 startNewLineIfNeeded();
472 OS <<
"#pragma clang __debug ";
475 setEmittedDirectiveOnThisLine();
478 void PrintPPOutputPPCallbacks::
480 startNewLineIfNeeded();
482 OS <<
"#pragma " << Namespace <<
" diagnostic push";
483 setEmittedDirectiveOnThisLine();
486 void PrintPPOutputPPCallbacks::
488 startNewLineIfNeeded();
490 OS <<
"#pragma " << Namespace <<
" diagnostic pop";
491 setEmittedDirectiveOnThisLine();
494 void PrintPPOutputPPCallbacks::PragmaDiagnostic(
SourceLocation Loc,
498 startNewLineIfNeeded();
500 OS <<
"#pragma " << Namespace <<
" diagnostic ";
518 OS <<
" \"" << Str <<
'"';
519 setEmittedDirectiveOnThisLine();
523 StringRef WarningSpec,
525 startNewLineIfNeeded();
527 OS <<
"#pragma warning(" << WarningSpec <<
':';
531 setEmittedDirectiveOnThisLine();
534 void PrintPPOutputPPCallbacks::PragmaWarningPush(
SourceLocation Loc,
536 startNewLineIfNeeded();
538 OS <<
"#pragma warning(push";
542 setEmittedDirectiveOnThisLine();
545 void PrintPPOutputPPCallbacks::PragmaWarningPop(
SourceLocation Loc) {
546 startNewLineIfNeeded();
548 OS <<
"#pragma warning(pop)";
549 setEmittedDirectiveOnThisLine();
557 bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(
Token &Tok) {
580 if (ColNo <= 1 && Tok.
is(tok::hash))
584 for (; ColNo > 1; --ColNo)
590 void PrintPPOutputPPCallbacks::HandleNewlinesInToken(
const char *TokStr,
592 unsigned NumNewlines = 0;
593 for (; Len; --Len, ++TokStr) {
594 if (*TokStr !=
'\n' &&
602 (TokStr[1] ==
'\n' || TokStr[1] ==
'\r') &&
603 TokStr[0] != TokStr[1]) {
609 if (NumNewlines == 0)
return;
611 CurLine += NumNewlines;
618 PrintPPOutputPPCallbacks *Callbacks;
621 bool ShouldExpandTokens;
623 UnknownPragmaHandler(
const char *prefix, PrintPPOutputPPCallbacks *callbacks,
624 bool RequireTokenExpansion)
625 : Prefix(prefix), Callbacks(callbacks),
626 ShouldExpandTokens(RequireTokenExpansion) {}
628 Token &PragmaTok)
override {
631 Callbacks->startNewLineIfNeeded();
633 Callbacks->OS.write(Prefix, strlen(Prefix));
635 if (ShouldExpandTokens) {
638 auto Toks = llvm::make_unique<Token[]>(1);
640 PP.EnterTokenStream(std::move(Toks), 1,
650 while (PragmaTok.
isNot(tok::eod)) {
652 Callbacks->AvoidConcat(PrevPrevToken, PrevToken, PragmaTok))
653 Callbacks->OS <<
' ';
655 Callbacks->OS.write(&TokSpell[0], TokSpell.size());
657 PrevPrevToken = PrevToken;
658 PrevToken = PragmaTok;
660 if (ShouldExpandTokens)
665 Callbacks->setEmittedDirectiveOnThisLine();
672 PrintPPOutputPPCallbacks *Callbacks,
674 bool DropComments = PP.
getLangOpts().TraditionalCPP &&
678 Token PrevPrevTok, PrevTok;
682 if (Callbacks->hasEmittedDirectiveOnThisLine()) {
683 Callbacks->startNewLineIfNeeded();
693 (Callbacks->hasEmittedTokensOnThisLine() &&
695 Callbacks->AvoidConcat(PrevPrevTok, PrevTok, Tok))) {
699 if (DropComments && Tok.
is(tok::comment)) {
705 }
else if (Tok.
is(tok::annot_module_include)) {
710 }
else if (Tok.
is(tok::annot_module_begin)) {
717 Callbacks->BeginModule(
721 }
else if (Tok.
is(tok::annot_module_end)) {
722 Callbacks->EndModule(
732 const char *TokPtr =
Buffer;
734 OS.write(TokPtr, Len);
738 if (Tok.
getKind() == tok::comment || Tok.
getKind() == tok::unknown)
739 Callbacks->HandleNewlinesInToken(TokPtr, Len);
742 OS.write(&S[0], S.size());
746 if (Tok.
getKind() == tok::comment || Tok.
getKind() == tok::unknown)
747 Callbacks->HandleNewlinesInToken(&S[0], S.size());
749 Callbacks->setEmittedTokensOnThisLine();
753 PrevPrevTok = PrevTok;
761 return LHS->first->getName().compare(RHS->first->getName());
779 auto *MD =
I->second.getLatest();
780 if (MD && MD->isDefined())
783 llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(),
MacroIDCompare);
785 for (
unsigned i = 0, e = MacrosByID.size(); i != e; ++i) {
801 assert(Opts.
ShowMacros &&
"Not yet implemented!");
810 PrintPPOutputPPCallbacks *Callbacks =
new PrintPPOutputPPCallbacks(
817 std::unique_ptr<UnknownPragmaHandler> MicrosoftExtHandler(
818 new UnknownPragmaHandler(
819 "#pragma", Callbacks,
822 std::unique_ptr<UnknownPragmaHandler> GCCHandler(
new UnknownPragmaHandler(
823 "#pragma GCC", Callbacks,
826 std::unique_ptr<UnknownPragmaHandler> ClangHandler(
new UnknownPragmaHandler(
827 "#pragma clang", Callbacks,
839 std::unique_ptr<UnknownPragmaHandler> OpenMPHandler(
840 new UnknownPragmaHandler(
"#pragma omp", Callbacks,
bool isAtStartOfLine() const
isAtStartOfLine - Return true if this token is at the start of a line.
SourceManager & getSourceManager() const
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 isInvalid() const
Return true if this object is invalid or uninitialized.
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.
bool hasLeadingSpace() const
Return true if this token has whitespace before it.
A description of the current definition of a macro.
std::unique_ptr< llvm::MemoryBuffer > Buffer
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).
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing)...
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
Return the 'spelling' of the token at the given location; does not go up to the spelling location or ...
One of these records is kept for each identifier that is lexed.
const LangOptions & getLangOpts() const
std::string getFullModuleName(bool AllowStringLiterals=false) const
Retrieve the full name of this module, including the path from its top-level module.
Token - This structure provides full information about a lexed token.
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
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
bool getCommentRetentionState() const
Defines the Diagnostic-related interfaces.
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.
detail::InMemoryDirectory::const_iterator I
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 * getAnnotationValue() const
param_iterator param_end() const
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)
StringRef getName() const
Return the actual identifier string.
Represents a character-granular source range.
static void outputPrintable(raw_ostream &OS, StringRef Str)
void EnterMainSourceFile()
Enter the specified FileID as the main source file, which implicitly adds the builtin defines etc...
Defines the clang::Preprocessor interface.
void RemovePragmaHandler(StringRef Namespace, PragmaHandler *Handler)
Remove the specific pragma handler from this preprocessor.
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.
unsigned Map[FirstTargetAddressSpace]
The type of a lookup table which maps from language-specific address spaces to target-specific ones...
unsigned ShowIncludeDirectives
Print includes, imports etc. within preprocessed output.
const char * getLiteralData() const
getLiteralData - For a literal token (numeric constant, string, etc), this returns a pointer to the s...
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.
Encodes a location in the source.
IdentifierInfo *const * param_iterator
Parameters - The list of parameters for a function-like macro.
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
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {...
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)
Return true if this character is an ASCII printable character; that is, a character that should take ...
Present this diagnostic as a remark.
bool isGNUVarargs() const
PragmaHandler - Instances of this interface defined to handle the various pragmas that the language f...
const MacroInfo * getMacroInfo() const
detail::InMemoryDirectory::const_iterator E
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.
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.
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
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.