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