@@ -3677,7 +3677,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3677
3677
3678
3678
// In C++ the implicit 'this' function parameter also counts, and they are
3679
3679
// counted from one.
3680
- bool HasImplicitThisParam = isInstanceMethod (D);
3680
+ bool HasImplicitThisParam = checkIfMethodHasImplicitObjectParameter (D);
3681
3681
unsigned NumArgs = getFunctionOrMethodNumParams (D) + HasImplicitThisParam;
3682
3682
3683
3683
IdentifierInfo *II = AL.getArgAsIdent (0 )->Ident ;
@@ -3790,7 +3790,7 @@ static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
3790
3790
return ;
3791
3791
}
3792
3792
3793
- bool HasImplicitThisParam = isInstanceMethod (D);
3793
+ bool HasImplicitThisParam = checkIfMethodHasImplicitObjectParameter (D);
3794
3794
int32_t NumArgs = getFunctionOrMethodNumParams (D);
3795
3795
3796
3796
FunctionDecl *FD = D->getAsFunction ();
@@ -5596,6 +5596,181 @@ static void handlePreferredTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5596
5596
D->addAttr (::new (S.Context ) PreferredTypeAttr (S.Context , AL, ParmTSI));
5597
5597
}
5598
5598
5599
+ // Diagnosing missing format attributes is implemented in two steps:
5600
+ // 1. Detect missing format attributes while checking function calls.
5601
+ // 2. Emit diagnostic in part that processes function body.
5602
+ // For this purpose it is created vector that stores information about format
5603
+ // attributes. There are no two format attributes with same arguments in a
5604
+ // vector. Vector could contains attributes that only store information about
5605
+ // format type (format string and first to check argument are set to -1).
5606
+ namespace {
5607
+ std::vector<FormatAttr *> MissingAttributes;
5608
+ } // end anonymous namespace
5609
+
5610
+ // This function is called only if function call is not inside template body.
5611
+ // TODO: Add call for function calls inside template body.
5612
+ // Detects and stores missing format attributes in a vector.
5613
+ void Sema::DetectMissingFormatAttributes (const FunctionDecl *Callee,
5614
+ ArrayRef<const Expr *> Args,
5615
+ SourceLocation Loc) {
5616
+ assert (Callee);
5617
+
5618
+ // If there is no caller, exit.
5619
+ const FunctionDecl *Caller = getCurFunctionDecl ();
5620
+ if (!getCurFunctionDecl ())
5621
+ return ;
5622
+
5623
+ // Check if callee function is a format function.
5624
+ // If it is, check if caller function misses format attributes.
5625
+
5626
+ if (!Callee->hasAttr <FormatAttr>())
5627
+ return ;
5628
+
5629
+ // va_list is not intended to be passed to variadic function.
5630
+ if (Callee->isVariadic ())
5631
+ return ;
5632
+
5633
+ // Check if va_list is passed to callee function.
5634
+ // If va_list is not passed, return.
5635
+ bool hasVaList = false ;
5636
+ for (const auto *Param : Callee->parameters ()) {
5637
+ if (Param->getOriginalType ().getCanonicalType () ==
5638
+ getASTContext ().getBuiltinVaListType ().getCanonicalType ()) {
5639
+ hasVaList = true ;
5640
+ break ;
5641
+ }
5642
+ }
5643
+ if (!hasVaList)
5644
+ return ;
5645
+
5646
+ unsigned int FormatArgumentIndexOffset =
5647
+ checkIfMethodHasImplicitObjectParameter (Callee) ? 2 : 1 ;
5648
+
5649
+ // If callee function is format function and format arguments are not
5650
+ // relevant to emit diagnostic, save only information about format type
5651
+ // (format index and first-to-check argument index are set to -1).
5652
+ // Information about format type is later used to determine if there are
5653
+ // more than one format type found.
5654
+
5655
+ unsigned int NumArgs = Args.size ();
5656
+ // Check if function has format attribute with forwarded format string.
5657
+ IdentifierInfo *AttrType;
5658
+ const ParmVarDecl *FormatStringArg;
5659
+ if (!llvm::any_of (
5660
+ Callee->specific_attrs <FormatAttr>(), [&](const FormatAttr *Attr) {
5661
+ AttrType = Attr->getType ();
5662
+
5663
+ int OffsetFormatIndex =
5664
+ Attr->getFormatIdx () - FormatArgumentIndexOffset;
5665
+ if (OffsetFormatIndex < 0 || (unsigned )OffsetFormatIndex >= NumArgs)
5666
+ return false ;
5667
+
5668
+ if (const auto *FormatArgExpr = dyn_cast<DeclRefExpr>(
5669
+ Args[OffsetFormatIndex]->IgnoreParenCasts ()))
5670
+ if (FormatStringArg = dyn_cast_or_null<ParmVarDecl>(
5671
+ FormatArgExpr->getReferencedDeclOfCallee ()))
5672
+ return true ;
5673
+ return false ;
5674
+ })) {
5675
+ MissingAttributes.push_back (
5676
+ FormatAttr::CreateImplicit (getASTContext (), AttrType, -1 , -1 ));
5677
+ return ;
5678
+ }
5679
+
5680
+ unsigned ArgumentIndexOffset =
5681
+ checkIfMethodHasImplicitObjectParameter (Caller) ? 2 : 1 ;
5682
+
5683
+ unsigned NumOfCallerFunctionParams = Caller->getNumParams ();
5684
+
5685
+ // Compare caller and callee function format attribute arguments (archetype
5686
+ // and format string). If they don't match, caller misses format attribute.
5687
+ if (llvm::any_of (
5688
+ Caller->specific_attrs <FormatAttr>(), [&](const FormatAttr *Attr) {
5689
+ if (Attr->getType () != AttrType)
5690
+ return false ;
5691
+ int OffsetFormatIndex = Attr->getFormatIdx () - ArgumentIndexOffset;
5692
+
5693
+ if (OffsetFormatIndex < 0 ||
5694
+ (unsigned )OffsetFormatIndex >= NumOfCallerFunctionParams)
5695
+ return false ;
5696
+
5697
+ if (Caller->parameters ()[OffsetFormatIndex] != FormatStringArg)
5698
+ return false ;
5699
+
5700
+ return true ;
5701
+ })) {
5702
+ MissingAttributes.push_back (
5703
+ FormatAttr::CreateImplicit (getASTContext (), AttrType, -1 , -1 ));
5704
+ return ;
5705
+ }
5706
+
5707
+ // Get format string index
5708
+ int FormatStringIndex =
5709
+ FormatStringArg->getFunctionScopeIndex () + ArgumentIndexOffset;
5710
+
5711
+ // Get first argument index
5712
+ int FirstToCheck = Caller->isVariadic ()
5713
+ ? (NumOfCallerFunctionParams + ArgumentIndexOffset)
5714
+ : 0 ;
5715
+
5716
+ // Do not add duplicate in a vector of missing format attributes.
5717
+ if (!llvm::any_of (MissingAttributes, [&](const FormatAttr *Attr) {
5718
+ return Attr->getType () == AttrType &&
5719
+ Attr->getFormatIdx () == FormatStringIndex &&
5720
+ Attr->getFirstArg () == FirstToCheck;
5721
+ }))
5722
+ MissingAttributes.push_back (FormatAttr::CreateImplicit (
5723
+ getASTContext (), AttrType, FormatStringIndex, FirstToCheck, Loc));
5724
+ }
5725
+
5726
+ // This function is called only if caller function is not template.
5727
+ // TODO: Add call for template functions.
5728
+ // Emits missing format attribute diagnostics.
5729
+ void Sema::EmitMissingFormatAttributesDiagnostic (const FunctionDecl *Caller) {
5730
+ const clang::IdentifierInfo *AttrType = MissingAttributes[0 ]->getType ();
5731
+ for (unsigned i = 1 ; i < MissingAttributes.size (); ++i) {
5732
+ if (AttrType != MissingAttributes[i]->getType ()) {
5733
+ // Clear vector of missing attributes because it could be used in
5734
+ // diagnosing missing format attributes in another caller.
5735
+ MissingAttributes.clear ();
5736
+ return ;
5737
+ }
5738
+ }
5739
+
5740
+ for (const FormatAttr *FA : MissingAttributes) {
5741
+ // If format index and first-to-check argument index are negative, it means
5742
+ // that this attribute is only saved for multiple format types checking.
5743
+ if (FA->getFormatIdx () < 0 || FA->getFirstArg () < 0 )
5744
+ continue ;
5745
+
5746
+ // If caller function has format attributes and callee format attribute type
5747
+ // mismatches caller attribute type, do not emit diagnostic.
5748
+ if (Caller->hasAttr <FormatAttr>() &&
5749
+ !llvm::any_of (Caller->specific_attrs <FormatAttr>(),
5750
+ [FA](const FormatAttr *FunctionAttr) {
5751
+ return FA->getType () == FunctionAttr->getType ();
5752
+ }))
5753
+ continue ;
5754
+
5755
+ // Emit diagnostic
5756
+ SourceLocation Loc = Caller->getFirstDecl ()->getLocation ();
5757
+ Diag (Loc, diag::warn_missing_format_attribute)
5758
+ << FA->getType () << Caller
5759
+ << FixItHint::CreateInsertion (Loc,
5760
+ (llvm::Twine (" __attribute__((format(" ) +
5761
+ FA->getType ()->getName () + " , " +
5762
+ llvm::Twine (FA->getFormatIdx ()) + " , " +
5763
+ llvm::Twine (FA->getFirstArg ()) + " )))" )
5764
+ .str ());
5765
+ Diag (FA->getLocation (), diag::note_format_function) << FA->getType ();
5766
+ }
5767
+
5768
+ // Clear vector of missing attributes after emitting diagnostics for caller
5769
+ // function because it could be used in diagnosing missing format attributes
5770
+ // in another caller.
5771
+ MissingAttributes.clear ();
5772
+ }
5773
+
5599
5774
// ===----------------------------------------------------------------------===//
5600
5775
// Microsoft specific attribute handlers.
5601
5776
// ===----------------------------------------------------------------------===//
0 commit comments