+++ /dev/null
-//===--- FormatStringConverter.cpp - clang-tidy----------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Implementation of the FormatStringConverter class which is used to convert
-/// printf format strings to C++ std::formatter format strings.
-///
-//===----------------------------------------------------------------------===//
-
-#include "FormatStringConverter.h"
-#include "../utils/FixItHintUtils.h"
-#include "clang/AST/Expr.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Tooling/FixIt.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/Debug.h"
-
-using namespace clang::ast_matchers;
-using namespace clang::analyze_printf;
-
-namespace clang::tidy::utils {
-using clang::analyze_format_string::ConversionSpecifier;
-
-/// Is the passed type the actual "char" type, whether that be signed or
-/// unsigned, rather than explicit signed char or unsigned char types.
-static bool isRealCharType(const clang::QualType &Ty) {
- using namespace clang;
- const Type *DesugaredType = Ty->getUnqualifiedDesugaredType();
- if (const auto *BT = llvm::dyn_cast<BuiltinType>(DesugaredType))
- return (BT->getKind() == BuiltinType::Char_U ||
- BT->getKind() == BuiltinType::Char_S);
- return false;
-}
-
-/// If possible, return the text name of the signed type that corresponds to the
-/// passed integer type. If the passed type is already signed then its name is
-/// just returned. Only supports BuiltinTypes.
-static std::optional<std::string>
-getCorrespondingSignedTypeName(const clang::QualType &QT) {
- using namespace clang;
- const auto UQT = QT.getUnqualifiedType();
- if (const auto *BT = llvm::dyn_cast<BuiltinType>(UQT)) {
- switch (BT->getKind()) {
- case BuiltinType::UChar:
- case BuiltinType::Char_U:
- case BuiltinType::SChar:
- case BuiltinType::Char_S:
- return "signed char";
- case BuiltinType::UShort:
- case BuiltinType::Short:
- return "short";
- case BuiltinType::UInt:
- case BuiltinType::Int:
- return "int";
- case BuiltinType::ULong:
- case BuiltinType::Long:
- return "long";
- case BuiltinType::ULongLong:
- case BuiltinType::LongLong:
- return "long long";
- default:
- llvm::dbgs() << "Unknown corresponding signed type for BuiltinType '"
- << QT.getAsString() << "'\n";
- return std::nullopt;
- }
- }
-
- // Deal with fixed-width integer types from <cstdint>. Use std:: prefix only
- // if the argument type does.
- const std::string TypeName = UQT.getAsString();
- StringRef SimplifiedTypeName{TypeName};
- const bool InStd = SimplifiedTypeName.consume_front("std::");
- const StringRef Prefix = InStd ? "std::" : "";
-
- if (SimplifiedTypeName.starts_with("uint") &&
- SimplifiedTypeName.ends_with("_t"))
- return (Twine(Prefix) + SimplifiedTypeName.drop_front()).str();
-
- if (SimplifiedTypeName == "size_t")
- return (Twine(Prefix) + "ssize_t").str();
-
- llvm::dbgs() << "Unknown corresponding signed type for non-BuiltinType '"
- << UQT.getAsString() << "'\n";
- return std::nullopt;
-}
-
-/// If possible, return the text name of the unsigned type that corresponds to
-/// the passed integer type. If the passed type is already unsigned then its
-/// name is just returned. Only supports BuiltinTypes.
-static std::optional<std::string>
-getCorrespondingUnsignedTypeName(const clang::QualType &QT) {
- using namespace clang;
- const auto UQT = QT.getUnqualifiedType();
- if (const auto *BT = llvm::dyn_cast<BuiltinType>(UQT)) {
- switch (BT->getKind()) {
- case BuiltinType::SChar:
- case BuiltinType::Char_S:
- case BuiltinType::UChar:
- case BuiltinType::Char_U:
- return "unsigned char";
- case BuiltinType::Short:
- case BuiltinType::UShort:
- return "unsigned short";
- case BuiltinType::Int:
- case BuiltinType::UInt:
- return "unsigned int";
- case BuiltinType::Long:
- case BuiltinType::ULong:
- return "unsigned long";
- case BuiltinType::LongLong:
- case BuiltinType::ULongLong:
- return "unsigned long long";
- default:
- llvm::dbgs() << "Unknown corresponding unsigned type for BuiltinType '"
- << UQT.getAsString() << "'\n";
- return std::nullopt;
- }
- }
-
- // Deal with fixed-width integer types from <cstdint>. Use std:: prefix only
- // if the argument type does.
- const std::string TypeName = UQT.getAsString();
- StringRef SimplifiedTypeName{TypeName};
- const bool InStd = SimplifiedTypeName.consume_front("std::");
- const StringRef Prefix = InStd ? "std::" : "";
-
- if (SimplifiedTypeName.starts_with("int") &&
- SimplifiedTypeName.ends_with("_t"))
- return (Twine(Prefix) + "u" + SimplifiedTypeName).str();
-
- if (SimplifiedTypeName == "ssize_t")
- return (Twine(Prefix) + "size_t").str();
- if (SimplifiedTypeName == "ptrdiff_t")
- return (Twine(Prefix) + "size_t").str();
-
- llvm::dbgs() << "Unknown corresponding unsigned type for non-BuiltinType '"
- << UQT.getAsString() << "'\n";
- return std::nullopt;
-}
-
-static std::optional<std::string>
-castTypeForArgument(ConversionSpecifier::Kind ArgKind,
- const clang::QualType &QT) {
- if (ArgKind == ConversionSpecifier::Kind::uArg)
- return getCorrespondingUnsignedTypeName(QT);
- return getCorrespondingSignedTypeName(QT);
-}
-
-static bool isMatchingSignedness(ConversionSpecifier::Kind ArgKind,
- const clang::QualType &ArgType) {
- if (ArgKind == ConversionSpecifier::Kind::uArg)
- return ArgType->isUnsignedIntegerType();
- return ArgType->isSignedIntegerType();
-}
-
-namespace {
-AST_MATCHER(clang::QualType, isRealChar) {
- return clang::tidy::utils::isRealCharType(Node);
-}
-} // namespace
-
-static bool castMismatchedIntegerTypes(const CallExpr *Call, bool StrictMode) {
- /// For printf-style functions, the signedness of the type printed is
- /// indicated by the corresponding type in the format string.
- /// std::print will determine the signedness from the type of the
- /// argument. This means that it is necessary to generate a cast in
- /// StrictMode to ensure that the exact behaviour is maintained.
- /// However, for templated functions like absl::PrintF and
- /// fmt::printf, the signedness of the type printed is also taken from
- /// the actual argument like std::print, so such casts are never
- /// necessary. printf-style functions are variadic, whereas templated
- /// ones aren't, so we can use that to distinguish between the two
- /// cases.
- if (StrictMode) {
- const FunctionDecl *FuncDecl = Call->getDirectCallee();
- assert(FuncDecl);
- return FuncDecl->isVariadic();
- }
- return false;
-}
-
-FormatStringConverter::FormatStringConverter(ASTContext *ContextIn,
- const CallExpr *Call,
- unsigned FormatArgOffset,
- bool StrictMode,
- const LangOptions &LO)
- : Context(ContextIn),
- CastMismatchedIntegerTypes(castMismatchedIntegerTypes(Call, StrictMode)),
- Args(Call->getArgs()), NumArgs(Call->getNumArgs()),
- ArgsOffset(FormatArgOffset + 1), LangOpts(LO) {
- assert(ArgsOffset <= NumArgs);
- FormatExpr = llvm::dyn_cast<StringLiteral>(
- Args[FormatArgOffset]->IgnoreImplicitAsWritten());
- assert(FormatExpr);
- if (!FormatExpr->isOrdinary())
- return; // No wide string support yet
- PrintfFormatString = FormatExpr->getString();
-
- // Assume that the output will be approximately the same size as the input,
- // but perhaps with a few escapes expanded.
- const size_t EstimatedGrowth = 8;
- StandardFormatString.reserve(PrintfFormatString.size() + EstimatedGrowth);
- StandardFormatString.push_back('\"');
-
- const bool IsFreeBsdkPrintf = false;
-
- using clang::analyze_format_string::ParsePrintfString;
- ParsePrintfString(*this, PrintfFormatString.data(),
- PrintfFormatString.data() + PrintfFormatString.size(),
- LangOpts, Context->getTargetInfo(), IsFreeBsdkPrintf);
- finalizeFormatText();
-}
-
-void FormatStringConverter::emitAlignment(const PrintfSpecifier &FS,
- std::string &FormatSpec) {
- ConversionSpecifier::Kind ArgKind = FS.getConversionSpecifier().getKind();
-
- // We only care about alignment if a field width is specified
- if (FS.getFieldWidth().getHowSpecified() != OptionalAmount::NotSpecified) {
- if (ArgKind == ConversionSpecifier::sArg) {
- // Strings are left-aligned by default with std::format, so we only
- // need to emit an alignment if this one needs to be right aligned.
- if (!FS.isLeftJustified())
- FormatSpec.push_back('>');
- } else {
- // Numbers are right-aligned by default with std::format, so we only
- // need to emit an alignment if this one needs to be left aligned.
- if (FS.isLeftJustified())
- FormatSpec.push_back('<');
- }
- }
-}
-
-void FormatStringConverter::emitSign(const PrintfSpecifier &FS,
- std::string &FormatSpec) {
- const ConversionSpecifier Spec = FS.getConversionSpecifier();
-
- // Ignore on something that isn't numeric. For printf it's would be a
- // compile-time warning but ignored at runtime, but for std::format it
- // ought to be a compile-time error.
- if (Spec.isAnyIntArg() || Spec.isDoubleArg()) {
- // + is preferred to ' '
- if (FS.hasPlusPrefix())
- FormatSpec.push_back('+');
- else if (FS.hasSpacePrefix())
- FormatSpec.push_back(' ');
- }
-}
-
-void FormatStringConverter::emitAlternativeForm(const PrintfSpecifier &FS,
- std::string &FormatSpec) {
- if (FS.hasAlternativeForm()) {
- switch (FS.getConversionSpecifier().getKind()) {
- case ConversionSpecifier::Kind::aArg:
- case ConversionSpecifier::Kind::AArg:
- case ConversionSpecifier::Kind::eArg:
- case ConversionSpecifier::Kind::EArg:
- case ConversionSpecifier::Kind::fArg:
- case ConversionSpecifier::Kind::FArg:
- case ConversionSpecifier::Kind::gArg:
- case ConversionSpecifier::Kind::GArg:
- case ConversionSpecifier::Kind::xArg:
- case ConversionSpecifier::Kind::XArg:
- case ConversionSpecifier::Kind::oArg:
- FormatSpec.push_back('#');
- break;
- default:
- // Alternative forms don't exist for other argument kinds
- break;
- }
- }
-}
-
-void FormatStringConverter::emitFieldWidth(const PrintfSpecifier &FS,
- std::string &FormatSpec) {
- {
- const OptionalAmount FieldWidth = FS.getFieldWidth();
- switch (FieldWidth.getHowSpecified()) {
- case OptionalAmount::NotSpecified:
- break;
- case OptionalAmount::Constant:
- FormatSpec.append(llvm::utostr(FieldWidth.getConstantAmount()));
- break;
- case OptionalAmount::Arg:
- FormatSpec.push_back('{');
- if (FieldWidth.usesPositionalArg()) {
- // std::format argument identifiers are zero-based, whereas printf
- // ones are one based.
- assert(FieldWidth.getPositionalArgIndex() > 0U);
- FormatSpec.append(llvm::utostr(FieldWidth.getPositionalArgIndex() - 1));
- }
- FormatSpec.push_back('}');
- break;
- case OptionalAmount::Invalid:
- break;
- }
- }
-}
-
-void FormatStringConverter::emitPrecision(const PrintfSpecifier &FS,
- std::string &FormatSpec) {
- const OptionalAmount FieldPrecision = FS.getPrecision();
- switch (FieldPrecision.getHowSpecified()) {
- case OptionalAmount::NotSpecified:
- break;
- case OptionalAmount::Constant:
- FormatSpec.push_back('.');
- FormatSpec.append(llvm::utostr(FieldPrecision.getConstantAmount()));
- break;
- case OptionalAmount::Arg:
- FormatSpec.push_back('.');
- FormatSpec.push_back('{');
- if (FieldPrecision.usesPositionalArg()) {
- // std::format argument identifiers are zero-based, whereas printf
- // ones are one based.
- assert(FieldPrecision.getPositionalArgIndex() > 0U);
- FormatSpec.append(
- llvm::utostr(FieldPrecision.getPositionalArgIndex() - 1));
- }
- FormatSpec.push_back('}');
- break;
- case OptionalAmount::Invalid:
- break;
- }
-}
-
-void FormatStringConverter::emitStringArgument(const Expr *Arg) {
- // If the argument is the result of a call to std::string::c_str() or
- // data() with a return type of char then we can remove that call and
- // pass the std::string directly. We don't want to do so if the return
- // type is not a char pointer (though it's unlikely that such code would
- // compile without warnings anyway.) See RedundantStringCStrCheck.
-
- if (!StringCStrCallExprMatcher) {
- // Lazily create the matcher
- const auto StringDecl = type(hasUnqualifiedDesugaredType(recordType(
- hasDeclaration(cxxRecordDecl(hasName("::std::basic_string"))))));
- const auto StringExpr = expr(
- anyOf(hasType(StringDecl), hasType(qualType(pointsTo(StringDecl)))));
-
- StringCStrCallExprMatcher =
- cxxMemberCallExpr(
- on(StringExpr.bind("arg")), callee(memberExpr().bind("member")),
- callee(cxxMethodDecl(hasAnyName("c_str", "data"),
- returns(pointerType(pointee(isRealChar()))))))
- .bind("call");
- }
-
- auto CStrMatches = match(*StringCStrCallExprMatcher, *Arg, *Context);
- if (CStrMatches.size() == 1)
- ArgCStrRemovals.push_back(CStrMatches.front());
- else if (Arg->getType()->isPointerType()) {
- const QualType Pointee = Arg->getType()->getPointeeType();
- // printf is happy to print signed char and unsigned char strings, but
- // std::format only likes char strings.
- if (Pointee->isCharType() && !isRealCharType(Pointee))
- ArgFixes.emplace_back(Arg, "reinterpret_cast<const char *>(");
- }
-}
-
-bool FormatStringConverter::emitIntegerArgument(
- ConversionSpecifier::Kind ArgKind, const Expr *Arg, unsigned ArgIndex,
- std::string &FormatSpec) {
- const clang::QualType &ArgType = Arg->getType();
- if (ArgType->isBooleanType()) {
- // std::format will print bool as either "true" or "false" by default,
- // but printf prints them as "0" or "1". Be compatible with printf by
- // requesting decimal output.
- FormatSpec.push_back('d');
- } else if (ArgType->isEnumeralType()) {
- // std::format will try to find a specialization to print the enum
- // (and probably fail), whereas printf would have just expected it to
- // be passed as its underlying type. However, printf will have forced
- // the signedness based on the format string, so we need to do the
- // same.
- if (const auto *ET = ArgType->getAs<EnumType>()) {
- if (const std::optional<std::string> MaybeCastType =
- castTypeForArgument(ArgKind, ET->getDecl()->getIntegerType()))
- ArgFixes.emplace_back(
- Arg, (Twine("static_cast<") + *MaybeCastType + ">(").str());
- else
- return conversionNotPossible(
- (Twine("argument ") + Twine(ArgIndex) + " has unexpected enum type")
- .str());
- }
- } else if (CastMismatchedIntegerTypes &&
- !isMatchingSignedness(ArgKind, ArgType)) {
- // printf will happily print an unsigned type as signed if told to.
- // Even -Wformat doesn't warn for this. std::format will format as
- // unsigned unless we cast it.
- if (const std::optional<std::string> MaybeCastType =
- castTypeForArgument(ArgKind, ArgType))
- ArgFixes.emplace_back(
- Arg, (Twine("static_cast<") + *MaybeCastType + ">(").str());
- else
- return conversionNotPossible(
- (Twine("argument ") + Twine(ArgIndex) + " cannot be cast to " +
- Twine(ArgKind == ConversionSpecifier::Kind::uArg ? "unsigned"
- : "signed") +
- " integer type to match format"
- " specifier and StrictMode is enabled")
- .str());
- } else if (isRealCharType(ArgType) || !ArgType->isIntegerType()) {
- // Only specify integer if the argument is of a different type
- FormatSpec.push_back('d');
- }
- return true;
-}
-
-/// Append the corresponding standard format string type fragment to FormatSpec,
-/// and store any argument fixes for later application.
-/// @returns true on success, false on failure
-bool FormatStringConverter::emitType(const PrintfSpecifier &FS, const Expr *Arg,
- std::string &FormatSpec) {
- ConversionSpecifier::Kind ArgKind = FS.getConversionSpecifier().getKind();
- switch (ArgKind) {
- case ConversionSpecifier::Kind::sArg:
- emitStringArgument(Arg);
- break;
- case ConversionSpecifier::Kind::cArg:
- // The type must be "c" to get a character unless the type is exactly
- // char (whether that be signed or unsigned for the target.)
- if (!isRealCharType(Arg->getType()))
- FormatSpec.push_back('c');
- break;
- case ConversionSpecifier::Kind::dArg:
- case ConversionSpecifier::Kind::iArg:
- case ConversionSpecifier::Kind::uArg:
- if (!emitIntegerArgument(ArgKind, Arg, FS.getArgIndex() + ArgsOffset,
- FormatSpec))
- return false;
- break;
- case ConversionSpecifier::Kind::pArg: {
- const clang::QualType &ArgType = Arg->getType();
- // std::format knows how to format void pointers and nullptrs
- if (!ArgType->isNullPtrType() && !ArgType->isVoidPointerType())
- ArgFixes.emplace_back(Arg, "static_cast<const void *>(");
- break;
- }
- case ConversionSpecifier::Kind::xArg:
- FormatSpec.push_back('x');
- break;
- case ConversionSpecifier::Kind::XArg:
- FormatSpec.push_back('X');
- break;
- case ConversionSpecifier::Kind::oArg:
- FormatSpec.push_back('o');
- break;
- case ConversionSpecifier::Kind::aArg:
- FormatSpec.push_back('a');
- break;
- case ConversionSpecifier::Kind::AArg:
- FormatSpec.push_back('A');
- break;
- case ConversionSpecifier::Kind::eArg:
- FormatSpec.push_back('e');
- break;
- case ConversionSpecifier::Kind::EArg:
- FormatSpec.push_back('E');
- break;
- case ConversionSpecifier::Kind::fArg:
- FormatSpec.push_back('f');
- break;
- case ConversionSpecifier::Kind::FArg:
- FormatSpec.push_back('F');
- break;
- case ConversionSpecifier::Kind::gArg:
- FormatSpec.push_back('g');
- break;
- case ConversionSpecifier::Kind::GArg:
- FormatSpec.push_back('G');
- break;
- default:
- // Something we don't understand
- return conversionNotPossible((Twine("argument ") +
- Twine(FS.getArgIndex() + ArgsOffset) +
- " has an unsupported format specifier")
- .str());
- }
-
- return true;
-}
-
-/// Append the standard format string equivalent of the passed PrintfSpecifier
-/// to StandardFormatString and store any argument fixes for later application.
-/// @returns true on success, false on failure
-bool FormatStringConverter::convertArgument(const PrintfSpecifier &FS,
- const Expr *Arg,
- std::string &StandardFormatString) {
- // The specifier must have an associated argument
- assert(FS.consumesDataArgument());
-
- StandardFormatString.push_back('{');
-
- if (FS.usesPositionalArg()) {
- // std::format argument identifiers are zero-based, whereas printf ones
- // are one based.
- assert(FS.getPositionalArgIndex() > 0U);
- StandardFormatString.append(llvm::utostr(FS.getPositionalArgIndex() - 1));
- }
-
- // std::format format argument parts to potentially emit:
- // [[fill]align][sign]["#"]["0"][width]["."precision][type]
- std::string FormatSpec;
-
- // printf doesn't support specifying the fill character - it's always a
- // space, so we never need to generate one.
-
- emitAlignment(FS, FormatSpec);
- emitSign(FS, FormatSpec);
- emitAlternativeForm(FS, FormatSpec);
-
- if (FS.hasLeadingZeros())
- FormatSpec.push_back('0');
-
- emitFieldWidth(FS, FormatSpec);
- emitPrecision(FS, FormatSpec);
-
- if (!emitType(FS, Arg, FormatSpec))
- return false;
-
- if (!FormatSpec.empty()) {
- StandardFormatString.push_back(':');
- StandardFormatString.append(FormatSpec);
- }
-
- StandardFormatString.push_back('}');
- return true;
-}
-
-/// Called for each format specifier by ParsePrintfString.
-bool FormatStringConverter::HandlePrintfSpecifier(const PrintfSpecifier &FS,
- const char *StartSpecifier,
- unsigned SpecifierLen,
- const TargetInfo &Target) {
-
- const size_t StartSpecifierPos = StartSpecifier - PrintfFormatString.data();
- assert(StartSpecifierPos + SpecifierLen <= PrintfFormatString.size());
-
- // Everything before the specifier needs copying verbatim
- assert(StartSpecifierPos >= PrintfFormatStringPos);
-
- appendFormatText(StringRef(PrintfFormatString.begin() + PrintfFormatStringPos,
- StartSpecifierPos - PrintfFormatStringPos));
-
- const ConversionSpecifier::Kind ArgKind =
- FS.getConversionSpecifier().getKind();
-
- // Skip over specifier
- PrintfFormatStringPos = StartSpecifierPos + SpecifierLen;
- assert(PrintfFormatStringPos <= PrintfFormatString.size());
-
- FormatStringNeededRewriting = true;
-
- if (ArgKind == ConversionSpecifier::Kind::nArg) {
- // std::print doesn't do the equivalent of %n
- return conversionNotPossible("'%n' is not supported in format string");
- }
-
- if (ArgKind == ConversionSpecifier::Kind::PrintErrno) {
- // std::print doesn't support %m. In theory we could insert a
- // strerror(errno) parameter (assuming that libc has a thread-safe
- // implementation, which glibc does), but that would require keeping track
- // of the input and output parameter indices for position arguments too.
- return conversionNotPossible("'%m' is not supported in format string");
- }
-
- if (ArgKind == ConversionSpecifier::PercentArg) {
- StandardFormatString.push_back('%');
- return true;
- }
-
- const unsigned ArgIndex = FS.getArgIndex() + ArgsOffset;
- if (ArgIndex >= NumArgs) {
- // Argument index out of range. Give up.
- return conversionNotPossible(
- (Twine("argument index ") + Twine(ArgIndex) + " is out of range")
- .str());
- }
-
- return convertArgument(FS, Args[ArgIndex]->IgnoreImplicitAsWritten(),
- StandardFormatString);
-}
-
-/// Called at the very end just before applying fixes to capture the last part
-/// of the format string.
-void FormatStringConverter::finalizeFormatText() {
- appendFormatText(
- StringRef(PrintfFormatString.begin() + PrintfFormatStringPos,
- PrintfFormatString.size() - PrintfFormatStringPos));
- PrintfFormatStringPos = PrintfFormatString.size();
-
- if (StringRef(StandardFormatString).ends_with("\\n") &&
- !StringRef(StandardFormatString).ends_with("\\\\n")) {
- UsePrintNewlineFunction = true;
- FormatStringNeededRewriting = true;
- StandardFormatString.erase(StandardFormatString.end() - 2,
- StandardFormatString.end());
- }
-
- StandardFormatString.push_back('\"');
-}
-
-/// Append literal parts of the format text, reinstating escapes as required.
-void FormatStringConverter::appendFormatText(const StringRef Text) {
- for (const char Ch : Text) {
- if (Ch == '\a')
- StandardFormatString += "\\a";
- else if (Ch == '\b')
- StandardFormatString += "\\b";
- else if (Ch == '\f')
- StandardFormatString += "\\f";
- else if (Ch == '\n')
- StandardFormatString += "\\n";
- else if (Ch == '\r')
- StandardFormatString += "\\r";
- else if (Ch == '\t')
- StandardFormatString += "\\t";
- else if (Ch == '\v')
- StandardFormatString += "\\v";
- else if (Ch == '\"')
- StandardFormatString += "\\\"";
- else if (Ch == '\\')
- StandardFormatString += "\\\\";
- else if (Ch == '{') {
- StandardFormatString += "{{";
- FormatStringNeededRewriting = true;
- } else if (Ch == '}') {
- StandardFormatString += "}}";
- FormatStringNeededRewriting = true;
- } else if (Ch < 32) {
- StandardFormatString += "\\x";
- StandardFormatString += llvm::hexdigit(Ch >> 4, true);
- StandardFormatString += llvm::hexdigit(Ch & 0xf, true);
- } else
- StandardFormatString += Ch;
- }
-}
-
-/// Called by the check when it is ready to apply the fixes.
-void FormatStringConverter::applyFixes(DiagnosticBuilder &Diag,
- SourceManager &SM) {
- if (FormatStringNeededRewriting) {
- Diag << FixItHint::CreateReplacement(
- CharSourceRange::getTokenRange(FormatExpr->getBeginLoc(),
- FormatExpr->getEndLoc()),
- StandardFormatString);
- }
-
- for (const auto &[Arg, Replacement] : ArgFixes) {
- SourceLocation AfterOtherSide =
- Lexer::findNextToken(Arg->getEndLoc(), SM, LangOpts)->getLocation();
-
- Diag << FixItHint::CreateInsertion(Arg->getBeginLoc(), Replacement)
- << FixItHint::CreateInsertion(AfterOtherSide, ")");
- }
-
- for (const auto &Match : ArgCStrRemovals) {
- const auto *Call = Match.getNodeAs<CallExpr>("call");
- const auto *Arg = Match.getNodeAs<Expr>("arg");
- const auto *Member = Match.getNodeAs<MemberExpr>("member");
- const bool Arrow = Member->isArrow();
- const std::string ArgText =
- Arrow ? utils::fixit::formatDereference(*Arg, *Context)
- : tooling::fixit::getText(*Arg, *Context).str();
- if (!ArgText.empty())
- Diag << FixItHint::CreateReplacement(Call->getSourceRange(), ArgText);
- }
-}
-} // namespace clang::tidy::utils
+++ /dev/null
-// RUN: %check_clang_tidy -check-suffixes=,STRICT \
-// RUN: -std=c++23 %s modernize-use-std-print %t -- \
-// RUN: -config="{CheckOptions: [{key: StrictMode, value: true}]}" \
-// RUN: -- -isystem %clang_tidy_headers
-// RUN: %check_clang_tidy -check-suffixes=,NOTSTRICT \
-// RUN: -std=c++23 %s modernize-use-std-print %t -- \
-// RUN: -config="{CheckOptions: [{key: StrictMode, value: false}]}" \
-// RUN: -- -isystem %clang_tidy_headers
-#include <cstddef>
-#include <cstdint>
-#include <cstdio>
-// CHECK-FIXES: #include <print>
-#include <inttypes.h>
-#include <string.h>
-#include <string>
-
-void printf_simple() {
- printf("Hello");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("Hello");
-}
-
-void printf_newline() {
- printf("Hello\n");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello");
-
- printf("Split" "\n");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Split");
-
- printf("Double\n\n");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Double\n");
-}
-
-void printf_deceptive_newline() {
- printf("Hello\\n");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("Hello\\n");
-
- printf("Hello\x0a");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello");
-}
-
-void fprintf_simple() {
- fprintf(stderr, "Hello");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'fprintf' [modernize-use-std-print]
- // CHECK-FIXES: std::print(stderr, "Hello");
-}
-
-void std_printf_simple() {
- std::printf("std::Hello");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("std::Hello");
-}
-
-void printf_escape() {
- printf("before \t");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("before \t");
-
- printf("\n after");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("\n after");
-
- printf("before \a after");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("before \a after");
-
- printf("Bell\a%dBackspace\bFF%s\fNewline\nCR\rTab\tVT\vEscape\x1b\x07%d", 42, "string", 99);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("Bell\a{}Backspace\bFF{}\fNewline\nCR\rTab\tVT\vEscape\x1b\a{}", 42, "string", 99);
-
- printf("not special \x1b\x01\x7f");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("not special \x1b\x01\x7f");
-}
-
-void printf_percent() {
- printf("before %%");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("before %");
-
- printf("%% after");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("% after");
-
- printf("before %% after");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("before % after");
-
- printf("Hello %% and another %%");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("Hello % and another %");
-
- printf("Not a string %%s");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("Not a string %s");
-}
-
-void printf_curlies() {
- printf("%d {}", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{} {{[{][{]}}}}", 42);
-
- printf("{}");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{{[{][{]}}}}");
-}
-
-void printf_unsupported_format_specifiers() {
- int pos;
- printf("%d %n %d\n", 42, &pos, 72);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: unable to use 'std::println' instead of 'printf' because '%n' is not supported in format string [modernize-use-std-print]
-
- printf("Error %m\n");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: unable to use 'std::println' instead of 'printf' because '%m' is not supported in format string [modernize-use-std-print]
-}
-
-void printf_not_string_literal(const char *fmt) {
- // We can't convert the format string if it's not a literal
- printf(fmt, 42);
-}
-
-void printf_inttypes_ugliness() {
- // The one advantage of the checker seeing the token pasted version of the
- // format string is that we automatically cope with the horrendously-ugly
- // inttypes.h macros!
- int64_t u64 = 42;
- uintmax_t umax = 4242;
- printf("uint64:%" PRId64 " uintmax:%" PRIuMAX "\n", u64, umax);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("uint64:{} uintmax:{}", u64, umax);
-}
-
-void printf_raw_string() {
- // This one doesn't require the format string to be changed, so it stays intact
- printf(R"(First\Second)");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print(R"(First\Second)");
-
- // This one does require the format string to be changed, so unfortunately it
- // gets reformatted as a normal string.
- printf(R"(First %d\Second)", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("First {}\\Second", 42);
-}
-
-void printf_integer_d() {
- const bool b = true;
- // The "d" type is necessary here for compatibility with printf since
- // std::print will print booleans as "true" or "false".
- printf("Integer %d from bool\n", b);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {:d} from bool", b);
-
- // The "d" type is necessary here for compatibility with printf since
- // std::print will print booleans as "true" or "false".
- printf("Integer %i from bool\n", b);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {:d} from bool", b);
-
- // The 'd' is always necessary since otherwise the parameter will be formatted as a character
- const char c = 'A';
- printf("Integer %d from char\n", c);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {:d} from char", c);
-
- printf("Integer %i from char\n", 'A');
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {:d} from char", 'A');
-
- const signed char sc = 'A';
- printf("Integer %hhd from signed char\n", sc);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {} from signed char", sc);
-
- printf("Integer %hhi from signed char\n", sc);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {} from signed char", sc);
-
- const unsigned char uc = 'A';
- printf("Integer %hhd from unsigned char\n", uc);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integer {} from unsigned char", uc);
- // CHECK-FIXES-STRICT: std::println("Integer {} from unsigned char", static_cast<signed char>(uc));
-
- printf("Integer %hhi from unsigned char\n", uc);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integer {} from unsigned char", uc);
- // CHECK-FIXES-STRICT: std::println("Integer {} from unsigned char", static_cast<signed char>(uc));
-
- const int8_t i8 = 42;
- printf("Integer %" PRIi8 " from int8_t\n", i8);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {} from int8_t", i8);
-
- const int_fast8_t if8 = 42;
- printf("Integer %" PRIiFAST8 " from int_fast8_t\n", if8);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {} from int_fast8_t", if8);
-
- const int_least8_t il8 = 42;
- printf("Integer %" PRIiFAST8 " from int_least8_t\n", il8);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {} from int_least8_t", il8);
-
- const uint8_t u8 = 42U;
- const std::uint8_t su8 = u8;
- printf("Integers %" PRIi8 " and %" PRId8 " from uint8_t\n", u8, su8);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integers {} and {} from uint8_t", u8, su8);
- // CHECK-FIXES-STRICT: std::println("Integers {} and {} from uint8_t", static_cast<int8_t>(u8), static_cast<std::int8_t>(su8));
-
- const uint_fast8_t uf8 = 42U;
- printf("Integer %" PRIiFAST8 " from uint_fast8_t\n", uf8);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integer {} from uint_fast8_t", uf8);
- // CHECK-FIXES-STRICT: std::println("Integer {} from uint_fast8_t", static_cast<int_fast8_t>(uf8));
-
- const uint_least8_t ul8 = 42U;
- printf("Integer %" PRIiLEAST8 " from uint_least8_t\n", ul8);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integer {} from uint_least8_t", ul8);
- // CHECK-FIXES-STRICT: std::println("Integer {} from uint_least8_t", static_cast<int_least8_t>(ul8));
-
- const short s = 42;
- printf("Integer %hd from short\n", s);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {} from short", s);
-
- printf("Integer %hi from short\n", s);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {} from short", s);
-
- const unsigned short us = 42U;
- printf("Integer %hd from unsigned short\n", us);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integer {} from unsigned short", us);
- // CHECK-FIXES-STRICT: std::println("Integer {} from unsigned short", static_cast<short>(us));
-
- printf("Integer %hi from unsigned short\n", us);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integer {} from unsigned short", us);
- // CHECK-FIXES-STRICT: std::println("Integer {} from unsigned short", static_cast<short>(us));
-
- const int i = 42;
- printf("Integer %d from integer\n", i);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {} from integer", i);
-
- printf("Integer %i from integer\n", i);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {} from integer", i);
-
- const unsigned int ui = 42U;
- printf("Integer %d from unsigned integer\n", ui);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integer {} from unsigned integer", ui);
- // CHECK-FIXES-STRICT: std::println("Integer {} from unsigned integer", static_cast<int>(ui));
-
- printf("Integer %i from unsigned integer\n", ui);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integer {} from unsigned integer", ui);
- // CHECK-FIXES-STRICT: std::println("Integer {} from unsigned integer", static_cast<int>(ui));
-
- const long l = 42L;
- printf("Integer %ld from long\n", l);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {} from long", l);
-
- printf("Integer %li from long\n", l);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {} from long", l);
-
- const unsigned long ul = 42UL;
- printf("Integer %ld from unsigned long\n", ul);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integer {} from unsigned long", ul);
- // CHECK-FIXES-STRICT: std::println("Integer {} from unsigned long", static_cast<long>(ul));
-
- printf("Integer %li from unsigned long\n", ul);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integer {} from unsigned long", ul);
- // CHECK-FIXES-STRICT: std::println("Integer {} from unsigned long", static_cast<long>(ul));
-
- const long long ll = 42LL;
- printf("Integer %lld from long long\n", ll);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {} from long long", ll);
-
- printf("Integer %lli from long long\n", ll);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integer {} from long long", ll);
-
- const unsigned long long ull = 42ULL;
- printf("Integer %lld from unsigned long long\n", ull);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integer {} from unsigned long long", ull);
- // CHECK-FIXES-STRICT: std::println("Integer {} from unsigned long long", static_cast<long long>(ull));
-
- printf("Integer %lli from unsigned long long\n", ull);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integer {} from unsigned long long", ull);
- // CHECK-FIXES-STRICT: std::println("Integer {} from unsigned long long", static_cast<long long>(ull));
-
- const intmax_t im = 42;
- const std::intmax_t sim = im;
- printf("Integers %jd and %jd from intmax_t\n", im, sim);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integers {} and {} from intmax_t", im, sim);
-
- printf("Integers %ji and %ji from intmax_t\n", im, sim);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integers {} and {} from intmax_t", im, sim);
-
- const uintmax_t uim = 42;
- const std::uintmax_t suim = uim;
- printf("Integers %jd and %jd from uintmax_t\n", uim, suim);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integers {} and {} from uintmax_t", uim, suim);
- // CHECK-FIXES-STRICT: std::println("Integers {} and {} from uintmax_t", static_cast<intmax_t>(uim), static_cast<std::intmax_t>(suim));
-
- printf("Integer %ji from intmax_t\n", uim);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integer {} from intmax_t", uim);
- // CHECK-FIXES-STRICT: std::println("Integer {} from intmax_t", static_cast<intmax_t>(uim));
-
- const int ai[] = { 0, 1, 2, 3};
- const ptrdiff_t pd = &ai[3] - &ai[0];
- const std::ptrdiff_t spd = pd;
- printf("Integers %td and %td from ptrdiff_t\n", pd, spd);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integers {} and {} from ptrdiff_t", pd, spd);
-
- printf("Integers %ti and %ti from ptrdiff_t\n", pd, spd);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Integers {} and {} from ptrdiff_t", pd, spd);
-
- const size_t z = 42UL;
- const std::size_t sz = z;
- printf("Integers %zd and %zd from size_t\n", z, sz);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Integers {} and {} from size_t", z, sz);
- // CHECK-FIXES-STRICT: std::println("Integers {} and {} from size_t", static_cast<ssize_t>(z), static_cast<std::ssize_t>(sz));
-}
-
-void printf_integer_u()
-{
- const bool b = true;
- // The "d" type is necessary here for compatibility with printf since
- // std::print will print booleans as "true" or "false".
- printf("Unsigned integer %u from bool\n", b);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Unsigned integer {:d} from bool", b);
-
- const char c = 'A';
- printf("Unsigned integer %hhu from char\n", c);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Unsigned integer {:d} from char", c);
- // CHECK-FIXES-STRICT: std::println("Unsigned integer {} from char", static_cast<unsigned char>(c));
-
- const signed char sc = 'A';
- printf("Unsigned integer %hhu from signed char\n", sc);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Unsigned integer {} from signed char", sc);
- // CHECK-FIXES-STRICT: std::println("Unsigned integer {} from signed char", static_cast<unsigned char>(sc));
-
- printf("Unsigned integer %u from signed char\n", sc);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Unsigned integer {} from signed char", sc);
- // CHECK-FIXES-STRICT: std::println("Unsigned integer {} from signed char", static_cast<unsigned char>(sc));
-
- const unsigned char uc = 'A';
- printf("Unsigned integer %hhu from unsigned char\n", uc);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Unsigned integer {} from unsigned char", uc);
-
- printf("Unsigned integer %u from unsigned char\n", uc);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Unsigned integer {} from unsigned char", uc);
-
- const int8_t i8 = 42;
- printf("Unsigned integer %" PRIu8 " from int8_t\n", i8);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Unsigned integer {} from int8_t", i8);
- // CHECK-FIXES-STRICT: std::println("Unsigned integer {} from int8_t", static_cast<uint8_t>(i8));
-
- const int_fast8_t if8 = 42;
- printf("Unsigned integer %" PRIuFAST8 " from int_fast8_t\n", if8);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Unsigned integer {} from int_fast8_t", if8);
- // CHECK-FIXES-STRICT: std::println("Unsigned integer {} from int_fast8_t", static_cast<uint_fast8_t>(if8));
-
- const int_least8_t il8 = 42;
- printf("Unsigned integer %" PRIuFAST8 " from int_least8_t\n", il8);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Unsigned integer {} from int_least8_t", il8);
- // CHECK-FIXES-STRICT: std::println("Unsigned integer {} from int_least8_t", static_cast<uint_least8_t>(il8));
-
- const uint8_t u8 = 42U;
- printf("Unsigned integer %" PRIu8 " from uint8_t\n", u8);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Unsigned integer {} from uint8_t", u8);
-
- const uint_fast8_t uf8 = 42U;
- printf("Unsigned integer %" PRIuFAST8 " from uint_fast8_t\n", uf8);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Unsigned integer {} from uint_fast8_t", uf8);
-
- const uint_least8_t ul8 = 42U;
- printf("Unsigned integer %" PRIuLEAST8 " from uint_least8_t\n", ul8);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Unsigned integer {} from uint_least8_t", ul8);
-
- const short s = 42;
- printf("Unsigned integer %hu from short\n", s);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Unsigned integer {} from short", s);
- // CHECK-FIXES-STRICT: std::println("Unsigned integer {} from short", static_cast<unsigned short>(s));
-
- const unsigned short us = 42U;
- printf("Unsigned integer %hu from unsigned short\n", us);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Unsigned integer {} from unsigned short", us);
-
- const int i = 42;
- printf("Unsigned integer %u from signed integer\n", i);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Unsigned integer {} from signed integer", i);
- // CHECK-FIXES-STRICT: std::println("Unsigned integer {} from signed integer", static_cast<unsigned int>(i));
-
- const unsigned int ui = 42U;
- printf("Unsigned integer %u from unsigned integer\n", ui);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Unsigned integer {} from unsigned integer", ui);
-
- const long l = 42L;
- printf("Unsigned integer %u from signed long\n", l);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Unsigned integer {} from signed long", l);
- // CHECK-FIXES-STRICT: std::println("Unsigned integer {} from signed long", static_cast<unsigned long>(l));
-
- const unsigned long ul = 42UL;
- printf("Unsigned integer %lu from unsigned long\n", ul);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Unsigned integer {} from unsigned long", ul);
-
- const long long ll = 42LL;
- printf("Unsigned integer %llu from long long\n", ll);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Unsigned integer {} from long long", ll);
- // CHECK-FIXES-STRICT: std::println("Unsigned integer {} from long long", static_cast<unsigned long long>(ll));
-
- const unsigned long long ull = 42ULL;
- printf("Unsigned integer %llu from unsigned long long\n", ull);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Unsigned integer {} from unsigned long long", ull);
-
- const intmax_t im = 42;
- const std::intmax_t sim = im;
- printf("Unsigned integers %ju and %ju from intmax_t\n", im, sim);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Unsigned integers {} and {} from intmax_t", im, sim);
- // CHECK-FIXES-STRICT: std::println("Unsigned integers {} and {} from intmax_t", static_cast<uintmax_t>(im), static_cast<std::uintmax_t>(sim));
-
- const uintmax_t uim = 42U;
- const std::uintmax_t suim = uim;
- printf("Unsigned integers %ju and %ju from uintmax_t\n", uim, suim);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Unsigned integers {} and {} from uintmax_t", uim, suim);
-
- const int ai[] = { 0, 1, 2, 3};
- const ptrdiff_t pd = &ai[3] - &ai[0];
- const std::ptrdiff_t spd = pd;
- printf("Unsigned integers %tu and %tu from ptrdiff_t\n", pd, spd);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES-NOTSTRICT: std::println("Unsigned integers {} and {} from ptrdiff_t", pd, spd);
- // CHECK-FIXES-STRICT: std::println("Unsigned integers {} and {} from ptrdiff_t", static_cast<size_t>(pd), static_cast<std::size_t>(spd));
-
- const size_t z = 42U;
- const std::size_t sz = z;
- printf("Unsigned integers %zu and %zu from size_t\n", z, sz);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Unsigned integers {} and {} from size_t", z, sz);
-}
-
-// This checks that we get the argument offset right with the extra FILE * argument
-void fprintf_integer() {
- fprintf(stderr, "Integer %d from integer\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'fprintf' [modernize-use-std-print]
- // CHECK-FIXES: std::println(stderr, "Integer {} from integer", 42);
-
- fprintf(stderr, "Integer %i from integer\n", 65);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'fprintf' [modernize-use-std-print]
- // CHECK-FIXES: std::println(stderr, "Integer {} from integer", 65);
-
- fprintf(stderr, "Integer %i from char\n", 'A');
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'fprintf' [modernize-use-std-print]
- // CHECK-FIXES: std::println(stderr, "Integer {:d} from char", 'A');
-
- fprintf(stderr, "Integer %d from char\n", 'A');
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'fprintf' [modernize-use-std-print]
- // CHECK-FIXES: std::println(stderr, "Integer {:d} from char", 'A');
-}
-
-void printf_char() {
- const char c = 'A';
- printf("Char %c from char\n", c);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Char {} from char", c);
-
- const signed char sc = 'A';
- printf("Char %c from signed char\n", sc);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Char {:c} from signed char", sc);
-
- const unsigned char uc = 'A';
- printf("Char %c from unsigned char\n", uc);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Char {:c} from unsigned char", uc);
-
- const int i = 65;
- printf("Char %c from integer\n", i);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Char {:c} from integer", i);
-
- const unsigned int ui = 65;
- printf("Char %c from unsigned integer\n", ui);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Char {:c} from unsigned integer", ui);
-
- const unsigned long long ull = 65;
- printf("Char %c from unsigned long long\n", ull);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Char {:c} from unsigned long long", ull);
-}
-
-void printf_bases() {
- printf("Hex %lx\n", 42L);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hex {:x}", 42L);
-
- printf("HEX %X\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("HEX {:X}", 42);
-
- printf("Oct %lo\n", 42L);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Oct {:o}", 42L);
-}
-
-void printf_alternative_forms() {
- printf("Hex %#lx\n", 42L);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hex {:#x}", 42L);
-
- printf("HEX %#X\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("HEX {:#X}", 42);
-
- printf("Oct %#lo\n", 42L);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Oct {:#o}", 42L);
-
- printf("Double %#f %#F\n", -42.0, -42.0);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Double {:#f} {:#F}", -42.0, -42.0);
-
- printf("Double %#g %#G\n", -42.0, -42.0);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Double {:#g} {:#G}", -42.0, -42.0);
-
- printf("Double %#e %#E\n", -42.0, -42.0);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Double {:#e} {:#E}", -42.0, -42.0);
-
- printf("Double %#a %#A\n", -42.0, -42.0);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Double {:#a} {:#A}", -42.0, -42.0);
-
- // Characters don't have an alternate form
- printf("Char %#c\n", 'A');
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Char {}", 'A');
-
- // Strings don't have an alternate form
- printf("Char %#c\n", 'A');
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Char {}", 'A');
-}
-
-void printf_string() {
- printf("Hello %s after\n", "Goodbye");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {} after", "Goodbye");
-
- // std::print can't print signed char strings.
- const signed char *sstring = reinterpret_cast<const signed char *>("ustring");
- printf("signed char string %s\n", sstring);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("signed char string {}", reinterpret_cast<const char *>(sstring));
-
- // std::print can't print unsigned char strings.
- const unsigned char *ustring = reinterpret_cast<const unsigned char *>("ustring");
- printf("unsigned char string %s\n", ustring);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("unsigned char string {}", reinterpret_cast<const char *>(ustring));
-}
-
-void printf_float() {
- // If the type is not specified then either f or e will be used depending on
- // whichever is shorter. This means that it is necessary to be specific to
- // maintain compatibility with printf.
-
- // TODO: Should we force a cast here, since printf will promote to double
- // automatically, but std::format will not, which could result in different
- // output?
-
- const float f = 42.0F;
- printf("Hello %f after\n", f);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:f} after", f);
-
- printf("Hello %g after\n", f);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:g} after", f);
-
- printf("Hello %e after\n", f);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:e} after", f);
-}
-
-void printf_double() {
- // If the type is not specified then either f or e will be used depending on
- // whichever is shorter. This means that it is necessary to be specific to
- // maintain compatibility with printf.
-
- const double d = 42.0;
- printf("Hello %f after\n", d);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:f} after", d);
-
- printf("Hello %g after\n", d);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:g} after", d);
-
- printf("Hello %e after\n", d);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:e} after", d);
-}
-
-void printf_long_double() {
- // If the type is not specified then either f or e will be used depending on
- // whichever is shorter. This means that it is necessary to be specific to
- // maintain compatibility with printf.
-
- const long double ld = 42.0L;
- printf("Hello %Lf after\n", ld);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:f} after", ld);
-
- printf("Hello %g after\n", ld);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:g} after", ld);
-
- printf("Hello %e after\n", ld);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:e} after", ld);
-}
-
-void printf_pointer() {
- int i;
- double j;
- printf("Int* %p %s %p\n", &i, "Double*", &j);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Int* {} {} {}", static_cast<const void *>(&i), "Double*", static_cast<const void *>(&j));
-
- printf("%p\n", nullptr);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("{}", nullptr);
-
- const auto np = nullptr;
- printf("%p\n", np);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("{}", np);
-
- // NULL isn't a pointer, so std::print needs some help.
- printf("%p\n", NULL);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("{}", static_cast<const void *>(NULL));
-
- printf("%p\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("{}", static_cast<const void *>(42));
-
- // If we already have a void pointer then no cast is required.
- printf("%p\n", reinterpret_cast<const void *>(44));
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("{}", reinterpret_cast<const void *>(44));
-
- const void *p;
- printf("%p\n", p);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("{}", p);
-
- // But a pointer to a pointer to void does need a cast
- const void **pp;
- printf("%p\n", pp);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("{}", static_cast<const void *>(pp));
-
- printf("%p\n", printf_pointer);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("{}", static_cast<const void *>(printf_pointer));
-}
-
-class AClass
-{
- int member;
-
- void printf_this_pointer()
- {
- printf("%p\n", this);
- // CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("{}", static_cast<const void *>(this));
- }
-
- void printf_pointer_to_member_function()
- {
- printf("%p\n", &AClass::printf_pointer_to_member_function);
- // CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("{}", static_cast<const void *>(&AClass::printf_pointer_to_member_function));
- }
-
- void printf_pointer_to_member_variable()
- {
- printf("%p\n", &AClass::member);
- // CHECK-MESSAGES: [[@LINE-1]]:5: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("{}", static_cast<const void *>(&AClass::member));
- }
-};
-
-void printf_positional_arg() {
- printf("%1$d", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{0}", 42);
-
- printf("before %1$d", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("before {0}", 42);
-
- printf("%1$d after", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{0} after", 42);
-
- printf("before %1$d after", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("before {0} after", 42);
-
- printf("before %2$d between %1$s after", "string", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("before {1} between {0} after", "string", 42);
-}
-
-// printf always defaults to right justification,, no matter what the type is of
-// the argument. std::format uses left justification by default for strings, and
-// right justification for numbers.
-void printf_right_justified() {
- printf("Right-justified integer %4d after\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Right-justified integer {:4} after", 42);
-
- printf("Right-justified double %4f\n", 227.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Right-justified double {:4f}", 227.2);
-
- printf("Right-justified double %4g\n", 227.4);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Right-justified double {:4g}", 227.4);
-
- printf("Right-justified integer with field width argument %*d after\n", 5, 424242);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Right-justified integer with field width argument {:{}} after", 5, 424242);
-
- printf("Right-justified integer with field width argument %2$*1$d after\n", 5, 424242);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Right-justified integer with field width argument {1:{0}} after", 5, 424242);
-
- printf("Right-justified string %20s\n", "Hello");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Right-justified string {:>20}", "Hello");
-
- printf("Right-justified string with field width argument %2$*1$s after\n", 20, "wibble");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Right-justified string with field width argument {1:>{0}} after", 20, "wibble");
-}
-
-// printf always requires - for left justification, no matter what the type is
-// of the argument. std::format uses left justification by default for strings,
-// and right justification for numbers.
-void printf_left_justified() {
- printf("Left-justified integer %-4d\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Left-justified integer {:<4}", 42);
-
- printf("Left-justified integer %--4d\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Left-justified integer {:<4}", 42);
-
- printf("Left-justified double %-4f\n", 227.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Left-justified double {:<4f}", 227.2);
-
- printf("Left-justified double %-4g\n", 227.4);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Left-justified double {:<4g}", 227.4);
-
- printf("Left-justified integer with field width argument %-*d after\n", 5, 424242);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Left-justified integer with field width argument {:<{}} after", 5, 424242);
-
- printf("Left-justified integer with field width argument %2$-*1$d after\n", 5, 424242);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Left-justified integer with field width argument {1:<{0}} after", 5, 424242);
-
- printf("Left-justified string %-20s\n", "Hello");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Left-justified string {:20}", "Hello");
-
- printf("Left-justified string with field width argument %2$-*1$s after\n", 5, "wibble");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Left-justified string with field width argument {1:{0}} after", 5, "wibble");
-}
-
-void printf_precision() {
- printf("Hello %.3f\n", 3.14159);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:.3f}", 3.14159);
-
- printf("Hello %10.3f\n", 3.14159);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:10.3f}", 3.14159);
-
- printf("Hello %.*f after\n", 10, 3.14159265358979323846);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:.{}f} after", 10, 3.14159265358979323846);
-
- printf("Hello %10.*f after\n", 3, 3.14159265358979323846);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:10.{}f} after", 3, 3.14159265358979323846);
-
- printf("Hello %*.*f after\n", 10, 4, 3.14159265358979323846);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:{}.{}f} after", 10, 4, 3.14159265358979323846);
-
- printf("Hello %1$.*2$f after\n", 3.14159265358979323846, 4);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {0:.{1}f} after", 3.14159265358979323846, 4);
-
- // Precision is ignored, but maintained on non-numeric arguments
- printf("Hello %.5s\n", "Goodbye");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:.5}", "Goodbye");
-
- printf("Hello %.5c\n", 'G');
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {:.5}", 'G');
-}
-
-void printf_field_width_and_precision() {
- printf("Hello %1$*2$.*3$f after\n", 3.14159265358979323846, 4, 2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Hello {0:{1}.{2}f} after", 3.14159265358979323846, 4, 2);
-}
-
-void printf_alternative_form() {
- printf("Wibble %#x\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Wibble {:#x}", 42);
-
- printf("Wibble %#20x\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Wibble {:#20x}", 42);
-
- printf("Wibble %#020x\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Wibble {:#020x}", 42);
-
- printf("Wibble %#-20x\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Wibble {:<#20x}", 42);
-}
-
-void printf_leading_plus() {
- printf("Positive integer %+d\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Positive integer {:+}", 42);
-
- printf("Positive double %+f\n", 42.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Positive double {:+f}", 42.2);
-
- printf("Positive double %+g\n", 42.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Positive double {:+g}", 42.2);
-
- // Ignore leading plus on strings to avoid potential runtime exception where
- // printf would have just ignored it.
- printf("Positive string %+s\n", "string");
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Positive string {}", "string");
-}
-
-void printf_leading_space() {
- printf("Spaced integer % d\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Spaced integer {: }", 42);
-
- printf("Spaced integer %- d\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Spaced integer {: }", 42);
-
- printf("Spaced double % f\n", 42.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Spaced double {: f}", 42.2);
-
- printf("Spaced double % g\n", 42.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Spaced double {: g}", 42.2);
-}
-
-void printf_leading_zero() {
- printf("Leading zero integer %03d\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Leading zero integer {:03}", 42);
-
- printf("Leading minus and zero integer %-03d minus ignored\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Leading minus and zero integer {:<03} minus ignored", 42);
-
- printf("Leading zero unsigned integer %03u\n", 42U);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Leading zero unsigned integer {:03}", 42U);
-
- printf("Leading zero double %03f\n", 42.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Leading zero double {:03f}", 42.2);
-
- printf("Leading zero double %03g\n", 42.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Leading zero double {:03g}", 42.2);
-}
-
-void printf_leading_plus_and_space() {
- // printf prefers plus to space. {fmt} will throw if both are present.
- printf("Spaced integer % +d\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Spaced integer {:+}", 42);
-
- printf("Spaced double %+ f\n", 42.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Spaced double {:+f}", 42.2);
-
- printf("Spaced double % +g\n", 42.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Spaced double {:+g}", 42.2);
-}
-
-void printf_leading_zero_and_plus() {
- printf("Leading zero integer %+03d\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Leading zero integer {:+03}", 42);
-
- printf("Leading zero double %0+3f\n", 42.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Leading zero double {:+03f}", 42.2);
-
- printf("Leading zero double %0+3g\n", 42.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Leading zero double {:+03g}", 42.2);
-}
-
-void printf_leading_zero_and_space() {
- printf("Leading zero and space integer %0 3d\n", 42);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Leading zero and space integer {: 03}", 42);
-
- printf("Leading zero and space double %0 3f\n", 42.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Leading zero and space double {: 03f}", 42.2);
-
- printf("Leading zero and space double %0 3g\n", 42.2);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("Leading zero and space double {: 03g}", 42.2);
-}
-
-// add signed plained enum too
-enum PlainEnum { red };
-enum SignedPlainEnum { black = -42 };
-enum BoolEnum : unsigned int { yellow };
-enum CharEnum : char { purple };
-enum SCharEnum : signed char { aquamarine };
-enum UCharEnum : unsigned char { pink };
-enum ShortEnum : short { beige };
-enum UShortEnum : unsigned short { grey };
-enum IntEnum : int { green };
-enum UIntEnum : unsigned int { blue };
-enum LongEnum : long { magenta };
-enum ULongEnum : unsigned long { cyan };
-enum LongLongEnum : long long { taupe };
-enum ULongLongEnum : unsigned long long { brown };
-
-void printf_enum_d() {
- PlainEnum plain_enum;
- printf("%d", plain_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<int>(plain_enum));
-
- SignedPlainEnum splain_enum;
- printf("%d", splain_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<int>(splain_enum));
-
- BoolEnum bool_enum;
- printf("%d", bool_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<int>(bool_enum));
-
- CharEnum char_enum;
- printf("%d", char_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<signed char>(char_enum));
-
- SCharEnum schar_enum;
- printf("%d", schar_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<signed char>(schar_enum));
-
- UCharEnum uchar_enum;
- printf("%d", uchar_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<signed char>(uchar_enum));
-
- ShortEnum short_enum;
- printf("%d", short_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<short>(short_enum));
-
- UShortEnum ushort_enum;
- printf("%d", ushort_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<short>(ushort_enum));
-
- IntEnum int_enum;
- printf("%d", int_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<int>(int_enum));
-
- UIntEnum uint_enum;
- printf("%d", uint_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<int>(uint_enum));
-
- LongEnum long_enum;
- printf("%d", long_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<long>(long_enum));
-
- ULongEnum ulong_enum;
- printf("%d", ulong_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<long>(ulong_enum));
-
- LongLongEnum longlong_enum;
- printf("%d", longlong_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<long long>(longlong_enum));
-
- ULongLongEnum ulonglong_enum;
- printf("%d", ulonglong_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<long long>(ulonglong_enum));
-}
-
-void printf_enum_u() {
- PlainEnum plain_enum;
- printf("%u", plain_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned int>(plain_enum));
-
- SignedPlainEnum splain_enum;
- printf("%u", splain_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned int>(splain_enum));
-
- BoolEnum bool_enum;
- printf("%u", bool_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned int>(bool_enum));
-
- CharEnum char_enum;
- printf("%u", char_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned char>(char_enum));
-
- SCharEnum schar_enum;
- printf("%u", schar_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned char>(schar_enum));
-
- UCharEnum uchar_enum;
- printf("%u", uchar_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned char>(uchar_enum));
-
- ShortEnum short_enum;
- printf("%u", short_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned short>(short_enum));
-
- UShortEnum ushort_enum;
- printf("%u", ushort_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned short>(ushort_enum));
-
- IntEnum int_enum;
- printf("%u", int_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned int>(int_enum));
-
- UIntEnum uint_enum;
- printf("%u", uint_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned int>(uint_enum));
-
- LongEnum long_enum;
- printf("%u", long_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned long>(long_enum));
-
- ULongEnum ulong_enum;
- printf("%u", ulong_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned long>(ulong_enum));
-
- LongLongEnum longlong_enum;
- printf("%u", longlong_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned long long>(longlong_enum));
-
- ULongLongEnum ulonglong_enum;
- printf("%u", ulonglong_enum);
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("{}", static_cast<unsigned long long>(ulonglong_enum));
-}
-
-void printf_string_function(const char *(*callback)()) {
- printf("printf string from callback %s", callback());
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("printf string from callback {}", callback());
-}
-
-template <typename CharType>
-struct X
-{
- const CharType *str() const;
-};
-
-void printf_string_member_function(const X<char> &x, const X<const char> &cx) {
- printf("printf string from member function %s", x.str());
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("printf string from member function {}", x.str());
-
- printf("printf string from member function on const %s", cx.str());
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("printf string from member function on const {}", cx.str());
-}
-
-void printf_string_cstr(const std::string &s1, const std::string &s2) {
- printf("printf string one c_str %s", s1.c_str());
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("printf string one c_str {}", s1);
-
- printf("printf string two c_str %s %s\n", s1.c_str(), s2.data());
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("printf string two c_str {} {}", s1, s2);
-}
-
-void printf_not_char_string_cstr(const std::wstring &ws1) {
- // This test is to check that we only remove
- // std::basic_string<CharType>::c_str()/data() when CharType is char. I've
- // been unable to come up with a genuine situation where someone would have
- // actually successfully called those methods when this isn't the case without
- // -Wformat warning, but it seems sensible to restrict removal regardless.
- printf("printf bogus wstring c_str %s", ws1.c_str());
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("printf bogus wstring c_str {}", ws1.c_str());
-}
-
-void fprintf_string_cstr(const std::string &s1) {
- fprintf(stderr, "fprintf string c_str %s", s1.c_str());
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'fprintf' [modernize-use-std-print]
- // CHECK-FIXES: std::print(stderr, "fprintf string c_str {}", s1);
-}
-
-void printf_string_pointer_cstr(const std::string *s1, const std::string *s2) {
- printf("printf string pointer one c_str %s", s1->c_str());
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("printf string pointer one c_str {}", *s1);
-
- printf("printf string pointer two c_str %s %s\n", s1->c_str(), s2->data());
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("printf string pointer two c_str {} {}", *s1, *s2);
-}
-
-void fprintf_string_pointer_cstr(const std::string *s1) {
- fprintf(stderr, "fprintf string pointer c_str %s", s1->c_str());
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'fprintf' [modernize-use-std-print]
- // CHECK-FIXES: std::print(stderr, "fprintf string pointer c_str {}", *s1);
-}
-
-template <typename T>
-struct iterator {
- T *operator->();
- T &operator*();
-};
-
-void printf_iterator_cstr(iterator<std::string> i1, iterator<std::string> i2)
-{
- printf("printf iterator c_str %s %s\n", i1->c_str(), i2->data());
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::println' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::println("printf iterator c_str {} {}", *i1, *i2);
-}
-
-// Something that isn't std::string, so the calls to c_str() and data() must not
-// be removed even though the printf call will be replaced.
-struct S
-{
- const char *c_str() const;
- const char *data() const;
-};
-
-void p(S s1, S *s2)
-{
- printf("Not std::string %s %s", s1.c_str(), s2->c_str());
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("Not std::string {} {}", s1.c_str(), s2->c_str());
-
- printf("Not std::string %s %s", s1.data(), s2->data());
- // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use 'std::print' instead of 'printf' [modernize-use-std-print]
- // CHECK-FIXES: std::print("Not std::string {} {}", s1.data(), s2->data());
-}