#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/TextDiagnostic.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace clang;
TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os,
DiagnosticOptions *diags,
bool _OwnsOutputStream)
: OS(os), DiagOpts(diags),
OwnsOutputStream(_OwnsOutputStream) {
}
TextDiagnosticPrinter::~TextDiagnosticPrinter() {
if (OwnsOutputStream)
delete &OS;
}
void TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
const Preprocessor *PP) {
TextDiag.reset(new TextDiagnostic(OS, LO, &*DiagOpts));
}
void TextDiagnosticPrinter::EndSourceFile() {
TextDiag.reset();
}
static void printDiagnosticOptions(raw_ostream &OS,
DiagnosticsEngine::Level Level,
const Diagnostic &Info,
const DiagnosticOptions &DiagOpts) {
bool Started = false;
if (DiagOpts.ShowOptionNames) {
if (Info.getID() == diag::fatal_too_many_errors) {
OS << " [-ferror-limit=]";
return;
}
if (Level == DiagnosticsEngine::Error &&
DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID()) &&
!DiagnosticIDs::isDefaultMappingAsError(Info.getID())) {
OS << " [-Werror";
Started = true;
}
StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
if (!Opt.empty()) {
OS << (Started ? "," : " [")
<< (Level == DiagnosticsEngine::Remark ? "-R" : "-W") << Opt;
StringRef OptValue = Info.getDiags()->getFlagValue();
if (!OptValue.empty())
OS << "=" << OptValue;
Started = true;
}
}
if (DiagOpts.ShowCategories) {
unsigned DiagCategory =
DiagnosticIDs::getCategoryNumberForDiag(Info.getID());
if (DiagCategory) {
OS << (Started ? "," : " [");
Started = true;
if (DiagOpts.ShowCategories == 1)
OS << DiagCategory;
else {
assert(DiagOpts.ShowCategories == 2 && "Invalid ShowCategories value");
OS << DiagnosticIDs::getCategoryNameFromID(DiagCategory);
}
}
}
if (Started)
OS << ']';
}
void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
const Diagnostic &Info) {
DiagnosticConsumer::HandleDiagnostic(Level, Info);
SmallString<100> OutStr;
Info.FormatDiagnostic(OutStr);
llvm::raw_svector_ostream DiagMessageStream(OutStr);
printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts);
uint64_t StartOfLocationInfo = OS.tell();
if (!Prefix.empty())
OS << Prefix << ": ";
if (!Info.getLocation().isValid()) {
TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
TextDiagnostic::printDiagnosticMessage(
OS, Level == DiagnosticsEngine::Note,
DiagMessageStream.str(), OS.tell() - StartOfLocationInfo,
DiagOpts->MessageLength, DiagOpts->ShowColors);
OS.flush();
return;
}
assert(DiagOpts && "Unexpected diagnostic without options set");
assert(Info.hasSourceManager() &&
"Unexpected diagnostic with no source manager");
assert(TextDiag && "Unexpected diagnostic outside source file processing");
TextDiag->emitDiagnostic(
FullSourceLoc(Info.getLocation(), Info.getSourceManager()), Level,
DiagMessageStream.str(), Info.getRanges(), Info.getFixItHints());
OS.flush();
}