MacroExpansionContext.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- MacroExpansionContext.h - Macro expansion information ----*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_CLANG_ANALYSIS_MACROEXPANSIONCONTEXT_H
  14. #define LLVM_CLANG_ANALYSIS_MACROEXPANSIONCONTEXT_H
  15. #include "clang/Basic/LangOptions.h"
  16. #include "clang/Basic/SourceLocation.h"
  17. #include "clang/Lex/Preprocessor.h"
  18. #include "llvm/ADT/DenseMap.h"
  19. #include "llvm/ADT/SmallString.h"
  20. #include "llvm/ADT/SmallVector.h"
  21. #include <optional>
  22. namespace clang {
  23. namespace detail {
  24. class MacroExpansionRangeRecorder;
  25. } // namespace detail
  26. /// MacroExpansionContext tracks the macro expansions processed by the
  27. /// Preprocessor. It means that it can track source locations from a single
  28. /// translation unit. For every macro expansion it can tell you what text will
  29. /// be substituted.
  30. ///
  31. /// It was designed to deal with:
  32. /// - regular macros
  33. /// - macro functions
  34. /// - variadic macros
  35. /// - transitive macro expansions
  36. /// - macro redefinition
  37. /// - unbalanced parenthesis
  38. ///
  39. /// \code{.c}
  40. /// void bar();
  41. /// #define retArg(x) x
  42. /// #define retArgUnclosed retArg(bar()
  43. /// #define BB CC
  44. /// #define applyInt BB(int)
  45. /// #define CC(x) retArgUnclosed
  46. ///
  47. /// void unbalancedMacros() {
  48. /// applyInt );
  49. /// //^~~~~~~~~~^ is the substituted range
  50. /// // Substituted text is "applyInt )"
  51. /// // Expanded text is "bar()"
  52. /// }
  53. ///
  54. /// #define expandArgUnclosedCommaExpr(x) (x, bar(), 1
  55. /// #define f expandArgUnclosedCommaExpr
  56. ///
  57. /// void unbalancedMacros2() {
  58. /// int x = f(f(1)) )); // Look at the parenthesis!
  59. /// // ^~~~~~^ is the substituted range
  60. /// // Substituted text is "f(f(1))"
  61. /// // Expanded text is "((1,bar(),1,bar(),1"
  62. /// }
  63. /// \endcode
  64. /// \remark Currently we don't respect the whitespaces between expanded tokens,
  65. /// so the output for this example might differ from the -E compiler
  66. /// invocation.
  67. /// \remark All whitespaces are consumed while constructing the expansion.
  68. /// After all identifier a single space inserted to produce a valid C
  69. /// code even if identifier follows an other identifiers such as
  70. /// variable declarations.
  71. /// \remark MacroExpansionContext object must outlive the Preprocessor
  72. /// parameter.
  73. class MacroExpansionContext {
  74. public:
  75. /// Creates a MacroExpansionContext.
  76. /// \remark You must call registerForPreprocessor to set the required
  77. /// onTokenLexed callback and the PPCallbacks.
  78. explicit MacroExpansionContext(const LangOptions &LangOpts);
  79. /// Register the necessary callbacks to the Preprocessor to record the
  80. /// expansion events and the generated tokens. Must ensure that this object
  81. /// outlives the given Preprocessor.
  82. void registerForPreprocessor(Preprocessor &PP);
  83. /// \param MacroExpansionLoc Must be the expansion location of a macro.
  84. /// \return The textual representation of the token sequence which was
  85. /// substituted in place of the macro after the preprocessing.
  86. /// If no macro was expanded at that location, returns std::nullopt.
  87. std::optional<StringRef>
  88. getExpandedText(SourceLocation MacroExpansionLoc) const;
  89. /// \param MacroExpansionLoc Must be the expansion location of a macro.
  90. /// \return The text from the original source code which were substituted by
  91. /// the macro expansion chain from the given location.
  92. /// If no macro was expanded at that location, returns std::nullopt.
  93. std::optional<StringRef>
  94. getOriginalText(SourceLocation MacroExpansionLoc) const;
  95. LLVM_DUMP_METHOD void dumpExpansionRangesToStream(raw_ostream &OS) const;
  96. LLVM_DUMP_METHOD void dumpExpandedTextsToStream(raw_ostream &OS) const;
  97. LLVM_DUMP_METHOD void dumpExpansionRanges() const;
  98. LLVM_DUMP_METHOD void dumpExpandedTexts() const;
  99. private:
  100. friend class detail::MacroExpansionRangeRecorder;
  101. using MacroExpansionText = SmallString<40>;
  102. using ExpansionMap = llvm::DenseMap<SourceLocation, MacroExpansionText>;
  103. using ExpansionRangeMap = llvm::DenseMap<SourceLocation, SourceLocation>;
  104. /// Associates the textual representation of the expanded tokens at the given
  105. /// macro expansion location.
  106. ExpansionMap ExpandedTokens;
  107. /// Tracks which source location was the last affected by any macro
  108. /// substitution starting from a given macro expansion location.
  109. ExpansionRangeMap ExpansionRanges;
  110. Preprocessor *PP = nullptr;
  111. SourceManager *SM = nullptr;
  112. const LangOptions &LangOpts;
  113. /// This callback is called by the preprocessor.
  114. /// It stores the textual representation of the expanded token sequence for a
  115. /// macro expansion location.
  116. void onTokenLexed(const Token &Tok);
  117. };
  118. } // end namespace clang
  119. #endif // LLVM_CLANG_ANALYSIS_MACROEXPANSIONCONTEXT_H
  120. #ifdef __GNUC__
  121. #pragma GCC diagnostic pop
  122. #endif