factoring and commenting

This commit is contained in:
David Ungar
2018-08-03 09:10:43 -07:00
parent b4b3b0fcec
commit cb3af7c0d4
3 changed files with 93 additions and 43 deletions

View File

@@ -136,41 +136,57 @@ public:
/// current file. /// current file.
class FileSpecificDiagnosticConsumer : public DiagnosticConsumer { class FileSpecificDiagnosticConsumer : public DiagnosticConsumer {
public: public:
class Subconsumer;
/// 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 /// A diagnostic consumer, along with the name of the buffer that it should
/// be associated with. /// be associated with.
class Subconsumer { class Subconsumer {
public: friend std::unique_ptr<DiagnosticConsumer> FileSpecificDiagnosticConsumer::consolidateSubconsumers(SmallVectorImpl<Subconsumer> &subconsumers);
/// The name of the buffer that a consumer should
/// The name of the input file that a consumer and diagnostics should
/// be associated with. An empty string means that a consumer is not /// be associated with. An empty string means that a consumer is not
/// associated with any particular buffer, and should only receive /// associated with any particular buffer, and should only receive
/// diagnostics that are not in any of the other consumers' files. /// diagnostics that are not in any of the other consumers' files.
std::string bufferName; std::string inputFileName;
/// The consumer (if any) for diagnostics associated with the inputFileName.
/// A null pointer for the DiagnosticConsumer means that diagnostics for /// A null pointer for the DiagnosticConsumer means that diagnostics for
/// this file should not be emitted. /// this file should not be emitted.
std::unique_ptr<DiagnosticConsumer> consumer; std::unique_ptr<DiagnosticConsumer> consumer;
// Has this subconsumer ever handled a diagnostic that is an error? // Has this subconsumer ever handled a diagnostic that is an error?
bool handledError = false; bool hasAnErrorBeenConsumed = false;
Subconsumer(std::string bufferName,
public:
std::string getInputFileName() const { return inputFileName; }
DiagnosticConsumer *getConsumer() const { return consumer.get(); }
Subconsumer(std::string inputFileName,
std::unique_ptr<DiagnosticConsumer> consumer) std::unique_ptr<DiagnosticConsumer> consumer)
: bufferName(bufferName), consumer(std::move(consumer)) {} : inputFileName(inputFileName), consumer(std::move(consumer)) {}
void handleDiagnostic(SourceManager &SM, SourceLoc Loc, void handleDiagnostic(SourceManager &SM, SourceLoc Loc,
DiagnosticKind Kind, DiagnosticKind Kind,
StringRef FormatString, StringRef FormatString,
ArrayRef<DiagnosticArgument> FormatArgs, ArrayRef<DiagnosticArgument> FormatArgs,
const DiagnosticInfo &Info) { const DiagnosticInfo &Info) {
if (!consumer) if (!getConsumer())
return; // Suppress non-primary diagnostic in batch mode. return; // Suppress non-primary diagnostic in batch mode.
handledError |= Kind == DiagnosticKind::Error; hasAnErrorBeenConsumed |= Kind == DiagnosticKind::Error;
consumer.get()->handleDiagnostic(SM, Loc, Kind, FormatString, FormatArgs, Info); getConsumer()->handleDiagnostic(SM, Loc, Kind, FormatString, FormatArgs, Info);
} }
void informDriverOfIncompleteBatchModeCompilation() { void informDriverOfIncompleteBatchModeCompilation() {
if (!handledError && consumer) if (!hasAnErrorBeenConsumed && getConsumer())
consumer.get()->informDriverOfIncompleteBatchModeCompilation(); getConsumer()->informDriverOfIncompleteBatchModeCompilation();
} }
}; };
@@ -181,12 +197,16 @@ private:
public: public:
// The commented-out consts are there because the data does not change // The commented-out consts are there because the data does not change
// but the swap method gets called on this structure. // but the swap method gets called on this structure.
struct ConsumerSpecificInformation { class ConsumerSpecificInformation {
private:
/// The range of SourceLoc's for which diagnostics should be directed to
/// this subconsumer.
/*const*/ CharSourceRange range; /*const*/ CharSourceRange range;
/// Index into Subconsumers vector. /// Index into Subconsumers vector for this subconsumer.
unsigned subconsumerIndex; /*const*/ unsigned subconsumerIndex;
public:
ConsumerSpecificInformation(const CharSourceRange range, ConsumerSpecificInformation(const CharSourceRange range,
unsigned subconsumerIndex) unsigned subconsumerIndex)
: range(range), subconsumerIndex(subconsumerIndex) {} : range(range), subconsumerIndex(subconsumerIndex) {}
@@ -194,6 +214,29 @@ public:
Subconsumer &subconsumer(FileSpecificDiagnosticConsumer &c) const { Subconsumer &subconsumer(FileSpecificDiagnosticConsumer &c) const {
return c.Subconsumers[subconsumerIndex]; return c.Subconsumers[subconsumerIndex];
} }
/// Compare according to range:
bool operator < (const ConsumerSpecificInformation &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 ConsumerSpecificInformation &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: private:
@@ -220,7 +263,7 @@ private:
bool HasAnErrorBeenConsumed = false; bool HasAnErrorBeenConsumed = false;
public:
/// Takes ownership of the DiagnosticConsumers specified in \p consumers. /// Takes ownership of the DiagnosticConsumers specified in \p consumers.
/// ///
/// There must not be two consumers for the same file (i.e., having the same /// There must not be two consumers for the same file (i.e., having the same
@@ -228,6 +271,10 @@ public:
explicit FileSpecificDiagnosticConsumer( explicit FileSpecificDiagnosticConsumer(
SmallVectorImpl<Subconsumer> &consumers); SmallVectorImpl<Subconsumer> &consumers);
public:
void handleDiagnostic(SourceManager &SM, SourceLoc Loc, void handleDiagnostic(SourceManager &SM, SourceLoc Loc,
DiagnosticKind Kind, DiagnosticKind Kind,
StringRef FormatString, StringRef FormatString,

View File

@@ -38,7 +38,7 @@ static bool hasDuplicateFileNames(
ArrayRef<FileSpecificDiagnosticConsumer::Subconsumer> subconsumers) { ArrayRef<FileSpecificDiagnosticConsumer::Subconsumer> subconsumers) {
llvm::StringSet<> seenFiles; llvm::StringSet<> seenFiles;
for (const auto &subconsumer : subconsumers) { for (const auto &subconsumer : subconsumers) {
if (subconsumer.bufferName.empty()) { if (subconsumer.getInputFileName().empty()) {
// We can handle multiple subconsumers that aren't associated with any // We can handle multiple subconsumers that aren't associated with any
// file, because they only collect diagnostics that aren't in any of the // 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 // special files. This isn't an important use case to support, but also
@@ -46,13 +46,24 @@ static bool hasDuplicateFileNames(
continue; continue;
} }
bool isUnique = seenFiles.insert(subconsumer.bufferName).second; bool isUnique = seenFiles.insert(subconsumer.getInputFileName()).second;
if (!isUnique) if (!isUnique)
return true; return true;
} }
return false; 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( FileSpecificDiagnosticConsumer::FileSpecificDiagnosticConsumer(
SmallVectorImpl<Subconsumer> &subconsumers) SmallVectorImpl<Subconsumer> &subconsumers)
: Subconsumers(std::move(subconsumers)) { : Subconsumers(std::move(subconsumers)) {
@@ -67,11 +78,11 @@ void FileSpecificDiagnosticConsumer::computeConsumersOrderedByRange(
// Look up each file's source range and add it to the "map" (to be sorted). // Look up each file's source range and add it to the "map" (to be sorted).
for (const unsigned subconsumerIndex: indices(Subconsumers)) { for (const unsigned subconsumerIndex: indices(Subconsumers)) {
const Subconsumer &subconsumer = Subconsumers[subconsumerIndex]; const Subconsumer &subconsumer = Subconsumers[subconsumerIndex];
if (subconsumer.bufferName.empty()) if (subconsumer.getInputFileName().empty())
continue; continue;
Optional<unsigned> bufferID = Optional<unsigned> bufferID =
SM.getIDForBufferIdentifier(subconsumer.bufferName); SM.getIDForBufferIdentifier(subconsumer.getInputFileName());
assert(bufferID.hasValue() && "consumer registered for unknown file"); assert(bufferID.hasValue() && "consumer registered for unknown file");
CharSourceRange range = SM.getRangeForBuffer(bufferID.getValue()); CharSourceRange range = SM.getRangeForBuffer(bufferID.getValue());
ConsumersOrderedByRange.emplace_back( ConsumersOrderedByRange.emplace_back(
@@ -85,9 +96,7 @@ void FileSpecificDiagnosticConsumer::computeConsumersOrderedByRange(
std::sort(ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(), std::sort(ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(),
[](const ConsumerSpecificInformation &left, [](const ConsumerSpecificInformation &left,
const ConsumerSpecificInformation &right) -> bool { const ConsumerSpecificInformation &right) -> bool {
auto compare = std::less<const char *>(); return left < right;
return compare(getRawLoc(left.range.getEnd()).getPointer(),
getRawLoc(right.range.getEnd()).getPointer());
}); });
// Check that the ranges are non-overlapping. If the files really are all // Check that the ranges are non-overlapping. If the files really are all
@@ -98,7 +107,7 @@ void FileSpecificDiagnosticConsumer::computeConsumersOrderedByRange(
ConsumersOrderedByRange.end(), ConsumersOrderedByRange.end(),
[](const ConsumerSpecificInformation &left, [](const ConsumerSpecificInformation &left,
const ConsumerSpecificInformation &right) { const ConsumerSpecificInformation &right) {
return left.range.overlaps(right.range); return left.overlaps(right);
}) && }) &&
"overlapping ranges despite having distinct files"); "overlapping ranges despite having distinct files");
} }
@@ -122,10 +131,10 @@ FileSpecificDiagnosticConsumer::consumerSpecificInformationForLocation(
// than trying to build a nonsensical map (and actually crashing since we // than trying to build a nonsensical map (and actually crashing since we
// can't find buffers for the inputs). // can't find buffers for the inputs).
assert(!Subconsumers.empty()); assert(!Subconsumers.empty());
if (!SM.getIDForBufferIdentifier(Subconsumers.begin()->bufferName) if (!SM.getIDForBufferIdentifier(Subconsumers.begin()->getInputFileName())
.hasValue()) { .hasValue()) {
assert(llvm::none_of(Subconsumers, [&](const Subconsumer &subconsumer) { assert(llvm::none_of(Subconsumers, [&](const Subconsumer &subconsumer) {
return SM.getIDForBufferIdentifier(subconsumer.bufferName).hasValue(); return SM.getIDForBufferIdentifier(subconsumer.getInputFileName()).hasValue();
})); }));
return None; return None;
} }
@@ -141,13 +150,11 @@ FileSpecificDiagnosticConsumer::consumerSpecificInformationForLocation(
std::lower_bound( std::lower_bound(
ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(), loc, ConsumersOrderedByRange.begin(), ConsumersOrderedByRange.end(), loc,
[](const ConsumerSpecificInformation &entry, SourceLoc loc) -> bool { [](const ConsumerSpecificInformation &entry, SourceLoc loc) -> bool {
auto compare = std::less<const char *>(); return entry.endsAfter(loc);
return compare(getRawLoc(entry.range.getEnd()).getPointer(),
getRawLoc(loc).getPointer());
}); });
if (possiblyContainingRangeIter != ConsumersOrderedByRange.end() && if (possiblyContainingRangeIter != ConsumersOrderedByRange.end() &&
possiblyContainingRangeIter->range.contains(loc)) { possiblyContainingRangeIter->contains(loc)) {
return const_cast<ConsumerSpecificInformation *>( return const_cast<ConsumerSpecificInformation *>(
possiblyContainingRangeIter); possiblyContainingRangeIter);
} }
@@ -191,7 +198,7 @@ bool FileSpecificDiagnosticConsumer::finishProcessing() {
bool hadError = false; bool hadError = false;
for (auto &subconsumer : Subconsumers) for (auto &subconsumer : Subconsumers)
hadError |= hadError |=
subconsumer.consumer && subconsumer.consumer->finishProcessing(); subconsumer.getConsumer() && subconsumer.getConsumer()->finishProcessing();
return hadError; return hadError;
} }

View File

@@ -1619,11 +1619,7 @@ createDispatchingDiagnosticConsumerIfNeeded(
}); });
} }
if (subconsumers.empty()) return FileSpecificDiagnosticConsumer::consolidateSubconsumers(subconsumers);
return nullptr;
if (subconsumers.size() == 1)
return std::move(subconsumers.front()).consumer;
return llvm::make_unique<FileSpecificDiagnosticConsumer>(subconsumers);
} }
/// Creates a diagnostic consumer that handles serializing diagnostics, based on /// Creates a diagnostic consumer that handles serializing diagnostics, based on