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,
137 PragmaMessageKind
Kind, StringRef Str)
override;
138 void PragmaDebug(
SourceLocation Loc, StringRef DebugType)
override;
139 void PragmaDiagnosticPush(
SourceLocation Loc, StringRef Namespace)
override;
140 void PragmaDiagnosticPop(
SourceLocation Loc, StringRef Namespace)
override;
150 bool HandleFirstTokOnLine(
Token &
Tok);
161 bool MoveToLine(
unsigned LineNo);
163 bool AvoidConcat(
const Token &PrevPrevTok,
const Token &PrevTok,
165 return ConcatInfo.
AvoidConcat(PrevPrevTok, PrevTok, Tok);
167 void WriteLineInfo(
unsigned LineNo,
const char *Extra=
nullptr,
168 unsigned ExtraLen=0);
169 bool LineMarkersAreDisabled()
const {
return DisableLineMarkers; }
170 void HandleNewlinesInToken(
const char *TokStr,
unsigned Len);
173 void MacroDefined(
const Token &MacroNameTok,
177 void MacroUndefined(
const Token &MacroNameTok,
181 void BeginModule(
const Module *M);
182 void EndModule(
const Module *M);
186 void PrintPPOutputPPCallbacks::WriteLineInfo(
unsigned LineNo,
189 startNewLineIfNeeded(
false);
192 if (UseLineDirectives) {
193 OS <<
"#line" <<
' ' << LineNo <<
' ' <<
'"';
194 OS.write_escaped(CurFilename);
197 OS <<
'#' <<
' ' << LineNo <<
' ' <<
'"';
198 OS.write_escaped(CurFilename);
202 OS.write(Extra, ExtraLen);
216 bool PrintPPOutputPPCallbacks::MoveToLine(
unsigned LineNo) {
219 if (LineNo-CurLine <= 8) {
220 if (LineNo-CurLine == 1)
222 else if (LineNo == CurLine)
225 const char *NewLines =
"\n\n\n\n\n\n\n\n";
226 OS.write(NewLines, LineNo-CurLine);
228 }
else if (!DisableLineMarkers) {
230 WriteLineInfo(LineNo,
nullptr, 0);
234 startNewLineIfNeeded(
false);
242 PrintPPOutputPPCallbacks::startNewLineIfNeeded(
bool ShouldUpdateCurrentLine) {
243 if (EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) {
245 EmittedTokensOnThisLine =
false;
246 EmittedDirectiveOnThisLine =
false;
247 if (ShouldUpdateCurrentLine)
259 FileChangeReason Reason,
275 MoveToLine(IncludeLoc);
289 FileType = NewFileType;
291 if (DisableLineMarkers) {
292 startNewLineIfNeeded(
false);
297 WriteLineInfo(CurLine);
306 IsFirstFileEntered =
true;
312 WriteLineInfo(CurLine,
" 1", 2);
315 WriteLineInfo(CurLine,
" 2", 2);
319 WriteLineInfo(CurLine);
324 void PrintPPOutputPPCallbacks::InclusionDirective(
326 const Token &IncludeTok,
331 StringRef SearchPath,
332 StringRef RelativePath,
337 if (DumpIncludeDirectives) {
338 startNewLineIfNeeded();
340 const std::string TokenText = PP.getSpelling(IncludeTok);
341 assert(!TokenText.empty());
342 OS <<
"#" << TokenText <<
" " 343 << (IsAngled ?
'<' :
'"') << FileName << (IsAngled ?
'>' :
'"')
344 <<
" /* clang -E -dI */";
345 setEmittedDirectiveOnThisLine();
346 startNewLineIfNeeded();
352 case tok::pp_include:
354 case tok::pp_include_next:
355 startNewLineIfNeeded();
358 <<
" /* clang -E: implicit import for " 359 <<
"#" << PP.getSpelling(IncludeTok) <<
" " 360 << (IsAngled ?
'<' :
'"') << FileName << (IsAngled ?
'>' :
'"')
364 EmittedTokensOnThisLine =
true;
365 startNewLineIfNeeded();
368 case tok::pp___include_macros:
377 llvm_unreachable(
"unknown include directive kind");
384 void PrintPPOutputPPCallbacks::BeginModule(
const Module *M) {
385 startNewLineIfNeeded();
387 setEmittedDirectiveOnThisLine();
391 void PrintPPOutputPPCallbacks::EndModule(
const Module *M) {
392 startNewLineIfNeeded();
394 setEmittedDirectiveOnThisLine();
399 void PrintPPOutputPPCallbacks::Ident(
SourceLocation Loc, StringRef S) {
402 OS.write(
"#ident ", strlen(
"#ident "));
403 OS.write(S.begin(), S.size());
404 EmittedTokensOnThisLine =
true;
408 void PrintPPOutputPPCallbacks::MacroDefined(
const Token &MacroNameTok,
418 setEmittedDirectiveOnThisLine();
421 void PrintPPOutputPPCallbacks::MacroUndefined(
const Token &MacroNameTok,
425 if (!DumpDefines)
return;
429 setEmittedDirectiveOnThisLine();
433 for (
unsigned char Char : Str) {
434 if (
isPrintable(Char) && Char !=
'\\' && Char !=
'"')
438 << (char)(
'0' + ((Char >> 6) & 7))
439 << (char)(
'0' + ((Char >> 3) & 7))
440 << (char)(
'0' + ((Char >> 0) & 7));
446 PragmaMessageKind
Kind,
448 startNewLineIfNeeded();
451 if (!Namespace.empty())
452 OS << Namespace <<
' ';
467 if (
Kind == PMK_Message)
469 setEmittedDirectiveOnThisLine();
473 StringRef DebugType) {
474 startNewLineIfNeeded();
477 OS <<
"#pragma clang __debug ";
480 setEmittedDirectiveOnThisLine();
483 void PrintPPOutputPPCallbacks::
485 startNewLineIfNeeded();
487 OS <<
"#pragma " << Namespace <<
" diagnostic push";
488 setEmittedDirectiveOnThisLine();
491 void PrintPPOutputPPCallbacks::
493 startNewLineIfNeeded();
495 OS <<
"#pragma " << Namespace <<
" diagnostic pop";
496 setEmittedDirectiveOnThisLine();
499 void PrintPPOutputPPCallbacks::PragmaDiagnostic(
SourceLocation Loc,
503 startNewLineIfNeeded();
505 OS <<
"#pragma " << Namespace <<
" diagnostic ";
523 OS <<
" \"" << Str <<
'"';
524 setEmittedDirectiveOnThisLine();
528 StringRef WarningSpec,
530 startNewLineIfNeeded();
532 OS <<
"#pragma warning(" << WarningSpec <<
':';
536 setEmittedDirectiveOnThisLine();
539 void PrintPPOutputPPCallbacks::PragmaWarningPush(
SourceLocation Loc,
541 startNewLineIfNeeded();
543 OS <<
"#pragma warning(push";
547 setEmittedDirectiveOnThisLine();
550 void PrintPPOutputPPCallbacks::PragmaWarningPop(
SourceLocation Loc) {
551 startNewLineIfNeeded();
553 OS <<
"#pragma warning(pop)";
554 setEmittedDirectiveOnThisLine();
557 void PrintPPOutputPPCallbacks::
559 startNewLineIfNeeded();
561 OS <<
"#pragma clang assume_nonnull begin";
562 setEmittedDirectiveOnThisLine();
565 void PrintPPOutputPPCallbacks::
567 startNewLineIfNeeded();
569 OS <<
"#pragma clang assume_nonnull end";
570 setEmittedDirectiveOnThisLine();
578 bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(
Token &
Tok) {
601 if (ColNo <= 1 && Tok.
is(tok::hash))
605 for (; ColNo > 1; --ColNo)
611 void PrintPPOutputPPCallbacks::HandleNewlinesInToken(
const char *TokStr,
613 unsigned NumNewlines = 0;
614 for (; Len; --Len, ++TokStr) {
615 if (*TokStr !=
'\n' &&
623 (TokStr[1] ==
'\n' || TokStr[1] ==
'\r') &&
624 TokStr[0] != TokStr[1]) {
630 if (NumNewlines == 0)
return;
632 CurLine += NumNewlines;
639 PrintPPOutputPPCallbacks *Callbacks;
642 bool ShouldExpandTokens;
644 UnknownPragmaHandler(
const char *prefix, PrintPPOutputPPCallbacks *callbacks,
645 bool RequireTokenExpansion)
646 : Prefix(prefix), Callbacks(callbacks),
647 ShouldExpandTokens(RequireTokenExpansion) {}
649 Token &PragmaTok)
override {
652 Callbacks->startNewLineIfNeeded();
654 Callbacks->OS.write(Prefix, strlen(Prefix));
656 if (ShouldExpandTokens) {
659 auto Toks = llvm::make_unique<Token[]>(1);
661 PP.EnterTokenStream(std::move(Toks), 1,
671 while (PragmaTok.
isNot(tok::eod)) {
673 Callbacks->AvoidConcat(PrevPrevToken, PrevToken, PragmaTok))
674 Callbacks->OS <<
' ';
676 Callbacks->OS.write(&TokSpell[0], TokSpell.size());
678 PrevPrevToken = PrevToken;
679 PrevToken = PragmaTok;
681 if (ShouldExpandTokens)
686 Callbacks->setEmittedDirectiveOnThisLine();
693 PrintPPOutputPPCallbacks *Callbacks,
695 bool DropComments = PP.
getLangOpts().TraditionalCPP &&
699 Token PrevPrevTok, PrevTok;
703 if (Callbacks->hasEmittedDirectiveOnThisLine()) {
704 Callbacks->startNewLineIfNeeded();
714 (Callbacks->hasEmittedTokensOnThisLine() &&
716 Callbacks->AvoidConcat(PrevPrevTok, PrevTok, Tok))) {
720 if (DropComments && Tok.
is(tok::comment)) {
726 }
else if (Tok.
is(tok::eod)) {
732 }
else if (Tok.
is(tok::annot_module_include)) {
737 }
else if (Tok.
is(tok::annot_module_begin)) {
744 Callbacks->BeginModule(
748 }
else if (Tok.
is(tok::annot_module_end)) {
749 Callbacks->EndModule(
763 }
else if (Tok.
getLength() < llvm::array_lengthof(Buffer)) {
764 const char *TokPtr = Buffer;
766 OS.write(TokPtr, Len);
770 if (Tok.
getKind() == tok::comment || Tok.
getKind() == tok::unknown)
771 Callbacks->HandleNewlinesInToken(TokPtr, Len);
774 OS.write(&S[0], S.size());
778 if (Tok.
getKind() == tok::comment || Tok.
getKind() == tok::unknown)
779 Callbacks->HandleNewlinesInToken(&S[0], S.size());
781 Callbacks->setEmittedTokensOnThisLine();
785 PrevPrevTok = PrevTok;
793 return LHS->first->getName().compare(RHS->first->getName());
811 auto *MD = I->second.getLatest();
812 if (MD && MD->isDefined())
815 llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(),
MacroIDCompare);
817 for (
unsigned i = 0, e = MacrosByID.size(); i != e; ++i) {
833 assert(Opts.
ShowMacros &&
"Not yet implemented!");
842 PrintPPOutputPPCallbacks *Callbacks =
new PrintPPOutputPPCallbacks(
849 std::unique_ptr<UnknownPragmaHandler> MicrosoftExtHandler(
850 new UnknownPragmaHandler(
851 "#pragma", Callbacks,
854 std::unique_ptr<UnknownPragmaHandler> GCCHandler(
new UnknownPragmaHandler(
855 "#pragma GCC", Callbacks,
858 std::unique_ptr<UnknownPragmaHandler> ClangHandler(
new UnknownPragmaHandler(
859 "#pragma clang", Callbacks,
871 std::unique_ptr<UnknownPragmaHandler> OpenMPHandler(
872 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.
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.
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.