11#include "llvm/Support/Debug.h"
14#define DEBUG_TYPE "macro-expansion-context"
24 MacroExpansionContext::ExpansionRangeMap &ExpansionRanges;
29 MacroExpansionContext::ExpansionRangeMap &ExpansionRanges)
30 : PP(PP), SM(SM), ExpansionRanges(ExpansionRanges) {}
39 assert(MacroNameBegin == SM.getExpansionLoc(Range.getBegin()));
41 const SourceLocation ExpansionEnd = [Range, &SM = SM, &MacroName] {
43 if (Range.getBegin() == Range.getEnd())
44 return SM.getExpansionLoc(
48 return SM.getExpansionLoc(Range.getEnd()).getLocWithOffset(1);
52 LLVM_DEBUG(llvm::dbgs() <<
"MacroExpands event: '";
55 <<
"' with length " << MacroName.
getLength() <<
" at ";
56 MacroNameBegin.
print(llvm::dbgs(), SM);
57 llvm::dbgs() <<
", expansion end at ";
58 ExpansionEnd.
print(llvm::dbgs(), SM); llvm::dbgs() <<
'\n';);
62 MacroExpansionContext::ExpansionRangeMap::iterator It;
64 std::tie(It, Inserted) =
65 ExpansionRanges.try_emplace(MacroNameBegin, ExpansionEnd);
67 LLVM_DEBUG(llvm::dbgs() <<
"maps ";
68 It->getFirst().
print(llvm::dbgs(), SM); llvm::dbgs() <<
" to ";
69 It->getSecond().print(llvm::dbgs(), SM);
70 llvm::dbgs() <<
'\n';);
72 if (SM.isBeforeInTranslationUnit(It->getSecond(), ExpansionEnd)) {
73 It->getSecond() = ExpansionEnd;
75 llvm::dbgs() <<
"remaps "; It->getFirst().
print(llvm::dbgs(), SM);
76 llvm::dbgs() <<
" to "; It->getSecond().print(llvm::dbgs(), SM);
77 llvm::dbgs() <<
'\n';);
88 : LangOpts(LangOpts) {}
95 PP->addPPCallbacks(std::make_unique<detail::MacroExpansionRangeRecorder>(
96 *PP, *SM, ExpansionRanges));
98 PP->setTokenWatcher([
this](
const Token &
Tok) { onTokenLexed(
Tok); });
101std::optional<StringRef>
107 if (ExpansionRanges.find_as(MacroExpansionLoc) == ExpansionRanges.end())
111 const auto It = ExpandedTokens.find_as(MacroExpansionLoc);
112 if (It == ExpandedTokens.end())
113 return StringRef{
""};
116 return It->getSecond().str();
119std::optional<StringRef>
124 const auto It = ExpansionRanges.find_as(MacroExpansionLoc);
125 if (It == ExpansionRanges.end())
128 assert(It->getFirst() != It->getSecond() &&
129 "Every macro expansion must cover a non-empty range.");
138 std::optional<StringRef> ExpandedText =
getExpandedText(MacroExpansionLoc);
142 auto [It, Inserted] =
143 FormattedExpandedTokens.try_emplace(MacroExpansionLoc,
"");
145 return StringRef(It->getSecond());
149 std::string MacroCodeBlock = ExpandedText->str();
151 std::vector<clang::tooling::Range> Ranges;
152 Ranges.emplace_back(0, MacroCodeBlock.length());
155 Style, MacroCodeBlock, Ranges,
"<macro-expansion>");
160 It->getSecond() =
Result ? std::move(*
Result) : std::move(MacroCodeBlock);
162 return StringRef(It->getSecond());
173 std::vector<std::pair<SourceLocation, SourceLocation>> LocalExpansionRanges;
174 LocalExpansionRanges.reserve(ExpansionRanges.size());
175 for (
const auto &
Record : ExpansionRanges)
176 LocalExpansionRanges.emplace_back(
178 llvm::sort(LocalExpansionRanges);
180 OS <<
"\n=============== ExpansionRanges ===============\n";
181 for (
const auto &
Record : LocalExpansionRanges) {
183 Record.first.print(OS, *SM);
185 Record.second.print(OS, *SM);
191 std::vector<std::pair<SourceLocation, MacroExpansionText>>
193 LocalExpandedTokens.reserve(ExpandedTokens.size());
194 for (
const auto &
Record : ExpandedTokens)
195 LocalExpandedTokens.emplace_back(
197 llvm::sort(LocalExpandedTokens);
199 OS <<
"\n=============== ExpandedTokens ===============\n";
200 for (
const auto &
Record : LocalExpandedTokens) {
202 Record.first.print(OS, *SM);
203 OS <<
" -> '" <<
Record.second <<
"'\n";
208 assert(
Tok.isNot(tok::raw_identifier));
211 if (
Tok.isAnnotation())
219 OS << II->getName() <<
' ';
220 }
else if (
Tok.isLiteral() && !
Tok.needsCleaning() &&
Tok.getLiteralData()) {
221 OS << StringRef(
Tok.getLiteralData(),
Tok.getLength());
224 if (
Tok.getLength() <
sizeof(Tmp)) {
225 const char *TokPtr = Tmp;
228 OS.write(TokPtr, Len);
230 OS <<
"<too long token>";
235void MacroExpansionContext::onTokenLexed(
const Token &
Tok) {
240 LLVM_DEBUG(llvm::dbgs() <<
"lexed macro expansion token '";
242 SLoc.
print(llvm::dbgs(), *SM); llvm::dbgs() <<
'\n';);
245 SourceLocation CurrExpansionLoc = SM->getExpansionLoc(SLoc);
247 MacroExpansionText TokenAsString;
248 llvm::raw_svector_ostream
OS(TokenAsString);
255 ExpansionMap::iterator It;
257 std::tie(It, Inserted) =
258 ExpandedTokens.try_emplace(CurrExpansionLoc, std::move(TokenAsString));
260 It->getSecond().append(TokenAsString);
static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx, QualType Ty)
llvm::MachO::Record Record
static void dumpTokenInto(const clang::Preprocessor &PP, llvm::raw_ostream &OS, clang::Token Tok)
static CharSourceRange getCharRange(SourceRange R)
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
MacroArgs - An instance of this class captures information about the formal arguments specified to a ...
A description of the current definition of a macro.
void registerForPreprocessor(Preprocessor &PP)
Register the necessary callbacks to the Preprocessor to record the expansion events and the generated...
LLVM_DUMP_METHOD void dumpExpandedTextsToStream(raw_ostream &OS) const
LLVM_DUMP_METHOD void dumpExpandedTexts() const
LLVM_DUMP_METHOD void dumpExpansionRanges() const
MacroExpansionContext(const LangOptions &LangOpts)
Creates a MacroExpansionContext.
std::optional< StringRef > getFormattedExpandedText(SourceLocation MacroExpansionLoc) const
LLVM_DUMP_METHOD void dumpExpansionRangesToStream(raw_ostream &OS) const
std::optional< StringRef > getExpandedText(SourceLocation MacroExpansionLoc) const
std::optional< StringRef > getOriginalText(SourceLocation MacroExpansionLoc) const
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
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 ...
Encodes a location in the source.
void print(raw_ostream &OS, const SourceManager &SM) const
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
Token - This structure provides full information about a lexed token.
IdentifierInfo * getIdentifierInfo() const
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
unsigned getLength() const
void MacroExpands(const Token &MacroName, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) override
Called by Preprocessor::HandleMacroExpandedIdentifier when a macro invocation is found.
MacroExpansionRangeRecorder(const Preprocessor &PP, SourceManager &SM, MacroExpansionContext::ExpansionRangeMap &ExpansionRanges)
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.