clang 22.0.0git
RewriteMacros.cpp
Go to the documentation of this file.
1//===--- RewriteMacros.cpp - Rewrite macros into their expansions ---------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This code rewrites macro invocations into their expansions. This gives you
10// a macro expanded file that retains comments and #includes.
11//
12//===----------------------------------------------------------------------===//
13
18#include "llvm/ADT/RewriteBuffer.h"
19#include <cstdio>
20
21using namespace clang;
22using llvm::RewriteBuffer;
23
24/// isSameToken - Return true if the two specified tokens start have the same
25/// content.
26static bool isSameToken(Token &RawTok, Token &PPTok) {
27 // If two tokens have the same kind and the same identifier info, they are
28 // obviously the same.
29 if (PPTok.getKind() == RawTok.getKind() &&
30 PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo())
31 return true;
32
33 // Otherwise, if they are different but have the same identifier info, they
34 // are also considered to be the same. This allows keywords and raw lexed
35 // identifiers with the same name to be treated the same.
36 if (PPTok.getIdentifierInfo() &&
37 PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo())
38 return true;
39
40 return false;
41}
42
43
44/// GetNextRawTok - Return the next raw token in the stream, skipping over
45/// comments if ReturnComment is false.
46static const Token &GetNextRawTok(const std::vector<Token> &RawTokens,
47 unsigned &CurTok, bool ReturnComment) {
48 assert(CurTok < RawTokens.size() && "Overran eof!");
49
50 // If the client doesn't want comments and we have one, skip it.
51 if (!ReturnComment && RawTokens[CurTok].is(tok::comment))
52 ++CurTok;
53
54 return RawTokens[CurTok++];
55}
56
57
58/// LexRawTokensFromMainFile - Lets all the raw tokens from the main file into
59/// the specified vector.
61 std::vector<Token> &RawTokens) {
63
64 // Create a lexer to lex all the tokens of the main file in raw mode. Even
65 // though it is in raw mode, it will not return comments.
66 llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(SM.getMainFileID());
67 Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts());
68
69 // Switch on comment lexing because we really do want them.
70 RawLex.SetCommentRetentionState(true);
71
72 Token RawTok;
73 do {
74 RawLex.LexFromRawLexer(RawTok);
75
76 // If we have an identifier with no identifier info for our raw token, look
77 // up the identifier info. This is important for equality comparison of
78 // identifier tokens.
79 if (RawTok.is(tok::raw_identifier))
80 PP.LookUpIdentifierInfo(RawTok);
81
82 RawTokens.push_back(RawTok);
83 } while (RawTok.isNot(tok::eof));
84}
85
86
87/// RewriteMacrosInInput - Implement -rewrite-macros mode.
88void clang::RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS) {
90
92 Rewrite.setSourceMgr(SM, PP.getLangOpts());
93 RewriteBuffer &RB = Rewrite.getEditBuffer(SM.getMainFileID());
94
95 std::vector<Token> RawTokens;
96 LexRawTokensFromMainFile(PP, RawTokens);
97 unsigned CurRawTok = 0;
98 Token RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
99
100
101 // Get the first preprocessing token.
103 Token PPTok;
104 PP.Lex(PPTok);
105
106 // Preprocess the input file in parallel with raw lexing the main file. Ignore
107 // all tokens that are preprocessed from a file other than the main file (e.g.
108 // a header). If we see tokens that are in the preprocessed file but not the
109 // lexed file, we have a macro expansion. If we see tokens in the lexed file
110 // that aren't in the preprocessed view, we have macros that expand to no
111 // tokens, or macro arguments etc.
112 while (RawTok.isNot(tok::eof) || PPTok.isNot(tok::eof)) {
113 SourceLocation PPLoc = SM.getExpansionLoc(PPTok.getLocation());
114
115 // If PPTok is from a different source file, ignore it.
116 if (!SM.isWrittenInMainFile(PPLoc)) {
117 PP.Lex(PPTok);
118 continue;
119 }
120
121 // If the raw file hits a preprocessor directive, they will be extra tokens
122 // in the raw file that don't exist in the preprocsesed file. However, we
123 // choose to preserve them in the output file and otherwise handle them
124 // specially.
125 if (RawTok.is(tok::hash) && RawTok.isAtStartOfLine()) {
126 // If this is a #warning directive or #pragma mark (GNU extensions),
127 // comment the line out.
128 if (RawTokens[CurRawTok].is(tok::identifier)) {
129 const IdentifierInfo *II = RawTokens[CurRawTok].getIdentifierInfo();
130 if (II->getName() == "warning") {
131 // Comment out #warning.
132 RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//");
133 } else if (II->getName() == "pragma" &&
134 RawTokens[CurRawTok+1].is(tok::identifier) &&
135 (RawTokens[CurRawTok+1].getIdentifierInfo()->getName() ==
136 "mark")) {
137 // Comment out #pragma mark.
138 RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//");
139 }
140 }
141
142 // Otherwise, if this is a #include or some other directive, just leave it
143 // in the file by skipping over the line.
144 RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
145 while (!RawTok.isAtStartOfLine() && RawTok.isNot(tok::eof))
146 RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
147 continue;
148 }
149
150 // Okay, both tokens are from the same file. Get their offsets from the
151 // start of the file.
152 unsigned PPOffs = SM.getFileOffset(PPLoc);
153 unsigned RawOffs = SM.getFileOffset(RawTok.getLocation());
154
155 // If the offsets are the same and the token kind is the same, ignore them.
156 if (PPOffs == RawOffs && isSameToken(RawTok, PPTok)) {
157 RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
158 PP.Lex(PPTok);
159 continue;
160 }
161
162 // If the PP token is farther along than the raw token, something was
163 // deleted. Comment out the raw token.
164 if (RawOffs <= PPOffs) {
165 // Comment out a whole run of tokens instead of bracketing each one with
166 // comments. Add a leading space if RawTok didn't have one.
167 bool HasSpace = RawTok.hasLeadingSpace();
168 RB.InsertTextAfter(RawOffs, &" /*"[HasSpace]);
169 unsigned EndPos;
170
171 do {
172 EndPos = RawOffs+RawTok.getLength();
173
174 RawTok = GetNextRawTok(RawTokens, CurRawTok, true);
175 RawOffs = SM.getFileOffset(RawTok.getLocation());
176
177 if (RawTok.is(tok::comment)) {
178 // Skip past the comment.
179 RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
180 break;
181 }
182
183 } while (RawOffs <= PPOffs && !RawTok.isAtStartOfLine() &&
184 (PPOffs != RawOffs || !isSameToken(RawTok, PPTok)));
185
186 RB.InsertTextBefore(EndPos, "*/");
187 continue;
188 }
189
190 // Otherwise, there was a replacement an expansion. Insert the new token
191 // in the output buffer. Insert the whole run of new tokens at once to get
192 // them in the right order.
193 unsigned InsertPos = PPOffs;
194 std::string Expansion;
195 while (PPOffs < RawOffs) {
196 Expansion += ' ' + PP.getSpelling(PPTok);
197 PP.Lex(PPTok);
198 PPLoc = SM.getExpansionLoc(PPTok.getLocation());
199 PPOffs = SM.getFileOffset(PPLoc);
200 }
201 Expansion += ' ';
202 RB.InsertTextBefore(InsertPos, Expansion);
203 }
204
205 // Get the buffer corresponding to MainFileID. If we haven't changed it, then
206 // we are done.
207 if (const RewriteBuffer *RewriteBuf =
208 Rewrite.getRewriteBufferFor(SM.getMainFileID())) {
209 //printf("Changed:\n");
210 *OS << std::string(RewriteBuf->begin(), RewriteBuf->end());
211 } else {
212 fprintf(stderr, "No changes\n");
213 }
214 OS->flush();
215}
#define SM(sm)
Definition: OffloadArch.cpp:16
Defines the clang::Preprocessor interface.
static bool isSameToken(Token &RawTok, Token &PPTok)
isSameToken - Return true if the two specified tokens start have the same content.
static const Token & GetNextRawTok(const std::vector< Token > &RawTokens, unsigned &CurTok, bool ReturnComment)
GetNextRawTok - Return the next raw token in the stream, skipping over comments if ReturnComment is f...
static void LexRawTokensFromMainFile(Preprocessor &PP, std::vector< Token > &RawTokens)
LexRawTokensFromMainFile - Lets all the raw tokens from the main file into the specified vector.
Defines the SourceManager interface.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens.
Definition: Lexer.h:78
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
Definition: Lexer.h:236
void SetCommentRetentionState(bool Mode)
SetCommentRetentionMode - Change the comment retention mode of the lexer to the specified mode.
Definition: Lexer.h:269
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:145
IdentifierInfo * LookUpIdentifierInfo(Token &Identifier) const
Given a tok::raw_identifier token, look up the identifier information for the token and install it in...
void Lex(Token &Result)
Lex the next token for this preprocessor.
void EnterMainSourceFile()
Enter the specified FileID as the main source file, which implicitly adds the builtin defines etc.
SourceManager & getSourceManager() const
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 ...
const LangOptions & getLangOpts() const
Rewriter - This is the main interface to the rewrite buffers.
Definition: Rewriter.h:32
Encodes a location in the source.
This class handles loading and caching of source files into memory.
Token - This structure provides full information about a lexed token.
Definition: Token.h:36
IdentifierInfo * getIdentifierInfo() const
Definition: Token.h:189
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
Definition: Token.h:134
unsigned getLength() const
Definition: Token.h:137
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)) {....
Definition: Token.h:102
tok::TokenKind getKind() const
Definition: Token.h:97
bool isAtStartOfLine() const
isAtStartOfLine - Return true if this token is at the start of a line.
Definition: Token.h:278
bool hasLeadingSpace() const
Return true if this token has whitespace before it.
Definition: Token.h:282
bool isNot(tok::TokenKind K) const
Definition: Token.h:103
The JSON file list parser is used to communicate input to InstallAPI.
@ Rewrite
We are substituting template parameters for (typically) other template parameters in order to rewrite...
void RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS)
RewriteMacrosInInput - Implement -rewrite-macros mode.