17
17
#define DEBUG_TYPE " swift-ast"
18
18
#include " swift/AST/DiagnosticConsumer.h"
19
19
#include " swift/AST/DiagnosticEngine.h"
20
+ #include " swift/AST/DiagnosticsFrontend.h"
20
21
#include " swift/Basic/Defer.h"
21
22
#include " swift/Basic/SourceManager.h"
22
23
#include " llvm/ADT/STLExtras.h"
@@ -71,44 +72,38 @@ void FileSpecificDiagnosticConsumer::computeConsumersOrderedByRange(
71
72
Optional<unsigned > bufferID = SM.getIDForBufferIdentifier (pair.first );
72
73
assert (bufferID.hasValue () && " consumer registered for unknown file" );
73
74
CharSourceRange range = SM.getRangeForBuffer (bufferID.getValue ());
74
- ConsumersOrderedByRange.emplace_back (range, pair.second .get ());
75
+ ConsumersOrderedByRange.emplace_back (
76
+ ConsumerSpecificInformation (range, pair.second .get ()));
75
77
}
76
78
77
79
// Sort the "map" by buffer /end/ location, for use with std::lower_bound
78
80
// later. (Sorting by start location would produce the same sort, since the
79
81
// ranges must not be overlapping, but since we need to check end locations
80
82
// later it's consistent to sort by that here.)
81
83
std::sort (ConsumersOrderedByRange.begin (), ConsumersOrderedByRange.end (),
82
- [](const ConsumersOrderedByRangeEntry &left,
83
- const ConsumersOrderedByRangeEntry &right) -> bool {
84
- auto compare = std::less<const char *>();
85
- return compare (getRawLoc (left.first .getEnd ()).getPointer (),
86
- getRawLoc (right.first .getEnd ()).getPointer ());
87
- });
84
+ [](const ConsumerSpecificInformation &left,
85
+ const ConsumerSpecificInformation &right) -> bool {
86
+ auto compare = std::less<const char *>();
87
+ return compare (getRawLoc (left.range .getEnd ()).getPointer (),
88
+ getRawLoc (right.range .getEnd ()).getPointer ());
89
+ });
88
90
89
91
// Check that the ranges are non-overlapping. If the files really are all
90
92
// distinct, this should be trivially true, but if it's ever not we might end
91
93
// up mis-filing diagnostics.
92
94
assert (ConsumersOrderedByRange.end () ==
93
- std::adjacent_find (ConsumersOrderedByRange.begin (),
94
- ConsumersOrderedByRange.end (),
95
- [](const ConsumersOrderedByRangeEntry &left,
96
- const ConsumersOrderedByRangeEntry &right) {
97
- return left.first .overlaps (right.first );
98
- }) &&
95
+ std::adjacent_find (ConsumersOrderedByRange.begin (),
96
+ ConsumersOrderedByRange.end (),
97
+ [](const ConsumerSpecificInformation &left,
98
+ const ConsumerSpecificInformation &right) {
99
+ return left.range .overlaps (right.range );
100
+ }) &&
99
101
" overlapping ranges despite having distinct files" );
100
102
}
101
103
102
- Optional<DiagnosticConsumer *>
103
- FileSpecificDiagnosticConsumer::consumerForLocation (SourceManager &SM,
104
- SourceLoc loc) const {
105
- // If there's only one consumer, we'll use it no matter what, because...
106
- // - ...all diagnostics within the file will go to that consumer.
107
- // - ...all diagnostics not within the file will not be claimed by any
108
- // consumer, and so will go to all (one) consumers.
109
- if (SubConsumers.size () == 1 )
110
- return SubConsumers.front ().second .get ();
111
-
104
+ Optional<FileSpecificDiagnosticConsumer::ConsumerSpecificInformation *>
105
+ FileSpecificDiagnosticConsumer::consumerSpecificInformationForLocation (
106
+ SourceManager &SM, SourceLoc loc) const {
112
107
// Diagnostics with invalid locations always go to every consumer.
113
108
if (loc.isInvalid ())
114
109
return None;
@@ -139,20 +134,19 @@ FileSpecificDiagnosticConsumer::consumerForLocation(SourceManager &SM,
139
134
// that /might/ contain 'loc'. Specifically, since the ranges are sorted
140
135
// by end location, it's looking for the first range where the end location
141
136
// is greater than or equal to 'loc'.
142
- auto possiblyContainingRangeIter =
143
- std::lower_bound (ConsumersOrderedByRange.begin (),
144
- ConsumersOrderedByRange.end (),
145
- loc,
146
- [](const ConsumersOrderedByRangeEntry &entry,
147
- SourceLoc loc) -> bool {
148
- auto compare = std::less<const char *>();
149
- return compare (getRawLoc (entry.first .getEnd ()).getPointer (),
150
- getRawLoc (loc).getPointer ());
151
- });
137
+ const ConsumerSpecificInformation *possiblyContainingRangeIter =
138
+ std::lower_bound (
139
+ ConsumersOrderedByRange.begin (), ConsumersOrderedByRange.end (), loc,
140
+ [](const ConsumerSpecificInformation &entry, SourceLoc loc) -> bool {
141
+ auto compare = std::less<const char *>();
142
+ return compare (getRawLoc (entry.range .getEnd ()).getPointer (),
143
+ getRawLoc (loc).getPointer ());
144
+ });
152
145
153
146
if (possiblyContainingRangeIter != ConsumersOrderedByRange.end () &&
154
- possiblyContainingRangeIter->first .contains (loc)) {
155
- return possiblyContainingRangeIter->second ;
147
+ possiblyContainingRangeIter->range .contains (loc)) {
148
+ return const_cast <ConsumerSpecificInformation *>(
149
+ possiblyContainingRangeIter);
156
150
}
157
151
158
152
return None;
@@ -163,41 +157,76 @@ void FileSpecificDiagnosticConsumer::handleDiagnostic(
163
157
StringRef FormatString, ArrayRef<DiagnosticArgument> FormatArgs,
164
158
const DiagnosticInfo &Info) {
165
159
166
- Optional<DiagnosticConsumer *> specificConsumer;
160
+ HasAnErrorBeenConsumed |= Kind == DiagnosticKind::Error;
161
+
162
+ Optional<ConsumerSpecificInformation *> consumerSpecificInfo;
167
163
switch (Kind) {
168
164
case DiagnosticKind::Error:
169
165
case DiagnosticKind::Warning:
170
166
case DiagnosticKind::Remark:
171
- specificConsumer = consumerForLocation (SM, Loc);
172
- ConsumerForSubsequentNotes = specificConsumer ;
167
+ consumerSpecificInfo = consumerSpecificInformationForLocation (SM, Loc);
168
+ ConsumerSpecificInfoForSubsequentNotes = consumerSpecificInfo ;
173
169
break ;
174
170
case DiagnosticKind::Note:
175
- specificConsumer = ConsumerForSubsequentNotes ;
171
+ consumerSpecificInfo = ConsumerSpecificInfoForSubsequentNotes ;
176
172
break ;
177
173
}
178
-
179
- if (!specificConsumer.hasValue ()) {
174
+ if (!consumerSpecificInfo.hasValue ()) {
180
175
for (auto &subConsumer : SubConsumers) {
181
176
if (subConsumer.second ) {
182
177
subConsumer.second ->handleDiagnostic (SM, Loc, Kind, FormatString,
183
178
FormatArgs, Info);
184
179
}
185
180
}
186
- } else if (DiagnosticConsumer *c = specificConsumer.getValue ())
187
- c->handleDiagnostic (SM, Loc, Kind, FormatString, FormatArgs, Info);
188
- else
189
- ; // Suppress non-primary diagnostic in batch mode.
181
+ return ;
182
+ }
183
+ if (!consumerSpecificInfo.getValue ()->consumer )
184
+ return ; // Suppress non-primary diagnostic in batch mode.
185
+
186
+ consumerSpecificInfo.getValue ()->consumer ->handleDiagnostic (
187
+ SM, Loc, Kind, FormatString, FormatArgs, Info);
188
+ consumerSpecificInfo.getValue ()->hasAnErrorBeenEmitted |=
189
+ Kind == DiagnosticKind::Error;
190
190
}
191
191
192
- bool FileSpecificDiagnosticConsumer::finishProcessing () {
192
+ bool FileSpecificDiagnosticConsumer::finishProcessing (SourceManager &SM) {
193
+ addNonSpecificErrors (SM);
194
+
193
195
// Deliberately don't use std::any_of here because we don't want early-exit
194
196
// behavior.
197
+
195
198
bool hadError = false ;
196
199
for (auto &subConsumer : SubConsumers)
197
- hadError |= subConsumer.second && subConsumer.second ->finishProcessing ();
200
+ hadError |= subConsumer.second && subConsumer.second ->finishProcessing (SM );
198
201
return hadError;
199
202
}
200
203
204
+ static void produceNonSpecificError (
205
+ FileSpecificDiagnosticConsumer::ConsumerSpecificInformation &info,
206
+ SourceManager &SM) {
207
+ Diagnostic diagnostic (
208
+ diag::error_compilation_stopped_by_errors_in_other_files);
209
+
210
+ // Stolen from DiagnosticEngine::emitDiagnostic
211
+ DiagnosticInfo Info;
212
+ Info.ID = diagnostic.getID ();
213
+
214
+ info.consumer ->handleDiagnostic (
215
+ SM, info.range .getStart (), DiagnosticKind::Error,
216
+ DiagnosticEngine::diagnosticStringFor (diagnostic.getID ()), {}, Info);
217
+ }
218
+
219
+ void FileSpecificDiagnosticConsumer::addNonSpecificErrors (SourceManager &SM) {
220
+ if (!HasAnErrorBeenConsumed)
221
+ return ;
222
+ for (auto &info : ConsumersOrderedByRange) {
223
+ if (!info.hasAnErrorBeenEmitted && info.consumer ) {
224
+ produceNonSpecificError (info, SM);
225
+ info.hasAnErrorBeenEmitted = true ;
226
+ }
227
+ }
228
+ }
229
+
201
230
void NullDiagnosticConsumer::handleDiagnostic (
202
231
SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind,
203
232
StringRef FormatString, ArrayRef<DiagnosticArgument> FormatArgs,
0 commit comments