[PATCH] D48734: [Sema] Consider all format_arg attributes.

2018-07-03 Thread Michael Kruse via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC336239: [Sema] Consider all format_arg attributes. (authored 
by Meinersbur, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D48734?vs=153643=154038#toc

Repository:
  rC Clang

https://reviews.llvm.org/D48734

Files:
  lib/Sema/SemaChecking.cpp
  test/Sema/attr-format_arg.c


Index: test/Sema/attr-format_arg.c
===
--- test/Sema/attr-format_arg.c
+++ test/Sema/attr-format_arg.c
@@ -4,10 +4,27 @@
 
 const char* f(const char *s) __attribute__((format_arg(1)));
 
+const char *h(const char *msg1, const char *msg2)
+__attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
 void g(const char *s) {
   printf("%d", 123);
   printf("%d %d", 123); // expected-warning{{more '%' conversions than data 
arguments}}
 
   printf(f("%d"), 123);
   printf(f("%d %d"), 123); // expected-warning{{more '%' conversions than data 
arguments}}
+
+  printf(h(
+"", // expected-warning {{format string is empty}}
+""  // expected-warning {{format string is empty}}
+  ), 123);
+  printf(h(
+"%d",
+""  // expected-warning {{format string is empty}}
+  ), 123);
+  printf(h(
+"", // expected-warning {{format string is empty}}
+"%d"
+  ), 123);
+  printf(h("%d", "%d"), 123);
 }
Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -5518,13 +5518,22 @@
   case Stmt::CXXMemberCallExprClass: {
 const CallExpr *CE = cast(E);
 if (const NamedDecl *ND = 
dyn_cast_or_null(CE->getCalleeDecl())) {
-  if (const FormatArgAttr *FA = ND->getAttr()) {
+  bool IsFirst = true;
+  StringLiteralCheckType CommonResult;
+  for (const auto *FA : ND->specific_attrs()) {
 const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
-return checkFormatStringExpr(S, Arg, Args,
- HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall,
- CheckedVarArgs, UncoveredArg, Offset);
-  } else if (const FunctionDecl *FD = dyn_cast(ND)) {
+StringLiteralCheckType Result = checkFormatStringExpr(
+S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
+CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
+if (IsFirst) {
+  CommonResult = Result;
+  IsFirst = false;
+}
+  }
+  if (!IsFirst)
+return CommonResult;
+
+  if (const auto *FD = dyn_cast(ND)) {
 unsigned BuiltinID = FD->getBuiltinID();
 if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
 BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {


Index: test/Sema/attr-format_arg.c
===
--- test/Sema/attr-format_arg.c
+++ test/Sema/attr-format_arg.c
@@ -4,10 +4,27 @@
 
 const char* f(const char *s) __attribute__((format_arg(1)));
 
+const char *h(const char *msg1, const char *msg2)
+__attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
 void g(const char *s) {
   printf("%d", 123);
   printf("%d %d", 123); // expected-warning{{more '%' conversions than data arguments}}
 
   printf(f("%d"), 123);
   printf(f("%d %d"), 123); // expected-warning{{more '%' conversions than data arguments}}
+
+  printf(h(
+"", // expected-warning {{format string is empty}}
+""  // expected-warning {{format string is empty}}
+  ), 123);
+  printf(h(
+"%d",
+""  // expected-warning {{format string is empty}}
+  ), 123);
+  printf(h(
+"", // expected-warning {{format string is empty}}
+"%d"
+  ), 123);
+  printf(h("%d", "%d"), 123);
 }
Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -5518,13 +5518,22 @@
   case Stmt::CXXMemberCallExprClass: {
 const CallExpr *CE = cast(E);
 if (const NamedDecl *ND = dyn_cast_or_null(CE->getCalleeDecl())) {
-  if (const FormatArgAttr *FA = ND->getAttr()) {
+  bool IsFirst = true;
+  StringLiteralCheckType CommonResult;
+  for (const auto *FA : ND->specific_attrs()) {
 const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
-return checkFormatStringExpr(S, Arg, Args,
- HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall,
- CheckedVarArgs, UncoveredArg, Offset);
-  } else if (const FunctionDecl *FD = dyn_cast(ND)) {
+StringLiteralCheckType Result = checkFormatStringExpr(
+S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
+

[PATCH] D48734: [Sema] Consider all format_arg attributes.

2018-07-03 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman accepted this revision.
aaron.ballman added a comment.
This revision is now accepted and ready to land.

LGTM!


Repository:
  rC Clang

https://reviews.llvm.org/D48734



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48734: [Sema] Consider all format_arg attributes.

2018-06-30 Thread Michael Kruse via Phabricator via cfe-commits
Meinersbur updated this revision to Diff 153643.
Meinersbur added a comment.

- Reinsert test for the change in this patch


Repository:
  rC Clang

https://reviews.llvm.org/D48734

Files:
  lib/Sema/SemaChecking.cpp
  test/Sema/attr-format_arg.c


Index: test/Sema/attr-format_arg.c
===
--- test/Sema/attr-format_arg.c
+++ test/Sema/attr-format_arg.c
@@ -4,10 +4,27 @@
 
 const char* f(const char *s) __attribute__((format_arg(1)));
 
+const char *h(const char *msg1, const char *msg2)
+__attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
 void g(const char *s) {
   printf("%d", 123);
   printf("%d %d", 123); // expected-warning{{more '%' conversions than data 
arguments}}
 
   printf(f("%d"), 123);
   printf(f("%d %d"), 123); // expected-warning{{more '%' conversions than data 
arguments}}
+
+  printf(h(
+"", // expected-warning {{format string is empty}}
+""  // expected-warning {{format string is empty}}
+  ), 123);
+  printf(h(
+"%d",
+""  // expected-warning {{format string is empty}}
+  ), 123);
+  printf(h(
+"", // expected-warning {{format string is empty}}
+"%d"
+  ), 123);
+  printf(h("%d", "%d"), 123);
 }
Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -5518,13 +5518,22 @@
   case Stmt::CXXMemberCallExprClass: {
 const CallExpr *CE = cast(E);
 if (const NamedDecl *ND = 
dyn_cast_or_null(CE->getCalleeDecl())) {
-  if (const FormatArgAttr *FA = ND->getAttr()) {
+  bool IsFirst = true;
+  StringLiteralCheckType CommonResult;
+  for (const auto *FA : ND->specific_attrs()) {
 const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
-return checkFormatStringExpr(S, Arg, Args,
- HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall,
- CheckedVarArgs, UncoveredArg, Offset);
-  } else if (const FunctionDecl *FD = dyn_cast(ND)) {
+StringLiteralCheckType Result = checkFormatStringExpr(
+S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
+CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
+if (IsFirst) {
+  CommonResult = Result;
+  IsFirst = false;
+}
+  }
+  if (!IsFirst)
+return CommonResult;
+
+  if (const auto *FD = dyn_cast(ND)) {
 unsigned BuiltinID = FD->getBuiltinID();
 if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
 BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {


Index: test/Sema/attr-format_arg.c
===
--- test/Sema/attr-format_arg.c
+++ test/Sema/attr-format_arg.c
@@ -4,10 +4,27 @@
 
 const char* f(const char *s) __attribute__((format_arg(1)));
 
+const char *h(const char *msg1, const char *msg2)
+__attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
 void g(const char *s) {
   printf("%d", 123);
   printf("%d %d", 123); // expected-warning{{more '%' conversions than data arguments}}
 
   printf(f("%d"), 123);
   printf(f("%d %d"), 123); // expected-warning{{more '%' conversions than data arguments}}
+
+  printf(h(
+"", // expected-warning {{format string is empty}}
+""  // expected-warning {{format string is empty}}
+  ), 123);
+  printf(h(
+"%d",
+""  // expected-warning {{format string is empty}}
+  ), 123);
+  printf(h(
+"", // expected-warning {{format string is empty}}
+"%d"
+  ), 123);
+  printf(h("%d", "%d"), 123);
 }
Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -5518,13 +5518,22 @@
   case Stmt::CXXMemberCallExprClass: {
 const CallExpr *CE = cast(E);
 if (const NamedDecl *ND = dyn_cast_or_null(CE->getCalleeDecl())) {
-  if (const FormatArgAttr *FA = ND->getAttr()) {
+  bool IsFirst = true;
+  StringLiteralCheckType CommonResult;
+  for (const auto *FA : ND->specific_attrs()) {
 const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
-return checkFormatStringExpr(S, Arg, Args,
- HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall,
- CheckedVarArgs, UncoveredArg, Offset);
-  } else if (const FunctionDecl *FD = dyn_cast(ND)) {
+StringLiteralCheckType Result = checkFormatStringExpr(
+S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
+CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
+if (IsFirst) {
+  CommonResult = Result;
+  IsFirst = 

[PATCH] D48734: [Sema] Consider all format_arg attributes.

2018-06-30 Thread Michael Kruse via Phabricator via cfe-commits
Meinersbur updated this revision to Diff 153642.
Meinersbur added a comment.

- Address Aaron's remarks


Repository:
  rC Clang

https://reviews.llvm.org/D48734

Files:
  lib/Sema/SemaChecking.cpp
  test/Sema/attr-format_arg.c


Index: test/Sema/attr-format_arg.c
===
--- test/Sema/attr-format_arg.c
+++ test/Sema/attr-format_arg.c
@@ -4,10 +4,23 @@
 
 const char* f(const char *s) __attribute__((format_arg(1)));
 
+const char *h(const char *msg1, const char *msg2)
+__attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
 void g(const char *s) {
   printf("%d", 123);
   printf("%d %d", 123); // expected-warning{{more '%' conversions than data 
arguments}}
 
   printf(f("%d"), 123);
   printf(f("%d %d"), 123); // expected-warning{{more '%' conversions than data 
arguments}}
+
+  printf(h(
+"%d",
+"" // expected-warning {{format string is empty}}
+  ), 123);
+  printf(h(
+"", // expected-warning {{format string is empty}}
+"%d"
+  ), 123);
+  printf(h("%d", "%d"), 123);
 }
Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -5518,13 +5518,22 @@
   case Stmt::CXXMemberCallExprClass: {
 const CallExpr *CE = cast(E);
 if (const NamedDecl *ND = 
dyn_cast_or_null(CE->getCalleeDecl())) {
-  if (const FormatArgAttr *FA = ND->getAttr()) {
+  bool IsFirst = true;
+  StringLiteralCheckType CommonResult;
+  for (const auto *FA : ND->specific_attrs()) {
 const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
-return checkFormatStringExpr(S, Arg, Args,
- HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall,
- CheckedVarArgs, UncoveredArg, Offset);
-  } else if (const FunctionDecl *FD = dyn_cast(ND)) {
+StringLiteralCheckType Result = checkFormatStringExpr(
+S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
+CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
+if (IsFirst) {
+  CommonResult = Result;
+  IsFirst = false;
+}
+  }
+  if (!IsFirst)
+return CommonResult;
+
+  if (const auto *FD = dyn_cast(ND)) {
 unsigned BuiltinID = FD->getBuiltinID();
 if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
 BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {


Index: test/Sema/attr-format_arg.c
===
--- test/Sema/attr-format_arg.c
+++ test/Sema/attr-format_arg.c
@@ -4,10 +4,23 @@
 
 const char* f(const char *s) __attribute__((format_arg(1)));
 
+const char *h(const char *msg1, const char *msg2)
+__attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
 void g(const char *s) {
   printf("%d", 123);
   printf("%d %d", 123); // expected-warning{{more '%' conversions than data arguments}}
 
   printf(f("%d"), 123);
   printf(f("%d %d"), 123); // expected-warning{{more '%' conversions than data arguments}}
+
+  printf(h(
+"%d",
+"" // expected-warning {{format string is empty}}
+  ), 123);
+  printf(h(
+"", // expected-warning {{format string is empty}}
+"%d"
+  ), 123);
+  printf(h("%d", "%d"), 123);
 }
Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -5518,13 +5518,22 @@
   case Stmt::CXXMemberCallExprClass: {
 const CallExpr *CE = cast(E);
 if (const NamedDecl *ND = dyn_cast_or_null(CE->getCalleeDecl())) {
-  if (const FormatArgAttr *FA = ND->getAttr()) {
+  bool IsFirst = true;
+  StringLiteralCheckType CommonResult;
+  for (const auto *FA : ND->specific_attrs()) {
 const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
-return checkFormatStringExpr(S, Arg, Args,
- HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall,
- CheckedVarArgs, UncoveredArg, Offset);
-  } else if (const FunctionDecl *FD = dyn_cast(ND)) {
+StringLiteralCheckType Result = checkFormatStringExpr(
+S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
+CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
+if (IsFirst) {
+  CommonResult = Result;
+  IsFirst = false;
+}
+  }
+  if (!IsFirst)
+return CommonResult;
+
+  if (const auto *FD = dyn_cast(ND)) {
 unsigned BuiltinID = FD->getBuiltinID();
 if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
 BuiltinID == 

[PATCH] D48734: [Sema] Consider all format_arg attributes.

2018-06-29 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: lib/Sema/SemaChecking.cpp:5523
+  StringLiteralCheckType CommonResult;
+  for (const FormatArgAttr *FA : ND->specific_attrs()) {
 const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());

You can use `const auto *FA` here instead; the type is spelled out in the 
initializer.



Comment at: lib/Sema/SemaChecking.cpp:5536
+
+  if (const FunctionDecl *FD = dyn_cast(ND)) {
 unsigned BuiltinID = FD->getBuiltinID();

`const auto *`



Comment at: test/Sema/attr-format_arg.c:17
+
+  printf(h("", ""), 123); // expected-warning 2{{format string is empty}}
 }

Can you add tests for the other permutations as well? It would also be useful 
to put the string literals on their own line so that the expected-warning 
designation matches the specific argument that's being diagnosed. e.g.,
```
h(
  "%d",
  ""
)
h(
  "", 
  "%d"
)
h(
  "%d",
  "%d"
)
```



Repository:
  rC Clang

https://reviews.llvm.org/D48734



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48734: [Sema] Consider all format_arg attributes.

2018-06-28 Thread Michael Kruse via Phabricator via cfe-commits
Meinersbur added inline comments.



Comment at: lib/Sema/SemaChecking.cpp:5534
+  if (!IsFirst)
+return CommonResult;
+

Not sure what should be returned here; To minimize surprises, this returns what 
the current version would have returned.


Repository:
  rC Clang

https://reviews.llvm.org/D48734



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D48734: [Sema] Consider all format_arg attributes.

2018-06-28 Thread Michael Kruse via Phabricator via cfe-commits
Meinersbur created this revision.
Meinersbur added reviewers: dlj, rsmith, Jean-Daniel.

If a function has multiple format_arg attributes, clang only considers the 
first it finds (because AttributeLists are in reverse order, it is textual 
last) and ignores all others.

Loop over all FormatArgAttr to print warnings for all declared format_arg 
attributes.

For instance, GNU gettext's ngettext (select plural or singular version of 
format string) has two __format_arg__ attributes.


Repository:
  rC Clang

https://reviews.llvm.org/D48734

Files:
  lib/Sema/SemaChecking.cpp
  test/Sema/attr-format_arg.c


Index: test/Sema/attr-format_arg.c
===
--- test/Sema/attr-format_arg.c
+++ test/Sema/attr-format_arg.c
@@ -4,10 +4,15 @@
 
 const char* f(const char *s) __attribute__((format_arg(1)));
 
+const char *h(const char *msg1, const char *msg2)
+__attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
 void g(const char *s) {
   printf("%d", 123);
   printf("%d %d", 123); // expected-warning{{more '%' conversions than data 
arguments}}
 
   printf(f("%d"), 123);
   printf(f("%d %d"), 123); // expected-warning{{more '%' conversions than data 
arguments}}
+
+  printf(h("", ""), 123); // expected-warning 2{{format string is empty}}
 }
Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -5518,13 +5518,22 @@
   case Stmt::CXXMemberCallExprClass: {
 const CallExpr *CE = cast(E);
 if (const NamedDecl *ND = 
dyn_cast_or_null(CE->getCalleeDecl())) {
-  if (const FormatArgAttr *FA = ND->getAttr()) {
+  bool IsFirst = true;
+  StringLiteralCheckType CommonResult;
+  for (const FormatArgAttr *FA : ND->specific_attrs()) {
 const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
-return checkFormatStringExpr(S, Arg, Args,
- HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall,
- CheckedVarArgs, UncoveredArg, Offset);
-  } else if (const FunctionDecl *FD = dyn_cast(ND)) {
+StringLiteralCheckType Result = checkFormatStringExpr(
+S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
+CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
+if (IsFirst) {
+  CommonResult = Result;
+  IsFirst = false;
+}
+  }
+  if (!IsFirst)
+return CommonResult;
+
+  if (const FunctionDecl *FD = dyn_cast(ND)) {
 unsigned BuiltinID = FD->getBuiltinID();
 if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
 BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {


Index: test/Sema/attr-format_arg.c
===
--- test/Sema/attr-format_arg.c
+++ test/Sema/attr-format_arg.c
@@ -4,10 +4,15 @@
 
 const char* f(const char *s) __attribute__((format_arg(1)));
 
+const char *h(const char *msg1, const char *msg2)
+__attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
 void g(const char *s) {
   printf("%d", 123);
   printf("%d %d", 123); // expected-warning{{more '%' conversions than data arguments}}
 
   printf(f("%d"), 123);
   printf(f("%d %d"), 123); // expected-warning{{more '%' conversions than data arguments}}
+
+  printf(h("", ""), 123); // expected-warning 2{{format string is empty}}
 }
Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -5518,13 +5518,22 @@
   case Stmt::CXXMemberCallExprClass: {
 const CallExpr *CE = cast(E);
 if (const NamedDecl *ND = dyn_cast_or_null(CE->getCalleeDecl())) {
-  if (const FormatArgAttr *FA = ND->getAttr()) {
+  bool IsFirst = true;
+  StringLiteralCheckType CommonResult;
+  for (const FormatArgAttr *FA : ND->specific_attrs()) {
 const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
-return checkFormatStringExpr(S, Arg, Args,
- HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall,
- CheckedVarArgs, UncoveredArg, Offset);
-  } else if (const FunctionDecl *FD = dyn_cast(ND)) {
+StringLiteralCheckType Result = checkFormatStringExpr(
+S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
+CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
+if (IsFirst) {
+  CommonResult = Result;
+  IsFirst = false;
+}
+  }
+  if (!IsFirst)
+return CommonResult;
+
+  if (const FunctionDecl *FD = dyn_cast(ND)) {
 unsigned BuiltinID =