clang-tools 24.0.0git
FormatStringConverter.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// Implementation of the FormatStringConverter class which is used to convert
11/// printf format strings to C++ std::formatter format strings.
12///
13//===----------------------------------------------------------------------===//
14
17#include "../utils/LexerUtils.h"
18#include "clang/AST/Expr.h"
19#include "clang/ASTMatchers/ASTMatchFinder.h"
20#include "clang/Basic/LangOptions.h"
21#include "clang/Lex/Lexer.h"
22#include "clang/Lex/Preprocessor.h"
23#include "clang/Tooling/FixIt.h"
24#include "llvm/ADT/StringExtras.h"
25#include "llvm/Support/Debug.h"
26#include "llvm/Support/Path.h"
27
28using namespace clang::ast_matchers;
29using namespace clang::analyze_printf;
30
31namespace clang::tidy::utils {
32using clang::analyze_format_string::ConversionSpecifier;
33
34/// Is the passed type the actual "char" type, whether that be signed or
35/// unsigned, rather than explicit signed char or unsigned char types.
36static bool isRealCharType(const QualType &Ty) {
37 using namespace clang;
38 const Type *DesugaredType = Ty->getUnqualifiedDesugaredType();
39 if (const auto *BT = dyn_cast<BuiltinType>(DesugaredType))
40 return (BT->getKind() == BuiltinType::Char_U ||
41 BT->getKind() == BuiltinType::Char_S);
42 return false;
43}
44
45/// If possible, return the text name of the signed type that corresponds to the
46/// passed integer type. If the passed type is already signed then its name is
47/// just returned. Only supports BuiltinTypes.
48static std::optional<std::string>
49getCorrespondingSignedTypeName(const QualType &QT) {
50 using namespace clang;
51 const auto UQT = QT.getUnqualifiedType();
52 if (const auto *BT = dyn_cast<BuiltinType>(UQT)) {
53 switch (BT->getKind()) {
54 case BuiltinType::UChar:
55 case BuiltinType::Char_U:
56 case BuiltinType::SChar:
57 case BuiltinType::Char_S:
58 return "signed char";
59 case BuiltinType::UShort:
60 case BuiltinType::Short:
61 return "short";
62 case BuiltinType::UInt:
63 case BuiltinType::Int:
64 return "int";
65 case BuiltinType::ULong:
66 case BuiltinType::Long:
67 return "long";
68 case BuiltinType::ULongLong:
69 case BuiltinType::LongLong:
70 return "long long";
71 default:
72 llvm::dbgs() << "Unknown corresponding signed type for BuiltinType '"
73 << QT.getAsString() << "'\n";
74 return std::nullopt;
75 }
76 }
77
78 // Deal with fixed-width integer types from <cstdint>. Use std:: prefix only
79 // if the argument type does.
80 const std::string TypeName = UQT.getAsString();
81 StringRef SimplifiedTypeName{TypeName};
82 const bool InStd = SimplifiedTypeName.consume_front("std::");
83 const StringRef Prefix = InStd ? "std::" : "";
84
85 if (SimplifiedTypeName.starts_with("uint") &&
86 SimplifiedTypeName.ends_with("_t"))
87 return (Twine(Prefix) + SimplifiedTypeName.drop_front()).str();
88
89 if (SimplifiedTypeName == "size_t")
90 return (Twine(Prefix) + "ssize_t").str();
91
92 llvm::dbgs() << "Unknown corresponding signed type for non-BuiltinType '"
93 << UQT.getAsString() << "'\n";
94 return std::nullopt;
95}
96
97/// If possible, return the text name of the unsigned type that corresponds to
98/// the passed integer type. If the passed type is already unsigned then its
99/// name is just returned. Only supports BuiltinTypes.
100static std::optional<std::string>
102 using namespace clang;
103 const auto UQT = QT.getUnqualifiedType();
104 if (const auto *BT = dyn_cast<BuiltinType>(UQT)) {
105 switch (BT->getKind()) {
106 case BuiltinType::SChar:
107 case BuiltinType::Char_S:
108 case BuiltinType::UChar:
109 case BuiltinType::Char_U:
110 return "unsigned char";
111 case BuiltinType::Short:
112 case BuiltinType::UShort:
113 return "unsigned short";
114 case BuiltinType::Int:
115 case BuiltinType::UInt:
116 return "unsigned int";
117 case BuiltinType::Long:
118 case BuiltinType::ULong:
119 return "unsigned long";
120 case BuiltinType::LongLong:
121 case BuiltinType::ULongLong:
122 return "unsigned long long";
123 default:
124 llvm::dbgs() << "Unknown corresponding unsigned type for BuiltinType '"
125 << UQT.getAsString() << "'\n";
126 return std::nullopt;
127 }
128 }
129
130 // Deal with fixed-width integer types from <cstdint>. Use std:: prefix only
131 // if the argument type does.
132 const std::string TypeName = UQT.getAsString();
133 StringRef SimplifiedTypeName{TypeName};
134 const bool InStd = SimplifiedTypeName.consume_front("std::");
135 const StringRef Prefix = InStd ? "std::" : "";
136
137 if (SimplifiedTypeName.starts_with("int") &&
138 SimplifiedTypeName.ends_with("_t"))
139 return (Twine(Prefix) + "u" + SimplifiedTypeName).str();
140
141 if (SimplifiedTypeName == "ssize_t")
142 return (Twine(Prefix) + "size_t").str();
143 if (SimplifiedTypeName == "ptrdiff_t")
144 return (Twine(Prefix) + "size_t").str();
145
146 llvm::dbgs() << "Unknown corresponding unsigned type for non-BuiltinType '"
147 << UQT.getAsString() << "'\n";
148 return std::nullopt;
149}
150
151static std::optional<std::string>
152castTypeForArgument(ConversionSpecifier::Kind ArgKind, const QualType &QT) {
153 if (ArgKind == ConversionSpecifier::Kind::uArg)
156}
157
158static bool isMatchingSignedness(ConversionSpecifier::Kind ArgKind,
159 const QualType &ArgType) {
160 if (const auto *BT = dyn_cast<BuiltinType>(ArgType)) {
161 // Unadorned char never matches any expected signedness since it
162 // could be signed or unsigned.
163 const auto ArgTypeKind = BT->getKind();
164 if (ArgTypeKind == BuiltinType::Char_U ||
165 ArgTypeKind == BuiltinType::Char_S)
166 return false;
167 }
168
169 if (ArgKind == ConversionSpecifier::Kind::uArg)
170 return ArgType->isUnsignedIntegerType();
171 return ArgType->isSignedIntegerType();
172}
173
174namespace {
175AST_MATCHER(QualType, isRealChar) { return utils::isRealCharType(Node); }
176} // namespace
177
178static bool castMismatchedIntegerTypes(const CallExpr *Call, bool StrictMode) {
179 /// For printf-style functions, the signedness of the type printed is
180 /// indicated by the corresponding type in the format string.
181 /// std::print will determine the signedness from the type of the
182 /// argument. This means that it is necessary to generate a cast in
183 /// StrictMode to ensure that the exact behaviour is maintained.
184 /// However, for templated functions like absl::PrintF and
185 /// fmt::printf, the signedness of the type printed is also taken from
186 /// the actual argument like std::print, so such casts are never
187 /// necessary. printf-style functions are variadic, whereas templated
188 /// ones aren't, so we can use that to distinguish between the two
189 /// cases.
190 if (StrictMode) {
191 const FunctionDecl *FuncDecl = Call->getDirectCallee();
192 assert(FuncDecl);
193 return FuncDecl->isVariadic();
194 }
195 return false;
196}
197
199 ASTContext *ContextIn, const CallExpr *Call, unsigned FormatArgOffset,
200 const Configuration ConfigIn, const LangOptions &LO, SourceManager &SM,
201 Preprocessor &PP)
202 : Context(ContextIn), Config(ConfigIn),
203 CastMismatchedIntegerTypes(
204 castMismatchedIntegerTypes(Call, ConfigIn.StrictMode)),
205 Args(Call->getArgs()), NumArgs(Call->getNumArgs()),
206 ArgsOffset(FormatArgOffset + 1), LangOpts(LO) {
207 assert(ArgsOffset <= NumArgs);
208 FormatExpr = dyn_cast<StringLiteral>(
209 Args[FormatArgOffset]->IgnoreUnlessSpelledInSource());
210
211 assert(FormatExpr && FormatExpr->isOrdinary());
212
213 if (const std::optional<StringRef> MaybeMacroName =
214 formatStringContainsUnreplaceableMacro(Call, FormatExpr, SM, PP);
215 MaybeMacroName) {
216 conversionNotPossible(
217 ("format string contains unreplaceable macro '" + *MaybeMacroName + "'")
218 .str());
219 return;
220 }
221
222 PrintfFormatString = FormatExpr->getString();
223
224 // Assume that the output will be approximately the same size as the input,
225 // but perhaps with a few escapes expanded.
226 const size_t EstimatedGrowth = 8;
227 StandardFormatString.reserve(PrintfFormatString.size() + EstimatedGrowth);
228 StandardFormatString.push_back('\"');
229
230 const bool IsFreeBsdkPrintf = false;
231
232 using clang::analyze_format_string::ParsePrintfString;
233 ParsePrintfString(*this, PrintfFormatString.data(),
234 PrintfFormatString.data() + PrintfFormatString.size(),
235 LangOpts, Context->getTargetInfo(), IsFreeBsdkPrintf);
236 finalizeFormatText();
237}
238
239std::optional<StringRef>
240FormatStringConverter::formatStringContainsUnreplaceableMacro(
241 const CallExpr *Call, const StringLiteral *FormatExpr, SourceManager &SM,
242 Preprocessor &PP) {
243 // If a macro invocation surrounds the entire call then we don't want that to
244 // inhibit conversion. The whole format string will appear to come from that
245 // macro, as will the function call.
246 std::optional<StringRef> MaybeSurroundingMacroName;
247 if (const SourceLocation BeginCallLoc = Call->getBeginLoc();
248 BeginCallLoc.isMacroID())
249 MaybeSurroundingMacroName =
250 Lexer::getImmediateMacroName(BeginCallLoc, SM, PP.getLangOpts());
251
252 for (auto I = FormatExpr->tokloc_begin(), E = FormatExpr->tokloc_end();
253 I != E; ++I) {
254 const SourceLocation &TokenLoc = *I;
255 if (TokenLoc.isMacroID()) {
256 const StringRef MacroName =
257 Lexer::getImmediateMacroName(TokenLoc, SM, PP.getLangOpts());
258
259 if (MaybeSurroundingMacroName != MacroName) {
260 // glibc uses __PRI64_PREFIX and __PRIPTR_PREFIX to define the prefixes
261 // for types that change size so we must look for multiple prefixes.
262 if (!MacroName.starts_with("PRI") && !MacroName.starts_with("__PRI"))
263 return MacroName;
264
265 const SourceLocation TokenSpellingLoc = SM.getSpellingLoc(TokenLoc);
266 const OptionalFileEntryRef MaybeFileEntry =
267 SM.getFileEntryRefForID(SM.getFileID(TokenSpellingLoc));
268 if (!MaybeFileEntry)
269 return MacroName;
270
271 HeaderSearch &HS = PP.getHeaderSearchInfo();
272 // Check if the file is a system header
273 if (!isSystem(HS.getFileDirFlavor(*MaybeFileEntry)) ||
274 llvm::sys::path::filename(MaybeFileEntry->getName()) !=
275 "inttypes.h")
276 return MacroName;
277 }
278 }
279 }
280 return std::nullopt;
281}
282
283void FormatStringConverter::emitAlignment(const PrintfSpecifier &FS,
284 std::string &FormatSpec) {
285 const ConversionSpecifier::Kind ArgKind =
286 FS.getConversionSpecifier().getKind();
287
288 // We only care about alignment if a field width is specified
289 if (FS.getFieldWidth().getHowSpecified() != OptionalAmount::NotSpecified) {
290 if (ArgKind == ConversionSpecifier::sArg) {
291 // Strings are left-aligned by default with std::format, so we only
292 // need to emit an alignment if this one needs to be right aligned.
293 if (!FS.isLeftJustified())
294 FormatSpec.push_back('>');
295 } else {
296 // Numbers are right-aligned by default with std::format, so we only
297 // need to emit an alignment if this one needs to be left aligned.
298 if (FS.isLeftJustified())
299 FormatSpec.push_back('<');
300 }
301 }
302}
303
304void FormatStringConverter::emitSign(const PrintfSpecifier &FS,
305 std::string &FormatSpec) {
306 const ConversionSpecifier Spec = FS.getConversionSpecifier();
307
308 // Ignore on something that isn't numeric. For printf it's would be a
309 // compile-time warning but ignored at runtime, but for std::format it
310 // ought to be a compile-time error.
311 if (Spec.isAnyIntArg() || Spec.isDoubleArg()) {
312 // + is preferred to ' '
313 if (FS.hasPlusPrefix())
314 FormatSpec.push_back('+');
315 else if (FS.hasSpacePrefix())
316 FormatSpec.push_back(' ');
317 }
318}
319
320void FormatStringConverter::emitAlternativeForm(const PrintfSpecifier &FS,
321 std::string &FormatSpec) {
322 if (FS.hasAlternativeForm()) {
323 switch (FS.getConversionSpecifier().getKind()) {
324 case ConversionSpecifier::Kind::aArg:
325 case ConversionSpecifier::Kind::AArg:
326 case ConversionSpecifier::Kind::eArg:
327 case ConversionSpecifier::Kind::EArg:
328 case ConversionSpecifier::Kind::fArg:
329 case ConversionSpecifier::Kind::FArg:
330 case ConversionSpecifier::Kind::gArg:
331 case ConversionSpecifier::Kind::GArg:
332 case ConversionSpecifier::Kind::xArg:
333 case ConversionSpecifier::Kind::XArg:
334 case ConversionSpecifier::Kind::oArg:
335 FormatSpec.push_back('#');
336 break;
337 default:
338 // Alternative forms don't exist for other argument kinds
339 break;
340 }
341 }
342}
343
344void FormatStringConverter::emitFieldWidth(const PrintfSpecifier &FS,
345 std::string &FormatSpec) {
346 {
347 const OptionalAmount FieldWidth = FS.getFieldWidth();
348 switch (FieldWidth.getHowSpecified()) {
349 case OptionalAmount::NotSpecified:
350 break;
351 case OptionalAmount::Constant:
352 FormatSpec.append(llvm::utostr(FieldWidth.getConstantAmount()));
353 break;
354 case OptionalAmount::Arg:
355 FormatSpec.push_back('{');
356 if (FieldWidth.usesPositionalArg()) {
357 // std::format argument identifiers are zero-based, whereas printf
358 // ones are one based.
359 assert(FieldWidth.getPositionalArgIndex() > 0U);
360 FormatSpec.append(llvm::utostr(FieldWidth.getPositionalArgIndex() - 1));
361 }
362 FormatSpec.push_back('}');
363 break;
364 case OptionalAmount::Invalid:
365 break;
366 }
367 }
368}
369
370void FormatStringConverter::emitPrecision(const PrintfSpecifier &FS,
371 std::string &FormatSpec) {
372 const OptionalAmount FieldPrecision = FS.getPrecision();
373 switch (FieldPrecision.getHowSpecified()) {
374 case OptionalAmount::NotSpecified:
375 break;
376 case OptionalAmount::Constant:
377 FormatSpec.push_back('.');
378 FormatSpec.append(llvm::utostr(FieldPrecision.getConstantAmount()));
379 break;
380 case OptionalAmount::Arg:
381 FormatSpec.push_back('.');
382 FormatSpec.push_back('{');
383 if (FieldPrecision.usesPositionalArg()) {
384 // std::format argument identifiers are zero-based, whereas printf
385 // ones are one based.
386 assert(FieldPrecision.getPositionalArgIndex() > 0U);
387 FormatSpec.append(
388 llvm::utostr(FieldPrecision.getPositionalArgIndex() - 1));
389 }
390 FormatSpec.push_back('}');
391 break;
392 case OptionalAmount::Invalid:
393 break;
394 }
395}
396
397void FormatStringConverter::maybeRotateArguments(const PrintfSpecifier &FS) {
398 unsigned ArgCount = 0;
399 const OptionalAmount FieldWidth = FS.getFieldWidth();
400 const OptionalAmount FieldPrecision = FS.getPrecision();
401
402 if (FieldWidth.getHowSpecified() == OptionalAmount::Arg &&
403 !FieldWidth.usesPositionalArg())
404 ++ArgCount;
405 if (FieldPrecision.getHowSpecified() == OptionalAmount::Arg &&
406 !FieldPrecision.usesPositionalArg())
407 ++ArgCount;
408
409 if (ArgCount)
410 ArgRotates.emplace_back(FS.getArgIndex() + ArgsOffset, ArgCount);
411}
412
413void FormatStringConverter::emitStringArgument(unsigned ArgIndex,
414 const Expr *Arg) {
415 // If the argument is the result of a call to std::string::c_str() or
416 // data() with a return type of char then we can remove that call and
417 // pass the std::string directly. We don't want to do so if the return
418 // type is not a char pointer (though it's unlikely that such code would
419 // compile without warnings anyway.) See RedundantStringCStrCheck.
420
421 if (!StringCStrCallExprMatcher) {
422 // Lazily create the matcher
423 const auto StringDecl = type(hasUnqualifiedDesugaredType(recordType(
424 hasDeclaration(cxxRecordDecl(hasName("::std::basic_string"))))));
425 const auto StringExpr = expr(
426 anyOf(hasType(StringDecl), hasType(qualType(pointsTo(StringDecl)))));
427
428 StringCStrCallExprMatcher =
429 cxxMemberCallExpr(
430 on(StringExpr.bind("arg")), callee(memberExpr().bind("member")),
431 callee(cxxMethodDecl(hasAnyName("c_str", "data"),
432 returns(pointerType(pointee(isRealChar()))))))
433 .bind("call");
434 }
435
436 auto CStrMatches = match(*StringCStrCallExprMatcher, *Arg, *Context);
437 if (CStrMatches.size() == 1) {
438 ArgCStrRemovals.push_back(CStrMatches.front());
439 } else if (Arg->getType()->isPointerType()) {
440 const QualType Pointee = Arg->getType()->getPointeeType();
441 // printf is happy to print signed char and unsigned char strings, but
442 // std::format only likes char strings.
443 if (Pointee->isCharType() && !isRealCharType(Pointee))
444 ArgFixes.emplace_back(ArgIndex, "reinterpret_cast<const char *>(");
445 }
446}
447
448bool FormatStringConverter::emitIntegerArgument(
449 ConversionSpecifier::Kind ArgKind, const Expr *Arg, unsigned ArgIndex,
450 std::string &FormatSpec) {
451 const QualType &ArgType = Arg->getType();
452 if (ArgType->isBooleanType()) {
453 // std::format will print bool as either "true" or "false" by default,
454 // but printf prints them as "0" or "1". Be compatible with printf by
455 // requesting decimal output.
456 FormatSpec.push_back('d');
457 } else if (ArgType->isEnumeralType()) {
458 // std::format will try to find a specialization to print the enum
459 // (and probably fail), whereas printf would have just expected it to
460 // be passed as its underlying type. However, printf will have forced
461 // the signedness based on the format string, so we need to do the
462 // same.
463 if (const auto *ED = ArgType->getAsEnumDecl()) {
464 if (const std::optional<std::string> MaybeCastType =
465 castTypeForArgument(ArgKind, ED->getIntegerType()))
466 ArgFixes.emplace_back(
467 ArgIndex, (Twine("static_cast<") + *MaybeCastType + ">(").str());
468 else
469 return conversionNotPossible(
470 (Twine("argument ") + Twine(ArgIndex) + " has unexpected enum type")
471 .str());
472 }
473 } else if (CastMismatchedIntegerTypes &&
474 !isMatchingSignedness(ArgKind, ArgType)) {
475 // printf will happily print an unsigned type as signed if told to.
476 // Even -Wformat doesn't warn for this. std::format will format as
477 // unsigned unless we cast it.
478 if (const std::optional<std::string> MaybeCastType =
479 castTypeForArgument(ArgKind, ArgType))
480 ArgFixes.emplace_back(
481 ArgIndex, (Twine("static_cast<") + *MaybeCastType + ">(").str());
482 else
483 return conversionNotPossible(
484 (Twine("argument ") + Twine(ArgIndex) + " cannot be cast to " +
485 Twine(ArgKind == ConversionSpecifier::Kind::uArg ? "unsigned"
486 : "signed") +
487 " integer type to match format"
488 " specifier and StrictMode is enabled")
489 .str());
490 } else if (isRealCharType(ArgType) || !ArgType->isIntegerType()) {
491 // Only specify integer if the argument is of a different type
492 FormatSpec.push_back('d');
493 }
494 return true;
495}
496
497/// Append the corresponding standard format string type fragment to FormatSpec,
498/// and store any argument fixes for later application.
499/// @returns true on success, false on failure
500bool FormatStringConverter::emitType(const PrintfSpecifier &FS, const Expr *Arg,
501 std::string &FormatSpec) {
502 const ConversionSpecifier::Kind ArgKind =
503 FS.getConversionSpecifier().getKind();
504 switch (ArgKind) {
505 case ConversionSpecifier::Kind::sArg:
506 emitStringArgument(FS.getArgIndex() + ArgsOffset, Arg);
507 break;
508 case ConversionSpecifier::Kind::cArg:
509 // The type must be "c" to get a character unless the type is exactly
510 // char (whether that be signed or unsigned for the target.)
511 if (!isRealCharType(Arg->getType()))
512 FormatSpec.push_back('c');
513 break;
514 case ConversionSpecifier::Kind::dArg:
515 case ConversionSpecifier::Kind::iArg:
516 case ConversionSpecifier::Kind::uArg:
517 if (!emitIntegerArgument(ArgKind, Arg, FS.getArgIndex() + ArgsOffset,
518 FormatSpec))
519 return false;
520 break;
521 case ConversionSpecifier::Kind::pArg: {
522 const QualType &ArgType = Arg->getType();
523 // std::format knows how to format void pointers and nullptrs
524 if (!ArgType->isNullPtrType() && !ArgType->isVoidPointerType())
525 ArgFixes.emplace_back(FS.getArgIndex() + ArgsOffset,
526 "static_cast<const void *>(");
527 break;
528 }
529 case ConversionSpecifier::Kind::xArg:
530 FormatSpec.push_back('x');
531 break;
532 case ConversionSpecifier::Kind::XArg:
533 FormatSpec.push_back('X');
534 break;
535 case ConversionSpecifier::Kind::oArg:
536 FormatSpec.push_back('o');
537 break;
538 case ConversionSpecifier::Kind::aArg:
539 FormatSpec.push_back('a');
540 break;
541 case ConversionSpecifier::Kind::AArg:
542 FormatSpec.push_back('A');
543 break;
544 case ConversionSpecifier::Kind::eArg:
545 FormatSpec.push_back('e');
546 break;
547 case ConversionSpecifier::Kind::EArg:
548 FormatSpec.push_back('E');
549 break;
550 case ConversionSpecifier::Kind::fArg:
551 FormatSpec.push_back('f');
552 break;
553 case ConversionSpecifier::Kind::FArg:
554 FormatSpec.push_back('F');
555 break;
556 case ConversionSpecifier::Kind::gArg:
557 FormatSpec.push_back('g');
558 break;
559 case ConversionSpecifier::Kind::GArg:
560 FormatSpec.push_back('G');
561 break;
562 default:
563 // Something we don't understand
564 return conversionNotPossible((Twine("argument ") +
565 Twine(FS.getArgIndex() + ArgsOffset) +
566 " has an unsupported format specifier")
567 .str());
568 }
569
570 return true;
571}
572
573/// Append the standard format string equivalent of the passed PrintfSpecifier
574/// to StandardFormatString and store any argument fixes for later application.
575/// @returns true on success, false on failure
576bool FormatStringConverter::convertArgument(const PrintfSpecifier &FS,
577 const Expr *Arg,
578 std::string &StandardFormatString) {
579 // The specifier must have an associated argument
580 assert(FS.consumesDataArgument());
581
582 StandardFormatString.push_back('{');
583
584 if (FS.usesPositionalArg()) {
585 // std::format argument identifiers are zero-based, whereas printf ones
586 // are one based.
587 assert(FS.getPositionalArgIndex() > 0U);
588 StandardFormatString.append(llvm::utostr(FS.getPositionalArgIndex() - 1));
589 }
590
591 // std::format format argument parts to potentially emit:
592 // [[fill]align][sign]["#"]["0"][width]["."precision][type]
593 std::string FormatSpec;
594
595 // printf doesn't support specifying the fill character - it's always a
596 // space, so we never need to generate one.
597
598 emitAlignment(FS, FormatSpec);
599 emitSign(FS, FormatSpec);
600 emitAlternativeForm(FS, FormatSpec);
601
602 if (FS.hasLeadingZeros())
603 FormatSpec.push_back('0');
604
605 emitFieldWidth(FS, FormatSpec);
606 emitPrecision(FS, FormatSpec);
607 maybeRotateArguments(FS);
608
609 if (!emitType(FS, Arg, FormatSpec))
610 return false;
611
612 if (!FormatSpec.empty()) {
613 StandardFormatString.push_back(':');
614 StandardFormatString.append(FormatSpec);
615 }
616
617 StandardFormatString.push_back('}');
618 return true;
619}
620
621/// Called for each format specifier by ParsePrintfString.
622bool FormatStringConverter::HandlePrintfSpecifier(const PrintfSpecifier &FS,
623 const char *StartSpecifier,
624 unsigned SpecifierLen,
625 const TargetInfo &Target) {
626 const size_t StartSpecifierPos = StartSpecifier - PrintfFormatString.data();
627 assert(StartSpecifierPos + SpecifierLen <= PrintfFormatString.size());
628
629 // Everything before the specifier needs copying verbatim
630 assert(StartSpecifierPos >= PrintfFormatStringPos);
631
632 appendFormatText(StringRef(PrintfFormatString.begin() + PrintfFormatStringPos,
633 StartSpecifierPos - PrintfFormatStringPos));
634
635 const ConversionSpecifier::Kind ArgKind =
636 FS.getConversionSpecifier().getKind();
637
638 // Skip over specifier
639 PrintfFormatStringPos = StartSpecifierPos + SpecifierLen;
640 assert(PrintfFormatStringPos <= PrintfFormatString.size());
641
642 FormatStringNeededRewriting = true;
643
644 if (ArgKind == ConversionSpecifier::Kind::nArg) {
645 // std::print doesn't do the equivalent of %n
646 return conversionNotPossible("'%n' is not supported in format string");
647 }
648
649 if (ArgKind == ConversionSpecifier::Kind::PrintErrno) {
650 // std::print doesn't support %m. In theory we could insert a
651 // strerror(errno) parameter (assuming that libc has a thread-safe
652 // implementation, which glibc does), but that would require keeping track
653 // of the input and output parameter indices for position arguments too.
654 return conversionNotPossible("'%m' is not supported in format string");
655 }
656
657 if (ArgKind == ConversionSpecifier::PercentArg) {
658 StandardFormatString.push_back('%');
659 return true;
660 }
661
662 const unsigned ArgIndex = FS.getArgIndex() + ArgsOffset;
663 if (ArgIndex >= NumArgs) {
664 // Argument index out of range. Give up.
665 return conversionNotPossible(
666 (Twine("argument index ") + Twine(ArgIndex) + " is out of range")
667 .str());
668 }
669
670 return convertArgument(FS, Args[ArgIndex]->IgnoreImplicitAsWritten(),
671 StandardFormatString);
672}
673
674/// Called at the very end just before applying fixes to capture the last part
675/// of the format string.
676void FormatStringConverter::finalizeFormatText() {
677 appendFormatText(
678 StringRef(PrintfFormatString.begin() + PrintfFormatStringPos,
679 PrintfFormatString.size() - PrintfFormatStringPos));
680 PrintfFormatStringPos = PrintfFormatString.size();
681
682 // It's clearer to convert printf("Hello\r\n"); to std::print("Hello\r\n")
683 // than to std::println("Hello\r");
684 // Use StringRef until C++20 std::string::ends_with() is available.
685 const auto StandardFormatStringRef = StringRef(StandardFormatString);
686 if (Config.AllowTrailingNewlineRemoval &&
687 StandardFormatStringRef.ends_with("\\n") &&
688 !StandardFormatStringRef.ends_with("\\\\n") &&
689 !StandardFormatStringRef.ends_with("\\r\\n")) {
690 UsePrintNewlineFunction = true;
691 FormatStringNeededRewriting = true;
692 StandardFormatString.erase(StandardFormatString.end() - 2,
693 StandardFormatString.end());
694 }
695
696 StandardFormatString.push_back('\"');
697}
698
699/// Append literal parts of the format text, reinstating escapes as required.
700void FormatStringConverter::appendFormatText(const StringRef Text) {
701 for (const char Ch : Text) {
702 const auto UCh = static_cast<unsigned char>(Ch);
703 if (Ch == '\a') {
704 StandardFormatString += "\\a";
705 } else if (Ch == '\b') {
706 StandardFormatString += "\\b";
707 } else if (Ch == '\f') {
708 StandardFormatString += "\\f";
709 } else if (Ch == '\n') {
710 StandardFormatString += "\\n";
711 } else if (Ch == '\r') {
712 StandardFormatString += "\\r";
713 } else if (Ch == '\t') {
714 StandardFormatString += "\\t";
715 } else if (Ch == '\v') {
716 StandardFormatString += "\\v";
717 } else if (Ch == '\"') {
718 StandardFormatString += "\\\"";
719 } else if (Ch == '\\') {
720 StandardFormatString += "\\\\";
721 } else if (Ch == '{') {
722 StandardFormatString += "{{";
723 FormatStringNeededRewriting = true;
724 } else if (Ch == '}') {
725 StandardFormatString += "}}";
726 FormatStringNeededRewriting = true;
727 } else if (UCh < 32) {
728 StandardFormatString += "\\x";
729 StandardFormatString += llvm::hexdigit(UCh >> 4, true);
730 StandardFormatString += llvm::hexdigit(UCh & 0xf, true);
731 } else {
732 StandardFormatString += Ch;
733 }
734 }
735}
736
737static std::string withoutCStrReplacement(const BoundNodes &CStrRemovalMatch,
738 const ASTContext &Context) {
739 const auto *Arg = CStrRemovalMatch.getNodeAs<Expr>("arg");
740 const auto *Member = CStrRemovalMatch.getNodeAs<MemberExpr>("member");
741 const bool Arrow = Member->isArrow();
742 return Arrow ? utils::fixit::formatDereference(*Arg, Context)
743 : tooling::fixit::getText(*Arg, Context).str();
744}
745
746/// Called by the check when it is ready to apply the fixes.
747void FormatStringConverter::applyFixes(DiagnosticBuilder &Diag,
748 SourceManager &SM) {
749 if (FormatStringNeededRewriting) {
750 Diag << FixItHint::CreateReplacement(
751 CharSourceRange::getTokenRange(FormatExpr->getBeginLoc(),
752 FormatExpr->getEndLoc()),
753 StandardFormatString);
754 }
755
756 // ArgCount is one less than the number of arguments to be rotated.
757 for (auto [ValueArgIndex, ArgCount] : ArgRotates) {
758 assert(ValueArgIndex < NumArgs);
759 assert(ValueArgIndex > ArgCount);
760
761 // First move the value argument to the right place. But if there's a
762 // pending c_str() removal then we must do that at the same time.
763 if (const auto CStrRemovalMatch =
764 llvm::find_if(ArgCStrRemovals,
765 [ArgStartPos = Args[ValueArgIndex]->getBeginLoc()](
766 const BoundNodes &Match) {
767 // This c_str() removal corresponds to the argument
768 // being moved if they start at the same location.
769 const Expr *CStrArg = Match.getNodeAs<Expr>("arg");
770 return ArgStartPos == CStrArg->getBeginLoc();
771 });
772 CStrRemovalMatch != ArgCStrRemovals.end()) {
773 const std::string ArgText =
774 withoutCStrReplacement(*CStrRemovalMatch, *Context);
775 assert(!ArgText.empty());
776
777 Diag << FixItHint::CreateReplacement(
778 Args[ValueArgIndex - ArgCount]->getSourceRange(), ArgText);
779
780 // That c_str() removal is now dealt with, so we don't need to do it again
781 ArgCStrRemovals.erase(CStrRemovalMatch);
782 } else {
783 Diag << tooling::fixit::createReplacement(*Args[ValueArgIndex - ArgCount],
784 *Args[ValueArgIndex], *Context);
785 }
786
787 // Now shift down the field width and precision (if either are present) to
788 // accommodate it.
789 for (size_t Offset = 0; Offset < ArgCount; ++Offset)
790 Diag << tooling::fixit::createReplacement(
791 *Args[ValueArgIndex - Offset], *Args[ValueArgIndex - Offset - 1],
792 *Context);
793
794 // Now we need to modify the ArgFix index too so that we fix the right
795 // argument. We don't need to care about the width and precision indices
796 // since they never need fixing.
797 for (auto &ArgFix : ArgFixes)
798 if (ArgFix.ArgIndex == ValueArgIndex)
799 ArgFix.ArgIndex = ValueArgIndex - ArgCount;
800 }
801
802 for (const auto &[ArgIndex, Replacement] : ArgFixes) {
803 const std::optional<Token> NextToken =
804 utils::lexer::findNextTokenSkippingComments(Args[ArgIndex]->getEndLoc(),
805 SM, LangOpts);
806 if (!NextToken)
807 continue;
808 const SourceLocation AfterOtherSide = NextToken->getLocation();
809
810 Diag << FixItHint::CreateInsertion(Args[ArgIndex]->getBeginLoc(),
811 Replacement, true)
812 << FixItHint::CreateInsertion(AfterOtherSide, ")", true);
813 }
814
815 for (const auto &Match : ArgCStrRemovals) {
816 const auto *Call = Match.getNodeAs<CallExpr>("call");
817 const std::string ArgText = withoutCStrReplacement(Match, *Context);
818 if (!ArgText.empty())
819 Diag << FixItHint::CreateReplacement(Call->getSourceRange(), ArgText);
820 }
821}
822} // namespace clang::tidy::utils
Declaration of the FormatStringConverter class which is used to convert printf format strings to C++ ...
void applyFixes(DiagnosticBuilder &Diag, SourceManager &SM)
Called by the check when it is ready to apply the fixes.
clang::analyze_format_string::ConversionSpecifier ConversionSpecifier
FormatStringConverter(ASTContext *Context, const CallExpr *Call, unsigned FormatArgOffset, Configuration Config, const LangOptions &LO, SourceManager &SM, Preprocessor &PP)
std::vector< std::string > match(const SymbolIndex &I, const FuzzyFindRequest &Req, bool *Incomplete)
std::string formatDereference(const Expr &ExprNode, const ASTContext &Context)
std::optional< Token > findNextTokenSkippingComments(SourceLocation Start, const SourceManager &SM, const LangOptions &LangOpts)
Definition LexerUtils.h:106
static bool isMatchingSignedness(ConversionSpecifier::Kind ArgKind, const QualType &ArgType)
static std::string withoutCStrReplacement(const BoundNodes &CStrRemovalMatch, const ASTContext &Context)
static bool isRealCharType(const QualType &Ty)
Is the passed type the actual "char" type, whether that be signed or unsigned, rather than explicit s...
static bool castMismatchedIntegerTypes(const CallExpr *Call, bool StrictMode)
static std::optional< std::string > castTypeForArgument(ConversionSpecifier::Kind ArgKind, const QualType &QT)
static std::optional< std::string > getCorrespondingSignedTypeName(const QualType &QT)
If possible, return the text name of the signed type that corresponds to the passed integer type.
static std::optional< std::string > getCorrespondingUnsignedTypeName(const QualType &QT)
If possible, return the text name of the unsigned type that corresponds to the passed integer type.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static constexpr const char FuncDecl[]