26 StrictMode(Options.get(
"StrictMode", false)),
27 PrintfLikeFunctions(
utils::options::parseStringList(
28 Options.get(
"PrintfLikeFunctions",
""))),
29 FprintfLikeFunctions(
utils::options::parseStringList(
30 Options.get(
"FprintfLikeFunctions",
""))),
31 ReplacementPrintFunction(
32 Options.get(
"ReplacementPrintFunction",
"std::print")),
33 ReplacementPrintlnFunction(
34 Options.get(
"ReplacementPrintlnFunction",
"std::println")),
35 IncludeInserter(Options.getLocalOrGlobal(
"IncludeStyle",
36 utils::IncludeSorter::IS_LLVM),
37 areDiagsSelfContained()),
38 MaybeHeaderToInclude(Options.get(
"PrintHeader")) {
40 if (PrintfLikeFunctions.empty() && FprintfLikeFunctions.empty()) {
41 PrintfLikeFunctions.emplace_back(
"::printf");
42 PrintfLikeFunctions.emplace_back(
"absl::PrintF");
43 FprintfLikeFunctions.emplace_back(
"::fprintf");
44 FprintfLikeFunctions.emplace_back(
"absl::FPrintF");
47 if (!MaybeHeaderToInclude && (ReplacementPrintFunction ==
"std::print" ||
48 ReplacementPrintlnFunction ==
"std::println"))
49 MaybeHeaderToInclude =
"<print>";
54 Options.store(Opts,
"StrictMode", StrictMode);
55 Options.store(Opts,
"PrintfLikeFunctions",
56 serializeStringList(PrintfLikeFunctions));
57 Options.store(Opts,
"FprintfLikeFunctions",
58 serializeStringList(FprintfLikeFunctions));
59 Options.store(Opts,
"ReplacementPrintFunction", ReplacementPrintFunction);
60 Options.store(Opts,
"ReplacementPrintlnFunction", ReplacementPrintlnFunction);
61 Options.store(Opts,
"IncludeStyle", IncludeInserter.getStyle());
62 if (MaybeHeaderToInclude)
63 Options.store(Opts,
"PrintHeader", *MaybeHeaderToInclude);
75 auto UnusedInCompoundStmt =
76 compoundStmt(forEach(MatchedCallExpr),
81 unless(hasParent(stmtExpr())));
83 ifStmt(eachOf(hasThen(MatchedCallExpr), hasElse(MatchedCallExpr)));
84 auto UnusedInWhileStmt = whileStmt(hasBody(MatchedCallExpr));
85 auto UnusedInDoStmt = doStmt(hasBody(MatchedCallExpr));
86 auto UnusedInForStmt =
87 forStmt(eachOf(hasLoopInit(MatchedCallExpr),
88 hasIncrement(MatchedCallExpr), hasBody(MatchedCallExpr)));
89 auto UnusedInRangeForStmt = cxxForRangeStmt(hasBody(MatchedCallExpr));
90 auto UnusedInCaseStmt = switchCase(forEach(MatchedCallExpr));
92 return stmt(anyOf(UnusedInCompoundStmt, UnusedInIfStmt, UnusedInWhileStmt,
93 UnusedInDoStmt, UnusedInForStmt, UnusedInRangeForStmt,
98 if (!PrintfLikeFunctions.empty())
101 callExpr(argumentCountAtLeast(1),
102 hasArgument(0, stringLiteral(isOrdinary())),
104 PrintfLikeFunctions))
109 if (!FprintfLikeFunctions.empty())
112 callExpr(argumentCountAtLeast(2),
113 hasArgument(1, stringLiteral(isOrdinary())),
115 FprintfLikeFunctions))
122 unsigned FormatArgOffset = 0;
123 const auto *OldFunction = Result.Nodes.getNodeAs<FunctionDecl>(
"func_decl");
124 const auto *Printf = Result.Nodes.getNodeAs<CallExpr>(
"printf");
126 Printf = Result.Nodes.getNodeAs<CallExpr>(
"fprintf");
133 assert(PP &&
"Preprocessor should be set by registerPPCallbacks");
135 Result.Context, Printf, FormatArgOffset, ConverterConfig, getLangOpts(),
136 *Result.SourceManager, *PP);
137 const Expr *PrintfCall = Printf->getCallee();
139 ? ReplacementPrintlnFunction
140 : ReplacementPrintFunction;
142 diag(PrintfCall->getBeginLoc(),
143 "unable to use '%0' instead of %1 because %2")
144 << PrintfCall->getSourceRange() << ReplacementFunction
145 << OldFunction->getIdentifier()
150 DiagnosticBuilder Diag =
151 diag(PrintfCall->getBeginLoc(),
"use '%0' instead of %1")
152 << ReplacementFunction << OldFunction->getIdentifier();
154 Diag << FixItHint::CreateReplacement(
155 CharSourceRange::getTokenRange(PrintfCall->getExprLoc(),
156 PrintfCall->getEndLoc()),
157 ReplacementFunction);
158 Converter.
applyFixes(Diag, *Result.SourceManager);
160 if (MaybeHeaderToInclude)
161 Diag << IncludeInserter.createIncludeInsertion(
162 Result.Context->getSourceManager().getFileID(PrintfCall->getBeginLoc()),
163 *MaybeHeaderToInclude);
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.