@@ -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,181 @@ 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
+ // Diagnosing missing format attributes is implemented in two steps:
5434
+ // 1. Detect missing format attributes while checking function calls.
5435
+ // 2. Emit diagnostic in part that processes function body.
5436
+ // For this purpose it is created vector that stores information about format
5437
+ // attributes. There are no two format attributes with same arguments in a
5438
+ // vector. Vector could contains attributes that only store information about
5439
+ // format type (format string and first to check argument are set to -1).
5440
+ namespace {
5441
+ std::vector<FormatAttr *> MissingAttributes;
5442
+ } // end anonymous namespace
5443
+
5444
+ // This function is called only if function call is not inside template body.
5445
+ // TODO: Add call for function calls inside template body.
5446
+ // Detects and stores missing format attributes in a vector.
5447
+ void Sema::DetectMissingFormatAttributes(const FunctionDecl *Callee,
5448
+ ArrayRef<const Expr *> Args,
5449
+ SourceLocation Loc) {
5450
+ assert(Callee);
5451
+
5452
+ // If there is no caller, exit.
5453
+ const FunctionDecl *Caller = getCurFunctionDecl();
5454
+ if (!getCurFunctionDecl())
5455
+ return;
5456
+
5457
+ // Check if callee function is a format function.
5458
+ // If it is, check if caller function misses format attributes.
5459
+
5460
+ if (!Callee->hasAttr<FormatAttr>())
5461
+ return;
5462
+
5463
+ // va_list is not intended to be passed to variadic function.
5464
+ if (Callee->isVariadic())
5465
+ return;
5466
+
5467
+ // Check if va_list is passed to callee function.
5468
+ // If va_list is not passed, return.
5469
+ bool hasVaList = false;
5470
+ for (const auto *Param : Callee->parameters()) {
5471
+ if (Param->getOriginalType().getCanonicalType() ==
5472
+ getASTContext().getBuiltinVaListType().getCanonicalType()) {
5473
+ hasVaList = true;
5474
+ break;
5475
+ }
5476
+ }
5477
+ if (!hasVaList)
5478
+ return;
5479
+
5480
+ unsigned int FormatArgumentIndexOffset =
5481
+ checkIfMethodHasImplicitObjectParameter(Callee) ? 2 : 1;
5482
+
5483
+ // If callee function is format function and format arguments are not
5484
+ // relevant to emit diagnostic, save only information about format type
5485
+ // (format index and first-to-check argument index are set to -1).
5486
+ // Information about format type is later used to determine if there are
5487
+ // more than one format type found.
5488
+
5489
+ unsigned int NumArgs = Args.size();
5490
+ // Check if function has format attribute with forwarded format string.
5491
+ IdentifierInfo *AttrType;
5492
+ const ParmVarDecl *FormatStringArg;
5493
+ if (!llvm::any_of(
5494
+ Callee->specific_attrs<FormatAttr>(), [&](const FormatAttr *Attr) {
5495
+ AttrType = Attr->getType();
5496
+
5497
+ int OffsetFormatIndex =
5498
+ Attr->getFormatIdx() - FormatArgumentIndexOffset;
5499
+ if (OffsetFormatIndex < 0 || (unsigned)OffsetFormatIndex >= NumArgs)
5500
+ return false;
5501
+
5502
+ if (const auto *FormatArgExpr = dyn_cast<DeclRefExpr>(
5503
+ Args[OffsetFormatIndex]->IgnoreParenCasts()))
5504
+ if (FormatStringArg = dyn_cast_or_null<ParmVarDecl>(
5505
+ FormatArgExpr->getReferencedDeclOfCallee()))
5506
+ return true;
5507
+ return false;
5508
+ })) {
5509
+ MissingAttributes.push_back(
5510
+ FormatAttr::CreateImplicit(getASTContext(), AttrType, -1, -1));
5511
+ return;
5512
+ }
5513
+
5514
+ unsigned ArgumentIndexOffset =
5515
+ checkIfMethodHasImplicitObjectParameter(Caller) ? 2 : 1;
5516
+
5517
+ unsigned NumOfCallerFunctionParams = Caller->getNumParams();
5518
+
5519
+ // Compare caller and callee function format attribute arguments (archetype
5520
+ // and format string). If they don't match, caller misses format attribute.
5521
+ if (llvm::any_of(
5522
+ Caller->specific_attrs<FormatAttr>(), [&](const FormatAttr *Attr) {
5523
+ if (Attr->getType() != AttrType)
5524
+ return false;
5525
+ int OffsetFormatIndex = Attr->getFormatIdx() - ArgumentIndexOffset;
5526
+
5527
+ if (OffsetFormatIndex < 0 ||
5528
+ (unsigned)OffsetFormatIndex >= NumOfCallerFunctionParams)
5529
+ return false;
5530
+
5531
+ if (Caller->parameters()[OffsetFormatIndex] != FormatStringArg)
5532
+ return false;
5533
+
5534
+ return true;
5535
+ })) {
5536
+ MissingAttributes.push_back(
5537
+ FormatAttr::CreateImplicit(getASTContext(), AttrType, -1, -1));
5538
+ return;
5539
+ }
5540
+
5541
+ // Get format string index
5542
+ int FormatStringIndex =
5543
+ FormatStringArg->getFunctionScopeIndex() + ArgumentIndexOffset;
5544
+
5545
+ // Get first argument index
5546
+ int FirstToCheck = Caller->isVariadic()
5547
+ ? (NumOfCallerFunctionParams + ArgumentIndexOffset)
5548
+ : 0;
5549
+
5550
+ // Do not add duplicate in a vector of missing format attributes.
5551
+ if (!llvm::any_of(MissingAttributes, [&](const FormatAttr *Attr) {
5552
+ return Attr->getType() == AttrType &&
5553
+ Attr->getFormatIdx() == FormatStringIndex &&
5554
+ Attr->getFirstArg() == FirstToCheck;
5555
+ }))
5556
+ MissingAttributes.push_back(FormatAttr::CreateImplicit(
5557
+ getASTContext(), AttrType, FormatStringIndex, FirstToCheck, Loc));
5558
+ }
5559
+
5560
+ // This function is called only if caller function is not template.
5561
+ // TODO: Add call for template functions.
5562
+ // Emits missing format attribute diagnostics.
5563
+ void Sema::EmitMissingFormatAttributesDiagnostic(const FunctionDecl *Caller) {
5564
+ const clang::IdentifierInfo *AttrType = MissingAttributes[0]->getType();
5565
+ for (unsigned i = 1; i < MissingAttributes.size(); ++i) {
5566
+ if (AttrType != MissingAttributes[i]->getType()) {
5567
+ // Clear vector of missing attributes because it could be used in
5568
+ // diagnosing missing format attributes in another caller.
5569
+ MissingAttributes.clear();
5570
+ return;
5571
+ }
5572
+ }
5573
+
5574
+ for (const FormatAttr *FA : MissingAttributes) {
5575
+ // If format index and first-to-check argument index are negative, it means
5576
+ // that this attribute is only saved for multiple format types checking.
5577
+ if (FA->getFormatIdx() < 0 || FA->getFirstArg() < 0)
5578
+ continue;
5579
+
5580
+ // If caller function has format attributes and callee format attribute type
5581
+ // mismatches caller attribute type, do not emit diagnostic.
5582
+ if (Caller->hasAttr<FormatAttr>() &&
5583
+ !llvm::any_of(Caller->specific_attrs<FormatAttr>(),
5584
+ [FA](const FormatAttr *FunctionAttr) {
5585
+ return FA->getType() == FunctionAttr->getType();
5586
+ }))
5587
+ continue;
5588
+
5589
+ // Emit diagnostic
5590
+ SourceLocation Loc = Caller->getFirstDecl()->getLocation();
5591
+ Diag(Loc, diag::warn_missing_format_attribute)
5592
+ << FA->getType() << Caller
5593
+ << FixItHint::CreateInsertion(Loc,
5594
+ (llvm::Twine("__attribute__((format(") +
5595
+ FA->getType()->getName() + ", " +
5596
+ llvm::Twine(FA->getFormatIdx()) + ", " +
5597
+ llvm::Twine(FA->getFirstArg()) + ")))")
5598
+ .str());
5599
+ Diag(FA->getLocation(), diag::note_format_function) << FA->getType();
5600
+ }
5601
+
5602
+ // Clear vector of missing attributes after emitting diagnostics for caller
5603
+ // function because it could be used in diagnosing missing format attributes
5604
+ // in another caller.
5605
+ MissingAttributes.clear();
5606
+ }
5607
+
5433
5608
//===----------------------------------------------------------------------===//
5434
5609
// Microsoft specific attribute handlers.
5435
5610
//===----------------------------------------------------------------------===//
0 commit comments