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)
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);
130 StringRef FileName,
bool IsAngled,
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;
149 bool HandleFirstTokOnLine(
Token &
Tok);
160 bool MoveToLine(
unsigned LineNo);
162 bool AvoidConcat(
const Token &PrevPrevTok,
const Token &PrevTok,
164 return ConcatInfo.
AvoidConcat(PrevPrevTok, PrevTok, Tok);
166 void WriteLineInfo(
unsigned LineNo,
const char *Extra=
nullptr,
167 unsigned ExtraLen=0);
168 bool LineMarkersAreDisabled()
const {
return DisableLineMarkers; }
169 void HandleNewlinesInToken(
const char *TokStr,
unsigned Len);
172 void MacroDefined(
const Token &MacroNameTok,
176 void MacroUndefined(
const Token &MacroNameTok,
180 void BeginModule(
const Module *M);
181 void EndModule(
const Module *M);
185 void PrintPPOutputPPCallbacks::WriteLineInfo(
unsigned LineNo,
188 startNewLineIfNeeded(
false);
191 if (UseLineDirectives) {
192 OS <<
"#line" <<
' ' << LineNo <<
' ' <<
'"';
193 OS.write_escaped(CurFilename);
196 OS <<
'#' <<
' ' << LineNo <<
' ' <<
'"';
197 OS.write_escaped(CurFilename);
201 OS.write(Extra, ExtraLen);
215 bool PrintPPOutputPPCallbacks::MoveToLine(
unsigned LineNo) {
218 if (LineNo-CurLine <= 8) {
219 if (LineNo-CurLine == 1)
221 else if (LineNo == CurLine)
224 const char *NewLines =
"\n\n\n\n\n\n\n\n";
225 OS.write(NewLines, LineNo-CurLine);
227 }
else if (!DisableLineMarkers) {
229 WriteLineInfo(LineNo,
nullptr, 0);
233 startNewLineIfNeeded(
false);
241 PrintPPOutputPPCallbacks::startNewLineIfNeeded(
bool ShouldUpdateCurrentLine) {
242 if (EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) {
244 EmittedTokensOnThisLine =
false;
245 EmittedDirectiveOnThisLine =
false;
246 if (ShouldUpdateCurrentLine)
258 FileChangeReason Reason,
274 MoveToLine(IncludeLoc);
288 FileType = NewFileType;
290 if (DisableLineMarkers) {
291 startNewLineIfNeeded(
false);
296 WriteLineInfo(CurLine);
305 IsFirstFileEntered =
true;
311 WriteLineInfo(CurLine,
" 1", 2);
314 WriteLineInfo(CurLine,
" 2", 2);
318 WriteLineInfo(CurLine);
323 void PrintPPOutputPPCallbacks::InclusionDirective(
SourceLocation HashLoc,
324 const Token &IncludeTok,
329 StringRef SearchPath,
330 StringRef RelativePath,
334 if (DumpIncludeDirectives) {
335 startNewLineIfNeeded();
337 const std::string TokenText = PP.getSpelling(IncludeTok);
338 assert(!TokenText.empty());
339 OS <<
"#" << TokenText <<
" " 340 << (IsAngled ?
'<' :
'"') << FileName << (IsAngled ?
'>' :
'"')
341 <<
" /* clang -E -dI */";
342 setEmittedDirectiveOnThisLine();
343 startNewLineIfNeeded();
349 case tok::pp_include:
351 case tok::pp_include_next:
352 startNewLineIfNeeded();
355 <<
" /* clang -E: implicit import for " 356 <<
"#" << PP.getSpelling(IncludeTok) <<
" " 357 << (IsAngled ?
'<' :
'"') << FileName << (IsAngled ?
'>' :
'"')
361 EmittedTokensOnThisLine =
true;
362 startNewLineIfNeeded();
365 case tok::pp___include_macros:
374 llvm_unreachable(
"unknown include directive kind");
381 void PrintPPOutputPPCallbacks::BeginModule(
const Module *M) {
382 startNewLineIfNeeded();
384 setEmittedDirectiveOnThisLine();
388 void PrintPPOutputPPCallbacks::EndModule(
const Module *M) {
389 startNewLineIfNeeded();
391 setEmittedDirectiveOnThisLine();
396 void PrintPPOutputPPCallbacks::Ident(
SourceLocation Loc, StringRef S) {
399 OS.write(
"#ident ", strlen(
"#ident "));
400 OS.write(S.begin(), S.size());
401 EmittedTokensOnThisLine =
true;
405 void PrintPPOutputPPCallbacks::MacroDefined(
const Token &MacroNameTok,
415 setEmittedDirectiveOnThisLine();
418 void PrintPPOutputPPCallbacks::MacroUndefined(
const Token &MacroNameTok,
422 if (!DumpDefines)
return;
426 setEmittedDirectiveOnThisLine();
430 for (
unsigned char Char : Str) {
431 if (
isPrintable(Char) && Char !=
'\\' && Char !=
'"')
435 << (char)(
'0' + ((Char >> 6) & 7))
436 << (char)(
'0' + ((Char >> 3) & 7))
437 << (char)(
'0' + ((Char >> 0) & 7));
443 PragmaMessageKind
Kind,
445 startNewLineIfNeeded();
448 if (!Namespace.empty())
449 OS << Namespace <<
' ';
464 if (
Kind == PMK_Message)
466 setEmittedDirectiveOnThisLine();
470 StringRef DebugType) {
471 startNewLineIfNeeded();
474 OS <<
"#pragma clang __debug ";
477 setEmittedDirectiveOnThisLine();
480 void PrintPPOutputPPCallbacks::
482 startNewLineIfNeeded();
484 OS <<
"#pragma " << Namespace <<
" diagnostic push";
485 setEmittedDirectiveOnThisLine();
488 void PrintPPOutputPPCallbacks::
490 startNewLineIfNeeded();
492 OS <<
"#pragma " << Namespace <<
" diagnostic pop";
493 setEmittedDirectiveOnThisLine();
496 void PrintPPOutputPPCallbacks::PragmaDiagnostic(
SourceLocation Loc,
500 startNewLineIfNeeded();
502 OS <<
"#pragma " << Namespace <<
" diagnostic ";
520 OS <<
" \"" << Str <<
'"';
521 setEmittedDirectiveOnThisLine();
525 StringRef WarningSpec,
527 startNewLineIfNeeded();
529 OS <<
"#pragma warning(" << WarningSpec <<
':';
533 setEmittedDirectiveOnThisLine();
536 void PrintPPOutputPPCallbacks::PragmaWarningPush(
SourceLocation Loc,
538 startNewLineIfNeeded();
540 OS <<
"#pragma warning(push";
544 setEmittedDirectiveOnThisLine();
547 void PrintPPOutputPPCallbacks::PragmaWarningPop(
SourceLocation Loc) {
548 startNewLineIfNeeded();
550 OS <<
"#pragma warning(pop)";
551 setEmittedDirectiveOnThisLine();
554 void PrintPPOutputPPCallbacks::
556 startNewLineIfNeeded();
558 OS <<
"#pragma clang assume_nonnull begin";
559 setEmittedDirectiveOnThisLine();
562 void PrintPPOutputPPCallbacks::
564 startNewLineIfNeeded();
566 OS <<
"#pragma clang assume_nonnull end";
567 setEmittedDirectiveOnThisLine();
575 bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(
Token &
Tok) {
598 if (ColNo <= 1 && Tok.
is(tok::hash))
602 for (; ColNo > 1; --ColNo)
608 void PrintPPOutputPPCallbacks::HandleNewlinesInToken(
const char *TokStr,
610 unsigned NumNewlines = 0;
611 for (; Len; --Len, ++TokStr) {
612 if (*TokStr !=
'\n' &&
620 (TokStr[1] ==
'\n' || TokStr[1] ==
'\r') &&
621 TokStr[0] != TokStr[1]) {
627 if (NumNewlines == 0)
return;
629 CurLine += NumNewlines;
636 PrintPPOutputPPCallbacks *Callbacks;
639 bool ShouldExpandTokens;
641 UnknownPragmaHandler(
const char *prefix, PrintPPOutputPPCallbacks *callbacks,
642 bool RequireTokenExpansion)
643 : Prefix(prefix), Callbacks(callbacks),
644 ShouldExpandTokens(RequireTokenExpansion) {}
646 Token &PragmaTok)
override {
649 Callbacks->startNewLineIfNeeded();
651 Callbacks->OS.write(Prefix, strlen(Prefix));
653 if (ShouldExpandTokens) {
656 auto Toks = llvm::make_unique<Token[]>(1);
658 PP.EnterTokenStream(std::move(Toks), 1,
668 while (PragmaTok.
isNot(tok::eod)) {
670 Callbacks->AvoidConcat(PrevPrevToken, PrevToken, PragmaTok))
671 Callbacks->OS <<
' ';
673 Callbacks->OS.write(&TokSpell[0], TokSpell.size());
675 PrevPrevToken = PrevToken;
676 PrevToken = PragmaTok;
678 if (ShouldExpandTokens)
683 Callbacks->setEmittedDirectiveOnThisLine();
690 PrintPPOutputPPCallbacks *Callbacks,
692 bool DropComments = PP.
getLangOpts().TraditionalCPP &&
696 Token PrevPrevTok, PrevTok;
700 if (Callbacks->hasEmittedDirectiveOnThisLine()) {
701 Callbacks->startNewLineIfNeeded();
711 (Callbacks->hasEmittedTokensOnThisLine() &&
713 Callbacks->AvoidConcat(PrevPrevTok, PrevTok, Tok))) {
717 if (DropComments && Tok.
is(tok::comment)) {
723 }
else if (Tok.
is(tok::eod)) {
729 }
else if (Tok.
is(tok::annot_module_include)) {
734 }
else if (Tok.
is(tok::annot_module_begin)) {
741 Callbacks->BeginModule(
745 }
else if (Tok.
is(tok::annot_module_end)) {
746 Callbacks->EndModule(
756 const char *TokPtr = Buffer;
758 OS.write(TokPtr, Len);
762 if (Tok.
getKind() == tok::comment || Tok.
getKind() == tok::unknown)
763 Callbacks->HandleNewlinesInToken(TokPtr, Len);
766 OS.write(&S[0], S.size());
770 if (Tok.
getKind() == tok::comment || Tok.
getKind() == tok::unknown)
771 Callbacks->HandleNewlinesInToken(&S[0], S.size());
773 Callbacks->setEmittedTokensOnThisLine();
777 PrevPrevTok = PrevTok;
785 return LHS->first->getName().compare(RHS->first->getName());
803 auto *MD = I->second.getLatest();
804 if (MD && MD->isDefined())
807 llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(),
MacroIDCompare);
809 for (
unsigned i = 0, e = MacrosByID.size(); i != e; ++i) {
825 assert(Opts.
ShowMacros &&
"Not yet implemented!");
834 PrintPPOutputPPCallbacks *Callbacks =
new PrintPPOutputPPCallbacks(
841 std::unique_ptr<UnknownPragmaHandler> MicrosoftExtHandler(
842 new UnknownPragmaHandler(
843 "#pragma", Callbacks,
846 std::unique_ptr<UnknownPragmaHandler> GCCHandler(
new UnknownPragmaHandler(
847 "#pragma GCC", Callbacks,
850 std::unique_ptr<UnknownPragmaHandler> ClangHandler(
new UnknownPragmaHandler(
851 "#pragma clang", Callbacks,
863 std::unique_ptr<UnknownPragmaHandler> OpenMPHandler(
864 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...
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.
PragmaIntroducerKind
Describes how the pragma was introduced, e.g., with #pragma, _Pragma, or __pragma.
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.
const FunctionProtoType * T
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.
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.