Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:26

0001 //===- MacroExpansionContext.h - Macro expansion information ----*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLVM_CLANG_ANALYSIS_MACROEXPANSIONCONTEXT_H
0010 #define LLVM_CLANG_ANALYSIS_MACROEXPANSIONCONTEXT_H
0011 
0012 #include "clang/Basic/LangOptions.h"
0013 #include "clang/Basic/SourceLocation.h"
0014 #include "clang/Lex/Preprocessor.h"
0015 #include "llvm/ADT/DenseMap.h"
0016 #include "llvm/ADT/SmallString.h"
0017 #include "llvm/ADT/SmallVector.h"
0018 #include <optional>
0019 
0020 namespace clang {
0021 
0022 namespace detail {
0023 class MacroExpansionRangeRecorder;
0024 } // namespace detail
0025 
0026 /// MacroExpansionContext tracks the macro expansions processed by the
0027 /// Preprocessor. It means that it can track source locations from a single
0028 /// translation unit. For every macro expansion it can tell you what text will
0029 /// be substituted.
0030 ///
0031 /// It was designed to deal with:
0032 ///  - regular macros
0033 ///  - macro functions
0034 ///  - variadic macros
0035 ///  - transitive macro expansions
0036 ///  - macro redefinition
0037 ///  - unbalanced parenthesis
0038 ///
0039 /// \code{.c}
0040 ///   void bar();
0041 ///   #define retArg(x) x
0042 ///   #define retArgUnclosed retArg(bar()
0043 ///   #define BB CC
0044 ///   #define applyInt BB(int)
0045 ///   #define CC(x) retArgUnclosed
0046 ///
0047 ///   void unbalancedMacros() {
0048 ///     applyInt  );
0049 ///   //^~~~~~~~~~^ is the substituted range
0050 ///   // Substituted text is "applyInt  )"
0051 ///   // Expanded text is "bar()"
0052 ///   }
0053 ///
0054 ///   #define expandArgUnclosedCommaExpr(x) (x, bar(), 1
0055 ///   #define f expandArgUnclosedCommaExpr
0056 ///
0057 ///   void unbalancedMacros2() {
0058 ///     int x =  f(f(1))  ));  // Look at the parenthesis!
0059 ///   //         ^~~~~~^ is the substituted range
0060 ///   // Substituted text is "f(f(1))"
0061 ///   // Expanded text is "((1,bar(),1,bar(),1"
0062 ///   }
0063 /// \endcode
0064 /// \remark Currently we don't respect the whitespaces between expanded tokens,
0065 ///         so the output for this example might differ from the -E compiler
0066 ///         invocation.
0067 /// \remark All whitespaces are consumed while constructing the expansion.
0068 ///         After all identifier a single space inserted to produce a valid C
0069 ///         code even if identifier follows an other identifiers such as
0070 ///         variable declarations.
0071 /// \remark MacroExpansionContext object must outlive the Preprocessor
0072 ///         parameter.
0073 class MacroExpansionContext {
0074 public:
0075   /// Creates a MacroExpansionContext.
0076   /// \remark You must call registerForPreprocessor to set the required
0077   ///         onTokenLexed callback and the PPCallbacks.
0078   explicit MacroExpansionContext(const LangOptions &LangOpts);
0079 
0080   /// Register the necessary callbacks to the Preprocessor to record the
0081   /// expansion events and the generated tokens. Must ensure that this object
0082   /// outlives the given Preprocessor.
0083   void registerForPreprocessor(Preprocessor &PP);
0084 
0085   /// \param MacroExpansionLoc Must be the expansion location of a macro.
0086   /// \return The textual representation of the token sequence which was
0087   ///         substituted in place of the macro after the preprocessing.
0088   ///         If no macro was expanded at that location, returns std::nullopt.
0089   std::optional<StringRef>
0090   getExpandedText(SourceLocation MacroExpansionLoc) const;
0091 
0092   /// \param MacroExpansionLoc Must be the expansion location of a macro.
0093   /// \return The text from the original source code which were substituted by
0094   ///         the macro expansion chain from the given location.
0095   ///         If no macro was expanded at that location, returns std::nullopt.
0096   std::optional<StringRef>
0097   getOriginalText(SourceLocation MacroExpansionLoc) const;
0098 
0099   LLVM_DUMP_METHOD void dumpExpansionRangesToStream(raw_ostream &OS) const;
0100   LLVM_DUMP_METHOD void dumpExpandedTextsToStream(raw_ostream &OS) const;
0101   LLVM_DUMP_METHOD void dumpExpansionRanges() const;
0102   LLVM_DUMP_METHOD void dumpExpandedTexts() const;
0103 
0104 private:
0105   friend class detail::MacroExpansionRangeRecorder;
0106   using MacroExpansionText = SmallString<40>;
0107   using ExpansionMap = llvm::DenseMap<SourceLocation, MacroExpansionText>;
0108   using ExpansionRangeMap = llvm::DenseMap<SourceLocation, SourceLocation>;
0109 
0110   /// Associates the textual representation of the expanded tokens at the given
0111   /// macro expansion location.
0112   ExpansionMap ExpandedTokens;
0113 
0114   /// Tracks which source location was the last affected by any macro
0115   /// substitution starting from a given macro expansion location.
0116   ExpansionRangeMap ExpansionRanges;
0117 
0118   Preprocessor *PP = nullptr;
0119   SourceManager *SM = nullptr;
0120   const LangOptions &LangOpts;
0121 
0122   /// This callback is called by the preprocessor.
0123   /// It stores the textual representation of the expanded token sequence for a
0124   /// macro expansion location.
0125   void onTokenLexed(const Token &Tok);
0126 };
0127 } // end namespace clang
0128 
0129 #endif // LLVM_CLANG_ANALYSIS_MACROEXPANSIONCONTEXT_H