[cfe-commits] [patch] Added a suggestion when a std::string is passed to printf()
Chandler Carruth
chandlerc at google.com
Wed Jun 6 14:59:35 PDT 2012
On Wed, Jun 6, 2012 at 2:35 PM, Sam Panzer <panzer at google.com> wrote:
> And here is another update that replaces the default non-POD error with a
> smarter (printf-specific) one, rather than just tacking on an extra warning.
Thanks, I really love this. =] Comments on the patch. A lot of this is just
style nit-picking to help you get used to the coding conventions in Clang.
+def warn_non_pod_string_passed_to_printf : Warning<
This warning name is a bit misleading now... How about:
warn_non_pod_vararg_with_format_string?
-
+def note_printf_c_str: Note< "did you mean to call .c_str()?">;
No space before the "
Also, you should probably pass 'c_str' from the name of the method so that
we can generalize this later if we would like (str, dunno, maybe some
interesting suggestions for ObjectiveC types).
I would probably use more of a prose form rather than potentially getting
the syntax wrong: "did you mean to call the %0 method?"
+ bool IsPrintfLike(FunctionDecl *FDecl, Expr **Args, unsigned NumArgs);
I would prefer 'hasFormatStringArgument'. I think that's more accurate.
+// Given a variadic function, decides whether it looks like we have a
+// printf-style format string and arguments)
+// This doesn't work for member functions.
Why not?
+bool Sema::IsPrintfLike(FunctionDecl *FDecl, Expr **Args, unsigned
NumArgs) {
+ // Anonymous and lambda functions will be assumed not to be printf.
+ if (!FDecl)
+ return false;
+
+ for (specific_attr_iterator<FormatAttr>
+ i = FDecl->specific_attr_begin<FormatAttr>(),
Prevailing style you should use in new patches is for iterator loop
variables to use capital letters: I and E.
+ e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
+ const FormatAttr *Format = *i;
+ unsigned format_idx = Format->getFormatIdx() - 1;
I think you can just use 'I->' here.
+
+ if (format_idx >= NumArgs) {
Avoid curlies on one-line ifs.
+ // There must be some other format
+ continue;
+ }
+
+ return true;
Reversing the logic would be shorter:
if (format_idx < NumArgs)
return true;
+ bool CheckFormatExpr(const analyze_printf::PrintfSpecifier &FS,
+ const char *startSpecifier,
Parameter names should be CamelCased. Function (and method) names should be
camelCased.
+ unsigned specifierLen,
+ const Expr *Ex);
'E' is the more common name for an Expr parameter.
+// Determines if the specified is a C++ class or struct containing
+// a member with the specified name and kind (e.g. a CXXMethodDecl named
+// "c_str()"
+template<typename FieldKind>
+static llvm::SmallPtrSet<FieldKind*, 1>
+CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) {
+ const RecordType *RT = Ty->getAs<RecordType>();
+ llvm::SmallPtrSet<FieldKind*, 1> Results;
+
+ if (!RT)
+ return Results;
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD)
+ return Results;
+
+ LookupResult R(S, &S.PP.getIdentifierTable().get(Name), SourceLocation(),
+ Sema::LookupMemberName);
+
+ // We just need to include all members of the right kind turned up by the
+ // filter, at this point.
+ if (S.LookupQualifiedName(R, RT->getDecl())) {
+ LookupResult::Filter filter = R.makeFilter();
+ while (filter.hasNext()) {
+ NamedDecl *decl = filter.next()->getUnderlyingDecl();
+ if (FieldKind *FK = dyn_cast<FieldKind>(decl)) {
+ Results.insert(FK);
+ }
+ }
+ filter.done();
+ }
+ return Results;
+}
+
+// Check if a (w)string was passed when a (w)char* was needed, and offer a
+// better diagnostic if so. ATR is assumed to be valid.
+// Returns true when a c_str() conversion method is found.
+bool
Please try not to break after return types unless you have to for
80-columns.
+CheckPrintfHandler::CheckForCStrMembers(
+ const analyze_printf::ArgTypeResult &ATR, const Expr *Ex,
+ const CharSourceRange &CSR) {
+ typedef llvm::SmallPtrSet<CXXMethodDecl*, 1> MethodSet;
+ MethodSet Results =
+ CXXRecordMembersNamed<CXXMethodDecl>("c_str", S, Ex->getType());
+
+ for (MethodSet::iterator it = Results.begin(), end = Results.end();
I and E here rather than it and end.
+ it != end; ++it) {
+ const CXXMethodDecl *Method = (*it);
Don't use extraneous parentheses please. Also, I suspect you can directly
use 'I->' below rather than creating a separate variable...
+ if (Method->getNumParams() == 0 &&
+ ATR.matchesType(S.Context, Method->getResultType())) {
+
+ S.Diag(Ex->getLocStart(), diag::note_printf_c_str)
+ << FixItHint::CreateInsertion(Ex->getLocEnd(), ".c_str()");
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool
CheckPrintfHandler::HandlePrintfSpecifier(const
analyze_printf::PrintfSpecifier
&FS,
const char *startSpecifier,
unsigned specifierLen) {
-
Please don't change unrelated whitespace.
+ // This should really be identical to the checks in SemaExpr.cpp.
Can you hoist them into a helper function, and call them from here?
ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E,
VariadicCallType CT,
- FunctionDecl *FDecl) {
+ FunctionDecl *FDecl,
+ bool DeferErrors) {
DeferErrors doesn't really clarify much for me... maybe "HasFormatString"?
@@ -585,9 +586,14 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr
*E, VariadicCallType CT,
getLangOpts().ObjCAutoRefCount &&
E->getType()->isObjCLifetimeType())
TrivialEnough = true;
-
+
You'll probably have to fix your editor to avoid unrelated whitespace
changes.
if (TrivialEnough) {
// Nothing to diagnose. This is okay.
+ } else if (DeferErrors) {
+ // In case the function looks sufficiently like printf,
+ // try to fix non-POD arguments (e.g. an std::string passed rather
than
+ // a char *).
+ // This is handled in SemaChecking, so we skip the error here.
I just would say: "If there is a format string argument, non-POD argument
checking is handled along with the format string checking".
+ // Decide if we're probably inspecting a printf-like function
I'm hopeful that with the function and variable name changes you can drop
this comment. It should be obvious from the code.
+
+ bool DeferErrors = IsPrintfLike(FDecl, Args, NumArgs);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20120606/6c2160e1/attachment.html>
More information about the cfe-commits
mailing list