Home | History | Annotate | Line # | Download | only in Frontend
      1 //===- FixItRewriter.h - Fix-It Rewriter Diagnostic Client ------*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This is a diagnostic client adaptor that performs rewrites as
     10 // suggested by code modification hints attached to diagnostics. It
     11 // then forwards any diagnostics to the adapted diagnostic client.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #ifndef LLVM_CLANG_REWRITE_FRONTEND_FIXITREWRITER_H
     16 #define LLVM_CLANG_REWRITE_FRONTEND_FIXITREWRITER_H
     17 
     18 #include "clang/Basic/Diagnostic.h"
     19 #include "clang/Basic/LLVM.h"
     20 #include "clang/Basic/SourceLocation.h"
     21 #include "clang/Edit/EditedSource.h"
     22 #include "clang/Rewrite/Core/Rewriter.h"
     23 #include <memory>
     24 #include <string>
     25 #include <utility>
     26 #include <vector>
     27 
     28 namespace clang {
     29 
     30 class LangOptions;
     31 class SourceManager;
     32 
     33 class FixItOptions {
     34 public:
     35   FixItOptions() = default;
     36   virtual ~FixItOptions();
     37 
     38   /// This file is about to be rewritten. Return the name of the file
     39   /// that is okay to write to.
     40   ///
     41   /// \param fd out parameter for file descriptor. After the call it may be set
     42   /// to an open file descriptor for the returned filename, or it will be -1
     43   /// otherwise.
     44   virtual std::string RewriteFilename(const std::string &Filename, int &fd) = 0;
     45 
     46   /// True if files should be updated in place. RewriteFilename is only called
     47   /// if this is false.
     48   bool InPlace = false;
     49 
     50   /// Whether to abort fixing a file when not all errors could be fixed.
     51   bool FixWhatYouCan = false;
     52 
     53   /// Whether to only fix warnings and not errors.
     54   bool FixOnlyWarnings = false;
     55 
     56   /// If true, only pass the diagnostic to the actual diagnostic consumer
     57   /// if it is an error or a fixit was applied as part of the diagnostic.
     58   /// It basically silences warnings without accompanying fixits.
     59   bool Silent = false;
     60 };
     61 
     62 class FixItRewriter : public DiagnosticConsumer {
     63   /// The diagnostics machinery.
     64   DiagnosticsEngine &Diags;
     65 
     66   edit::EditedSource Editor;
     67 
     68   /// The rewriter used to perform the various code
     69   /// modifications.
     70   Rewriter Rewrite;
     71 
     72   /// The diagnostic client that performs the actual formatting
     73   /// of error messages.
     74   DiagnosticConsumer *Client;
     75   std::unique_ptr<DiagnosticConsumer> Owner;
     76 
     77   /// Turn an input path into an output path. NULL implies overwriting
     78   /// the original.
     79   FixItOptions *FixItOpts;
     80 
     81   /// The number of rewriter failures.
     82   unsigned NumFailures = 0;
     83 
     84   /// Whether the previous diagnostic was not passed to the consumer.
     85   bool PrevDiagSilenced = false;
     86 
     87 public:
     88   /// Initialize a new fix-it rewriter.
     89   FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
     90                 const LangOptions &LangOpts, FixItOptions *FixItOpts);
     91 
     92   /// Destroy the fix-it rewriter.
     93   ~FixItRewriter() override;
     94 
     95   /// Check whether there are modifications for a given file.
     96   bool IsModified(FileID ID) const {
     97     return Rewrite.getRewriteBufferFor(ID) != nullptr;
     98   }
     99 
    100   using iterator = Rewriter::buffer_iterator;
    101 
    102   // Iteration over files with changes.
    103   iterator buffer_begin() { return Rewrite.buffer_begin(); }
    104   iterator buffer_end() { return Rewrite.buffer_end(); }
    105 
    106   /// Write a single modified source file.
    107   ///
    108   /// \returns true if there was an error, false otherwise.
    109   bool WriteFixedFile(FileID ID, raw_ostream &OS);
    110 
    111   /// Write the modified source files.
    112   ///
    113   /// \returns true if there was an error, false otherwise.
    114   bool WriteFixedFiles(
    115     std::vector<std::pair<std::string, std::string>> *RewrittenFiles = nullptr);
    116 
    117   /// IncludeInDiagnosticCounts - This method (whose default implementation
    118   /// returns true) indicates whether the diagnostics handled by this
    119   /// DiagnosticConsumer should be included in the number of diagnostics
    120   /// reported by DiagnosticsEngine.
    121   bool IncludeInDiagnosticCounts() const override;
    122 
    123   /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
    124   /// capturing it to a log as needed.
    125   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
    126                         const Diagnostic &Info) override;
    127 
    128   /// Emit a diagnostic via the adapted diagnostic client.
    129   void Diag(SourceLocation Loc, unsigned DiagID);
    130 };
    131 
    132 } // namespace clang
    133 
    134 #endif // LLVM_CLANG_REWRITE_FRONTEND_FIXITREWRITER_H
    135