12
12
13
13
#include " clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
14
14
#include " ModelInjector.h"
15
- #include " clang/Analysis/PathDiagnostic.h"
16
15
#include " clang/AST/Decl.h"
17
16
#include " clang/AST/DeclCXX.h"
18
17
#include " clang/AST/DeclObjC.h"
21
20
#include " clang/Analysis/CFG.h"
22
21
#include " clang/Analysis/CallGraph.h"
23
22
#include " clang/Analysis/CodeInjector.h"
23
+ #include " clang/Analysis/PathDiagnostic.h"
24
24
#include " clang/Basic/SourceManager.h"
25
25
#include " clang/CrossTU/CrossTranslationUnit.h"
26
26
#include " clang/Frontend/CompilerInstance.h"
27
27
#include " clang/Lex/Preprocessor.h"
28
+ #include " clang/Rewrite/Core/Rewriter.h"
28
29
#include " clang/StaticAnalyzer/Checkers/LocalCheckers.h"
29
30
#include " clang/StaticAnalyzer/Core/AnalyzerOptions.h"
30
31
#include " clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
33
34
#include " clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
34
35
#include " clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
35
36
#include " clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
37
+ #include " clang/Tooling/Core/Replacement.h"
38
+ #include " clang/Tooling/Tooling.h"
36
39
#include " llvm/ADT/PostOrderIterator.h"
37
40
#include " llvm/ADT/Statistic.h"
38
41
#include " llvm/Support/FileSystem.h"
46
49
47
50
using namespace clang ;
48
51
using namespace ento ;
52
+ using namespace tooling ;
49
53
50
54
#define DEBUG_TYPE " AnalysisConsumer"
51
55
@@ -84,11 +88,16 @@ void ento::createTextPathDiagnosticConsumer(
84
88
namespace {
85
89
class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer {
86
90
DiagnosticsEngine &Diag;
87
- bool IncludePath = false , ShouldEmitAsError = false , FixitsAsRemarks = false ;
91
+ LangOptions LO;
92
+
93
+ bool IncludePath = false ;
94
+ bool ShouldEmitAsError = false ;
95
+ bool FixitsAsRemarks = false ;
96
+ bool ApplyFixIts = false ;
88
97
89
98
public:
90
- ClangDiagPathDiagConsumer (DiagnosticsEngine &Diag)
91
- : Diag(Diag) {}
99
+ ClangDiagPathDiagConsumer (DiagnosticsEngine &Diag, LangOptions LO )
100
+ : Diag(Diag), LO(LO) {}
92
101
~ClangDiagPathDiagConsumer () override {}
93
102
StringRef getName () const override { return " ClangDiags" ; }
94
103
@@ -102,6 +111,7 @@ class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer {
102
111
void enablePaths () { IncludePath = true ; }
103
112
void enableWerror () { ShouldEmitAsError = true ; }
104
113
void enableFixitsAsRemarks () { FixitsAsRemarks = true ; }
114
+ void enableApplyFixIts () { ApplyFixIts = true ; }
105
115
106
116
void FlushDiagnosticsImpl (std::vector<const PathDiagnostic *> &Diags,
107
117
FilesMade *filesMade) override {
@@ -111,29 +121,44 @@ class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer {
111
121
: Diag.getCustomDiagID (DiagnosticsEngine::Warning, " %0" );
112
122
unsigned NoteID = Diag.getCustomDiagID (DiagnosticsEngine::Note, " %0" );
113
123
unsigned RemarkID = Diag.getCustomDiagID (DiagnosticsEngine::Remark, " %0" );
124
+ SourceManager &SM = Diag.getSourceManager ();
125
+
126
+ Replacements Repls;
127
+ auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String,
128
+ ArrayRef<SourceRange> Ranges,
129
+ ArrayRef<FixItHint> Fixits) {
130
+ if (!FixitsAsRemarks && !ApplyFixIts) {
131
+ Diag.Report (Loc, ID) << String << Ranges << Fixits;
132
+ return ;
133
+ }
134
+
135
+ Diag.Report (Loc, ID) << String << Ranges;
136
+ if (FixitsAsRemarks) {
137
+ for (const FixItHint &Hint : Fixits) {
138
+ llvm::SmallString<128 > Str;
139
+ llvm::raw_svector_ostream OS (Str);
140
+ // FIXME: Add support for InsertFromRange and
141
+ // BeforePreviousInsertion.
142
+ assert (!Hint.InsertFromRange .isValid () && " Not implemented yet!" );
143
+ assert (!Hint.BeforePreviousInsertions && " Not implemented yet!" );
144
+ OS << SM.getSpellingColumnNumber (Hint.RemoveRange .getBegin ()) << " -"
145
+ << SM.getSpellingColumnNumber (Hint.RemoveRange .getEnd ()) << " : '"
146
+ << Hint.CodeToInsert << " '" ;
147
+ Diag.Report (Loc, RemarkID) << OS.str ();
148
+ }
149
+ }
150
+
151
+ if (ApplyFixIts) {
152
+ for (const FixItHint &Hint : Fixits) {
153
+ Replacement Repl (SM, Hint.RemoveRange , Hint.CodeToInsert );
114
154
115
- auto reportPiece =
116
- [&](unsigned ID, SourceLocation Loc, StringRef String,
117
- ArrayRef<SourceRange> Ranges, ArrayRef<FixItHint> Fixits) {
118
- if (!FixitsAsRemarks) {
119
- Diag.Report (Loc, ID) << String << Ranges << Fixits;
120
- } else {
121
- Diag.Report (Loc, ID) << String << Ranges;
122
- for (const FixItHint &Hint : Fixits) {
123
- SourceManager &SM = Diag.getSourceManager ();
124
- llvm::SmallString<128 > Str;
125
- llvm::raw_svector_ostream OS (Str);
126
- // FIXME: Add support for InsertFromRange and
127
- // BeforePreviousInsertion.
128
- assert (!Hint.InsertFromRange .isValid () && " Not implemented yet!" );
129
- assert (!Hint.BeforePreviousInsertions && " Not implemented yet!" );
130
- OS << SM.getSpellingColumnNumber (Hint.RemoveRange .getBegin ())
131
- << " -" << SM.getSpellingColumnNumber (Hint.RemoveRange .getEnd ())
132
- << " : '" << Hint.CodeToInsert << " '" ;
133
- Diag.Report (Loc, RemarkID) << OS.str ();
134
- }
155
+ if (llvm::Error Err = Repls.add (Repl)) {
156
+ llvm::errs () << " Error applying replacement " << Repl.toString ()
157
+ << " : " << Err << " \n " ;
135
158
}
136
- };
159
+ }
160
+ }
161
+ };
137
162
138
163
for (std::vector<const PathDiagnostic *>::iterator I = Diags.begin (),
139
164
E = Diags.end ();
@@ -165,6 +190,16 @@ class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer {
165
190
Piece->getString (), Piece->getRanges (), Piece->getFixits ());
166
191
}
167
192
}
193
+
194
+ if (!ApplyFixIts || Repls.empty ())
195
+ return ;
196
+
197
+ Rewriter Rewrite (SM, LO);
198
+ if (!applyAllReplacements (Repls, Rewrite)) {
199
+ llvm::errs () << " An error occured during applying fix-it.\n " ;
200
+ }
201
+
202
+ Rewrite.overwriteChangedFiles ();
168
203
}
169
204
};
170
205
} // end anonymous namespace
@@ -257,7 +292,7 @@ class AnalysisConsumer : public AnalysisASTConsumer,
257
292
if (Opts->AnalysisDiagOpt != PD_NONE) {
258
293
// Create the PathDiagnosticConsumer.
259
294
ClangDiagPathDiagConsumer *clangDiags =
260
- new ClangDiagPathDiagConsumer (PP.getDiagnostics ());
295
+ new ClangDiagPathDiagConsumer (PP.getDiagnostics (), PP. getLangOpts () );
261
296
PathConsumers.push_back (clangDiags);
262
297
263
298
if (Opts->AnalyzerWerror )
@@ -266,6 +301,9 @@ class AnalysisConsumer : public AnalysisASTConsumer,
266
301
if (Opts->ShouldEmitFixItHintsAsRemarks )
267
302
clangDiags->enableFixitsAsRemarks ();
268
303
304
+ if (Opts->ShouldApplyFixIts )
305
+ clangDiags->enableApplyFixIts ();
306
+
269
307
if (Opts->AnalysisDiagOpt == PD_TEXT) {
270
308
clangDiags->enablePaths ();
271
309
0 commit comments