mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #18489 from davidungar/rdar-42314665-fix-batch-mode-truncation-bug
[Batch Mode] Rdar 42314665 fix batch mode truncation bug
This commit is contained in:
@@ -136,35 +136,113 @@ public:
|
||||
/// current file.
|
||||
class FileSpecificDiagnosticConsumer : public DiagnosticConsumer {
|
||||
public:
|
||||
/// A diagnostic consumer, along with the name of the buffer that it should
|
||||
/// be associated with. An empty string means that a consumer is not
|
||||
/// associated with any particular buffer, and should only receive diagnostics
|
||||
/// that are not in any of the other consumers' files.
|
||||
/// A null pointer for the DiagnosticConsumer means that diagnostics for this
|
||||
/// file should not be emitted.
|
||||
using ConsumerPair =
|
||||
std::pair<std::string, std::unique_ptr<DiagnosticConsumer>>;
|
||||
class Subconsumer;
|
||||
|
||||
private:
|
||||
/// All consumers owned by this FileSpecificDiagnosticConsumer.
|
||||
const SmallVector<ConsumerPair, 4> SubConsumers;
|
||||
/// Given a vector of subconsumers, return the most specific
|
||||
/// DiagnosticConsumer for that vector. That will be a
|
||||
/// FileSpecificDiagnosticConsumer if the vector has > 1 subconsumer, the
|
||||
/// subconsumer itself if the vector has just one, or a null pointer if there
|
||||
/// are no subconsumers. Takes ownership of the DiagnosticConsumers specified
|
||||
/// in \p subconsumers.
|
||||
static std::unique_ptr<DiagnosticConsumer>
|
||||
consolidateSubconsumers(SmallVectorImpl<Subconsumer> &subconsumers);
|
||||
|
||||
/// A diagnostic consumer, along with the name of the buffer that it should
|
||||
/// be associated with.
|
||||
class Subconsumer {
|
||||
friend std::unique_ptr<DiagnosticConsumer>
|
||||
FileSpecificDiagnosticConsumer::consolidateSubconsumers(
|
||||
SmallVectorImpl<Subconsumer> &subconsumers);
|
||||
|
||||
/// The name of the input file that a consumer and diagnostics should
|
||||
/// be associated with. An empty string means that a consumer is not
|
||||
/// associated with any particular buffer, and should only receive
|
||||
/// diagnostics that are not in any of the other consumers' files.
|
||||
std::string inputFileName;
|
||||
|
||||
/// The consumer (if any) for diagnostics associated with the inputFileName.
|
||||
/// A null pointer for the DiagnosticConsumer means that diagnostics for
|
||||
/// this file should not be emitted.
|
||||
std::unique_ptr<DiagnosticConsumer> consumer;
|
||||
|
||||
// Has this subconsumer ever handled a diagnostic that is an error?
|
||||
bool hasAnErrorBeenConsumed = false;
|
||||
|
||||
public:
|
||||
// The commented-out consts are there because the data does not change
|
||||
// but the swap method gets called on this structure.
|
||||
struct ConsumerSpecificInformation {
|
||||
/*const*/ CharSourceRange range;
|
||||
/// The DiagnosticConsumer may be empty if those diagnostics are not to be
|
||||
/// emitted.
|
||||
DiagnosticConsumer * /*const*/ consumer;
|
||||
bool hasAnErrorBeenEmitted = false;
|
||||
std::string getInputFileName() const { return inputFileName; }
|
||||
|
||||
ConsumerSpecificInformation(const CharSourceRange range,
|
||||
DiagnosticConsumer *const consumer)
|
||||
: range(range), consumer(consumer) {}
|
||||
DiagnosticConsumer *getConsumer() const { return consumer.get(); }
|
||||
|
||||
Subconsumer(std::string inputFileName,
|
||||
std::unique_ptr<DiagnosticConsumer> consumer)
|
||||
: inputFileName(inputFileName), consumer(std::move(consumer)) {}
|
||||
|
||||
void handleDiagnostic(SourceManager &SM, SourceLoc Loc,
|
||||
DiagnosticKind Kind,
|
||||
StringRef FormatString,
|
||||
ArrayRef<DiagnosticArgument> FormatArgs,
|
||||
const DiagnosticInfo &Info) {
|
||||
if (!getConsumer())
|
||||
return;
|
||||
hasAnErrorBeenConsumed |= Kind == DiagnosticKind::Error;
|
||||
getConsumer()->handleDiagnostic(SM, Loc, Kind, FormatString, FormatArgs,
|
||||
Info);
|
||||
}
|
||||
|
||||
void informDriverOfIncompleteBatchModeCompilation() {
|
||||
if (!hasAnErrorBeenConsumed && getConsumer())
|
||||
getConsumer()->informDriverOfIncompleteBatchModeCompilation();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
/// All consumers owned by this FileSpecificDiagnosticConsumer.
|
||||
SmallVector<Subconsumer, 4> Subconsumers;
|
||||
|
||||
public:
|
||||
class ConsumerAndRange {
|
||||
private:
|
||||
/// The range of SourceLoc's for which diagnostics should be directed to
|
||||
/// this subconsumer.
|
||||
/// Should be const but then the sort won't compile.
|
||||
/*const*/ CharSourceRange range;
|
||||
|
||||
/// Index into Subconsumers vector for this subconsumer.
|
||||
/// Should be const but then the sort won't compile.
|
||||
/*const*/ unsigned subconsumerIndex;
|
||||
|
||||
public:
|
||||
unsigned getSubconsumerIndex() const { return subconsumerIndex; }
|
||||
|
||||
ConsumerAndRange(const CharSourceRange range, unsigned subconsumerIndex)
|
||||
: range(range), subconsumerIndex(subconsumerIndex) {}
|
||||
|
||||
/// Compare according to range:
|
||||
bool operator<(const ConsumerAndRange &right) const {
|
||||
auto compare = std::less<const char *>();
|
||||
return compare(getRawLoc(range.getEnd()).getPointer(),
|
||||
getRawLoc(right.range.getEnd()).getPointer());
|
||||
}
|
||||
|
||||
/// Overlaps by range:
|
||||
bool overlaps(const ConsumerAndRange &other) const {
|
||||
return range.overlaps(other.range);
|
||||
}
|
||||
|
||||
/// Does my range end after \p loc?
|
||||
bool endsAfter(const SourceLoc loc) const {
|
||||
auto compare = std::less<const char *>();
|
||||
return compare(getRawLoc(range.getEnd()).getPointer(),
|
||||
getRawLoc(loc).getPointer());
|
||||
}
|
||||
|
||||
bool contains(const SourceLoc loc) const { return range.contains(loc); }
|
||||
};
|
||||
|
||||
private:
|
||||
Subconsumer &operator[](const ConsumerAndRange &consumerAndRange) {
|
||||
return Subconsumers[consumerAndRange.getSubconsumerIndex()];
|
||||
}
|
||||
/// The consumers owned by this FileSpecificDiagnosticConsumer, sorted by
|
||||
/// the end locations of each file so that a lookup by position can be done
|
||||
/// using binary search.
|
||||
@@ -173,8 +251,8 @@ private:
|
||||
/// This allows diagnostics to be emitted before files are actually opened,
|
||||
/// as long as they don't have source locations.
|
||||
///
|
||||
/// \see #consumerSpecificInformationForLocation
|
||||
SmallVector<ConsumerSpecificInformation, 4> ConsumersOrderedByRange;
|
||||
/// \see #subconsumerForLocation
|
||||
SmallVector<ConsumerAndRange, 4> ConsumersOrderedByRange;
|
||||
|
||||
/// Indicates which consumer to send Note diagnostics too.
|
||||
///
|
||||
@@ -183,19 +261,18 @@ private:
|
||||
///
|
||||
/// If None, Note diagnostics are sent to every consumer.
|
||||
/// If null, diagnostics are suppressed.
|
||||
Optional<ConsumerSpecificInformation *>
|
||||
ConsumerSpecificInfoForSubsequentNotes = None;
|
||||
Optional<Subconsumer *> SubconsumerForSubsequentNotes = None;
|
||||
|
||||
bool HasAnErrorBeenConsumed = false;
|
||||
|
||||
public:
|
||||
/// Takes ownership of the DiagnosticConsumers specified in \p consumers.
|
||||
///
|
||||
/// There must not be two consumers for the same file (i.e., having the same
|
||||
/// buffer name).
|
||||
explicit FileSpecificDiagnosticConsumer(
|
||||
SmallVectorImpl<ConsumerPair> &consumers);
|
||||
SmallVectorImpl<Subconsumer> &consumers);
|
||||
|
||||
public:
|
||||
void handleDiagnostic(SourceManager &SM, SourceLoc Loc,
|
||||
DiagnosticKind Kind,
|
||||
StringRef FormatString,
|
||||
@@ -209,16 +286,15 @@ private:
|
||||
/// Xcode will only see an error for a particular primary in that primary's
|
||||
/// serialized diagnostics file. So, tell the subconsumers to inform the
|
||||
/// driver of incomplete batch mode compilation.
|
||||
void tellSubconsumersToInformDriverOfIncompleteBatchModeCompilation() const;
|
||||
void tellSubconsumersToInformDriverOfIncompleteBatchModeCompilation();
|
||||
|
||||
void computeConsumersOrderedByRange(SourceManager &SM);
|
||||
|
||||
/// Returns nullptr if diagnostic is to be suppressed,
|
||||
/// None if diagnostic is to be distributed to every consumer,
|
||||
/// a particular consumer if diagnostic goes there.
|
||||
Optional<ConsumerSpecificInformation *>
|
||||
consumerSpecificInformationForLocation(SourceManager &SM,
|
||||
SourceLoc loc) const;
|
||||
Optional<FileSpecificDiagnosticConsumer::Subconsumer *>
|
||||
subconsumerForLocation(SourceManager &SM, SourceLoc loc);
|
||||
};
|
||||
|
||||
} // end namespace swift
|
||||
|
||||
@@ -35,58 +35,68 @@ llvm::SMLoc DiagnosticConsumer::getRawLoc(SourceLoc loc) {
|
||||
|
||||
LLVM_ATTRIBUTE_UNUSED
|
||||
static bool hasDuplicateFileNames(
|
||||
ArrayRef<FileSpecificDiagnosticConsumer::ConsumerPair> consumers) {
|
||||
ArrayRef<FileSpecificDiagnosticConsumer::Subconsumer> subconsumers) {
|
||||
llvm::StringSet<> seenFiles;
|
||||
for (const auto &consumerPair : consumers) {
|
||||
if (consumerPair.first.empty()) {
|
||||
// We can handle multiple consumers that aren't associated with any file,
|
||||
// because they only collect diagnostics that aren't in any of the special
|
||||
// files. This isn't an important use case to support, but also SmallSet
|
||||
// doesn't handle empty strings anyway!
|
||||
for (const auto &subconsumer : subconsumers) {
|
||||
if (subconsumer.getInputFileName().empty()) {
|
||||
// We can handle multiple subconsumers that aren't associated with any
|
||||
// file, because they only collect diagnostics that aren't in any of the
|
||||
// special files. This isn't an important use case to support, but also
|
||||
// SmallSet doesn't handle empty strings anyway!
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isUnique = seenFiles.insert(consumerPair.first).second;
|
||||
bool isUnique = seenFiles.insert(subconsumer.getInputFileName()).second;
|
||||
if (!isUnique)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<DiagnosticConsumer>
|
||||
FileSpecificDiagnosticConsumer::consolidateSubconsumers(
|
||||
SmallVectorImpl<Subconsumer> &subconsumers) {
|
||||
if (subconsumers.empty())
|
||||
return nullptr;
|
||||
if (subconsumers.size() == 1)
|
||||
return std::move(subconsumers.front()).consumer;
|
||||
// Cannot use return
|
||||
// llvm::make_unique<FileSpecificDiagnosticConsumer>(subconsumers); because
|
||||
// the constructor is private.
|
||||
return std::unique_ptr<DiagnosticConsumer>(
|
||||
new FileSpecificDiagnosticConsumer(subconsumers));
|
||||
}
|
||||
|
||||
FileSpecificDiagnosticConsumer::FileSpecificDiagnosticConsumer(
|
||||
SmallVectorImpl<ConsumerPair> &consumers)
|
||||
: SubConsumers(std::move(consumers)) {
|
||||
assert(!SubConsumers.empty() &&
|
||||
SmallVectorImpl<Subconsumer> &subconsumers)
|
||||
: Subconsumers(std::move(subconsumers)) {
|
||||
assert(!Subconsumers.empty() &&
|
||||
"don't waste time handling diagnostics that will never get emitted");
|
||||
assert(!hasDuplicateFileNames(SubConsumers) &&
|
||||
"having multiple consumers for the same file is not implemented");
|
||||
assert(!hasDuplicateFileNames(Subconsumers) &&
|
||||
"having multiple subconsumers for the same file is not implemented");
|
||||
}
|
||||
|
||||
void FileSpecificDiagnosticConsumer::computeConsumersOrderedByRange(
|
||||
SourceManager &SM) {
|
||||
// Look up each file's source range and add it to the "map" (to be sorted).
|
||||
for (const ConsumerPair &pair : SubConsumers) {
|
||||
if (pair.first.empty())
|
||||
for (const unsigned subconsumerIndex: indices(Subconsumers)) {
|
||||
const Subconsumer &subconsumer = Subconsumers[subconsumerIndex];
|
||||
if (subconsumer.getInputFileName().empty())
|
||||
continue;
|
||||
|
||||
Optional<unsigned> bufferID = SM.getIDForBufferIdentifier(pair.first);
|
||||
Optional<unsigned> bufferID =
|
||||
SM.getIDForBufferIdentifier(subconsumer.getInputFileName());
|
||||
assert(bufferID.hasValue() && "consumer registered for unknown file");
|
||||
CharSourceRange range = SM.getRangeForBuffer(bufferID.getValue());
|
||||
ConsumersOrderedByRange.emplace_back(
|
||||
ConsumerSpecificInformation(range, pair.second.get()));
|
||||
ConsumerAndRange(range, subconsumerIndex));
|
||||
}
|
||||
|
||||
// Sort the "map" by buffer /end/ location, for use with std::lower_bound
|
||||
// later. (Sorting by start location would produce the same sort, since the
|
||||
// ranges must not be overlapping, but since we need to check end locations
|
||||
// later it's consistent to sort by that here.)
|
||||
std::sort(ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(),
|
||||
[](const ConsumerSpecificInformation &left,
|
||||
const ConsumerSpecificInformation &right) -> bool {
|
||||
auto compare = std::less<const char *>();
|
||||
return compare(getRawLoc(left.range.getEnd()).getPointer(),
|
||||
getRawLoc(right.range.getEnd()).getPointer());
|
||||
});
|
||||
std::sort(ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end());
|
||||
|
||||
// Check that the ranges are non-overlapping. If the files really are all
|
||||
// distinct, this should be trivially true, but if it's ever not we might end
|
||||
@@ -94,16 +104,16 @@ void FileSpecificDiagnosticConsumer::computeConsumersOrderedByRange(
|
||||
assert(ConsumersOrderedByRange.end() ==
|
||||
std::adjacent_find(ConsumersOrderedByRange.begin(),
|
||||
ConsumersOrderedByRange.end(),
|
||||
[](const ConsumerSpecificInformation &left,
|
||||
const ConsumerSpecificInformation &right) {
|
||||
return left.range.overlaps(right.range);
|
||||
[](const ConsumerAndRange &left,
|
||||
const ConsumerAndRange &right) {
|
||||
return left.overlaps(right);
|
||||
}) &&
|
||||
"overlapping ranges despite having distinct files");
|
||||
}
|
||||
|
||||
Optional<FileSpecificDiagnosticConsumer::ConsumerSpecificInformation *>
|
||||
FileSpecificDiagnosticConsumer::consumerSpecificInformationForLocation(
|
||||
SourceManager &SM, SourceLoc loc) const {
|
||||
Optional<FileSpecificDiagnosticConsumer::Subconsumer *>
|
||||
FileSpecificDiagnosticConsumer::subconsumerForLocation(SourceManager &SM,
|
||||
SourceLoc loc) {
|
||||
// Diagnostics with invalid locations always go to every consumer.
|
||||
if (loc.isInvalid())
|
||||
return None;
|
||||
@@ -119,10 +129,12 @@ FileSpecificDiagnosticConsumer::consumerSpecificInformationForLocation(
|
||||
// source buffers are loaded in yet. In that case we return None, rather
|
||||
// than trying to build a nonsensical map (and actually crashing since we
|
||||
// can't find buffers for the inputs).
|
||||
assert(!SubConsumers.empty());
|
||||
if (!SM.getIDForBufferIdentifier(SubConsumers.begin()->first).hasValue()) {
|
||||
assert(llvm::none_of(SubConsumers, [&](const ConsumerPair &pair) {
|
||||
return SM.getIDForBufferIdentifier(pair.first).hasValue();
|
||||
assert(!Subconsumers.empty());
|
||||
if (!SM.getIDForBufferIdentifier(Subconsumers.begin()->getInputFileName())
|
||||
.hasValue()) {
|
||||
assert(llvm::none_of(Subconsumers, [&](const Subconsumer &subconsumer) {
|
||||
return SM.getIDForBufferIdentifier(subconsumer.getInputFileName())
|
||||
.hasValue();
|
||||
}));
|
||||
return None;
|
||||
}
|
||||
@@ -134,19 +146,17 @@ FileSpecificDiagnosticConsumer::consumerSpecificInformationForLocation(
|
||||
// that /might/ contain 'loc'. Specifically, since the ranges are sorted
|
||||
// by end location, it's looking for the first range where the end location
|
||||
// is greater than or equal to 'loc'.
|
||||
const ConsumerSpecificInformation *possiblyContainingRangeIter =
|
||||
std::lower_bound(
|
||||
const ConsumerAndRange *possiblyContainingRangeIter = std::lower_bound(
|
||||
ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(), loc,
|
||||
[](const ConsumerSpecificInformation &entry, SourceLoc loc) -> bool {
|
||||
auto compare = std::less<const char *>();
|
||||
return compare(getRawLoc(entry.range.getEnd()).getPointer(),
|
||||
getRawLoc(loc).getPointer());
|
||||
[](const ConsumerAndRange &entry, SourceLoc loc) -> bool {
|
||||
return entry.endsAfter(loc);
|
||||
});
|
||||
|
||||
if (possiblyContainingRangeIter != ConsumersOrderedByRange.end() &&
|
||||
possiblyContainingRangeIter->range.contains(loc)) {
|
||||
return const_cast<ConsumerSpecificInformation *>(
|
||||
possiblyContainingRangeIter);
|
||||
possiblyContainingRangeIter->contains(loc)) {
|
||||
auto *consumerAndRangeForLocation =
|
||||
const_cast<ConsumerAndRange *>(possiblyContainingRangeIter);
|
||||
return &(*this)[*consumerAndRangeForLocation];
|
||||
}
|
||||
|
||||
return None;
|
||||
@@ -159,34 +169,25 @@ void FileSpecificDiagnosticConsumer::handleDiagnostic(
|
||||
|
||||
HasAnErrorBeenConsumed |= Kind == DiagnosticKind::Error;
|
||||
|
||||
Optional<ConsumerSpecificInformation *> consumerSpecificInfo;
|
||||
Optional<FileSpecificDiagnosticConsumer::Subconsumer *> subconsumer;
|
||||
switch (Kind) {
|
||||
case DiagnosticKind::Error:
|
||||
case DiagnosticKind::Warning:
|
||||
case DiagnosticKind::Remark:
|
||||
consumerSpecificInfo = consumerSpecificInformationForLocation(SM, Loc);
|
||||
ConsumerSpecificInfoForSubsequentNotes = consumerSpecificInfo;
|
||||
subconsumer = subconsumerForLocation(SM, Loc);
|
||||
SubconsumerForSubsequentNotes = subconsumer;
|
||||
break;
|
||||
case DiagnosticKind::Note:
|
||||
consumerSpecificInfo = ConsumerSpecificInfoForSubsequentNotes;
|
||||
subconsumer = SubconsumerForSubsequentNotes;
|
||||
break;
|
||||
}
|
||||
if (!consumerSpecificInfo.hasValue()) {
|
||||
for (auto &subConsumer : SubConsumers) {
|
||||
if (subConsumer.second) {
|
||||
subConsumer.second->handleDiagnostic(SM, Loc, Kind, FormatString,
|
||||
if (subconsumer.hasValue()) {
|
||||
subconsumer.getValue()->handleDiagnostic(SM, Loc, Kind, FormatString,
|
||||
FormatArgs, Info);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!consumerSpecificInfo.getValue()->consumer)
|
||||
return; // Suppress non-primary diagnostic in batch mode.
|
||||
|
||||
consumerSpecificInfo.getValue()->consumer->handleDiagnostic(
|
||||
SM, Loc, Kind, FormatString, FormatArgs, Info);
|
||||
consumerSpecificInfo.getValue()->hasAnErrorBeenEmitted |=
|
||||
Kind == DiagnosticKind::Error;
|
||||
for (auto &subconsumer : Subconsumers)
|
||||
subconsumer.handleDiagnostic(SM, Loc, Kind, FormatString, FormatArgs, Info);
|
||||
}
|
||||
|
||||
bool FileSpecificDiagnosticConsumer::finishProcessing() {
|
||||
@@ -196,19 +197,18 @@ bool FileSpecificDiagnosticConsumer::finishProcessing() {
|
||||
// behavior.
|
||||
|
||||
bool hadError = false;
|
||||
for (auto &subConsumer : SubConsumers)
|
||||
hadError |= subConsumer.second && subConsumer.second->finishProcessing();
|
||||
for (auto &subconsumer : Subconsumers)
|
||||
hadError |= subconsumer.getConsumer() &&
|
||||
subconsumer.getConsumer()->finishProcessing();
|
||||
return hadError;
|
||||
}
|
||||
|
||||
void FileSpecificDiagnosticConsumer::
|
||||
tellSubconsumersToInformDriverOfIncompleteBatchModeCompilation() const {
|
||||
tellSubconsumersToInformDriverOfIncompleteBatchModeCompilation() {
|
||||
if (!HasAnErrorBeenConsumed)
|
||||
return;
|
||||
for (auto &info : ConsumersOrderedByRange) {
|
||||
if (!info.hasAnErrorBeenEmitted && info.consumer)
|
||||
info.consumer->informDriverOfIncompleteBatchModeCompilation();
|
||||
}
|
||||
for (auto &info : ConsumersOrderedByRange)
|
||||
(*this)[info].informDriverOfIncompleteBatchModeCompilation();
|
||||
}
|
||||
|
||||
void NullDiagnosticConsumer::handleDiagnostic(
|
||||
|
||||
@@ -1587,7 +1587,7 @@ static std::unique_ptr<DiagnosticConsumer>
|
||||
createDispatchingDiagnosticConsumerIfNeeded(
|
||||
const FrontendInputsAndOutputs &inputsAndOutputs,
|
||||
llvm::function_ref<std::unique_ptr<DiagnosticConsumer>(const InputFile &)>
|
||||
maybeCreateSingleConsumer) {
|
||||
maybeCreateConsumerForDiagnosticsFrom) {
|
||||
|
||||
// The "4" here is somewhat arbitrary. In practice we're going to have one
|
||||
// sub-consumer for each diagnostic file we're trying to output, which (again
|
||||
@@ -1597,12 +1597,12 @@ createDispatchingDiagnosticConsumerIfNeeded(
|
||||
// So a value of "4" here means that there would be no heap allocation on a
|
||||
// clean build of a module with up to 32 files on an 8-core machine, if the
|
||||
// user doesn't customize anything.
|
||||
SmallVector<FileSpecificDiagnosticConsumer::ConsumerPair, 4> subConsumers;
|
||||
SmallVector<FileSpecificDiagnosticConsumer::Subconsumer, 4> subconsumers;
|
||||
|
||||
inputsAndOutputs.forEachInputProducingSupplementaryOutput(
|
||||
[&](const InputFile &input) -> bool {
|
||||
if (auto subConsumer = maybeCreateSingleConsumer(input))
|
||||
subConsumers.emplace_back(input.file(), std::move(subConsumer));
|
||||
if (auto consumer = maybeCreateConsumerForDiagnosticsFrom(input))
|
||||
subconsumers.emplace_back(input.file(), std::move(consumer));
|
||||
return false;
|
||||
});
|
||||
// For batch mode, the compiler must swallow diagnostics pertaining to
|
||||
@@ -1614,16 +1614,12 @@ createDispatchingDiagnosticConsumerIfNeeded(
|
||||
if (inputsAndOutputs.hasMultiplePrimaryInputs()) {
|
||||
inputsAndOutputs.forEachNonPrimaryInput(
|
||||
[&](const InputFile &input) -> bool {
|
||||
subConsumers.emplace_back(input.file(), nullptr);
|
||||
subconsumers.emplace_back(input.file(), nullptr);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (subConsumers.empty())
|
||||
return nullptr;
|
||||
if (subConsumers.size() == 1)
|
||||
return std::move(subConsumers.front()).second;
|
||||
return llvm::make_unique<FileSpecificDiagnosticConsumer>(subConsumers);
|
||||
return FileSpecificDiagnosticConsumer::consolidateSubconsumers(subconsumers);
|
||||
}
|
||||
|
||||
/// Creates a diagnostic consumer that handles serializing diagnostics, based on
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace {
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
TEST(FileSpecificDiagnosticConsumer, SubConsumersFinishInOrder) {
|
||||
TEST(FileSpecificDiagnosticConsumer, SubconsumersFinishInOrder) {
|
||||
SourceManager sourceMgr;
|
||||
(void)sourceMgr.addMemBufferCopy("abcde", "A");
|
||||
(void)sourceMgr.addMemBufferCopy("vwxyz", "B");
|
||||
@@ -63,12 +63,13 @@ TEST(FileSpecificDiagnosticConsumer, SubConsumersFinishInOrder) {
|
||||
auto consumerUnaffiliated = llvm::make_unique<ExpectationDiagnosticConsumer>(
|
||||
consumerA.get(), None);
|
||||
|
||||
SmallVector<FileSpecificDiagnosticConsumer::ConsumerPair, 2> consumers;
|
||||
SmallVector<FileSpecificDiagnosticConsumer::Subconsumer, 2> consumers;
|
||||
consumers.emplace_back("A", std::move(consumerA));
|
||||
consumers.emplace_back("", std::move(consumerUnaffiliated));
|
||||
|
||||
FileSpecificDiagnosticConsumer topConsumer(consumers);
|
||||
topConsumer.finishProcessing();
|
||||
auto topConsumer =
|
||||
FileSpecificDiagnosticConsumer::consolidateSubconsumers(consumers);
|
||||
topConsumer->finishProcessing();
|
||||
}
|
||||
|
||||
TEST(FileSpecificDiagnosticConsumer, InvalidLocDiagsGoToEveryConsumer) {
|
||||
@@ -82,14 +83,15 @@ TEST(FileSpecificDiagnosticConsumer, InvalidLocDiagsGoToEveryConsumer) {
|
||||
auto consumerUnaffiliated = llvm::make_unique<ExpectationDiagnosticConsumer>(
|
||||
consumerA.get(), expected);
|
||||
|
||||
SmallVector<FileSpecificDiagnosticConsumer::ConsumerPair, 2> consumers;
|
||||
SmallVector<FileSpecificDiagnosticConsumer::Subconsumer, 2> consumers;
|
||||
consumers.emplace_back("A", std::move(consumerA));
|
||||
consumers.emplace_back("", std::move(consumerUnaffiliated));
|
||||
|
||||
FileSpecificDiagnosticConsumer topConsumer(consumers);
|
||||
topConsumer.handleDiagnostic(sourceMgr, SourceLoc(), DiagnosticKind::Error,
|
||||
auto topConsumer =
|
||||
FileSpecificDiagnosticConsumer::consolidateSubconsumers(consumers);
|
||||
topConsumer->handleDiagnostic(sourceMgr, SourceLoc(), DiagnosticKind::Error,
|
||||
"dummy", {}, DiagnosticInfo());
|
||||
topConsumer.finishProcessing();
|
||||
topConsumer->finishProcessing();
|
||||
}
|
||||
|
||||
TEST(FileSpecificDiagnosticConsumer, ErrorsWithLocationsGoToExpectedConsumers) {
|
||||
@@ -122,24 +124,25 @@ TEST(FileSpecificDiagnosticConsumer, ErrorsWithLocationsGoToExpectedConsumers) {
|
||||
auto consumerB = llvm::make_unique<ExpectationDiagnosticConsumer>(
|
||||
consumerA.get(), expectedB);
|
||||
|
||||
SmallVector<FileSpecificDiagnosticConsumer::ConsumerPair, 2> consumers;
|
||||
SmallVector<FileSpecificDiagnosticConsumer::Subconsumer, 2> consumers;
|
||||
consumers.emplace_back("A", std::move(consumerA));
|
||||
consumers.emplace_back("B", std::move(consumerB));
|
||||
|
||||
FileSpecificDiagnosticConsumer topConsumer(consumers);
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
auto topConsumer =
|
||||
FileSpecificDiagnosticConsumer::consolidateSubconsumers(consumers);
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
"front", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Error,
|
||||
"front", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Error,
|
||||
"middle", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Error,
|
||||
"middle", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Error,
|
||||
"back", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfB, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfB, DiagnosticKind::Error,
|
||||
"back", {}, DiagnosticInfo());
|
||||
topConsumer.finishProcessing();
|
||||
topConsumer->finishProcessing();
|
||||
}
|
||||
|
||||
TEST(FileSpecificDiagnosticConsumer,
|
||||
@@ -176,24 +179,25 @@ TEST(FileSpecificDiagnosticConsumer,
|
||||
auto consumerUnaffiliated = llvm::make_unique<ExpectationDiagnosticConsumer>(
|
||||
consumerA.get(), expectedUnaffiliated);
|
||||
|
||||
SmallVector<FileSpecificDiagnosticConsumer::ConsumerPair, 2> consumers;
|
||||
SmallVector<FileSpecificDiagnosticConsumer::Subconsumer, 2> consumers;
|
||||
consumers.emplace_back("A", std::move(consumerA));
|
||||
consumers.emplace_back("", std::move(consumerUnaffiliated));
|
||||
|
||||
FileSpecificDiagnosticConsumer topConsumer(consumers);
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
auto topConsumer =
|
||||
FileSpecificDiagnosticConsumer::consolidateSubconsumers(consumers);
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
"front", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Error,
|
||||
"front", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Error,
|
||||
"middle", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Error,
|
||||
"middle", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Error,
|
||||
"back", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfB, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfB, DiagnosticKind::Error,
|
||||
"back", {}, DiagnosticInfo());
|
||||
topConsumer.finishProcessing();
|
||||
topConsumer->finishProcessing();
|
||||
}
|
||||
|
||||
TEST(FileSpecificDiagnosticConsumer, WarningsAndRemarksAreTreatedLikeErrors) {
|
||||
@@ -221,20 +225,21 @@ TEST(FileSpecificDiagnosticConsumer, WarningsAndRemarksAreTreatedLikeErrors) {
|
||||
auto consumerUnaffiliated = llvm::make_unique<ExpectationDiagnosticConsumer>(
|
||||
consumerA.get(), expectedUnaffiliated);
|
||||
|
||||
SmallVector<FileSpecificDiagnosticConsumer::ConsumerPair, 2> consumers;
|
||||
SmallVector<FileSpecificDiagnosticConsumer::Subconsumer, 2> consumers;
|
||||
consumers.emplace_back("A", std::move(consumerA));
|
||||
consumers.emplace_back("", std::move(consumerUnaffiliated));
|
||||
|
||||
FileSpecificDiagnosticConsumer topConsumer(consumers);
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Warning,
|
||||
auto topConsumer =
|
||||
FileSpecificDiagnosticConsumer::consolidateSubconsumers(consumers);
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Warning,
|
||||
"warning", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Warning,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Warning,
|
||||
"warning", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Remark,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Remark,
|
||||
"remark", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Remark,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Remark,
|
||||
"remark", {}, DiagnosticInfo());
|
||||
topConsumer.finishProcessing();
|
||||
topConsumer->finishProcessing();
|
||||
}
|
||||
|
||||
TEST(FileSpecificDiagnosticConsumer, NotesAreAttachedToErrors) {
|
||||
@@ -273,30 +278,31 @@ TEST(FileSpecificDiagnosticConsumer, NotesAreAttachedToErrors) {
|
||||
auto consumerUnaffiliated = llvm::make_unique<ExpectationDiagnosticConsumer>(
|
||||
consumerA.get(), expectedUnaffiliated);
|
||||
|
||||
SmallVector<FileSpecificDiagnosticConsumer::ConsumerPair, 2> consumers;
|
||||
SmallVector<FileSpecificDiagnosticConsumer::Subconsumer, 2> consumers;
|
||||
consumers.emplace_back("A", std::move(consumerA));
|
||||
consumers.emplace_back("", std::move(consumerUnaffiliated));
|
||||
|
||||
FileSpecificDiagnosticConsumer topConsumer(consumers);
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
auto topConsumer =
|
||||
FileSpecificDiagnosticConsumer::consolidateSubconsumers(consumers);
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
"error", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Error,
|
||||
"error", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfB, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfB, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
"error", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.finishProcessing();
|
||||
topConsumer->finishProcessing();
|
||||
}
|
||||
|
||||
TEST(FileSpecificDiagnosticConsumer, NotesAreAttachedToWarningsAndRemarks) {
|
||||
@@ -335,30 +341,31 @@ TEST(FileSpecificDiagnosticConsumer, NotesAreAttachedToWarningsAndRemarks) {
|
||||
auto consumerUnaffiliated = llvm::make_unique<ExpectationDiagnosticConsumer>(
|
||||
consumerA.get(), expectedUnaffiliated);
|
||||
|
||||
SmallVector<FileSpecificDiagnosticConsumer::ConsumerPair, 2> consumers;
|
||||
SmallVector<FileSpecificDiagnosticConsumer::Subconsumer, 2> consumers;
|
||||
consumers.emplace_back("A", std::move(consumerA));
|
||||
consumers.emplace_back("", std::move(consumerUnaffiliated));
|
||||
|
||||
FileSpecificDiagnosticConsumer topConsumer(consumers);
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Warning,
|
||||
auto topConsumer =
|
||||
FileSpecificDiagnosticConsumer::consolidateSubconsumers(consumers);
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Warning,
|
||||
"warning", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Warning,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Warning,
|
||||
"warning", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfB, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfB, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Remark,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Remark,
|
||||
"remark", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.finishProcessing();
|
||||
topConsumer->finishProcessing();
|
||||
}
|
||||
|
||||
TEST(FileSpecificDiagnosticConsumer, NotesAreAttachedToErrorsEvenAcrossFiles) {
|
||||
@@ -394,30 +401,31 @@ TEST(FileSpecificDiagnosticConsumer, NotesAreAttachedToErrorsEvenAcrossFiles) {
|
||||
auto consumerB = llvm::make_unique<ExpectationDiagnosticConsumer>(
|
||||
consumerA.get(), expectedB);
|
||||
|
||||
SmallVector<FileSpecificDiagnosticConsumer::ConsumerPair, 2> consumers;
|
||||
SmallVector<FileSpecificDiagnosticConsumer::Subconsumer, 2> consumers;
|
||||
consumers.emplace_back("A", std::move(consumerA));
|
||||
consumers.emplace_back("B", std::move(consumerB));
|
||||
|
||||
FileSpecificDiagnosticConsumer topConsumer(consumers);
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
auto topConsumer =
|
||||
FileSpecificDiagnosticConsumer::consolidateSubconsumers(consumers);
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
"error", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Error,
|
||||
"error", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfB, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfB, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
"error", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.finishProcessing();
|
||||
topConsumer->finishProcessing();
|
||||
}
|
||||
|
||||
TEST(FileSpecificDiagnosticConsumer,
|
||||
@@ -457,30 +465,31 @@ TEST(FileSpecificDiagnosticConsumer,
|
||||
auto consumerUnaffiliated = llvm::make_unique<ExpectationDiagnosticConsumer>(
|
||||
consumerA.get(), expectedUnaffiliated);
|
||||
|
||||
SmallVector<FileSpecificDiagnosticConsumer::ConsumerPair, 2> consumers;
|
||||
SmallVector<FileSpecificDiagnosticConsumer::Subconsumer, 2> consumers;
|
||||
consumers.emplace_back("A", std::move(consumerA));
|
||||
consumers.emplace_back("", std::move(consumerUnaffiliated));
|
||||
|
||||
FileSpecificDiagnosticConsumer topConsumer(consumers);
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
auto topConsumer =
|
||||
FileSpecificDiagnosticConsumer::consolidateSubconsumers(consumers);
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
"error", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Error,
|
||||
"error", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfB, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfB, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
"error", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, middleOfB, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, backOfA, DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.finishProcessing();
|
||||
topConsumer->finishProcessing();
|
||||
}
|
||||
|
||||
|
||||
@@ -512,22 +521,23 @@ TEST(FileSpecificDiagnosticConsumer,
|
||||
auto consumerUnaffiliated = llvm::make_unique<ExpectationDiagnosticConsumer>(
|
||||
consumerA.get(), expectedUnaffiliated);
|
||||
|
||||
SmallVector<FileSpecificDiagnosticConsumer::ConsumerPair, 2> consumers;
|
||||
SmallVector<FileSpecificDiagnosticConsumer::Subconsumer, 2> consumers;
|
||||
consumers.emplace_back("A", std::move(consumerA));
|
||||
consumers.emplace_back("", std::move(consumerUnaffiliated));
|
||||
|
||||
FileSpecificDiagnosticConsumer topConsumer(consumers);
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
auto topConsumer =
|
||||
FileSpecificDiagnosticConsumer::consolidateSubconsumers(consumers);
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
"error", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, SourceLoc(), DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, SourceLoc(), DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfB, DiagnosticKind::Error,
|
||||
"error", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, SourceLoc(), DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, SourceLoc(), DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
topConsumer->handleDiagnostic(sourceMgr, frontOfA, DiagnosticKind::Error,
|
||||
"error", {}, DiagnosticInfo());
|
||||
topConsumer.handleDiagnostic(sourceMgr, SourceLoc(), DiagnosticKind::Note,
|
||||
topConsumer->handleDiagnostic(sourceMgr, SourceLoc(), DiagnosticKind::Note,
|
||||
"note", {}, DiagnosticInfo());
|
||||
topConsumer.finishProcessing();
|
||||
topConsumer->finishProcessing();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user