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/SmallString.h"
17#include "llvm/ADT/SmallVector.h"
18#include <optional>
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 std::nullopt.
89 std::optional<StringRef>
90 getExpandedText(SourceLocation MacroExpansionLoc) const;
91
92 /// \param MacroExpansionLoc Must be the expansion location of a macro.
93 /// \return The text from the original source code which were substituted by
94 /// the macro expansion chain from the given location.
95 /// If no macro was expanded at that location, returns std::nullopt.
96 std::optional<StringRef>
97 getOriginalText(SourceLocation MacroExpansionLoc) const;
98
99 LLVM_DUMP_METHOD void dumpExpansionRangesToStream(raw_ostream &OS) const;
100 LLVM_DUMP_METHOD void dumpExpandedTextsToStream(raw_ostream &OS) const;
101 LLVM_DUMP_METHOD void dumpExpansionRanges() const;
102 LLVM_DUMP_METHOD void dumpExpandedTexts() const;
103
104private:
105 friend class detail::MacroExpansionRangeRecorder;
106 using MacroExpansionText = SmallString<40>;
107 using ExpansionMap = llvm::DenseMap<SourceLocation, MacroExpansionText>;
108 using ExpansionRangeMap = llvm::DenseMap<SourceLocation, SourceLocation>;
109
110 /// Associates the textual representation of the expanded tokens at the given
111 /// macro expansion location.
112 ExpansionMap ExpandedTokens;
113
114 /// Tracks which source location was the last affected by any macro
115 /// substitution starting from a given macro expansion location.
116 ExpansionRangeMap ExpansionRanges;
117
118 Preprocessor *PP = nullptr;
119 SourceManager *SM = nullptr;
120 const LangOptions &LangOpts;
121
122 /// This callback is called by the preprocessor.
123 /// It stores the textual representation of the expanded token sequence for a
124 /// macro expansion location.
125 void onTokenLexed(const Token &Tok);
126};
127} // end namespace clang
128
129#endif // LLVM_CLANG_ANALYSIS_MACROEXPANSIONCONTEXT_H
130

source code of clang/include/clang/Analysis/MacroExpansionContext.h