xref: /netbsd-src/external/apache2/llvm/dist/clang/include/clang/Analysis/MacroExpansionContext.h (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
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