]> granicus.if.org Git - clang/commitdiff
Provide FIX-IT notes to describe what fix-it is doing behind the
authorDouglas Gregor <dgregor@apple.com>
Thu, 2 Apr 2009 17:13:00 +0000 (17:13 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 2 Apr 2009 17:13:00 +0000 (17:13 +0000)
scenes, using the underlying diagnostic client to format the
messages.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68324 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/Diagnostic.h
include/clang/Basic/DiagnosticFrontendKinds.td
include/clang/Frontend/FixItRewriter.h
lib/Frontend/FixItRewriter.cpp
tools/clang-cc/clang-cc.cpp

index a9f87107ab5aede584dfaaffd1014371869411e4..b930165ba144390d0e2581cfc3a4e8d003c2c55e 100644 (file)
@@ -299,6 +299,9 @@ public:
   /// @c Pos represents the source location associated with the diagnostic,
   /// which can be an invalid location if no position information is available.
   inline DiagnosticBuilder Report(FullSourceLoc Pos, unsigned DiagID);
+
+  /// \brief Clear out the current diagnostic.
+  void Clear() { CurDiagID = ~0U; }
   
 private:
   /// getDiagnosticLevel - This is an internal implementation helper used when
@@ -423,8 +426,8 @@ public:
     // DiagnosticClient.
     DiagObj->ProcessDiag();
 
-    // This diagnostic is no longer in flight.
-    DiagObj->CurDiagID = ~0U;
+    // Clear out the current diagnostic object.
+    DiagObj->Clear();
 
     // This diagnostic is dead.
     DiagObj = 0;
index 2b7dcdfd6a05f1cab6a0df614e13798215969cdd..e4e12fd98e2201d757830f57dfe608e9c32c2c34 100644 (file)
@@ -14,4 +14,12 @@ def err_fe_unknown_triple : Error<
 def err_fe_error_reading : Error<"error reading '%0'">;
 def err_fe_error_reading_stdin : Error<"error reading stdin">;
 
+def note_fixit_applied : Note<"FIX-IT applied suggested code changes">;
+def note_fixit_in_macro : Note<
+    "FIX-IT unable to apply suggested code changes in a macro">;
+def note_fixit_failed : Note<
+    "FIX-IT unable to apply suggested code changes">;
+def note_fixit_unfixed_error : Note<"FIX-IT detected an error it cannot fix">;
+def warn_fixit_no_changes : Note<
+    "FIX-IT detected errors it could not fix; no output will be generated">;
 }
index 3dc66674e458cc12f32558e115b81ad5cab8473d..752b00836ced4d0ff23b687b59b12bb558747ff8 100644 (file)
 #define LLVM_CLANG_FRONTEND_FIX_IT_REWRITER_H
 
 #include "clang/Basic/Diagnostic.h"
+#include "clang/Rewrite/Rewriter.h"
 
 namespace clang {
 
-class Rewriter;
 class SourceManager;
 
 class FixItRewriter : public DiagnosticClient {
-  /// \brief The adapted diagnostic client, to which we will forward
-  /// any diagnostics.
-  DiagnosticClient *Client;
+  /// \brief The diagnostics machinery.
+  Diagnostic &Diags;
 
   /// \brief The rewriter used to perform the various code
   /// modifications.
-  Rewriter *Rewrite;
+  Rewriter Rewrite;
+
+  /// \brief The diagnostic client that performs the actual formatting
+  /// of error messages.
+  DiagnosticClient *Client;
 
   /// \brief The number of rewriter failures.
   unsigned NumFailures;
 
 public:
   /// \brief Initialize a new fix-it rewriter.
-  FixItRewriter(DiagnosticClient *Client, SourceManager &SourceMgr);
+  FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr);
 
   /// \brief Destroy the fix-it rewriter.
   ~FixItRewriter();
@@ -58,6 +61,8 @@ public:
   virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
                                 const DiagnosticInfo &Info);
 
+  /// \brief Emit a diagnostic via the adapted diagnostic client.
+  void Diag(FullSourceLoc Loc, unsigned DiagID);
 };
 
 }
index a462657727a5ceefdef7a7f32e315cde3734ebb6..8883b91ab9ea63bcd3cfdf40b14db8a0ee8741b3 100644 (file)
 
 #include "clang/Frontend/FixItRewriter.h"
 #include "clang/Basic/SourceManager.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
 #include "llvm/ADT/OwningPtr.h"
 #include "llvm/Support/Streams.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/System/Path.h"
-#include <cstdio>
 using namespace clang;
 
-FixItRewriter::FixItRewriter(DiagnosticClient *Client, 
-                             SourceManager &SourceMgr)
-  : Client(Client), NumFailures(0) {
-  Rewrite = new Rewriter(SourceMgr);
+FixItRewriter::FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr)
+  : Diags(Diags), Rewrite(SourceMgr), NumFailures(0) {
+  Client = Diags.getClient();
+  Diags.setClient(this);
 }
 
 FixItRewriter::~FixItRewriter() {
-  delete Rewrite;
+  Diags.setClient(Client);
 }
 
 bool FixItRewriter::WriteFixedFile(const std::string &InFileName, 
                                    const std::string &OutFileName) {
   if (NumFailures > 0) {
-    // FIXME: Use diagnostic machinery!
-    std::fprintf(stderr, 
-                 "%d fix-it failures detected; code will not be modified\n",
-                 NumFailures);
+    Diag(FullSourceLoc(), diag::warn_fixit_no_changes);
     return true;
   }
 
@@ -67,9 +63,9 @@ bool FixItRewriter::WriteFixedFile(const std::string &InFileName,
     OwnedStream.reset(OutFile);
   }  
 
-  FileID MainFileID = Rewrite->getSourceMgr().getMainFileID();
+  FileID MainFileID = Rewrite.getSourceMgr().getMainFileID();
   if (const RewriteBuffer *RewriteBuf = 
-        Rewrite->getRewriteBufferFor(MainFileID)) {
+        Rewrite.getRewriteBufferFor(MainFileID)) {
     *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
   } else {
     std::fprintf(stderr, "Main file is unchanged\n");
@@ -95,30 +91,26 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
        Idx < Last; ++Idx) {
     const CodeModificationHint &Hint = Info.getCodeModificationHint(Idx);
     if (Hint.RemoveRange.isValid() &&
-        Rewrite->getRangeSize(Hint.RemoveRange) == -1) {
+        Rewrite.getRangeSize(Hint.RemoveRange) == -1) {
       CanRewrite = false;
       break;
     }
 
     if (Hint.InsertionLoc.isValid() && 
-        !Rewrite->isRewritable(Hint.InsertionLoc)) {
+        !Rewrite.isRewritable(Hint.InsertionLoc)) {
       CanRewrite = false;
       break;
     }
   }
 
   if (!CanRewrite) { 
-    if (Info.getNumCodeModificationHints() > 0) {
-      // FIXME: warn the user that this rewrite couldn't be done
-    }
+    if (Info.getNumCodeModificationHints() > 0)
+      Diag(Info.getLocation(), diag::note_fixit_in_macro);
 
     // If this was an error, refuse to perform any rewriting.
     if (DiagLevel == Diagnostic::Error || DiagLevel == Diagnostic::Fatal) {
-      if (++NumFailures == 1) {
-        // FIXME: use diagnostic machinery to print this.
-        std::fprintf(stderr, "error without fix-it advice detected; "
-                     "fix-it will produce no output\n");
-      }
+      if (++NumFailures == 1)
+        Diag(Info.getLocation(), diag::note_fixit_unfixed_error);
     }
     return;
   }
@@ -129,27 +121,43 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
     const CodeModificationHint &Hint = Info.getCodeModificationHint(Idx);
     if (!Hint.RemoveRange.isValid()) {
       // We're adding code.
-      if (Rewrite->InsertStrBefore(Hint.InsertionLoc, Hint.CodeToInsert))
+      if (Rewrite.InsertStrBefore(Hint.InsertionLoc, Hint.CodeToInsert))
         Failed = true;
       continue;
     }
     
     if (Hint.CodeToInsert.empty()) {
       // We're removing code.
-      if (Rewrite->RemoveText(Hint.RemoveRange.getBegin(),
-                              Rewrite->getRangeSize(Hint.RemoveRange)))
+      if (Rewrite.RemoveText(Hint.RemoveRange.getBegin(),
+                             Rewrite.getRangeSize(Hint.RemoveRange)))
         Failed = true;
       continue;
     } 
       
     // We're replacing code.
-    if (Rewrite->ReplaceText(Hint.RemoveRange.getBegin(),
-                             Rewrite->getRangeSize(Hint.RemoveRange),
-                             Hint.CodeToInsert.c_str(),
-                             Hint.CodeToInsert.size()))
+    if (Rewrite.ReplaceText(Hint.RemoveRange.getBegin(),
+                            Rewrite.getRangeSize(Hint.RemoveRange),
+                            Hint.CodeToInsert.c_str(),
+                            Hint.CodeToInsert.size()))
       Failed = true;
   }
 
-  if (Failed) // FIXME: notify the user that the rewrite failed.
+  if (Failed) {
     ++NumFailures;
+    Diag(Info.getLocation(), diag::note_fixit_failed);
+    return;
+  }
+
+  Diag(Info.getLocation(), diag::note_fixit_applied);
+}
+
+/// \brief Emit a diagnostic via the adapted diagnostic client.
+void FixItRewriter::Diag(FullSourceLoc Loc, unsigned DiagID) {
+  // When producing this diagnostic, we temporarily bypass ourselves,
+  // clear out any current diagnostic, and let the downstream client
+  // format the diagnostic.
+  Diags.setClient(Client);
+  Diags.Clear();
+  Diags.Report(Loc, DiagID);
+  Diags.setClient(this);  
 }
index ba891c7e56b9a6c32ce5abd168604e3b797d8e6d..1a1089674497f0e59844f17c81a03785efda3fcc 100644 (file)
@@ -1452,9 +1452,8 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
   case FixIt:
     llvm::TimeRegion Timer(ClangFrontendTimer);
     Consumer.reset(new ASTConsumer());
-    FixItRewrite = new FixItRewriter(PP.getDiagnostics().getClient(),
+    FixItRewrite = new FixItRewriter(PP.getDiagnostics(),
                                      PP.getSourceManager());
-    PP.getDiagnostics().setClient(FixItRewrite);
     break;
   }