Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:22

0001 //===--- FormatStringConverter.h - clang-tidy--------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 ///
0009 /// \file
0010 /// Declaration of the FormatStringConverter class which is used to convert
0011 /// printf format strings to C++ std::formatter format strings.
0012 ///
0013 //===----------------------------------------------------------------------===//
0014 
0015 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_FORMATSTRINGCONVERTER_H
0016 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_FORMATSTRINGCONVERTER_H
0017 
0018 #include "clang/AST/ASTContext.h"
0019 #include "clang/AST/FormatString.h"
0020 #include "clang/ASTMatchers/ASTMatchers.h"
0021 #include <string>
0022 
0023 namespace clang::tidy::utils {
0024 
0025 /// Convert a printf-style format string to a std::formatter-style one, and
0026 /// prepare any casts that are required to wrap the arguments to retain printf
0027 /// compatibility. This class is expecting to work on the already-cooked format
0028 /// string (i.e. all the escapes have been converted) so we have to convert them
0029 /// back. This means that we might not convert them back using the same form.
0030 class FormatStringConverter
0031     : public clang::analyze_format_string::FormatStringHandler {
0032 public:
0033   using ConversionSpecifier = clang::analyze_format_string::ConversionSpecifier;
0034   using PrintfSpecifier = analyze_printf::PrintfSpecifier;
0035 
0036   struct Configuration {
0037     bool StrictMode = false;
0038     bool AllowTrailingNewlineRemoval = false;
0039   };
0040 
0041   FormatStringConverter(ASTContext *Context, const CallExpr *Call,
0042                         unsigned FormatArgOffset, Configuration Config,
0043                         const LangOptions &LO, SourceManager &SM,
0044                         Preprocessor &PP);
0045 
0046   bool canApply() const { return ConversionNotPossibleReason.empty(); }
0047   const std::string &conversionNotPossibleReason() const {
0048     return ConversionNotPossibleReason;
0049   }
0050   void applyFixes(DiagnosticBuilder &Diag, SourceManager &SM);
0051   bool usePrintNewlineFunction() const { return UsePrintNewlineFunction; }
0052 
0053 private:
0054   ASTContext *Context;
0055   const Configuration Config;
0056   const bool CastMismatchedIntegerTypes;
0057   const Expr *const *Args;
0058   const unsigned NumArgs;
0059   unsigned ArgsOffset;
0060   const LangOptions &LangOpts;
0061   std::string ConversionNotPossibleReason;
0062   bool FormatStringNeededRewriting = false;
0063   bool UsePrintNewlineFunction = false;
0064   size_t PrintfFormatStringPos = 0U;
0065   StringRef PrintfFormatString;
0066 
0067   /// Lazily-created c_str() call matcher
0068   std::optional<clang::ast_matchers::StatementMatcher>
0069       StringCStrCallExprMatcher;
0070 
0071   const StringLiteral *FormatExpr;
0072   std::string StandardFormatString;
0073 
0074   /// Casts to be used to wrap arguments to retain printf compatibility.
0075   struct ArgumentFix {
0076     unsigned ArgIndex;
0077     std::string Fix;
0078 
0079     // We currently need this for emplace_back. Roll on C++20.
0080     explicit ArgumentFix(unsigned ArgIndex, std::string Fix)
0081         : ArgIndex(ArgIndex), Fix(std::move(Fix)) {}
0082   };
0083 
0084   std::vector<ArgumentFix> ArgFixes;
0085   std::vector<clang::ast_matchers::BoundNodes> ArgCStrRemovals;
0086 
0087   // Argument rotations to cope with the fact that std::print puts the value to
0088   // be formatted first and the width and precision afterwards whereas printf
0089   // puts the width and preicision first.
0090   std::vector<std::tuple<unsigned, unsigned>> ArgRotates;
0091 
0092   void emitAlignment(const PrintfSpecifier &FS, std::string &FormatSpec);
0093   void emitSign(const PrintfSpecifier &FS, std::string &FormatSpec);
0094   void emitAlternativeForm(const PrintfSpecifier &FS, std::string &FormatSpec);
0095   void emitFieldWidth(const PrintfSpecifier &FS, std::string &FormatSpec);
0096   void emitPrecision(const PrintfSpecifier &FS, std::string &FormatSpec);
0097   void emitStringArgument(unsigned ArgIndex, const Expr *Arg);
0098   bool emitIntegerArgument(ConversionSpecifier::Kind ArgKind, const Expr *Arg,
0099                            unsigned ArgIndex, std::string &FormatSpec);
0100 
0101   bool emitType(const PrintfSpecifier &FS, const Expr *Arg,
0102                 std::string &FormatSpec);
0103   bool convertArgument(const PrintfSpecifier &FS, const Expr *Arg,
0104                        std::string &StandardFormatString);
0105 
0106   void maybeRotateArguments(const PrintfSpecifier &FS);
0107 
0108   bool HandlePrintfSpecifier(const PrintfSpecifier &FS,
0109                              const char *StartSpecifier, unsigned SpecifierLen,
0110                              const TargetInfo &Target) override;
0111 
0112   void appendFormatText(StringRef Text);
0113   void finalizeFormatText();
0114   static std::optional<StringRef>
0115   formatStringContainsUnreplaceableMacro(const CallExpr *CallExpr,
0116                                          const StringLiteral *FormatExpr,
0117                                          SourceManager &SM, Preprocessor &PP);
0118   bool conversionNotPossible(std::string Reason) {
0119     ConversionNotPossibleReason = std::move(Reason);
0120     return false;
0121   }
0122 };
0123 
0124 } // namespace clang::tidy::utils
0125 
0126 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_FORMATSTRINGCONVERTER_H