33 unsigned NextAutoIndex = 0;
34 bool HasAutomatic =
false;
35 bool HasExplicit =
false;
37 while (!Fmt.empty()) {
38 const size_t OpenBrace = Fmt.find(
'{');
39 if (OpenBrace == StringRef::npos)
42 Fmt = Fmt.drop_front(OpenBrace);
45 if (Fmt.consume_front(
"{{"))
49 const size_t CloseBrace = Fmt.find(
'}');
50 if (CloseBrace == StringRef::npos)
51 return llvm::createStringError(
"unterminated brace in format string");
54 const StringRef Content = Fmt.substr(1, CloseBrace - 1);
55 Fmt = Fmt.drop_front(CloseBrace + 1);
58 StringRef IndexStr = Content.substr(0, Content.find_first_of(
",:"));
60 IndexStr = IndexStr.trim();
63 if (IndexStr.empty()) {
64 Index = NextAutoIndex++;
67 if (IndexStr.getAsInteger(10, Index))
68 return llvm::createStringError(
69 "invalid replacement index in format string");
73 Result.Indices.push_back(Index);
74 Result.MaxIndex = std::max(Result.MaxIndex, Index);
77 if (HasAutomatic && HasExplicit)
78 return llvm::createStringError(
79 "format string mixes automatic and explicit indices");
108 const auto *Call = Result.Nodes.getNodeAs<CallExpr>(
"call");
109 assert(Call && Call->getNumArgs() > 0);
111 const auto *FD = Call->getDirectCallee();
116 const FunctionDecl *TemplateDecl = FD;
117 if (
const FunctionTemplateDecl *Primary = FD->getPrimaryTemplate())
118 TemplateDecl = Primary->getTemplatedDecl();
120 const unsigned NumDeclParams = TemplateDecl->getNumParams();
121 if (NumDeclParams < 2)
124 const unsigned PackParamIndex = NumDeclParams - 1;
125 if (!TemplateDecl->getParamDecl(PackParamIndex)->isParameterPack())
128 const unsigned FmtStringIndex = PackParamIndex - 1;
130 if (Call->getNumArgs() <= FmtStringIndex)
134 const Expr *FmtArg = Call->getArg(FmtStringIndex)->IgnoreParenImpCasts();
135 const auto *FmtLiteral = dyn_cast<StringLiteral>(FmtArg);
139 const StringRef FmtString = FmtLiteral->getString();
140 const int NumFmtArgs = Call->getNumArgs() - PackParamIndex;
144 diag(FmtLiteral->getBeginLoc(), toString(ParsedOrErr.takeError()));
148 const ParseResult &Parsed = *ParsedOrErr;
149 const int NumRequiredArgs = Parsed.Indices.empty() ? 0 : Parsed.MaxIndex + 1;
151 if (NumRequiredArgs > NumFmtArgs) {
152 diag(FmtLiteral->getBeginLoc(),
153 "format string requires %0 argument%s0, but %1 argument%s1 "
154 "%plural{1:was|:were}1 provided")
155 << NumRequiredArgs << NumFmtArgs;
161 llvm::SmallBitVector UnusedIndices(NumFmtArgs,
true);
162 for (
const unsigned Index : Parsed.Indices)
163 UnusedIndices.reset(Index);
165 for (
const auto UnusedIndex : UnusedIndices.set_bits()) {
166 const Expr *UnusedArg = Call->getArg(PackParamIndex + UnusedIndex);
167 diag(UnusedArg->getBeginLoc(),
"argument unused in format string");