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