[cfe-commits] r68342 - in /cfe/trunk: include/clang/Frontend/FixItRewriter.h lib/Frontend/FixItRewriter.cpp test/FixIt/fixit-at.c tools/clang-cc/clang-cc.cpp

Douglas Gregor dgregor at apple.com
Thu Apr 2 12:05:20 PDT 2009


Author: dgregor
Date: Thu Apr  2 14:05:20 2009
New Revision: 68342

URL: http://llvm.org/viewvc/llvm-project?rev=68342&view=rev
Log:
Add a new command-line option "-fixit-at=file:line:column" that only
applies fix-its to error messages that occur at that specific location
in the program. 


Added:
    cfe/trunk/test/FixIt/fixit-at.c
Modified:
    cfe/trunk/include/clang/Frontend/FixItRewriter.h
    cfe/trunk/lib/Frontend/FixItRewriter.cpp
    cfe/trunk/tools/clang-cc/clang-cc.cpp

Modified: cfe/trunk/include/clang/Frontend/FixItRewriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FixItRewriter.h?rev=68342&r1=68341&r2=68342&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/FixItRewriter.h (original)
+++ cfe/trunk/include/clang/Frontend/FixItRewriter.h Thu Apr  2 14:05:20 2009
@@ -17,10 +17,23 @@
 
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Rewrite/Rewriter.h"
+#include "llvm/ADT/SmallVector.h"
 
 namespace clang {
 
 class SourceManager;
+class FileEntry;
+
+/// \brief Stores a source location in the form that it shows up on
+/// the Clang command line, e.g., file:line:column.
+///
+/// FIXME: Would prefer to use real SourceLocations, but I don't see a
+/// good way to resolve them during parsing.
+struct RequestedSourceLocation {
+  const FileEntry *File;
+  unsigned Line;
+  unsigned Column;
+};
 
 class FixItRewriter : public DiagnosticClient {
   /// \brief The diagnostics machinery.
@@ -37,6 +50,11 @@
   /// \brief The number of rewriter failures.
   unsigned NumFailures;
 
+  /// \brief Locations at which we should perform fix-its.
+  /// 
+  /// When empty, perform fix-it modifications everywhere.
+  llvm::SmallVector<RequestedSourceLocation, 4> FixItLocations;
+
 public:
   /// \brief Initialize a new fix-it rewriter.
   FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr);
@@ -44,6 +62,12 @@
   /// \brief Destroy the fix-it rewriter.
   ~FixItRewriter();
 
+  /// \brief Add a location where fix-it modifications should be
+  /// performed.
+  void addFixItLocation(RequestedSourceLocation Loc) {
+    FixItLocations.push_back(Loc);
+  }
+
   /// \brief Write the modified source file.
   ///
   /// \returns true if there was an error, false otherwise.

Modified: cfe/trunk/lib/Frontend/FixItRewriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FixItRewriter.cpp?rev=68342&r1=68341&r2=68342&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/FixItRewriter.cpp (original)
+++ cfe/trunk/lib/Frontend/FixItRewriter.cpp Thu Apr  2 14:05:20 2009
@@ -81,8 +81,43 @@
 
 void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
                                      const DiagnosticInfo &Info) {
-  if (Client)
-    Client->HandleDiagnostic(DiagLevel, Info);
+  Client->HandleDiagnostic(DiagLevel, Info);
+
+  // Skip over any diagnostics that are ignored.
+  if (DiagLevel == Diagnostic::Ignored)
+    return;
+
+  if (!FixItLocations.empty()) {
+    // The user has specified the locations where we should perform
+    // the various fix-it modifications.
+
+    // If this diagnostic does not have any code modifications,
+    // completely ignore it, even if it's an error: fix-it locations
+    // are meant to perform specific fix-ups even in the presence of
+    // other errors.
+    if (Info.getNumCodeModificationHints() == 0)
+      return;
+
+    // See if the location of the error is one that matches what the
+    // user requested.
+    bool AcceptableLocation = false;
+    const FileEntry *File 
+      = Rewrite.getSourceMgr().getFileEntryForID(
+                                            Info.getLocation().getFileID());
+    unsigned Line = Info.getLocation().getSpellingLineNumber();
+    unsigned Column = Info.getLocation().getSpellingColumnNumber();
+    for (llvm::SmallVector<RequestedSourceLocation, 4>::iterator
+           Loc = FixItLocations.begin(), LocEnd = FixItLocations.end();
+         Loc != LocEnd; ++Loc) {
+      if (Loc->File == File && Loc->Line == Line && Loc->Column == Column) {
+        AcceptableLocation = true;
+        break;
+      }
+    }
+
+    if (!AcceptableLocation)
+      return;
+  }
 
   // Make sure that we can perform all of the modifications we
   // in this diagnostic.

Added: cfe/trunk/test/FixIt/fixit-at.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-at.c?rev=68342&view=auto

==============================================================================
--- cfe/trunk/test/FixIt/fixit-at.c (added)
+++ cfe/trunk/test/FixIt/fixit-at.c Thu Apr  2 14:05:20 2009
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only -fixit-at=fixit-at.c:3:1 %s -o - | clang-cc -verify -x c -
+
+_Complex cd;
+
+int i0 = { 17 }; // expected-warning{{braces}}

Modified: cfe/trunk/tools/clang-cc/clang-cc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-cc/clang-cc.cpp?rev=68342&r1=68341&r2=68342&view=diff

==============================================================================
--- cfe/trunk/tools/clang-cc/clang-cc.cpp (original)
+++ cfe/trunk/tools/clang-cc/clang-cc.cpp Thu Apr  2 14:05:20 2009
@@ -58,9 +58,94 @@
 #include "llvm/System/Host.h"
 #include "llvm/System/Path.h"
 #include "llvm/System/Signals.h"
+#include <cstdlib>
+
 using namespace clang;
 
 //===----------------------------------------------------------------------===//
+// Source Location Parser
+//===----------------------------------------------------------------------===//
+
+/// \brief A source location that has been parsed on the command line.
+struct ParsedSourceLocation {
+  std::string FileName;
+  unsigned Line;
+  unsigned Column;
+
+  /// \brief Try to resolve the file name of a parsed source location.
+  ///
+  /// \returns true if there was an error, false otherwise.
+  bool ResolveLocation(FileManager &FileMgr, RequestedSourceLocation &Result);
+};
+
+bool
+ParsedSourceLocation::ResolveLocation(FileManager &FileMgr, 
+                                      RequestedSourceLocation &Result) {
+  const FileEntry *File = FileMgr.getFile(FileName);
+  if (!File)
+    return true;
+
+  Result.File = File;
+  Result.Line = Line;
+  Result.Column = Column;
+  return false;
+}
+
+namespace llvm {
+  namespace cl {
+    /// \brief Command-line option parser that parses source locations.
+    ///
+    /// Source locations are of the form filename:line:column.
+    template<>
+    class parser<ParsedSourceLocation> 
+      : public basic_parser<ParsedSourceLocation> {
+    public:
+      bool parse(Option &O, const char *ArgName, 
+                 const std::string &ArgValue,
+                 ParsedSourceLocation &Val);
+    };
+
+    bool 
+    parser<ParsedSourceLocation>::
+    parse(Option &O, const char *ArgName, const std::string &ArgValue, 
+          ParsedSourceLocation &Val) {
+      using namespace clang;
+
+      const char *ExpectedFormat 
+        = "source location must be of the form filename:line:column";
+      std::string::size_type SecondColon = ArgValue.rfind(':');
+      if (SecondColon == std::string::npos) {
+        std::fprintf(stderr, "%s\n", ExpectedFormat);
+        return true;
+      }
+      char *EndPtr;
+      long Column 
+        = std::strtol(ArgValue.c_str() + SecondColon + 1, &EndPtr, 10);
+      if (EndPtr != ArgValue.c_str() + ArgValue.size()) {
+        std::fprintf(stderr, "%s\n", ExpectedFormat);
+        return true;
+      }
+
+      std::string::size_type FirstColon = ArgValue.rfind(':', SecondColon-1);
+      if (SecondColon == std::string::npos) {
+        std::fprintf(stderr, "%s\n", ExpectedFormat);
+        return true;
+      }
+      long Line = std::strtol(ArgValue.c_str() + FirstColon + 1, &EndPtr, 10);
+      if (EndPtr != ArgValue.c_str() + SecondColon) {
+        std::fprintf(stderr, "%s\n", ExpectedFormat);
+        return true;
+      }
+      
+      Val.FileName = ArgValue.substr(0, FirstColon);
+      Val.Line = Line;
+      Val.Column = Column;
+      return false;
+    }
+  }
+}
+
+//===----------------------------------------------------------------------===//
 // Global options.
 //===----------------------------------------------------------------------===//
 
@@ -1262,6 +1347,13 @@
 }
 
 //===----------------------------------------------------------------------===//
+// Fix-It Options
+//===----------------------------------------------------------------------===//
+static llvm::cl::list<ParsedSourceLocation>
+FixItAtLocations("fixit-at", llvm::cl::value_desc("source-location"),
+   llvm::cl::desc("Perform Fix-It modifications at the given source location"));
+
+//===----------------------------------------------------------------------===//
 // Main driver
 //===----------------------------------------------------------------------===//
 
@@ -1454,6 +1546,35 @@
   if (Consumer) {
     llvm::OwningPtr<ASTContext> ContextOwner;
 
+    if (FixItAtLocations.size() > 0) {
+      // Even without the "-fixit" flag, with may have some specific
+      // locations where the user has requested fixes. Process those
+      // locations now.
+      if (!FixItRewrite)
+        FixItRewrite = new FixItRewriter(PP.getDiagnostics(),
+                                         PP.getSourceManager());
+
+      bool AddedFixitLocation = false;
+      for (unsigned Idx = 0, Last = FixItAtLocations.size(); 
+           Idx != Last; ++Idx) {
+        RequestedSourceLocation Requested;
+        if (FixItAtLocations[Idx].ResolveLocation(PP.getFileManager(), 
+                                                  Requested)) {
+          fprintf(stderr, "FIX-IT could not find file \"%s\"\n",
+                  FixItAtLocations[Idx].FileName.c_str());
+        } else {
+          FixItRewrite->addFixItLocation(Requested);
+          AddedFixitLocation = true;
+        }
+      }
+
+      if (!AddedFixitLocation) {
+        // All of the fix-it locations were bad. Don't fix anything.
+        delete FixItRewrite;
+        FixItRewrite = 0;
+      }
+    }
+
     ContextOwner.reset(new ASTContext(PP.getLangOptions(),
                                       PP.getSourceManager(),
                                       PP.getTargetInfo(),





More information about the cfe-commits mailing list