Alternate format string checking: issue warnings for incomplete format specifiers.

In addition, move ParseFormatString() and FormatStringHandler() from
the clang::analyze_printf to the clang namespace.  Hopefully this will
resolve some link errors on Linux.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94794 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Analysis/Analyses/PrintfFormatString.h b/include/clang/Analysis/Analyses/PrintfFormatString.h
index 3c4a971..e8b2d49 100644
--- a/include/clang/Analysis/Analyses/PrintfFormatString.h
+++ b/include/clang/Analysis/Analyses/PrintfFormatString.h
@@ -74,6 +74,11 @@
   bool isUIntArg() const { return kind >= oArg && kind <= XArg; }
   bool isDoubleArg() const { return kind >= fArg && kind <= AArg; }
   Kind getKind() const { return kind; }
+  unsigned getLength() const {
+    // Conversion specifiers currently only are represented by
+    // single characters, but we be flexible.
+    return 1;
+  }
   
 private:
   const char *Position;
@@ -187,24 +192,24 @@
   bool hasLeadingZeros() const { return flags & LeadingZeroes; }  
 };
 
-  
+} // end printf namespace
+
 class FormatStringHandler {
 public:
   FormatStringHandler() {}
   virtual ~FormatStringHandler();
   
   virtual void HandleIncompleteFormatSpecifier(const char *startSpecifier,
-                                               const char *endSpecifier) {}
+                                               unsigned specifierLen) {}
 
   virtual void HandleNullChar(const char *nullCharacter) {}
+    
+  virtual void 
+    HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
+                                     const char *startSpecifier,
+                                     unsigned specifierLen) {}
   
-  virtual void HandleIncompletePrecision(const char *periodChar) {}
-  
-  virtual void HandleInvalidConversionSpecifier(const FormatSpecifier &FS,
-                                                const char *startSpecifier,
-                                                unsigned specifierLen) {}
-  
-  virtual bool HandleFormatSpecifier(const FormatSpecifier &FS,
+  virtual bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS,
                                      const char *startSpecifier,
                                      unsigned specifierLen) {
     return true;
@@ -215,6 +220,5 @@
                        const char *beg, const char *end);
 
 
-} // end printf namespace
 } // end clang namespace
 #endif
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 5f1e5f1..af64ccb 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2445,6 +2445,8 @@
   "more data arguments than '%%' conversions">, InGroup<FormatExtraArgs>;
 def warn_printf_invalid_conversion : Warning<
   "invalid conversion '%0'">, InGroup<Format>;
+def warn_printf_incomplete_specifier : Warning<
+  "incomplete format specifier '%0'">, InGroup<Format>;
 def warn_printf_missing_format_string : Warning<
   "format string missing">, InGroup<Format>;
 def warn_null_arg : Warning<
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 3f03420..bf1e894 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -16,6 +16,7 @@
 
 using clang::analyze_printf::FormatSpecifier;
 using clang::analyze_printf::OptionalAmount;
+using namespace clang;
 
 namespace {
 class FormatSpecifierResult {
@@ -83,9 +84,8 @@
   return OptionalAmount();  
 }
 
-static FormatSpecifierResult
-ParseFormatSpecifier(clang::analyze_printf::FormatStringHandler &H,
-                     const char *&Beg, const char *E) {
+static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
+                                                  const char *&Beg, const char *E) {
   
   using namespace clang::analyze_printf;
   
@@ -113,7 +113,7 @@
   
   if (I == E) {
     // No more characters left?
-    H.HandleIncompleteFormatSpecifier(Start, E);
+    H.HandleIncompleteFormatSpecifier(Start, E - Start);
     return true;
   }
       
@@ -136,7 +136,7 @@
 
   if (I == E) {
     // No more characters left?
-    H.HandleIncompleteFormatSpecifier(Start, E);
+    H.HandleIncompleteFormatSpecifier(Start, E - Start);
     return true;
   }
   
@@ -145,15 +145,15 @@
       
   if (I == E) {
     // No more characters left?
-    H.HandleIncompleteFormatSpecifier(Start, E);
+    H.HandleIncompleteFormatSpecifier(Start, E - Start);
     return true;
   }  
   
   // Look for the precision (if any).  
   if (*I == '.') {
-    const char *startPrecision = I++;
+    ++I;
     if (I == E) {
-      H.HandleIncompletePrecision(I - 1);
+      H.HandleIncompleteFormatSpecifier(Start, E - Start);
       return true;
     }
     
@@ -161,7 +161,7 @@
 
     if (I == E) {
       // No more characters left?
-      H.HandleIncompletePrecision(startPrecision);
+      H.HandleIncompleteFormatSpecifier(Start, E - Start);
       return true;
     }
   }
@@ -188,7 +188,7 @@
   
   if (I == E) {
     // No more characters left?
-    H.HandleIncompleteFormatSpecifier(Start, E);
+    H.HandleIncompleteFormatSpecifier(Start, E - Start);
     return true;
   }
   
@@ -230,8 +230,7 @@
   return FormatSpecifierResult(Start, FS);
 }
 
-namespace clang { namespace analyze_printf {
-bool ParseFormatString(FormatStringHandler &H,
+bool clang::ParseFormatString(FormatStringHandler &H,
                        const char *I, const char *E) {
   // Keep looking for a format specifier until we have exhausted the string.
   while (I != E) {
@@ -254,4 +253,3 @@
 }
 
 FormatStringHandler::~FormatStringHandler() {}
-}} // end namespace clang::analyze_printf
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index a6d5097..1a7a203 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -1282,7 +1282,7 @@
 
 
 namespace {
-class CheckPrintfHandler : public analyze_printf::FormatStringHandler {
+class CheckPrintfHandler : public FormatStringHandler {
   Sema &S;
   const StringLiteral *FExpr;
   const Expr *OrigFormatExpr;
@@ -1306,11 +1306,9 @@
       TheCall(theCall), FormatIdx(formatIdx) {}
   
   void DoneProcessing();
-   
-//  void HandleIncompleteFormatSpecifier(const char *startSpecifier,
-//                                       const char *endSpecifier);
-  
-//  void HandleIncompletePrecision(const char *periodChar);
+     
+  void HandleIncompleteFormatSpecifier(const char *startSpecifier,
+                                       unsigned specifierLen);
   
   void HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
                                         const char *startSpecifier,
@@ -1341,16 +1339,25 @@
 }
 
 void CheckPrintfHandler::
+HandleIncompleteFormatSpecifier(const char *startSpecifier,
+                                unsigned specifierLen) {  
+  SourceLocation Loc = getLocationOfByte(startSpecifier);
+  S.Diag(Loc, diag::warn_printf_incomplete_specifier)
+    << llvm::StringRef(startSpecifier, specifierLen)
+    << getFormatRange();
+}
+
+void CheckPrintfHandler::
 HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS,
                                  const char *startSpecifier,
                                  unsigned specifierLen) {
   
   ++NumConversions;
-  
-  SourceLocation Loc =
-    getLocationOfByte(FS.getConversionSpecifier().getStart());
+  const analyze_printf::ConversionSpecifier &CS =
+    FS.getConversionSpecifier();  
+  SourceLocation Loc = getLocationOfByte(CS.getStart());
   S.Diag(Loc, diag::warn_printf_invalid_conversion)
-      << llvm::StringRef(startSpecifier, specifierLen)
+      << llvm::StringRef(CS.getStart(), CS.getLength())
       << getFormatRange();  
 }
 
@@ -1495,8 +1502,8 @@
                        isa<ObjCStringLiteral>(OrigFormatExpr), Str,
                        HasVAListArg, TheCall, format_idx);
 
-  analyze_printf::ParseFormatString(H, Str, Str + StrLen);
-  H.DoneProcessing();
+  if (!ParseFormatString(H, Str, Str + StrLen))
+    H.DoneProcessing();
 }
 
 //===--- CHECK: Return Address of Stack Variable --------------------------===//