Skip to content

Commit f74b7e5

Browse files
author
David Ungar
authored
Merge pull request #18489 from davidungar/rdar-42314665-fix-batch-mode-truncation-bug
[Batch Mode] Rdar 42314665 fix batch mode truncation bug
2 parents 8f36061 + 7e19f78 commit f74b7e5

File tree

4 files changed

+342
-260
lines changed

4 files changed

+342
-260
lines changed

include/swift/AST/DiagnosticConsumer.h

Lines changed: 105 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -136,35 +136,113 @@ class NullDiagnosticConsumer : public DiagnosticConsumer {
136136
/// current file.
137137
class FileSpecificDiagnosticConsumer : public DiagnosticConsumer {
138138
public:
139+
class Subconsumer;
140+
141+
/// Given a vector of subconsumers, return the most specific
142+
/// DiagnosticConsumer for that vector. That will be a
143+
/// FileSpecificDiagnosticConsumer if the vector has > 1 subconsumer, the
144+
/// subconsumer itself if the vector has just one, or a null pointer if there
145+
/// are no subconsumers. Takes ownership of the DiagnosticConsumers specified
146+
/// in \p subconsumers.
147+
static std::unique_ptr<DiagnosticConsumer>
148+
consolidateSubconsumers(SmallVectorImpl<Subconsumer> &subconsumers);
149+
139150
/// A diagnostic consumer, along with the name of the buffer that it should
140-
/// be associated with. An empty string means that a consumer is not
141-
/// associated with any particular buffer, and should only receive diagnostics
142-
/// that are not in any of the other consumers' files.
143-
/// A null pointer for the DiagnosticConsumer means that diagnostics for this
144-
/// file should not be emitted.
145-
using ConsumerPair =
146-
std::pair<std::string, std::unique_ptr<DiagnosticConsumer>>;
151+
/// be associated with.
152+
class Subconsumer {
153+
friend std::unique_ptr<DiagnosticConsumer>
154+
FileSpecificDiagnosticConsumer::consolidateSubconsumers(
155+
SmallVectorImpl<Subconsumer> &subconsumers);
156+
157+
/// The name of the input file that a consumer and diagnostics should
158+
/// be associated with. An empty string means that a consumer is not
159+
/// associated with any particular buffer, and should only receive
160+
/// diagnostics that are not in any of the other consumers' files.
161+
std::string inputFileName;
162+
163+
/// The consumer (if any) for diagnostics associated with the inputFileName.
164+
/// A null pointer for the DiagnosticConsumer means that diagnostics for
165+
/// this file should not be emitted.
166+
std::unique_ptr<DiagnosticConsumer> consumer;
167+
168+
// Has this subconsumer ever handled a diagnostic that is an error?
169+
bool hasAnErrorBeenConsumed = false;
170+
171+
public:
172+
std::string getInputFileName() const { return inputFileName; }
173+
174+
DiagnosticConsumer *getConsumer() const { return consumer.get(); }
175+
176+
Subconsumer(std::string inputFileName,
177+
std::unique_ptr<DiagnosticConsumer> consumer)
178+
: inputFileName(inputFileName), consumer(std::move(consumer)) {}
179+
180+
void handleDiagnostic(SourceManager &SM, SourceLoc Loc,
181+
DiagnosticKind Kind,
182+
StringRef FormatString,
183+
ArrayRef<DiagnosticArgument> FormatArgs,
184+
const DiagnosticInfo &Info) {
185+
if (!getConsumer())
186+
return;
187+
hasAnErrorBeenConsumed |= Kind == DiagnosticKind::Error;
188+
getConsumer()->handleDiagnostic(SM, Loc, Kind, FormatString, FormatArgs,
189+
Info);
190+
}
191+
192+
void informDriverOfIncompleteBatchModeCompilation() {
193+
if (!hasAnErrorBeenConsumed && getConsumer())
194+
getConsumer()->informDriverOfIncompleteBatchModeCompilation();
195+
}
196+
};
147197

148198
private:
149199
/// All consumers owned by this FileSpecificDiagnosticConsumer.
150-
const SmallVector<ConsumerPair, 4> SubConsumers;
200+
SmallVector<Subconsumer, 4> Subconsumers;
151201

152202
public:
153-
// The commented-out consts are there because the data does not change
154-
// but the swap method gets called on this structure.
155-
struct ConsumerSpecificInformation {
203+
class ConsumerAndRange {
204+
private:
205+
/// The range of SourceLoc's for which diagnostics should be directed to
206+
/// this subconsumer.
207+
/// Should be const but then the sort won't compile.
156208
/*const*/ CharSourceRange range;
157-
/// The DiagnosticConsumer may be empty if those diagnostics are not to be
158-
/// emitted.
159-
DiagnosticConsumer * /*const*/ consumer;
160-
bool hasAnErrorBeenEmitted = false;
161-
162-
ConsumerSpecificInformation(const CharSourceRange range,
163-
DiagnosticConsumer *const consumer)
164-
: range(range), consumer(consumer) {}
209+
210+
/// Index into Subconsumers vector for this subconsumer.
211+
/// Should be const but then the sort won't compile.
212+
/*const*/ unsigned subconsumerIndex;
213+
214+
public:
215+
unsigned getSubconsumerIndex() const { return subconsumerIndex; }
216+
217+
ConsumerAndRange(const CharSourceRange range, unsigned subconsumerIndex)
218+
: range(range), subconsumerIndex(subconsumerIndex) {}
219+
220+
/// Compare according to range:
221+
bool operator<(const ConsumerAndRange &right) const {
222+
auto compare = std::less<const char *>();
223+
return compare(getRawLoc(range.getEnd()).getPointer(),
224+
getRawLoc(right.range.getEnd()).getPointer());
225+
}
226+
227+
/// Overlaps by range:
228+
bool overlaps(const ConsumerAndRange &other) const {
229+
return range.overlaps(other.range);
230+
}
231+
232+
/// Does my range end after \p loc?
233+
bool endsAfter(const SourceLoc loc) const {
234+
auto compare = std::less<const char *>();
235+
return compare(getRawLoc(range.getEnd()).getPointer(),
236+
getRawLoc(loc).getPointer());
237+
}
238+
239+
bool contains(const SourceLoc loc) const { return range.contains(loc); }
165240
};
166241

167242
private:
243+
Subconsumer &operator[](const ConsumerAndRange &consumerAndRange) {
244+
return Subconsumers[consumerAndRange.getSubconsumerIndex()];
245+
}
168246
/// The consumers owned by this FileSpecificDiagnosticConsumer, sorted by
169247
/// the end locations of each file so that a lookup by position can be done
170248
/// using binary search.
@@ -173,8 +251,8 @@ class FileSpecificDiagnosticConsumer : public DiagnosticConsumer {
173251
/// This allows diagnostics to be emitted before files are actually opened,
174252
/// as long as they don't have source locations.
175253
///
176-
/// \see #consumerSpecificInformationForLocation
177-
SmallVector<ConsumerSpecificInformation, 4> ConsumersOrderedByRange;
254+
/// \see #subconsumerForLocation
255+
SmallVector<ConsumerAndRange, 4> ConsumersOrderedByRange;
178256

179257
/// Indicates which consumer to send Note diagnostics too.
180258
///
@@ -183,19 +261,18 @@ class FileSpecificDiagnosticConsumer : public DiagnosticConsumer {
183261
///
184262
/// If None, Note diagnostics are sent to every consumer.
185263
/// If null, diagnostics are suppressed.
186-
Optional<ConsumerSpecificInformation *>
187-
ConsumerSpecificInfoForSubsequentNotes = None;
264+
Optional<Subconsumer *> SubconsumerForSubsequentNotes = None;
188265

189266
bool HasAnErrorBeenConsumed = false;
190267

191-
public:
192268
/// Takes ownership of the DiagnosticConsumers specified in \p consumers.
193269
///
194270
/// There must not be two consumers for the same file (i.e., having the same
195271
/// buffer name).
196272
explicit FileSpecificDiagnosticConsumer(
197-
SmallVectorImpl<ConsumerPair> &consumers);
273+
SmallVectorImpl<Subconsumer> &consumers);
198274

275+
public:
199276
void handleDiagnostic(SourceManager &SM, SourceLoc Loc,
200277
DiagnosticKind Kind,
201278
StringRef FormatString,
@@ -209,16 +286,15 @@ class FileSpecificDiagnosticConsumer : public DiagnosticConsumer {
209286
/// Xcode will only see an error for a particular primary in that primary's
210287
/// serialized diagnostics file. So, tell the subconsumers to inform the
211288
/// driver of incomplete batch mode compilation.
212-
void tellSubconsumersToInformDriverOfIncompleteBatchModeCompilation() const;
289+
void tellSubconsumersToInformDriverOfIncompleteBatchModeCompilation();
213290

214291
void computeConsumersOrderedByRange(SourceManager &SM);
215292

216293
/// Returns nullptr if diagnostic is to be suppressed,
217294
/// None if diagnostic is to be distributed to every consumer,
218295
/// a particular consumer if diagnostic goes there.
219-
Optional<ConsumerSpecificInformation *>
220-
consumerSpecificInformationForLocation(SourceManager &SM,
221-
SourceLoc loc) const;
296+
Optional<FileSpecificDiagnosticConsumer::Subconsumer *>
297+
subconsumerForLocation(SourceManager &SM, SourceLoc loc);
222298
};
223299

224300
} // end namespace swift

0 commit comments

Comments
 (0)