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:
David Ungar
2018-08-06 22:04:36 -07:00
committed by GitHub
4 changed files with 345 additions and 263 deletions

View File

@@ -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

View File

@@ -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(

View File

@@ -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

View File

@@ -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();
}