MacroExpansionContext.cpp 8.1 KB

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