1 //===- MacroExpansionContext.h - 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 9 #ifndef LLVM_CLANG_ANALYSIS_MACROEXPANSIONCONTEXT_H 10 #define LLVM_CLANG_ANALYSIS_MACROEXPANSIONCONTEXT_H 11 12 #include "clang/Basic/LangOptions.h" 13 #include "clang/Basic/SourceLocation.h" 14 #include "clang/Lex/Preprocessor.h" 15 #include "llvm/ADT/DenseMap.h" 16 #include "llvm/ADT/Optional.h" 17 #include "llvm/ADT/SmallString.h" 18 #include "llvm/ADT/SmallVector.h" 19 20 namespace clang { 21 22 namespace detail { 23 class MacroExpansionRangeRecorder; 24 } // namespace detail 25 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 80 /// Register the necessary callbacks to the Preprocessor to record the 81 /// expansion events and the generated tokens. Must ensure that this object 82 /// outlives the given Preprocessor. 83 void registerForPreprocessor(Preprocessor &PP); 84 85 /// \param MacroExpansionLoc Must be the expansion location of a macro. 86 /// \return The textual representation of the token sequence which was 87 /// substituted in place of the macro after the preprocessing. 88 /// If no macro was expanded at that location, returns llvm::None. 89 Optional<StringRef> getExpandedText(SourceLocation MacroExpansionLoc) const; 90 91 /// \param MacroExpansionLoc Must be the expansion location of a macro. 92 /// \return The text from the original source code which were substituted by 93 /// the macro expansion chain from the given location. 94 /// If no macro was expanded at that location, returns llvm::None. 95 Optional<StringRef> getOriginalText(SourceLocation MacroExpansionLoc) const; 96 97 LLVM_DUMP_METHOD void dumpExpansionRangesToStream(raw_ostream &OS) const; 98 LLVM_DUMP_METHOD void dumpExpandedTextsToStream(raw_ostream &OS) const; 99 LLVM_DUMP_METHOD void dumpExpansionRanges() const; 100 LLVM_DUMP_METHOD void dumpExpandedTexts() const; 101 102 private: 103 friend class detail::MacroExpansionRangeRecorder; 104 using MacroExpansionText = SmallString<40>; 105 using ExpansionMap = llvm::DenseMap<SourceLocation, MacroExpansionText>; 106 using ExpansionRangeMap = llvm::DenseMap<SourceLocation, SourceLocation>; 107 108 /// Associates the textual representation of the expanded tokens at the given 109 /// macro expansion location. 110 ExpansionMap ExpandedTokens; 111 112 /// Tracks which source location was the last affected by any macro 113 /// substitution starting from a given macro expansion location. 114 ExpansionRangeMap ExpansionRanges; 115 116 Preprocessor *PP = nullptr; 117 SourceManager *SM = nullptr; 118 const LangOptions &LangOpts; 119 120 /// This callback is called by the preprocessor. 121 /// It stores the textual representation of the expanded token sequence for a 122 /// macro expansion location. 123 void onTokenLexed(const Token &Tok); 124 }; 125 } // end namespace clang 126 127 #endif // LLVM_CLANG_ANALYSIS_MACROEXPANSIONCONTEXT_H 128