TextDiagnosticPrinter.cpp [plain text]
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnostic.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/ADT/SmallString.h"
#include <algorithm>
using namespace clang;
TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os,
const DiagnosticOptions &diags,
bool _OwnsOutputStream)
: OS(os), LangOpts(0), DiagOpts(&diags), SM(0),
OwnsOutputStream(_OwnsOutputStream) {
}
TextDiagnosticPrinter::~TextDiagnosticPrinter() {
if (OwnsOutputStream)
delete &OS;
}
void TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
const Preprocessor *PP) {
LangOpts = &LO;
}
void TextDiagnosticPrinter::EndSourceFile() {
LangOpts = 0;
TextDiag.reset(0);
}
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;
}
bool EnabledByDefault;
if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(),
EnabledByDefault) &&
!EnabledByDefault) {
OS << (Started ? "," : " [") << "-pedantic";
Started = true;
}
StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
if (!Opt.empty()) {
OS << (Started ? "," : " [") << "-W" << Opt;
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, DiagMessageStream.str(),
OS.tell() - StartOfLocationInfo,
DiagOpts->MessageLength,
DiagOpts->ShowColors);
OS.flush();
return;
}
assert(LangOpts && "Unexpected diagnostic outside source file processing");
assert(DiagOpts && "Unexpected diagnostic without options set");
assert(Info.hasSourceManager() &&
"Unexpected diagnostic with no source manager");
if (!TextDiag || SM != &Info.getSourceManager()) {
SM = &Info.getSourceManager();
TextDiag.reset(new TextDiagnostic(OS, *SM, *LangOpts, *DiagOpts));
}
TextDiag->emitDiagnostic(Info.getLocation(), Level, DiagMessageStream.str(),
Info.getRanges(),
llvm::makeArrayRef(Info.getFixItHints(),
Info.getNumFixItHints()));
OS.flush();
}
DiagnosticConsumer *
TextDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const {
return new TextDiagnosticPrinter(OS, *DiagOpts, false);
}