2121#include " clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
2222#include " clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2323#include " llvm/ADT/StringExtras.h"
24+ #include " llvm/Support/FormatVariadic.h"
2425#include " llvm/Support/raw_ostream.h"
2526
2627using namespace clang ;
@@ -182,7 +183,8 @@ static void describeUninitializedArgumentInCall(const CallEvent &Call,
182183namespace {
183184class FindUninitializedField {
184185public:
185- SmallVector<const FieldDecl *, 10 > FieldChain;
186+ using FieldChainTy = SmallVector<const FieldDecl *, 10 >;
187+ FieldChainTy FieldChain;
186188
187189private:
188190 StoreManager &StoreMgr;
@@ -219,27 +221,32 @@ class FindUninitializedField {
219221
220222 return false ;
221223 }
224+ };
225+ } // namespace
222226
223- void printFieldChain (llvm::raw_ostream &OS) {
224- if (FieldChain.size () == 1 )
225- OS << " (e.g., field: '" << *FieldChain[0 ] << " ')" ;
227+ namespace llvm {
228+ template <> struct format_provider <FindUninitializedField::FieldChainTy> {
229+ static void format (const FindUninitializedField::FieldChainTy &V,
230+ raw_ostream &Stream, StringRef Style) {
231+ if (V.size () == 1 )
232+ Stream << " (e.g., field: '" << *V[0 ] << " ')" ;
226233 else {
227- OS << " (e.g., via the field chain: '" ;
234+ Stream << " (e.g., via the field chain: '" ;
228235 bool First = true ;
229- for (SmallVectorImpl< const FieldDecl *>::iterator DI = FieldChain .begin (),
230- DE = FieldChain .end ();
236+ for (FindUninitializedField::FieldChainTy::const_iterator DI = V .begin (),
237+ DE = V .end ();
231238 DI != DE; ++DI) {
232239 if (First)
233240 First = false ;
234241 else
235- OS << ' .' ;
236- OS << **DI;
242+ Stream << ' .' ;
243+ Stream << **DI;
237244 }
238- OS << " ')" ;
245+ Stream << " ')" ;
239246 }
240247 }
241248};
242- } // namespace
249+ } // namespace llvm
243250
244251bool CallAndMessageChecker::uninitRefOrPointer (
245252 CheckerContext &C, SVal V, SourceRange ArgRange, const Expr *ArgEx,
@@ -276,15 +283,11 @@ bool CallAndMessageChecker::uninitRefOrPointer(
276283
277284 if (PointeeV.isUndef ()) {
278285 if (ExplodedNode *N = C.generateErrorNode ()) {
279- SmallString<200 > Buf;
280- llvm::raw_svector_ostream Os (Buf);
281- Os << (ArgumentNumber + 1 ) << llvm::getOrdinalSuffix (ArgumentNumber + 1 )
282- << " function call argument is " ;
283- if (ParamT->isPointerType ())
284- Os << " a pointer to uninitialized value" ;
285- else
286- Os << " an uninitialized value" ;
287- auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str (), N);
286+ std::string Msg = llvm::formatv (
287+ " {0}{1} function call argument is {2} uninitialized value" ,
288+ ArgumentNumber + 1 , llvm::getOrdinalSuffix (ArgumentNumber + 1 ),
289+ ParamT->isPointerType () ? " a pointer to" : " an" );
290+ auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
288291 R->addRange (ArgRange);
289292 if (ArgEx)
290293 bugreporter::trackExpressionValue (N, ArgEx, *R);
@@ -302,23 +305,15 @@ bool CallAndMessageChecker::uninitRefOrPointer(
302305
303306 if (F.Find (D->getRegion ())) {
304307 if (ExplodedNode *N = C.generateErrorNode ()) {
305- SmallString<512 > Buf;
306- llvm::raw_svector_ostream Os (Buf);
307- Os << (ArgumentNumber + 1 ) << llvm::getOrdinalSuffix (ArgumentNumber + 1 )
308- << " function call argument" ;
309- if (ParamT->isPointerType ())
310- Os << " points to" ;
311- else
312- Os << " references" ;
313- Os << " an uninitialized value" ;
314-
315- F.printFieldChain (Os);
316-
317- auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str (), N);
308+ std::string Msg = llvm::formatv (
309+ " {0}{1} function call argument {2} an uninitialized value {3}" ,
310+ (ArgumentNumber + 1 ), llvm::getOrdinalSuffix (ArgumentNumber + 1 ),
311+ ParamT->isPointerType () ? " points to" : " references" , F.FieldChain );
312+ auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
318313 R->addRange (ArgRange);
319-
320314 if (ArgEx)
321315 bugreporter::trackExpressionValue (N, ArgEx, *R);
316+
322317 C.emitReport (std::move (R));
323318 }
324319 return true ;
@@ -370,13 +365,12 @@ bool CallAndMessageChecker::PreVisitProcessArg(
370365 return true ;
371366 }
372367 if (ExplodedNode *N = C.generateErrorNode ()) {
373- SmallString<512 > Str;
374- llvm::raw_svector_ostream os (Str);
375- os << " Passed-by-value struct argument contains uninitialized data" ;
376- F.printFieldChain (os);
368+ std::string Msg = llvm::formatv (
369+ " Passed-by-value struct argument contains uninitialized data {0}" ,
370+ F.FieldChain );
377371
378372 // Generate a report for this bug.
379- auto R = std::make_unique<PathSensitiveBugReport>(BT, os. str () , N);
373+ auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg , N);
380374 R->addRange (ArgRange);
381375
382376 if (ArgEx)
0 commit comments