aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/include/clang/Analysis/MacroExpansionContext.h
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/include/clang/Analysis/MacroExpansionContext.h')
-rw-r--r--contrib/llvm-project/clang/include/clang/Analysis/MacroExpansionContext.h129
1 files changed, 129 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/include/clang/Analysis/MacroExpansionContext.h b/contrib/llvm-project/clang/include/clang/Analysis/MacroExpansionContext.h
new file mode 100644
index 000000000000..2a27aba76656
--- /dev/null
+++ b/contrib/llvm-project/clang/include/clang/Analysis/MacroExpansionContext.h
@@ -0,0 +1,129 @@
+//===- MacroExpansionContext.h - Macro expansion information ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_MACROEXPANSIONCONTEXT_H
+#define LLVM_CLANG_ANALYSIS_MACROEXPANSIONCONTEXT_H
+
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include <optional>
+
+namespace clang {
+
+namespace detail {
+class MacroExpansionRangeRecorder;
+} // namespace detail
+
+/// MacroExpansionContext tracks the macro expansions processed by the
+/// Preprocessor. It means that it can track source locations from a single
+/// translation unit. For every macro expansion it can tell you what text will
+/// be substituted.
+///
+/// It was designed to deal with:
+/// - regular macros
+/// - macro functions
+/// - variadic macros
+/// - transitive macro expansions
+/// - macro redefinition
+/// - unbalanced parenthesis
+///
+/// \code{.c}
+/// void bar();
+/// #define retArg(x) x
+/// #define retArgUnclosed retArg(bar()
+/// #define BB CC
+/// #define applyInt BB(int)
+/// #define CC(x) retArgUnclosed
+///
+/// void unbalancedMacros() {
+/// applyInt );
+/// //^~~~~~~~~~^ is the substituted range
+/// // Substituted text is "applyInt )"
+/// // Expanded text is "bar()"
+/// }
+///
+/// #define expandArgUnclosedCommaExpr(x) (x, bar(), 1
+/// #define f expandArgUnclosedCommaExpr
+///
+/// void unbalancedMacros2() {
+/// int x = f(f(1)) )); // Look at the parenthesis!
+/// // ^~~~~~^ is the substituted range
+/// // Substituted text is "f(f(1))"
+/// // Expanded text is "((1,bar(),1,bar(),1"
+/// }
+/// \endcode
+/// \remark Currently we don't respect the whitespaces between expanded tokens,
+/// so the output for this example might differ from the -E compiler
+/// invocation.
+/// \remark All whitespaces are consumed while constructing the expansion.
+/// After all identifier a single space inserted to produce a valid C
+/// code even if identifier follows an other identifiers such as
+/// variable declarations.
+/// \remark MacroExpansionContext object must outlive the Preprocessor
+/// parameter.
+class MacroExpansionContext {
+public:
+ /// Creates a MacroExpansionContext.
+ /// \remark You must call registerForPreprocessor to set the required
+ /// onTokenLexed callback and the PPCallbacks.
+ explicit MacroExpansionContext(const LangOptions &LangOpts);
+
+ /// Register the necessary callbacks to the Preprocessor to record the
+ /// expansion events and the generated tokens. Must ensure that this object
+ /// outlives the given Preprocessor.
+ void registerForPreprocessor(Preprocessor &PP);
+
+ /// \param MacroExpansionLoc Must be the expansion location of a macro.
+ /// \return The textual representation of the token sequence which was
+ /// substituted in place of the macro after the preprocessing.
+ /// If no macro was expanded at that location, returns std::nullopt.
+ std::optional<StringRef>
+ getExpandedText(SourceLocation MacroExpansionLoc) const;
+
+ /// \param MacroExpansionLoc Must be the expansion location of a macro.
+ /// \return The text from the original source code which were substituted by
+ /// the macro expansion chain from the given location.
+ /// If no macro was expanded at that location, returns std::nullopt.
+ std::optional<StringRef>
+ getOriginalText(SourceLocation MacroExpansionLoc) const;
+
+ LLVM_DUMP_METHOD void dumpExpansionRangesToStream(raw_ostream &OS) const;
+ LLVM_DUMP_METHOD void dumpExpandedTextsToStream(raw_ostream &OS) const;
+ LLVM_DUMP_METHOD void dumpExpansionRanges() const;
+ LLVM_DUMP_METHOD void dumpExpandedTexts() const;
+
+private:
+ friend class detail::MacroExpansionRangeRecorder;
+ using MacroExpansionText = SmallString<40>;
+ using ExpansionMap = llvm::DenseMap<SourceLocation, MacroExpansionText>;
+ using ExpansionRangeMap = llvm::DenseMap<SourceLocation, SourceLocation>;
+
+ /// Associates the textual representation of the expanded tokens at the given
+ /// macro expansion location.
+ ExpansionMap ExpandedTokens;
+
+ /// Tracks which source location was the last affected by any macro
+ /// substitution starting from a given macro expansion location.
+ ExpansionRangeMap ExpansionRanges;
+
+ Preprocessor *PP = nullptr;
+ SourceManager *SM = nullptr;
+ const LangOptions &LangOpts;
+
+ /// This callback is called by the preprocessor.
+ /// It stores the textual representation of the expanded token sequence for a
+ /// macro expansion location.
+ void onTokenLexed(const Token &Tok);
+};
+} // end namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_MACROEXPANSIONCONTEXT_H