================ @@ -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