mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-12 19:38:50 +00:00

It's also possible to just write "= nullptr", but there's some question of whether that's as readable, so I leave it up to authors to pick which they prefer for now. If we want to discuss standardizing on one or the other, we can do that at some point in the future. llvm-svn: 213439
162 lines
6.2 KiB
C++
162 lines
6.2 KiB
C++
//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This diagnostic client prints out their diagnostic messages.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
|
#include "clang/Basic/DiagnosticOptions.h"
|
|
#include "clang/Basic/FileManager.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/MemoryBuffer.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) {
|
|
// Build the TextDiagnostic utility.
|
|
TextDiag.reset(new TextDiagnostic(OS, LO, &*DiagOpts));
|
|
}
|
|
|
|
void TextDiagnosticPrinter::EndSourceFile() {
|
|
TextDiag.reset();
|
|
}
|
|
|
|
/// \brief Print any diagnostic option information to a raw_ostream.
|
|
///
|
|
/// This implements all of the logic for adding diagnostic options to a message
|
|
/// (via OS). Each relevant option is comma separated and all are enclosed in
|
|
/// the standard bracketing: " [...]".
|
|
static void printDiagnosticOptions(raw_ostream &OS,
|
|
DiagnosticsEngine::Level Level,
|
|
const Diagnostic &Info,
|
|
const DiagnosticOptions &DiagOpts) {
|
|
bool Started = false;
|
|
if (DiagOpts.ShowOptionNames) {
|
|
// Handle special cases for non-warnings early.
|
|
if (Info.getID() == diag::fatal_too_many_errors) {
|
|
OS << " [-ferror-limit=]";
|
|
return;
|
|
}
|
|
|
|
// The code below is somewhat fragile because we are essentially trying to
|
|
// report to the user what happened by inferring what the diagnostic engine
|
|
// did. Eventually it might make more sense to have the diagnostic engine
|
|
// include some "why" information in the diagnostic.
|
|
|
|
// If this is a warning which has been mapped to an error by the user (as
|
|
// inferred by checking whether the default mapping is to an error) then
|
|
// flag it as such. Note that diagnostics could also have been mapped by a
|
|
// pragma, but we don't currently have a way to distinguish this.
|
|
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 the user wants to see category information, include it too.
|
|
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) {
|
|
// Default implementation (Warnings/errors count).
|
|
DiagnosticConsumer::HandleDiagnostic(Level, Info);
|
|
|
|
// Render the diagnostic message into a temporary buffer eagerly. We'll use
|
|
// this later as we print out the diagnostic to the terminal.
|
|
SmallString<100> OutStr;
|
|
Info.FormatDiagnostic(OutStr);
|
|
|
|
llvm::raw_svector_ostream DiagMessageStream(OutStr);
|
|
printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts);
|
|
|
|
// Keeps track of the starting position of the location
|
|
// information (e.g., "foo.c:10:4:") that precedes the error
|
|
// message. We use this information to determine how long the
|
|
// file+line+column number prefix is.
|
|
uint64_t StartOfLocationInfo = OS.tell();
|
|
|
|
if (!Prefix.empty())
|
|
OS << Prefix << ": ";
|
|
|
|
// Use a dedicated, simpler path for diagnostics without a valid location.
|
|
// This is important as if the location is missing, we may be emitting
|
|
// diagnostics in a context that lacks language options, a source manager, or
|
|
// other infrastructure necessary when emitting more rich diagnostics.
|
|
if (!Info.getLocation().isValid()) {
|
|
TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts->ShowColors,
|
|
DiagOpts->CLFallbackMode);
|
|
TextDiagnostic::printDiagnosticMessage(OS, Level, DiagMessageStream.str(),
|
|
OS.tell() - StartOfLocationInfo,
|
|
DiagOpts->MessageLength,
|
|
DiagOpts->ShowColors);
|
|
OS.flush();
|
|
return;
|
|
}
|
|
|
|
// Assert that the rest of our infrastructure is setup properly.
|
|
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(Info.getLocation(), Level, DiagMessageStream.str(),
|
|
Info.getRanges(),
|
|
Info.getFixItHints(),
|
|
&Info.getSourceManager());
|
|
|
|
OS.flush();
|
|
}
|