[cfe-commits] r163772 - in /cfe/trunk: include/clang/Analysis/Analyses/FormatString.h lib/Analysis/FormatString.cpp lib/Sema/SemaChecking.cpp test/FixIt/format-darwin.m test/Sema/format-strings-darwin.c

Jordan Rose jordan_rose at apple.com
Wed Sep 12 19:11:15 PDT 2012


Author: jrose
Date: Wed Sep 12 21:11:15 2012
New Revision: 163772

URL: http://llvm.org/viewvc/llvm-project?rev=163772&view=rev
Log:
Format strings: offer a fixit for Darwin's %D/%U/%O to ISO %d/%u/%o.

<rdar://problem/12061922>

Modified:
    cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
    cfe/trunk/lib/Analysis/FormatString.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/FixIt/format-darwin.m
    cfe/trunk/test/Sema/format-strings-darwin.c

Modified: cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/FormatString.h?rev=163772&r1=163771&r2=163772&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/FormatString.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/FormatString.h Wed Sep 12 21:11:15 2012
@@ -162,7 +162,7 @@
     ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg
   };
 
-  ConversionSpecifier(bool isPrintf)
+  ConversionSpecifier(bool isPrintf = true)
     : IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {}
 
   ConversionSpecifier(bool isPrintf, const char *pos, Kind k)
@@ -200,6 +200,8 @@
   const char *toString() const;
 
   bool isPrintfKind() const { return IsPrintf; }
+  
+  llvm::Optional<ConversionSpecifier> getStandardSpecifier() const;
 
 protected:
   bool IsPrintf;

Modified: cfe/trunk/lib/Analysis/FormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatString.cpp?rev=163772&r1=163771&r2=163772&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/FormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/FormatString.cpp Wed Sep 12 21:11:15 2012
@@ -527,6 +527,29 @@
   return NULL;
 }
 
+llvm::Optional<ConversionSpecifier>
+ConversionSpecifier::getStandardSpecifier() const {
+  ConversionSpecifier::Kind NewKind;
+  
+  switch (getKind()) {
+  default:
+    return llvm::Optional<ConversionSpecifier>();
+  case DArg:
+    NewKind = dArg;
+    break;
+  case UArg:
+    NewKind = uArg;
+    break;
+  case OArg:
+    NewKind = oArg;
+    break;
+  }
+
+  ConversionSpecifier FixedCS(*this);
+  FixedCS.setKind(NewKind);
+  return FixedCS;
+}
+
 //===----------------------------------------------------------------------===//
 // Methods on OptionalAmount.
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=163772&r1=163771&r2=163772&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Sep 12 21:11:15 2012
@@ -2095,11 +2095,28 @@
 void CheckFormatHandler::HandleNonStandardConversionSpecifier(
     const analyze_format_string::ConversionSpecifier &CS,
     const char *startSpecifier, unsigned specifierLen) {
-  EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << CS.toString()
-                       << 1,
-                       getLocationOfByte(CS.getStart()),
-                       /*IsStringLocation*/true,
-                       getSpecifierRange(startSpecifier, specifierLen));
+  using namespace analyze_format_string;
+
+  // See if we know how to fix this conversion specifier.
+  llvm::Optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
+  if (FixedCS) {
+    EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+                          << CS.toString() << /*conversion specifier*/1,
+                         getLocationOfByte(CS.getStart()),
+                         /*IsStringLocation*/true,
+                         getSpecifierRange(startSpecifier, specifierLen));
+
+    CharSourceRange CSRange = getSpecifierRange(CS.getStart(), CS.getLength());
+    S.Diag(getLocationOfByte(CS.getStart()), diag::note_format_fix_specifier)
+      << FixedCS->toString()
+      << FixItHint::CreateReplacement(CSRange, FixedCS->toString());
+  } else {
+    EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+                          << CS.toString() << /*conversion specifier*/1,
+                         getLocationOfByte(CS.getStart()),
+                         /*IsStringLocation*/true,
+                         getSpecifierRange(startSpecifier, specifierLen));
+  }
 }
 
 void CheckFormatHandler::HandlePosition(const char *startPos,

Modified: cfe/trunk/test/FixIt/format-darwin.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/format-darwin.m?rev=163772&r1=163771&r2=163772&view=diff
==============================================================================
--- cfe/trunk/test/FixIt/format-darwin.m (original)
+++ cfe/trunk/test/FixIt/format-darwin.m Wed Sep 12 21:11:15 2012
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -fblocks -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -fblocks -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -fblocks -Wformat-non-iso -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -fblocks -Wformat-non-iso -verify %s
 
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks %s 2>&1 | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks -Wformat-non-iso %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks -Wformat-non-iso %s 2>&1 | FileCheck %s
 
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks %s 2>&1 | FileCheck -check-prefix=CHECK-32 %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks %s 2>&1 | FileCheck -check-prefix=CHECK-64 %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks -Wformat-non-iso %s 2>&1 | FileCheck -check-prefix=CHECK-32 %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fdiagnostics-parseable-fixits -fblocks -Wformat-non-iso %s 2>&1 | FileCheck -check-prefix=CHECK-64 %s
 
 int printf(const char * restrict, ...);
 
@@ -181,11 +181,18 @@
 }
 
 void testCapitals() {
-  printf("%D", 1); // no-warning
-  printf("%U", 1); // no-warning
-  printf("%O", 1); // no-warning
+  printf("%D", 1); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+  printf("%U", 1); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'u'?}}
+  printf("%O", 1); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'o'?}}
   
-  printf("%lD", 1); // expected-warning{{format specifies type 'long' but the argument has type 'int'}}
+  // CHECK: fix-it:"{{.*}}":{184:12-184:13}:"d"
+  // CHECK: fix-it:"{{.*}}":{185:12-185:13}:"u"
+  // CHECK: fix-it:"{{.*}}":{186:12-186:13}:"o"
 
-  // CHECK: fix-it:"{{.*}}":{188:11-188:14}:"%D"
+  
+  printf("%lD", 1); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}} expected-warning{{format specifies type 'long' but the argument has type 'int'}}
+
+  // FIXME: offering two somewhat-conflicting fixits is less than ideal.
+  // CHECK: fix-it:"{{.*}}":{193:13-193:14}:"d"
+  // CHECK: fix-it:"{{.*}}":{193:11-193:14}:"%D"
 }

Modified: cfe/trunk/test/Sema/format-strings-darwin.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings-darwin.c?rev=163772&r1=163771&r2=163772&view=diff
==============================================================================
--- cfe/trunk/test/Sema/format-strings-darwin.c (original)
+++ cfe/trunk/test/Sema/format-strings-darwin.c Wed Sep 12 21:11:15 2012
@@ -22,12 +22,12 @@
   printf("%O", tooLong);
 
 #ifdef ALLOWED
-  // expected-warning at -8 {{'D' conversion specifier is not supported by ISO C}}
-  // expected-warning at -8 {{'D' conversion specifier is not supported by ISO C}} expected-warning at -8 {{format specifies type 'int' but the argument has type 'long'}}
-  // expected-warning at -8 {{'U' conversion specifier is not supported by ISO C}}
-  // expected-warning at -8 {{'U' conversion specifier is not supported by ISO C}} expected-warning at -8 {{format specifies type 'unsigned int' but the argument has type 'long'}}
-  // expected-warning at -8 {{'O' conversion specifier is not supported by ISO C}}
-  // expected-warning at -8 {{'O' conversion specifier is not supported by ISO C}} expected-warning at -8 {{format specifies type 'unsigned int' but the argument has type 'long'}}
+  // expected-warning at -8 {{'D' conversion specifier is not supported by ISO C}} expected-note at -8 {{did you mean to use 'd'?}}
+  // expected-warning at -8 {{'D' conversion specifier is not supported by ISO C}} expected-note at -8 {{did you mean to use 'd'?}} expected-warning at -8 {{format specifies type 'int' but the argument has type 'long'}}
+  // expected-warning at -8 {{'U' conversion specifier is not supported by ISO C}} expected-note at -8 {{did you mean to use 'u'?}}
+  // expected-warning at -8 {{'U' conversion specifier is not supported by ISO C}} expected-note at -8 {{did you mean to use 'u'?}} expected-warning at -8 {{format specifies type 'unsigned int' but the argument has type 'long'}}
+  // expected-warning at -8 {{'O' conversion specifier is not supported by ISO C}} expected-note at -8 {{did you mean to use 'o'?}}
+  // expected-warning at -8 {{'O' conversion specifier is not supported by ISO C}} expected-note at -8 {{did you mean to use 'o'?}} expected-warning at -8 {{format specifies type 'unsigned int' but the argument has type 'long'}}
 #else
   // expected-warning at -15 {{invalid conversion specifier 'D'}}
   // expected-warning at -15 {{invalid conversion specifier 'D'}}
@@ -40,25 +40,25 @@
 
 #ifdef ALLOWED
 void testPrintf(short x, long y) {
-  printf("%hD", x); // expected-warning{{conversion specifier is not supported by ISO C}}
-  printf("%lD", y); // expected-warning{{conversion specifier is not supported by ISO C}}
-  printf("%hU", x); // expected-warning{{conversion specifier is not supported by ISO C}}
-  printf("%lU", y); // expected-warning{{conversion specifier is not supported by ISO C}}
-  printf("%hO", x); // expected-warning{{conversion specifier is not supported by ISO C}}
-  printf("%lO", y); // expected-warning{{conversion specifier is not supported by ISO C}}
+  printf("%hD", x); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+  printf("%lD", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+  printf("%hU", x); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'u'?}}
+  printf("%lU", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'u'?}}
+  printf("%hO", x); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'o'?}}
+  printf("%lO", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'o'?}}
 
-  printf("%+'0.5lD", y); // expected-warning{{conversion specifier is not supported by ISO C}}
-  printf("% '0.5lD", y); // expected-warning{{conversion specifier is not supported by ISO C}}
-  printf("%#0.5lO", y); // expected-warning{{conversion specifier is not supported by ISO C}}
-  printf("%'0.5lU", y); // expected-warning{{conversion specifier is not supported by ISO C}}
+  printf("%+'0.5lD", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+  printf("% '0.5lD", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+  printf("%#0.5lO", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'o'?}}
+  printf("%'0.5lU", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'u'?}}
 }
 
 void testScanf(short *x, long *y) {
-  scanf("%hD", x); // expected-warning{{conversion specifier is not supported by ISO C}}
-  scanf("%lD", y); // expected-warning{{conversion specifier is not supported by ISO C}}
-  scanf("%hU", x); // expected-warning{{conversion specifier is not supported by ISO C}}
-  scanf("%lU", y); // expected-warning{{conversion specifier is not supported by ISO C}}
-  scanf("%hO", x); // expected-warning{{conversion specifier is not supported by ISO C}}
-  scanf("%lO", y); // expected-warning{{conversion specifier is not supported by ISO C}}
+  scanf("%hD", x); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+  scanf("%lD", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'd'?}}
+  scanf("%hU", x); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'u'?}}
+  scanf("%lU", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'u'?}}
+  scanf("%hO", x); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'o'?}}
+  scanf("%lO", y); // expected-warning{{conversion specifier is not supported by ISO C}} expected-note {{did you mean to use 'o'?}}
 }
 #endif





More information about the cfe-commits mailing list