[clang] [clang] Catch missing format attributes (PR #105479)

Aaron Puchert via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 9 10:13:29 PDT 2024


================
@@ -5335,6 +5335,230 @@ static void handlePreferredTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   D->addAttr(::new (S.Context) PreferredTypeAttr(S.Context, AL, ParmTSI));
 }
 
+// Returns vector of format attributes. There are no two attributes with same
+// arguments in returning vector. There can be attributes that effectively only
+// store information about format type.
+static std::vector<FormatAttr *>
+GetMissingFormatAttributes(Sema &S, Stmt *Body, const FunctionDecl *FDecl) {
+  unsigned int ArgumentIndexOffset =
+      checkIfMethodHasImplicitObjectParameter(FDecl) ? 2 : 1;
+
+  std::vector<FormatAttr *> MissingAttributes;
+
+  // Iterate over body statements.
+  for (auto *Child : Body->children()) {
+    // If child statement is compound statement, recursively get missing
+    // attributes.
+    if (dyn_cast_or_null<CompoundStmt>(Child)) {
+      std::vector<FormatAttr *> CompoundStmtMissingAttributes =
+          GetMissingFormatAttributes(S, Child, FDecl);
+
+      // If there are already missing attributes with same arguments, do not add
+      // duplicates.
+      for (FormatAttr *FA : CompoundStmtMissingAttributes) {
+        if (!llvm::any_of(MissingAttributes, [&](const FormatAttr *Attr) {
+              return FA->getType() == Attr->getType() &&
+                     FA->getFormatIdx() == Attr->getFormatIdx() &&
+                     FA->getFirstArg() == Attr->getFirstArg();
+            }))
+          MissingAttributes.push_back(FA);
+      }
+
+      continue;
+    }
+
+    ValueStmt *VS = dyn_cast<ValueStmt>(Child);
+    if (!VS)
+      continue;
+    CallExpr *TheCall = dyn_cast_or_null<CallExpr>(VS->getExprStmt());
+    if (!TheCall)
+      continue;
+
+    const FunctionDecl *CalleeFunction =
+        dyn_cast_or_null<FunctionDecl>(TheCall->getCalleeDecl());
+    if (!CalleeFunction || !CalleeFunction->hasAttr<FormatAttr>())
+      continue;
+
+    // va_list is not intended to be passed to variadic function.
+    if (CalleeFunction->isVariadic())
+      continue;
+
+    Expr **Args = TheCall->getArgs();
+    unsigned int NumArgs = TheCall->getNumArgs();
+
+    // Check if va_list is passed to callee function.
+    // If va_list is not passed, continue to the next iteration.
+    bool hasVaList = false;
+    for (unsigned int i = 0; i < NumArgs; ++i) {
+      if (const IdentifierInfo *II = Args[i]
+                                         ->IgnoreParenCasts()
+                                         ->getType()
+                                         .getCanonicalType()
+                                         .getBaseTypeIdentifier()) {
+        if (II->getName() == S.getASTContext()
+                                 .getBuiltinVaListType()
+                                 .getCanonicalType()
+                                 .getBaseTypeIdentifier()
+                                 ->getName()) {
----------------
aaronpuchert wrote:

Previously you compared canonical types, which seems preferable to me. Why compare names instead?

https://github.com/llvm/llvm-project/pull/105479


More information about the cfe-commits mailing list