================
@@ -5918,6 +5918,181 @@ static void handlePreferredTypeAttr(Sema &S, Decl *D, 
const ParsedAttr &AL) {
   D->addAttr(::new (S.Context) PreferredTypeAttr(S.Context, AL, ParmTSI));
 }
 
+// Diagnosing missing format attributes is implemented in two steps:
+// 1. Detect missing format attributes while checking function calls.
+// 2. Emit diagnostic in part that processes function body.
+// For this purpose it is created vector that stores information about format
+// attributes. There are no two format attributes with same arguments in a
+// vector. Vector could contains attributes that only store information about
+// format type (format string and first to check argument are set to -1).
+namespace {
+std::vector<FormatAttr *> MissingAttributes;
+} // end anonymous namespace
+
+// This function is called only if function call is not inside template body.
+// TODO: Add call for function calls inside template body.
+// Detects and stores missing format attributes in a vector.
+void Sema::DetectMissingFormatAttributes(const FunctionDecl *Callee,
+                                         ArrayRef<const Expr *> Args,
+                                         SourceLocation Loc) {
+  assert(Callee);
+
+  // If there is no caller, exit.
+  const FunctionDecl *Caller = getCurFunctionDecl();
+  if (!getCurFunctionDecl())
+    return;
+
+  // Check if callee function is a format function.
+  // If it is, check if caller function misses format attributes.
+
+  if (!Callee->hasAttr<FormatAttr>())
+    return;
+
+  // va_list is not intended to be passed to variadic function.
+  if (Callee->isVariadic())
+    return;
+
+  // Check if va_list is passed to callee function.
+  // If va_list is not passed, return.
+  bool hasVaList = false;
+  for (const auto *Param : Callee->parameters()) {
+    if (Param->getOriginalType().getCanonicalType() ==
+        getASTContext().getBuiltinVaListType().getCanonicalType()) {
+      hasVaList = true;
+      break;
+    }
+  }
+  if (!hasVaList)
+    return;
+
+  unsigned int FormatArgumentIndexOffset =
+      checkIfMethodHasImplicitObjectParameter(Callee) ? 2 : 1;
+
+  // If callee function is format function and format arguments are not
+  // relevant to emit diagnostic, save only information about format type
+  // (format index and first-to-check argument index are set to -1).
+  // Information about format type is later used to determine if there are
+  // more than one format type found.
+
+  unsigned int NumArgs = Args.size();
+  // Check if function has format attribute with forwarded format string.
+  IdentifierInfo *AttrType;
+  const ParmVarDecl *FormatStringArg;
+  if (!llvm::any_of(
+          Callee->specific_attrs<FormatAttr>(), [&](const FormatAttr *Attr) {
+            AttrType = Attr->getType();
+
+            int OffsetFormatIndex =
+                Attr->getFormatIdx() - FormatArgumentIndexOffset;
+            if (OffsetFormatIndex < 0 || (unsigned)OffsetFormatIndex >= 
NumArgs)
+              return false;
+
+            if (const auto *FormatArgExpr = dyn_cast<DeclRefExpr>(
+                    Args[OffsetFormatIndex]->IgnoreParenCasts()))
+              if (FormatStringArg = dyn_cast_or_null<ParmVarDecl>(
+                      FormatArgExpr->getReferencedDeclOfCallee()))
+                return true;
+            return false;
+          })) {
+    MissingAttributes.push_back(
+        FormatAttr::CreateImplicit(getASTContext(), AttrType, -1, -1));
+    return;
+  }
+
+  unsigned ArgumentIndexOffset =
+      checkIfMethodHasImplicitObjectParameter(Caller) ? 2 : 1;
+
+  unsigned NumOfCallerFunctionParams = Caller->getNumParams();
+
+  // Compare caller and callee function format attribute arguments (archetype
+  // and format string). If they don't match, caller misses format attribute.
+  if (llvm::any_of(
+          Caller->specific_attrs<FormatAttr>(), [&](const FormatAttr *Attr) {
+            if (Attr->getType() != AttrType)
+              return false;
+            int OffsetFormatIndex = Attr->getFormatIdx() - ArgumentIndexOffset;
+
+            if (OffsetFormatIndex < 0 ||
+                (unsigned)OffsetFormatIndex >= NumOfCallerFunctionParams)
+              return false;
+
+            if (Caller->parameters()[OffsetFormatIndex] != FormatStringArg)
+              return false;
+
+            return true;
+          })) {
+    MissingAttributes.push_back(
+        FormatAttr::CreateImplicit(getASTContext(), AttrType, -1, -1));
+    return;
+  }
+
+  // Get format string index
+  int FormatStringIndex =
+      FormatStringArg->getFunctionScopeIndex() + ArgumentIndexOffset;
+
+  // Get first argument index
+  int FirstToCheck = Caller->isVariadic()
+                         ? (NumOfCallerFunctionParams + ArgumentIndexOffset)
+                         : 0;
+
+  // Do not add duplicate in a vector of missing format attributes.
+  if (!llvm::any_of(MissingAttributes, [&](const FormatAttr *Attr) {
+        return Attr->getType() == AttrType &&
+               Attr->getFormatIdx() == FormatStringIndex &&
+               Attr->getFirstArg() == FirstToCheck;
+      }))
+    MissingAttributes.push_back(FormatAttr::CreateImplicit(
+        getASTContext(), AttrType, FormatStringIndex, FirstToCheck, Loc));
----------------
aaronpuchert wrote:

I think we should just not bother doing this and emit the warning right here.

https://github.com/llvm/llvm-project/pull/105479
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to