@@ -3899,7 +3899,7 @@ static bool handleFormatAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
3899
3899
3900
3900
// In C++ the implicit 'this' function parameter also counts, and they are
3901
3901
// counted from one.
3902
- bool HasImplicitThisParam = isInstanceMethod (D);
3902
+ bool HasImplicitThisParam = checkIfMethodHasImplicitObjectParameter (D);
3903
3903
Info->NumArgs = getFunctionOrMethodNumParams (D) + HasImplicitThisParam;
3904
3904
3905
3905
Info->Identifier = AL.getArgAsIdent (0 )->Ident ;
@@ -4042,7 +4042,7 @@ static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
4042
4042
return ;
4043
4043
}
4044
4044
4045
- bool HasImplicitThisParam = isInstanceMethod (D);
4045
+ bool HasImplicitThisParam = checkIfMethodHasImplicitObjectParameter (D);
4046
4046
int32_t NumArgs = getFunctionOrMethodNumParams (D);
4047
4047
4048
4048
FunctionDecl *FD = D->getAsFunction ();
@@ -5918,6 +5918,181 @@ static void handlePreferredTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5918
5918
D->addAttr (::new (S.Context ) PreferredTypeAttr (S.Context , AL, ParmTSI));
5919
5919
}
5920
5920
5921
+ // Diagnosing missing format attributes is implemented in two steps:
5922
+ // 1. Detect missing format attributes while checking function calls.
5923
+ // 2. Emit diagnostic in part that processes function body.
5924
+ // For this purpose it is created vector that stores information about format
5925
+ // attributes. There are no two format attributes with same arguments in a
5926
+ // vector. Vector could contains attributes that only store information about
5927
+ // format type (format string and first to check argument are set to -1).
5928
+ namespace {
5929
+ std::vector<FormatAttr *> MissingAttributes;
5930
+ } // end anonymous namespace
5931
+
5932
+ // This function is called only if function call is not inside template body.
5933
+ // TODO: Add call for function calls inside template body.
5934
+ // Detects and stores missing format attributes in a vector.
5935
+ void Sema::DetectMissingFormatAttributes (const FunctionDecl *Callee,
5936
+ ArrayRef<const Expr *> Args,
5937
+ SourceLocation Loc) {
5938
+ assert (Callee);
5939
+
5940
+ // If there is no caller, exit.
5941
+ const FunctionDecl *Caller = getCurFunctionDecl ();
5942
+ if (!getCurFunctionDecl ())
5943
+ return ;
5944
+
5945
+ // Check if callee function is a format function.
5946
+ // If it is, check if caller function misses format attributes.
5947
+
5948
+ if (!Callee->hasAttr <FormatAttr>())
5949
+ return ;
5950
+
5951
+ // va_list is not intended to be passed to variadic function.
5952
+ if (Callee->isVariadic ())
5953
+ return ;
5954
+
5955
+ // Check if va_list is passed to callee function.
5956
+ // If va_list is not passed, return.
5957
+ bool hasVaList = false ;
5958
+ for (const auto *Param : Callee->parameters ()) {
5959
+ if (Param->getOriginalType ().getCanonicalType () ==
5960
+ getASTContext ().getBuiltinVaListType ().getCanonicalType ()) {
5961
+ hasVaList = true ;
5962
+ break ;
5963
+ }
5964
+ }
5965
+ if (!hasVaList)
5966
+ return ;
5967
+
5968
+ unsigned int FormatArgumentIndexOffset =
5969
+ checkIfMethodHasImplicitObjectParameter (Callee) ? 2 : 1 ;
5970
+
5971
+ // If callee function is format function and format arguments are not
5972
+ // relevant to emit diagnostic, save only information about format type
5973
+ // (format index and first-to-check argument index are set to -1).
5974
+ // Information about format type is later used to determine if there are
5975
+ // more than one format type found.
5976
+
5977
+ unsigned int NumArgs = Args.size ();
5978
+ // Check if function has format attribute with forwarded format string.
5979
+ IdentifierInfo *AttrType;
5980
+ const ParmVarDecl *FormatStringArg;
5981
+ if (!llvm::any_of (
5982
+ Callee->specific_attrs <FormatAttr>(), [&](const FormatAttr *Attr) {
5983
+ AttrType = Attr->getType ();
5984
+
5985
+ int OffsetFormatIndex =
5986
+ Attr->getFormatIdx () - FormatArgumentIndexOffset;
5987
+ if (OffsetFormatIndex < 0 || (unsigned )OffsetFormatIndex >= NumArgs)
5988
+ return false ;
5989
+
5990
+ if (const auto *FormatArgExpr = dyn_cast<DeclRefExpr>(
5991
+ Args[OffsetFormatIndex]->IgnoreParenCasts ()))
5992
+ if (FormatStringArg = dyn_cast_or_null<ParmVarDecl>(
5993
+ FormatArgExpr->getReferencedDeclOfCallee ()))
5994
+ return true ;
5995
+ return false ;
5996
+ })) {
5997
+ MissingAttributes.push_back (
5998
+ FormatAttr::CreateImplicit (getASTContext (), AttrType, -1 , -1 ));
5999
+ return ;
6000
+ }
6001
+
6002
+ unsigned ArgumentIndexOffset =
6003
+ checkIfMethodHasImplicitObjectParameter (Caller) ? 2 : 1 ;
6004
+
6005
+ unsigned NumOfCallerFunctionParams = Caller->getNumParams ();
6006
+
6007
+ // Compare caller and callee function format attribute arguments (archetype
6008
+ // and format string). If they don't match, caller misses format attribute.
6009
+ if (llvm::any_of (
6010
+ Caller->specific_attrs <FormatAttr>(), [&](const FormatAttr *Attr) {
6011
+ if (Attr->getType () != AttrType)
6012
+ return false ;
6013
+ int OffsetFormatIndex = Attr->getFormatIdx () - ArgumentIndexOffset;
6014
+
6015
+ if (OffsetFormatIndex < 0 ||
6016
+ (unsigned )OffsetFormatIndex >= NumOfCallerFunctionParams)
6017
+ return false ;
6018
+
6019
+ if (Caller->parameters ()[OffsetFormatIndex] != FormatStringArg)
6020
+ return false ;
6021
+
6022
+ return true ;
6023
+ })) {
6024
+ MissingAttributes.push_back (
6025
+ FormatAttr::CreateImplicit (getASTContext (), AttrType, -1 , -1 ));
6026
+ return ;
6027
+ }
6028
+
6029
+ // Get format string index
6030
+ int FormatStringIndex =
6031
+ FormatStringArg->getFunctionScopeIndex () + ArgumentIndexOffset;
6032
+
6033
+ // Get first argument index
6034
+ int FirstToCheck = Caller->isVariadic ()
6035
+ ? (NumOfCallerFunctionParams + ArgumentIndexOffset)
6036
+ : 0 ;
6037
+
6038
+ // Do not add duplicate in a vector of missing format attributes.
6039
+ if (!llvm::any_of (MissingAttributes, [&](const FormatAttr *Attr) {
6040
+ return Attr->getType () == AttrType &&
6041
+ Attr->getFormatIdx () == FormatStringIndex &&
6042
+ Attr->getFirstArg () == FirstToCheck;
6043
+ }))
6044
+ MissingAttributes.push_back (FormatAttr::CreateImplicit (
6045
+ getASTContext (), AttrType, FormatStringIndex, FirstToCheck, Loc));
6046
+ }
6047
+
6048
+ // This function is called only if caller function is not template.
6049
+ // TODO: Add call for template functions.
6050
+ // Emits missing format attribute diagnostics.
6051
+ void Sema::EmitMissingFormatAttributesDiagnostic (const FunctionDecl *Caller) {
6052
+ const clang::IdentifierInfo *AttrType = MissingAttributes[0 ]->getType ();
6053
+ for (unsigned i = 1 ; i < MissingAttributes.size (); ++i) {
6054
+ if (AttrType != MissingAttributes[i]->getType ()) {
6055
+ // Clear vector of missing attributes because it could be used in
6056
+ // diagnosing missing format attributes in another caller.
6057
+ MissingAttributes.clear ();
6058
+ return ;
6059
+ }
6060
+ }
6061
+
6062
+ for (const FormatAttr *FA : MissingAttributes) {
6063
+ // If format index and first-to-check argument index are negative, it means
6064
+ // that this attribute is only saved for multiple format types checking.
6065
+ if (FA->getFormatIdx () < 0 || FA->getFirstArg () < 0 )
6066
+ continue ;
6067
+
6068
+ // If caller function has format attributes and callee format attribute type
6069
+ // mismatches caller attribute type, do not emit diagnostic.
6070
+ if (Caller->hasAttr <FormatAttr>() &&
6071
+ !llvm::any_of (Caller->specific_attrs <FormatAttr>(),
6072
+ [FA](const FormatAttr *FunctionAttr) {
6073
+ return FA->getType () == FunctionAttr->getType ();
6074
+ }))
6075
+ continue ;
6076
+
6077
+ // Emit diagnostic
6078
+ SourceLocation Loc = Caller->getFirstDecl ()->getLocation ();
6079
+ Diag (Loc, diag::warn_missing_format_attribute)
6080
+ << FA->getType () << Caller
6081
+ << FixItHint::CreateInsertion (Loc,
6082
+ (llvm::Twine (" __attribute__((format(" ) +
6083
+ FA->getType ()->getName () + " , " +
6084
+ llvm::Twine (FA->getFormatIdx ()) + " , " +
6085
+ llvm::Twine (FA->getFirstArg ()) + " )))" )
6086
+ .str ());
6087
+ Diag (FA->getLocation (), diag::note_format_function) << FA->getType ();
6088
+ }
6089
+
6090
+ // Clear vector of missing attributes after emitting diagnostics for caller
6091
+ // function because it could be used in diagnosing missing format attributes
6092
+ // in another caller.
6093
+ MissingAttributes.clear ();
6094
+ }
6095
+
5921
6096
// ===----------------------------------------------------------------------===//
5922
6097
// Microsoft specific attribute handlers.
5923
6098
// ===----------------------------------------------------------------------===//
0 commit comments