 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
54.2% |
39 / 72 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
75.0% |
54 / 72 |
| |
|
Line Coverage: |
64.2% |
61 / 95 |
| |
 |
|
 |
1 : //===--- FixItRewriter.cpp - 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 : #include "clang/Frontend/FixItRewriter.h"
17 : #include "clang/Basic/SourceManager.h"
18 : #include "clang/Frontend/FrontendDiagnostic.h"
19 : #include "llvm/Support/raw_ostream.h"
20 : #include "llvm/System/Path.h"
21 : #include "llvm/ADT/OwningPtr.h"
22 : #include <cstdio>
23 :
24 : using namespace clang;
25 :
26 : FixItRewriter::FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr,
27 12: const LangOptions &LangOpts)
28 12: : Diags(Diags), Rewrite(SourceMgr, LangOpts), NumFailures(0) {
29 12: Client = Diags.getClient();
30 12: Diags.setClient(this);
31 12: }
32 :
33 12: FixItRewriter::~FixItRewriter() {
34 12: Diags.setClient(Client);
12: branch 3 taken
0: branch 4 not taken
0: branch 9 not taken
0: branch 10 not taken
0: branch 15 not taken
0: branch 16 not taken
35 12: }
36 :
37 : bool FixItRewriter::WriteFixedFile(const std::string &InFileName,
38 12: const std::string &OutFileName) {
3: branch 0 taken
9: branch 1 taken
39 12: if (NumFailures > 0) {
40 3: Diag(FullSourceLoc(), diag::warn_fixit_no_changes);
41 3: return true;
42 : }
43 :
44 9: llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
45 : llvm::raw_ostream *OutFile;
9: branch 1 taken
0: branch 2 not taken
46 9: if (!OutFileName.empty()) {
47 9: std::string Err;
48 : OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(), Err,
49 9: llvm::raw_fd_ostream::F_Binary);
50 9: OwnedStream.reset(OutFile);
0: branch 1 not taken
0: branch 2 not taken
51 0: } else if (InFileName == "-") {
52 0: OutFile = &llvm::outs();
53 : } else {
54 0: llvm::sys::Path Path(InFileName);
55 0: std::string Suffix = Path.getSuffix();
56 0: Path.eraseSuffix();
57 0: Path.appendSuffix("fixit." + Suffix);
58 0: std::string Err;
59 : OutFile = new llvm::raw_fd_ostream(Path.c_str(), Err,
60 0: llvm::raw_fd_ostream::F_Binary);
61 0: OwnedStream.reset(OutFile);
62 : }
63 :
64 9: FileID MainFileID = Rewrite.getSourceMgr().getMainFileID();
8: branch 0 taken
1: branch 1 taken
65 9: if (const RewriteBuffer *RewriteBuf =
66 9: Rewrite.getRewriteBufferFor(MainFileID)) {
67 8: *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
68 : } else {
69 1: Diag(FullSourceLoc(), diag::note_fixit_main_file_unchanged);
70 : }
71 9: OutFile->flush();
72 :
73 9: return false;
74 : }
75 :
76 98: bool FixItRewriter::IncludeInDiagnosticCounts() const {
98: branch 0 taken
0: branch 1 not taken
77 98: return Client? Client->IncludeInDiagnosticCounts() : true;
78 : }
79 :
80 : void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
81 98: const DiagnosticInfo &Info) {
82 98: Client->HandleDiagnostic(DiagLevel, Info);
83 :
84 : // Skip over any diagnostics that are ignored.
0: branch 0 not taken
98: branch 1 taken
85 98: if (DiagLevel == Diagnostic::Ignored)
86 0: return;
87 :
0: branch 1 not taken
98: branch 2 taken
88 98: if (!FixItLocations.empty()) {
89 : // The user has specified the locations where we should perform
90 : // the various fix-it modifications.
91 :
92 : // If this diagnostic does not have any code modifications,
93 : // completely ignore it, even if it's an error: fix-it locations
94 : // are meant to perform specific fix-ups even in the presence of
95 : // other errors.
0: branch 1 not taken
0: branch 2 not taken
96 0: if (Info.getNumCodeModificationHints() == 0)
97 0: return;
98 :
99 : // See if the location of the error is one that matches what the
100 : // user requested.
101 0: bool AcceptableLocation = false;
102 : const FileEntry *File
103 : = Rewrite.getSourceMgr().getFileEntryForID(
104 0: Info.getLocation().getFileID());
105 0: unsigned Line = Info.getLocation().getSpellingLineNumber();
106 0: unsigned Column = Info.getLocation().getSpellingColumnNumber();
0: branch 0 not taken
0: branch 1 not taken
107 0: for (llvm::SmallVector<RequestedSourceLocation, 4>::iterator
108 0: Loc = FixItLocations.begin(), LocEnd = FixItLocations.end();
109 : Loc != LocEnd; ++Loc) {
0: branch 0 not taken
0: branch 1 not taken
0: branch 2 not taken
0: branch 3 not taken
0: branch 4 not taken
0: branch 5 not taken
110 0: if (Loc->File == File && Loc->Line == Line && Loc->Column == Column) {
111 0: AcceptableLocation = true;
112 0: break;
113 : }
114 : }
115 :
0: branch 0 not taken
0: branch 1 not taken
116 0: if (!AcceptableLocation)
117 0: return;
33: branch 0 taken
65: branch 1 taken
118 98: } else if (DiagLevel == Diagnostic::Note) {
119 : // Don't apply fix-it modifications in notes.
120 33: return;
121 : }
122 :
123 : // Make sure that we can perform all of the modifications we
124 : // in this diagnostic.
125 65: bool CanRewrite = Info.getNumCodeModificationHints() > 0;
65: branch 1 taken
65: branch 2 taken
126 130: for (unsigned Idx = 0, Last = Info.getNumCodeModificationHints();
127 : Idx < Last; ++Idx) {
128 65: const CodeModificationHint &Hint = Info.getCodeModificationHint(Idx);
36: branch 1 taken
29: branch 2 taken
0: branch 4 not taken
36: branch 5 taken
0: branch 6 not taken
65: branch 7 taken
129 65: if (Hint.RemoveRange.isValid() &&
130 : Rewrite.getRangeSize(Hint.RemoveRange) == -1) {
131 0: CanRewrite = false;
132 0: break;
133 : }
134 :
59: branch 1 taken
6: branch 2 taken
0: branch 4 not taken
59: branch 5 taken
0: branch 6 not taken
65: branch 7 taken
135 65: if (Hint.InsertionLoc.isValid() &&
136 : !Rewrite.isRewritable(Hint.InsertionLoc)) {
137 0: CanRewrite = false;
138 0: break;
139 : }
140 : }
141 :
8: branch 0 taken
57: branch 1 taken
142 65: if (!CanRewrite) {
0: branch 1 not taken
8: branch 2 taken
143 8: if (Info.getNumCodeModificationHints() > 0)
144 0: Diag(Info.getLocation(), diag::note_fixit_in_macro);
145 :
146 : // If this was an error, refuse to perform any rewriting.
1: branch 0 taken
7: branch 1 taken
0: branch 2 not taken
1: branch 3 taken
147 8: if (DiagLevel == Diagnostic::Error || DiagLevel == Diagnostic::Fatal) {
3: branch 0 taken
4: branch 1 taken
148 7: if (++NumFailures == 1)
149 3: Diag(Info.getLocation(), diag::note_fixit_unfixed_error);
150 : }
151 8: return;
152 : }
153 :
154 57: bool Failed = false;
65: branch 1 taken
57: branch 2 taken
155 122: for (unsigned Idx = 0, Last = Info.getNumCodeModificationHints();
156 : Idx < Last; ++Idx) {
157 65: const CodeModificationHint &Hint = Info.getCodeModificationHint(Idx);
29: branch 1 taken
36: branch 2 taken
158 65: if (!Hint.RemoveRange.isValid()) {
159 : // We're adding code.
0: branch 2 not taken
29: branch 3 taken
160 29: if (Rewrite.InsertTextBefore(Hint.InsertionLoc, Hint.CodeToInsert))
161 0: Failed = true;
162 29: continue;
163 : }
164 :
6: branch 1 taken
30: branch 2 taken
165 36: if (Hint.CodeToInsert.empty()) {
166 : // We're removing code.
0: branch 3 not taken
6: branch 4 taken
167 6: if (Rewrite.RemoveText(Hint.RemoveRange.getBegin(),
168 : Rewrite.getRangeSize(Hint.RemoveRange)))
169 0: Failed = true;
170 6: continue;
171 : }
172 :
173 : // We're replacing code.
0: branch 4 not taken
30: branch 5 taken
174 30: if (Rewrite.ReplaceText(Hint.RemoveRange.getBegin(),
175 : Rewrite.getRangeSize(Hint.RemoveRange),
176 : Hint.CodeToInsert))
177 0: Failed = true;
178 : }
179 :
0: branch 0 not taken
57: branch 1 taken
180 57: if (Failed) {
181 0: ++NumFailures;
182 0: Diag(Info.getLocation(), diag::note_fixit_failed);
183 0: return;
184 : }
185 :
186 57: Diag(Info.getLocation(), diag::note_fixit_applied);
187 : }
188 :
189 : /// \brief Emit a diagnostic via the adapted diagnostic client.
190 64: void FixItRewriter::Diag(FullSourceLoc Loc, unsigned DiagID) {
191 : // When producing this diagnostic, we temporarily bypass ourselves,
192 : // clear out any current diagnostic, and let the downstream client
193 : // format the diagnostic.
194 64: Diags.setClient(Client);
195 64: Diags.Clear();
196 64: Diags.Report(Loc, DiagID);
197 64: Diags.setClient(this);
198 64: }
Generated: 2010-02-10 01:31 by zcov