mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-13 03:41:11 +00:00

A 'remark' is information that is not an error or a warning, but rather some additional information provided to the user. In contrast to a 'note' a 'remark' is an independent diagnostic, whereas a 'note' always depends on another diagnostic. A typical use case for remark nodes is information provided to the user, e.g. information provided by the vectorizer about loops that have been vectorized. This patch provides the initial implementation of 'remarks'. It includes the actual definiton of the remark nodes, their printing as well as basic parameter handling. We are reusing the existing diagnostic parameters which means a remark can be enabled with normal '-Wdiagnostic-name' flags and can be upgraded to an error using '-Werror=diagnostic-name'. '-Werror' alone does not upgrade remarks. This patch is by intention minimal in terms of parameter handling. More experience and more discussions will most likely lead to further enhancements in the parameter handling. llvm-svn: 202475
175 lines
5.3 KiB
C++
175 lines
5.3 KiB
C++
//===--- LogDiagnosticPrinter.cpp - Log Diagnostic Printer ----------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Frontend/LogDiagnosticPrinter.h"
|
|
#include "clang/Basic/DiagnosticOptions.h"
|
|
#include "clang/Basic/FileManager.h"
|
|
#include "clang/Basic/SourceManager.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace clang;
|
|
|
|
LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os,
|
|
DiagnosticOptions *diags,
|
|
bool _OwnsOutputStream)
|
|
: OS(os), LangOpts(0), DiagOpts(diags),
|
|
OwnsOutputStream(_OwnsOutputStream) {
|
|
}
|
|
|
|
LogDiagnosticPrinter::~LogDiagnosticPrinter() {
|
|
if (OwnsOutputStream)
|
|
delete &OS;
|
|
}
|
|
|
|
static StringRef getLevelName(DiagnosticsEngine::Level Level) {
|
|
switch (Level) {
|
|
case DiagnosticsEngine::Ignored: return "ignored";
|
|
case DiagnosticsEngine::Remark: return "remark";
|
|
case DiagnosticsEngine::Note: return "note";
|
|
case DiagnosticsEngine::Warning: return "warning";
|
|
case DiagnosticsEngine::Error: return "error";
|
|
case DiagnosticsEngine::Fatal: return "fatal error";
|
|
}
|
|
llvm_unreachable("Invalid DiagnosticsEngine level!");
|
|
}
|
|
|
|
// Escape XML characters inside the raw string.
|
|
static void emitString(llvm::raw_svector_ostream &OS, const StringRef Raw) {
|
|
for (StringRef::iterator I = Raw.begin(), E = Raw.end(); I != E; ++I) {
|
|
char c = *I;
|
|
switch (c) {
|
|
default: OS << c; break;
|
|
case '&': OS << "&"; break;
|
|
case '<': OS << "<"; break;
|
|
case '>': OS << ">"; break;
|
|
case '\'': OS << "'"; break;
|
|
case '\"': OS << """; break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void LogDiagnosticPrinter::EndSourceFile() {
|
|
// We emit all the diagnostics in EndSourceFile. However, we don't emit any
|
|
// entry if no diagnostics were present.
|
|
//
|
|
// Note that DiagnosticConsumer has no "end-of-compilation" callback, so we
|
|
// will miss any diagnostics which are emitted after and outside the
|
|
// translation unit processing.
|
|
if (Entries.empty())
|
|
return;
|
|
|
|
// Write to a temporary string to ensure atomic write of diagnostic object.
|
|
SmallString<512> Msg;
|
|
llvm::raw_svector_ostream OS(Msg);
|
|
|
|
OS << "<dict>\n";
|
|
if (!MainFilename.empty()) {
|
|
OS << " <key>main-file</key>\n"
|
|
<< " <string>";
|
|
emitString(OS, MainFilename);
|
|
OS << "</string>\n";
|
|
}
|
|
if (!DwarfDebugFlags.empty()) {
|
|
OS << " <key>dwarf-debug-flags</key>\n"
|
|
<< " <string>";
|
|
emitString(OS, DwarfDebugFlags);
|
|
OS << "</string>\n";
|
|
}
|
|
OS << " <key>diagnostics</key>\n";
|
|
OS << " <array>\n";
|
|
for (unsigned i = 0, e = Entries.size(); i != e; ++i) {
|
|
DiagEntry &DE = Entries[i];
|
|
|
|
OS << " <dict>\n";
|
|
OS << " <key>level</key>\n"
|
|
<< " <string>";
|
|
emitString(OS, getLevelName(DE.DiagnosticLevel));
|
|
OS << "</string>\n";
|
|
if (!DE.Filename.empty()) {
|
|
OS << " <key>filename</key>\n"
|
|
<< " <string>";
|
|
emitString(OS, DE.Filename);
|
|
OS << "</string>\n";
|
|
}
|
|
if (DE.Line != 0) {
|
|
OS << " <key>line</key>\n"
|
|
<< " <integer>" << DE.Line << "</integer>\n";
|
|
}
|
|
if (DE.Column != 0) {
|
|
OS << " <key>column</key>\n"
|
|
<< " <integer>" << DE.Column << "</integer>\n";
|
|
}
|
|
if (!DE.Message.empty()) {
|
|
OS << " <key>message</key>\n"
|
|
<< " <string>";
|
|
emitString(OS, DE.Message);
|
|
OS << "</string>\n";
|
|
}
|
|
OS << " </dict>\n";
|
|
}
|
|
OS << " </array>\n";
|
|
OS << "</dict>\n";
|
|
|
|
this->OS << OS.str();
|
|
}
|
|
|
|
void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
|
|
const Diagnostic &Info) {
|
|
// Default implementation (Warnings/errors count).
|
|
DiagnosticConsumer::HandleDiagnostic(Level, Info);
|
|
|
|
// Initialize the main file name, if we haven't already fetched it.
|
|
if (MainFilename.empty() && Info.hasSourceManager()) {
|
|
const SourceManager &SM = Info.getSourceManager();
|
|
FileID FID = SM.getMainFileID();
|
|
if (!FID.isInvalid()) {
|
|
const FileEntry *FE = SM.getFileEntryForID(FID);
|
|
if (FE && FE->isValid())
|
|
MainFilename = FE->getName();
|
|
}
|
|
}
|
|
|
|
// Create the diag entry.
|
|
DiagEntry DE;
|
|
DE.DiagnosticID = Info.getID();
|
|
DE.DiagnosticLevel = Level;
|
|
|
|
// Format the message.
|
|
SmallString<100> MessageStr;
|
|
Info.FormatDiagnostic(MessageStr);
|
|
DE.Message = MessageStr.str();
|
|
|
|
// Set the location information.
|
|
DE.Filename = "";
|
|
DE.Line = DE.Column = 0;
|
|
if (Info.getLocation().isValid() && Info.hasSourceManager()) {
|
|
const SourceManager &SM = Info.getSourceManager();
|
|
PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
|
|
|
|
if (PLoc.isInvalid()) {
|
|
// At least print the file name if available:
|
|
FileID FID = SM.getFileID(Info.getLocation());
|
|
if (!FID.isInvalid()) {
|
|
const FileEntry *FE = SM.getFileEntryForID(FID);
|
|
if (FE && FE->isValid())
|
|
DE.Filename = FE->getName();
|
|
}
|
|
} else {
|
|
DE.Filename = PLoc.getFilename();
|
|
DE.Line = PLoc.getLine();
|
|
DE.Column = PLoc.getColumn();
|
|
}
|
|
}
|
|
|
|
// Record the diagnostic entry.
|
|
Entries.push_back(DE);
|
|
}
|
|
|