@@ -3624,7 +3624,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3624
3624
3625
3625
// In C++ the implicit 'this' function parameter also counts, and they are
3626
3626
// counted from one.
3627
- bool HasImplicitThisParam = isInstanceMethod (D);
3627
+ bool HasImplicitThisParam = checkIfMethodHasImplicitObjectParameter (D);
3628
3628
unsigned NumArgs = getFunctionOrMethodNumParams (D) + HasImplicitThisParam;
3629
3629
3630
3630
IdentifierInfo *II = AL.getArgAsIdent (0 )->Ident ;
@@ -3737,7 +3737,7 @@ static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3737
3737
return ;
3738
3738
}
3739
3739
3740
- bool HasImplicitThisParam = isInstanceMethod (D);
3740
+ bool HasImplicitThisParam = checkIfMethodHasImplicitObjectParameter (D);
3741
3741
int32_t NumArgs = getFunctionOrMethodNumParams (D);
3742
3742
3743
3743
FunctionDecl *FD = D->getAsFunction ();
@@ -5421,6 +5421,224 @@ static void handlePreferredTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5421
5421
D->addAttr (::new (S.Context ) PreferredTypeAttr (S.Context , AL, ParmTSI));
5422
5422
}
5423
5423
5424
+ // Returns vector of format attributes. There are no two attributes with same
5425
+ // arguments in returning vector. There can be attributes that effectively only
5426
+ // store information about format type.
5427
+ static std::vector<FormatAttr *>
5428
+ GetMissingFormatAttributes (Sema &S, Stmt *Body, const FunctionDecl *FDecl) {
5429
+ unsigned int ArgumentIndexOffset =
5430
+ checkIfMethodHasImplicitObjectParameter (FDecl) ? 2 : 1 ;
5431
+
5432
+ std::vector<FormatAttr *> MissingAttributes;
5433
+
5434
+ // Iterate over body statements.
5435
+ for (auto *Child : Body->children ()) {
5436
+ // If child statement is compound statement, recursively get missing
5437
+ // attributes.
5438
+ if (dyn_cast_or_null<CompoundStmt>(Child)) {
5439
+ std::vector<FormatAttr *> CompoundStmtMissingAttributes =
5440
+ GetMissingFormatAttributes (S, Child, FDecl);
5441
+
5442
+ // If there are already missing attributes with same arguments, do not add
5443
+ // duplicates.
5444
+ for (FormatAttr *FA : CompoundStmtMissingAttributes) {
5445
+ if (!llvm::any_of (MissingAttributes, [&](const FormatAttr *Attr) {
5446
+ return FA->getType () == Attr->getType () &&
5447
+ FA->getFormatIdx () == Attr->getFormatIdx () &&
5448
+ FA->getFirstArg () == Attr->getFirstArg ();
5449
+ }))
5450
+ MissingAttributes.push_back (FA);
5451
+ }
5452
+
5453
+ continue ;
5454
+ }
5455
+
5456
+ ValueStmt *VS = dyn_cast<ValueStmt>(Child);
5457
+ if (!VS)
5458
+ continue ;
5459
+ CallExpr *TheCall = dyn_cast_or_null<CallExpr>(VS->getExprStmt ());
5460
+ if (!TheCall)
5461
+ continue ;
5462
+
5463
+ const FunctionDecl *CalleeFunction =
5464
+ dyn_cast_or_null<FunctionDecl>(TheCall->getCalleeDecl ());
5465
+ if (!CalleeFunction || !CalleeFunction->hasAttr <FormatAttr>())
5466
+ continue ;
5467
+
5468
+ // va_list is not intended to be passed to variadic function.
5469
+ if (CalleeFunction->isVariadic ())
5470
+ continue ;
5471
+
5472
+ Expr **Args = TheCall->getArgs ();
5473
+ unsigned int NumArgs = TheCall->getNumArgs ();
5474
+
5475
+ // Check if va_list is passed to callee function.
5476
+ // If va_list is not passed, continue to the next iteration.
5477
+ bool hasVaList = false ;
5478
+ for (const auto *Param : CalleeFunction->parameters ()) {
5479
+ if (Param->getOriginalType ().getCanonicalType () ==
5480
+ S.getASTContext ().getBuiltinVaListType ().getCanonicalType ()) {
5481
+ hasVaList = true ;
5482
+ break ;
5483
+ }
5484
+ }
5485
+ if (!hasVaList)
5486
+ continue ;
5487
+
5488
+ // If callee expression is function, check if it is format function.
5489
+ // If it is, check if caller function misses format attributes.
5490
+
5491
+ unsigned int CalleeFunctionFormatArgumentIndexOffset =
5492
+ checkIfMethodHasImplicitObjectParameter (CalleeFunction) ? 2 : 1 ;
5493
+
5494
+ // If callee function is format function and format arguments are not
5495
+ // relevant to emit diagnostic, save only information about format type
5496
+ // (format index and first-to-check argument index are set to -1).
5497
+ // Information about format type is later used to determine if there are
5498
+ // more than one format type found.
5499
+
5500
+ // Check if function has format attribute with forwarded format string.
5501
+ IdentifierInfo *AttrType;
5502
+ const ParmVarDecl *FormatArg;
5503
+ if (!llvm::any_of (CalleeFunction->specific_attrs <FormatAttr>(),
5504
+ [&](const FormatAttr *Attr) {
5505
+ AttrType = Attr->getType ();
5506
+
5507
+ int OffsetFormatIndex =
5508
+ Attr->getFormatIdx () -
5509
+ CalleeFunctionFormatArgumentIndexOffset;
5510
+ if (OffsetFormatIndex < 0 ||
5511
+ (unsigned )OffsetFormatIndex >= NumArgs)
5512
+ return false ;
5513
+
5514
+ if (const auto *FormatArgExpr = dyn_cast<DeclRefExpr>(
5515
+ Args[OffsetFormatIndex]->IgnoreParenCasts ()))
5516
+ if (FormatArg = dyn_cast_or_null<ParmVarDecl>(
5517
+ FormatArgExpr->getReferencedDeclOfCallee ()))
5518
+ return true ;
5519
+ return false ;
5520
+ })) {
5521
+ MissingAttributes.push_back (
5522
+ FormatAttr::CreateImplicit (S.getASTContext (), AttrType, -1 , -1 ));
5523
+ continue ;
5524
+ }
5525
+
5526
+ // If format string argument is caller function parameter, get string index.
5527
+ // Otherwise, save only attribute type and go to next iteration.
5528
+ int StringIndex = [=]() -> int {
5529
+ for (const ParmVarDecl *Param : FDecl->parameters ()) {
5530
+ if (Param == FormatArg)
5531
+ return Param->getFunctionScopeIndex () + ArgumentIndexOffset;
5532
+ }
5533
+ return 0 ;
5534
+ }();
5535
+
5536
+ if (StringIndex == 0 ) {
5537
+ MissingAttributes.push_back (
5538
+ FormatAttr::CreateImplicit (S.getASTContext (), AttrType, -1 , -1 ));
5539
+ continue ;
5540
+ }
5541
+
5542
+ unsigned NumOfCallerFunctionParams = FDecl->getNumParams ();
5543
+
5544
+ // Compare caller and callee function format attribute arguments (archetype
5545
+ // and format string).
5546
+ if (llvm::any_of (
5547
+ FDecl->specific_attrs <FormatAttr>(), [&](const FormatAttr *Attr) {
5548
+ if (Attr->getType () != AttrType)
5549
+ return false ;
5550
+ int OffsetFormatIndex =
5551
+ Attr->getFormatIdx () - ArgumentIndexOffset;
5552
+
5553
+ if (OffsetFormatIndex < 0 ||
5554
+ (unsigned )OffsetFormatIndex >= NumOfCallerFunctionParams)
5555
+ return false ;
5556
+
5557
+ if (FDecl->parameters ()[OffsetFormatIndex] != FormatArg)
5558
+ return false ;
5559
+
5560
+ return true ;
5561
+ })) {
5562
+ MissingAttributes.push_back (
5563
+ FormatAttr::CreateImplicit (S.getASTContext (), AttrType, -1 , -1 ));
5564
+ continue ;
5565
+ }
5566
+
5567
+ // Get first argument index
5568
+ int FirstToCheck = FDecl->isVariadic ()
5569
+ ? (NumOfCallerFunctionParams + ArgumentIndexOffset)
5570
+ : 0 ;
5571
+
5572
+ // If there are already attributes which arguments matches arguments
5573
+ // detected in this iteration, do not add new attribute as it would be
5574
+ // duplicate.
5575
+ if (!llvm::any_of (MissingAttributes, [&](const FormatAttr *Attr) {
5576
+ return Attr->getType () == AttrType &&
5577
+ Attr->getFormatIdx () == StringIndex &&
5578
+ Attr->getFirstArg () == FirstToCheck;
5579
+ }))
5580
+ MissingAttributes.push_back (
5581
+ FormatAttr::CreateImplicit (S.getASTContext (), AttrType, StringIndex,
5582
+ FirstToCheck, TheCall->getBeginLoc ()));
5583
+ }
5584
+
5585
+ return MissingAttributes;
5586
+ }
5587
+
5588
+ // This function is called only if function call is not inside template body.
5589
+ // TODO: Add call for function calls inside template body.
5590
+ // Emit warnings if caller function misses format attributes.
5591
+ void Sema::DiagnoseMissingFormatAttributes (Stmt *Body,
5592
+ const FunctionDecl *FDecl) {
5593
+ assert (FDecl);
5594
+
5595
+ // If there are no function body, exit.
5596
+ if (!Body)
5597
+ return ;
5598
+
5599
+ // Get missing format attributes
5600
+ std::vector<FormatAttr *> MissingFormatAttributes =
5601
+ GetMissingFormatAttributes (*this , Body, FDecl);
5602
+ if (MissingFormatAttributes.empty ())
5603
+ return ;
5604
+
5605
+ // Check if there are more than one format type found. In that case do not
5606
+ // emit diagnostic.
5607
+ const clang::IdentifierInfo *AttrType = MissingFormatAttributes[0 ]->getType ();
5608
+ for (unsigned i = 1 ; i < MissingFormatAttributes.size (); ++i) {
5609
+ if (AttrType != MissingFormatAttributes[i]->getType ())
5610
+ return ;
5611
+ }
5612
+
5613
+ for (const FormatAttr *FA : MissingFormatAttributes) {
5614
+ // If format index and first-to-check argument index are negative, it means
5615
+ // that this attribute is only saved for multiple format types checking.
5616
+ if (FA->getFormatIdx () < 0 || FA->getFirstArg () < 0 )
5617
+ continue ;
5618
+
5619
+ // If caller function has format attributes and callee format attribute type
5620
+ // mismatches caller attribute type, do not emit diagnostic.
5621
+ if (FDecl->hasAttr <FormatAttr>() &&
5622
+ !llvm::any_of (FDecl->specific_attrs <FormatAttr>(),
5623
+ [FA](const FormatAttr *FunctionAttr) {
5624
+ return FA->getType () == FunctionAttr->getType ();
5625
+ }))
5626
+ continue ;
5627
+
5628
+ // Emit diagnostic
5629
+ SourceLocation Loc = FDecl->getFirstDecl ()->getLocation ();
5630
+ Diag (Loc, diag::warn_missing_format_attribute)
5631
+ << FA->getType () << FDecl
5632
+ << FixItHint::CreateInsertion (Loc,
5633
+ (llvm::Twine (" __attribute__((format(" ) +
5634
+ FA->getType ()->getName () + " , " +
5635
+ llvm::Twine (FA->getFormatIdx ()) + " , " +
5636
+ llvm::Twine (FA->getFirstArg ()) + " )))" )
5637
+ .str ());
5638
+ Diag (FA->getLocation (), diag::note_format_function) << FA->getType ();
5639
+ }
5640
+ }
5641
+
5424
5642
// ===----------------------------------------------------------------------===//
5425
5643
// Microsoft specific attribute handlers.
5426
5644
// ===----------------------------------------------------------------------===//
0 commit comments