MacroExpansionContext.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. //===- MacroExpansionContext.cpp - Macro expansion information --*- C++ -*-===//
  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. #include "clang/Analysis/MacroExpansionContext.h"
  9. #include "llvm/Support/Debug.h"
  10. #include <optional>
  11. #define DEBUG_TYPE "macro-expansion-context"
  12. static void dumpTokenInto(const clang::Preprocessor &PP, clang::raw_ostream &OS,
  13. clang::Token Tok);
  14. namespace clang {
  15. namespace detail {
  16. class MacroExpansionRangeRecorder : public PPCallbacks {
  17. const Preprocessor &PP;
  18. SourceManager &SM;
  19. MacroExpansionContext::ExpansionRangeMap &ExpansionRanges;
  20. public:
  21. explicit MacroExpansionRangeRecorder(
  22. const Preprocessor &PP, SourceManager &SM,
  23. MacroExpansionContext::ExpansionRangeMap &ExpansionRanges)
  24. : PP(PP), SM(SM), ExpansionRanges(ExpansionRanges) {}
  25. void MacroExpands(const Token &MacroName, const MacroDefinition &MD,
  26. SourceRange Range, const MacroArgs *Args) override {
  27. // Ignore annotation tokens like: _Pragma("pack(push, 1)")
  28. if (MacroName.getIdentifierInfo()->getName() == "_Pragma")
  29. return;
  30. SourceLocation MacroNameBegin = SM.getExpansionLoc(MacroName.getLocation());
  31. assert(MacroNameBegin == SM.getExpansionLoc(Range.getBegin()));
  32. const SourceLocation ExpansionEnd = [Range, &SM = SM, &MacroName] {
  33. // If the range is empty, use the length of the macro.
  34. if (Range.getBegin() == Range.getEnd())
  35. return SM.getExpansionLoc(
  36. MacroName.getLocation().getLocWithOffset(MacroName.getLength()));
  37. // Include the last character.
  38. return SM.getExpansionLoc(Range.getEnd()).getLocWithOffset(1);
  39. }();
  40. (void)PP;
  41. LLVM_DEBUG(llvm::dbgs() << "MacroExpands event: '";
  42. dumpTokenInto(PP, llvm::dbgs(), MacroName);
  43. llvm::dbgs()
  44. << "' with length " << MacroName.getLength() << " at ";
  45. MacroNameBegin.print(llvm::dbgs(), SM);
  46. llvm::dbgs() << ", expansion end at ";
  47. ExpansionEnd.print(llvm::dbgs(), SM); llvm::dbgs() << '\n';);
  48. // If the expansion range is empty, use the identifier of the macro as a
  49. // range.
  50. MacroExpansionContext::ExpansionRangeMap::iterator It;
  51. bool Inserted;
  52. std::tie(It, Inserted) =
  53. ExpansionRanges.try_emplace(MacroNameBegin, ExpansionEnd);
  54. if (Inserted) {
  55. LLVM_DEBUG(llvm::dbgs() << "maps ";
  56. It->getFirst().print(llvm::dbgs(), SM); llvm::dbgs() << " to ";
  57. It->getSecond().print(llvm::dbgs(), SM);
  58. llvm::dbgs() << '\n';);
  59. } else {
  60. if (SM.isBeforeInTranslationUnit(It->getSecond(), ExpansionEnd)) {
  61. It->getSecond() = ExpansionEnd;
  62. LLVM_DEBUG(
  63. llvm::dbgs() << "remaps "; It->getFirst().print(llvm::dbgs(), SM);
  64. llvm::dbgs() << " to "; It->getSecond().print(llvm::dbgs(), SM);
  65. llvm::dbgs() << '\n';);
  66. }
  67. }
  68. }
  69. };
  70. } // namespace detail
  71. } // namespace clang
  72. using namespace clang;
  73. MacroExpansionContext::MacroExpansionContext(const LangOptions &LangOpts)
  74. : LangOpts(LangOpts) {}
  75. void MacroExpansionContext::registerForPreprocessor(Preprocessor &NewPP) {
  76. PP = &NewPP;
  77. SM = &NewPP.getSourceManager();
  78. // Make sure that the Preprocessor does not outlive the MacroExpansionContext.
  79. PP->addPPCallbacks(std::make_unique<detail::MacroExpansionRangeRecorder>(
  80. *PP, *SM, ExpansionRanges));
  81. // Same applies here.
  82. PP->setTokenWatcher([this](const Token &Tok) { onTokenLexed(Tok); });
  83. }
  84. std::optional<StringRef>
  85. MacroExpansionContext::getExpandedText(SourceLocation MacroExpansionLoc) const {
  86. if (MacroExpansionLoc.isMacroID())
  87. return std::nullopt;
  88. // If there was no macro expansion at that location, return std::nullopt.
  89. if (ExpansionRanges.find_as(MacroExpansionLoc) == ExpansionRanges.end())
  90. return std::nullopt;
  91. // There was macro expansion, but resulted in no tokens, return empty string.
  92. const auto It = ExpandedTokens.find_as(MacroExpansionLoc);
  93. if (It == ExpandedTokens.end())
  94. return StringRef{""};
  95. // Otherwise we have the actual token sequence as string.
  96. return It->getSecond().str();
  97. }
  98. std::optional<StringRef>
  99. MacroExpansionContext::getOriginalText(SourceLocation MacroExpansionLoc) const {
  100. if (MacroExpansionLoc.isMacroID())
  101. return std::nullopt;
  102. const auto It = ExpansionRanges.find_as(MacroExpansionLoc);
  103. if (It == ExpansionRanges.end())
  104. return std::nullopt;
  105. assert(It->getFirst() != It->getSecond() &&
  106. "Every macro expansion must cover a non-empty range.");
  107. return Lexer::getSourceText(
  108. CharSourceRange::getCharRange(It->getFirst(), It->getSecond()), *SM,
  109. LangOpts);
  110. }
  111. void MacroExpansionContext::dumpExpansionRanges() const {
  112. dumpExpansionRangesToStream(llvm::dbgs());
  113. }
  114. void MacroExpansionContext::dumpExpandedTexts() const {
  115. dumpExpandedTextsToStream(llvm::dbgs());
  116. }
  117. void MacroExpansionContext::dumpExpansionRangesToStream(raw_ostream &OS) const {
  118. std::vector<std::pair<SourceLocation, SourceLocation>> LocalExpansionRanges;
  119. LocalExpansionRanges.reserve(ExpansionRanges.size());
  120. for (const auto &Record : ExpansionRanges)
  121. LocalExpansionRanges.emplace_back(
  122. std::make_pair(Record.getFirst(), Record.getSecond()));
  123. llvm::sort(LocalExpansionRanges);
  124. OS << "\n=============== ExpansionRanges ===============\n";
  125. for (const auto &Record : LocalExpansionRanges) {
  126. OS << "> ";
  127. Record.first.print(OS, *SM);
  128. OS << ", ";
  129. Record.second.print(OS, *SM);
  130. OS << '\n';
  131. }
  132. }
  133. void MacroExpansionContext::dumpExpandedTextsToStream(raw_ostream &OS) const {
  134. std::vector<std::pair<SourceLocation, MacroExpansionText>>
  135. LocalExpandedTokens;
  136. LocalExpandedTokens.reserve(ExpandedTokens.size());
  137. for (const auto &Record : ExpandedTokens)
  138. LocalExpandedTokens.emplace_back(
  139. std::make_pair(Record.getFirst(), Record.getSecond()));
  140. llvm::sort(LocalExpandedTokens);
  141. OS << "\n=============== ExpandedTokens ===============\n";
  142. for (const auto &Record : LocalExpandedTokens) {
  143. OS << "> ";
  144. Record.first.print(OS, *SM);
  145. OS << " -> '" << Record.second << "'\n";
  146. }
  147. }
  148. static void dumpTokenInto(const Preprocessor &PP, raw_ostream &OS, Token Tok) {
  149. assert(Tok.isNot(tok::raw_identifier));
  150. // Ignore annotation tokens like: _Pragma("pack(push, 1)")
  151. if (Tok.isAnnotation())
  152. return;
  153. if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
  154. // FIXME: For now, we don't respect whitespaces between macro expanded
  155. // tokens. We just emit a space after every identifier to produce a valid
  156. // code for `int a ;` like expansions.
  157. // ^-^-- Space after the 'int' and 'a' identifiers.
  158. OS << II->getName() << ' ';
  159. } else if (Tok.isLiteral() && !Tok.needsCleaning() && Tok.getLiteralData()) {
  160. OS << StringRef(Tok.getLiteralData(), Tok.getLength());
  161. } else {
  162. char Tmp[256];
  163. if (Tok.getLength() < sizeof(Tmp)) {
  164. const char *TokPtr = Tmp;
  165. // FIXME: Might use a different overload for cleaner callsite.
  166. unsigned Len = PP.getSpelling(Tok, TokPtr);
  167. OS.write(TokPtr, Len);
  168. } else {
  169. OS << "<too long token>";
  170. }
  171. }
  172. }
  173. void MacroExpansionContext::onTokenLexed(const Token &Tok) {
  174. SourceLocation SLoc = Tok.getLocation();
  175. if (SLoc.isFileID())
  176. return;
  177. LLVM_DEBUG(llvm::dbgs() << "lexed macro expansion token '";
  178. dumpTokenInto(*PP, llvm::dbgs(), Tok); llvm::dbgs() << "' at ";
  179. SLoc.print(llvm::dbgs(), *SM); llvm::dbgs() << '\n';);
  180. // Remove spelling location.
  181. SourceLocation CurrExpansionLoc = SM->getExpansionLoc(SLoc);
  182. MacroExpansionText TokenAsString;
  183. llvm::raw_svector_ostream OS(TokenAsString);
  184. // FIXME: Prepend newlines and space to produce the exact same output as the
  185. // preprocessor would for this token.
  186. dumpTokenInto(*PP, OS, Tok);
  187. ExpansionMap::iterator It;
  188. bool Inserted;
  189. std::tie(It, Inserted) =
  190. ExpandedTokens.try_emplace(CurrExpansionLoc, std::move(TokenAsString));
  191. if (!Inserted)
  192. It->getSecond().append(TokenAsString);
  193. }