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
20namespace clang {
21
22namespace detail {
23class 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.
73class MacroExpansionContext {
74public:
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
102private:
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