[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