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