Refactor SerializeDiagnosticsPrinter to using DiagnosticRenderer. This gives us comparative diagnostics

to TextDiagnosticPrinter.

This certainly can be cleaned up a bit.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146820 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ted Kremenek 2011-12-17 05:26:11 +00:00
Родитель 2898d4f764
Коммит 2a76410c0a
6 изменённых файлов: 225 добавлений и 80 удалений

Просмотреть файл

@ -19,6 +19,7 @@ class raw_ostream;
namespace clang {
class DiagnosticConsumer;
class DiagnosticsEngine;
class DiagnosticOptions;
namespace serialized_diags {
@ -52,7 +53,8 @@ enum RecordIDs {
/// This allows wrapper tools for Clang to get diagnostics from Clang
/// (via libclang) without needing to parse Clang's command line output.
///
DiagnosticConsumer *create(llvm::raw_ostream *OS);
DiagnosticConsumer *create(llvm::raw_ostream *OS,
const DiagnosticOptions &diags);
} // end serialized_diags namespace
} // end clang namespace

Просмотреть файл

@ -170,7 +170,7 @@ static void SetupSerializedDiagnostics(const DiagnosticOptions &DiagOpts,
}
DiagnosticConsumer *SerializedConsumer =
clang::serialized_diags::create(OS.take());
clang::serialized_diags::create(OS.take(), DiagOpts);
Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(),

Просмотреть файл

@ -18,6 +18,7 @@
#include "clang/Basic/Version.h"
#include "clang/Lex/Lexer.h"
#include "clang/Frontend/SerializedDiagnosticPrinter.h"
#include "clang/Frontend/DiagnosticRenderer.h"
using namespace clang;
using namespace clang::serialized_diags;
@ -44,11 +45,58 @@ public:
typedef llvm::SmallVector<uint64_t, 64> RecordData;
typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl;
class SDiagsWriter;
class SDiagsRenderer : public DiagnosticRenderer {
SDiagsWriter &Writer;
RecordData &Record;
public:
SDiagsRenderer(SDiagsWriter &Writer, RecordData &Record,
const SourceManager &SM,
const LangOptions &LangOpts,
const DiagnosticOptions &DiagOpts)
: DiagnosticRenderer(SM, LangOpts, DiagOpts),
Writer(Writer), Record(Record){}
virtual ~SDiagsRenderer() {}
protected:
virtual void emitDiagnosticMessage(SourceLocation Loc,
PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
StringRef Message,
ArrayRef<CharSourceRange> Ranges,
const Diagnostic *Info);
virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges) {}
virtual void emitBasicNote(StringRef Message);
void emitNote(SourceLocation Loc, StringRef Message);
virtual void emitIncludeLocation(SourceLocation Loc,
PresumedLoc PLoc);
virtual void emitCodeContext(SourceLocation Loc,
DiagnosticsEngine::Level Level,
SmallVectorImpl<CharSourceRange>& Ranges,
ArrayRef<FixItHint> Hints);
virtual void beginDiagnostic(const Diagnostic *Info,
DiagnosticsEngine::Level Level);
virtual void endDiagnostic(const Diagnostic *Info,
DiagnosticsEngine::Level Level);
};
class SDiagsWriter : public DiagnosticConsumer {
friend class SDiagsRenderer;
public:
explicit SDiagsWriter(llvm::raw_ostream *os)
: LangOpts(0), Stream(Buffer), OS(os), inNonNoteDiagnostic(false)
explicit SDiagsWriter(llvm::raw_ostream *os, const DiagnosticOptions &diags)
: LangOpts(0), DiagOpts(diags),
Stream(Buffer), OS(os), inNonNoteDiagnostic(false)
{
EmitPreamble();
}
@ -81,31 +129,39 @@ private:
void EmitMetaBlock();
/// \brief Emit a record for a CharSourceRange.
void EmitCharSourceRange(CharSourceRange R, SourceManager &SM);
void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM);
/// \brief Emit the string information for the category for a diagnostic.
unsigned getEmitCategory(unsigned DiagID);
/// \brief Emit the string information for the category.
unsigned getEmitCategory(unsigned category = 0);
/// \brief Emit the string information for diagnostic flags.
unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info);
unsigned DiagID = 0);
/// \brief Emit (lazily) the file string and retrieved the file identifier.
unsigned getEmitFile(SourceLocation Loc, SourceManager &SM);
unsigned getEmitFile(const char *Filename);
/// \brief Add SourceLocation information the specified record.
void AddLocToRecord(SourceLocation Loc, const SourceManager &SM,
PresumedLoc PLoc, RecordDataImpl &Record,
unsigned TokSize = 0);
/// \brief Add SourceLocation information the specified record.
void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
SourceManager &SM,
unsigned TokSize = 0);
const SourceManager &SM,
unsigned TokSize = 0) {
AddLocToRecord(Loc, SM, SM.getPresumedLoc(Loc), Record, TokSize);
}
/// \brief Add CharSourceRange information the specified record.
void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record,
SourceManager &SM);
const SourceManager &SM);
/// \brief The version of the diagnostics file.
enum { Version = 1 };
const LangOptions *LangOpts;
const DiagnosticOptions &DiagOpts;
/// \brief The byte buffer for the serialized content.
std::vector<unsigned char> Buffer;
@ -129,7 +185,7 @@ private:
llvm::DenseSet<unsigned> Categories;
/// \brief The collection of files used.
llvm::DenseMap<const FileEntry *, unsigned> Files;
llvm::DenseMap<const char *, unsigned> Files;
typedef llvm::DenseMap<const void *, std::pair<unsigned, llvm::StringRef> >
DiagFlagsTy;
@ -145,8 +201,9 @@ private:
namespace clang {
namespace serialized_diags {
DiagnosticConsumer *create(llvm::raw_ostream *OS) {
return new SDiagsWriter(OS);
DiagnosticConsumer *create(llvm::raw_ostream *OS,
const DiagnosticOptions &diags) {
return new SDiagsWriter(OS, diags);
}
} // end namespace serialized_diags
} // end namespace clang
@ -189,10 +246,11 @@ static void EmitRecordID(unsigned ID, const char *Name,
}
void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
const SourceManager &SM,
PresumedLoc PLoc,
RecordDataImpl &Record,
SourceManager &SM,
unsigned TokSize) {
if (Loc.isInvalid()) {
if (PLoc.isInvalid()) {
// Emit a "sentinel" location.
Record.push_back((unsigned)0); // File.
Record.push_back((unsigned)0); // Line.
@ -201,16 +259,15 @@ void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
return;
}
Loc = SM.getSpellingLoc(Loc);
Record.push_back(getEmitFile(Loc, SM));
Record.push_back(SM.getSpellingLineNumber(Loc));
Record.push_back(SM.getSpellingColumnNumber(Loc)+TokSize);
Record.push_back(getEmitFile(PLoc.getFilename()));
Record.push_back(PLoc.getLine());
Record.push_back(PLoc.getColumn()+TokSize);
Record.push_back(SM.getFileOffset(Loc));
}
void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
RecordDataImpl &Record,
SourceManager &SM) {
const SourceManager &SM) {
AddLocToRecord(Range.getBegin(), Record, SM);
unsigned TokSize = 0;
if (Range.isTokenRange())
@ -220,14 +277,11 @@ void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
AddLocToRecord(Range.getEnd(), Record, SM, TokSize);
}
unsigned SDiagsWriter::getEmitFile(SourceLocation Loc, SourceManager &SM) {
assert(Loc.isValid());
const std::pair<FileID, unsigned> &LocInfo = SM.getDecomposedLoc(Loc);
const FileEntry *FE = SM.getFileEntryForID(LocInfo.first);
if (!FE)
unsigned SDiagsWriter::getEmitFile(const char *FileName){
if (!FileName)
return 0;
unsigned &entry = Files[FE];
unsigned &entry = Files[FileName];
if (entry)
return entry;
@ -236,9 +290,9 @@ unsigned SDiagsWriter::getEmitFile(SourceLocation Loc, SourceManager &SM) {
RecordData Record;
Record.push_back(RECORD_FILENAME);
Record.push_back(entry);
Record.push_back(FE->getSize());
Record.push_back(FE->getModificationTime());
StringRef Name = FE->getName();
Record.push_back(0); // For legacy.
Record.push_back(0); // For legacy.
StringRef Name(FileName);
Record.push_back(Name.size());
Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name);
@ -246,7 +300,7 @@ unsigned SDiagsWriter::getEmitFile(SourceLocation Loc, SourceManager &SM) {
}
void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
SourceManager &SM) {
const SourceManager &SM) {
Record.clear();
Record.push_back(RECORD_SOURCE_RANGE);
AddCharSourceRangeToRecord(R, Record, SM);
@ -373,9 +427,7 @@ void SDiagsWriter::EmitMetaBlock() {
Stream.ExitBlock();
}
unsigned SDiagsWriter::getEmitCategory(unsigned int DiagID) {
unsigned category = DiagnosticIDs::getCategoryNumberForDiag(DiagID);
unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
if (Categories.count(category))
return category;
@ -394,11 +446,11 @@ unsigned SDiagsWriter::getEmitCategory(unsigned int DiagID) {
}
unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) {
unsigned DiagID) {
if (DiagLevel == DiagnosticsEngine::Note)
return 0; // No flag for notes.
StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
if (FlagName.empty())
return 0;
@ -424,8 +476,6 @@ unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) {
SourceManager &SM = Info.getSourceManager();
if (DiagLevel != DiagnosticsEngine::Note) {
if (inNonNoteDiagnostic) {
// We have encountered a non-note diagnostic. Finish up the previous
@ -434,52 +484,117 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
}
inNonNoteDiagnostic = true;
}
Stream.EnterSubblock(BLOCK_DIAG, 4);
// Emit the RECORD_DIAG record.
Record.clear();
Record.push_back(RECORD_DIAG);
Record.push_back(DiagLevel);
AddLocToRecord(Info.getLocation(), Record, SM);
// Emit the category string lazily and get the category ID.
Record.push_back(getEmitCategory(Info.getID()));
// Emit the diagnostic flag string lazily and get the mapped ID.
Record.push_back(getEmitDiagnosticFlag(DiagLevel, Info));
// Emit the diagnostic text.
diagBuf.clear();
Info.FormatDiagnostic(diagBuf); // Compute the diagnostic text.
Record.push_back(diagBuf.str().size());
Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, diagBuf.str());
// Compute the diagnostic text.
diagBuf.clear();
Info.FormatDiagnostic(diagBuf);
SourceManager &SM = Info.getSourceManager();
SDiagsRenderer Renderer(*this, Record, SM, *LangOpts, DiagOpts);
Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
diagBuf.str(),
Info.getRanges(),
llvm::makeArrayRef(Info.getFixItHints(),
Info.getNumFixItHints()),
&Info);
}
void
SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
StringRef Message,
ArrayRef<clang::CharSourceRange> Ranges,
const Diagnostic *Info) {
// Emit the RECORD_DIAG record.
Writer.Record.clear();
Writer.Record.push_back(RECORD_DIAG);
Writer.Record.push_back(Level);
Writer.AddLocToRecord(Loc, SM, PLoc, Record);
if (Info) {
// Emit the category string lazily and get the category ID.
unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
Writer.Record.push_back(Writer.getEmitCategory(DiagID));
// Emit the diagnostic flag string lazily and get the mapped ID.
Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level, Info->getID()));
}
else {
Writer.Record.push_back(Writer.getEmitCategory());
Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level));
}
Writer.Record.push_back(Message.size());
Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
Writer.Record, Message);
}
void SDiagsRenderer::beginDiagnostic(const Diagnostic *Info,
DiagnosticsEngine::Level Level) {
Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
}
void SDiagsRenderer::endDiagnostic(const Diagnostic *Info,
DiagnosticsEngine::Level Level) {
if (Info && Level != DiagnosticsEngine::Note)
return;
Writer.Stream.ExitBlock();
}
void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
DiagnosticsEngine::Level Level,
SmallVectorImpl<CharSourceRange> &Ranges,
ArrayRef<FixItHint> Hints) {
// Emit Source Ranges.
ArrayRef<CharSourceRange> Ranges = Info.getRanges();
for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end();
it != ei; ++it) {
if (it->isValid())
EmitCharSourceRange(*it, SM);
}
// Emit FixIts.
for (unsigned i = 0, n = Info.getNumFixItHints(); i != n; ++i) {
const FixItHint &fix = Info.getFixItHint(i);
if (fix.isNull())
continue;
Record.clear();
Record.push_back(RECORD_FIXIT);
AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM);
Record.push_back(fix.CodeToInsert.size());
Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record,
fix.CodeToInsert);
Writer.EmitCharSourceRange(*it, SM);
}
if (DiagLevel == DiagnosticsEngine::Note) {
// Notes currently cannot have child diagnostics. Complete the
// diagnostic now.
Stream.ExitBlock();
// Emit FixIts.
for (ArrayRef<FixItHint>::iterator it = Hints.begin(), et = Hints.end();
it != et; ++it) {
const FixItHint &fix = *it;
if (fix.isNull())
continue;
Writer.Record.clear();
Writer.Record.push_back(RECORD_FIXIT);
Writer.AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM);
Writer.Record.push_back(fix.CodeToInsert.size());
Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_FIXIT), Record,
fix.CodeToInsert);
}
}
void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message) {
Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
RecordData Record;
Record.push_back(RECORD_DIAG);
Record.push_back(DiagnosticsEngine::Note);
Writer.AddLocToRecord(Loc, Record, SM);
Record.push_back(Writer.getEmitCategory());
Record.push_back(Writer.getEmitDiagnosticFlag(DiagnosticsEngine::Note));
Record.push_back(Message.size());
Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
Record, Message);
Writer.Stream.ExitBlock();
}
void SDiagsRenderer::emitIncludeLocation(SourceLocation Loc,
PresumedLoc PLoc) {
// Generate a note indicating the include location.
llvm::SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
Message << "in file included from " << PLoc.getFilename() << ':'
<< PLoc.getLine() << ":";
emitNote(Loc, Message.str());
}
void SDiagsRenderer::emitBasicNote(StringRef Message) {
emitNote(SourceLocation(), Message);
}
void SDiagsWriter::finish() {
if (inNonNoteDiagnostic) {
// Finish off any diagnostics we were in the process of emitting.

Просмотреть файл

@ -13,7 +13,8 @@ void foo() {
// CHECK: {{.*}}serialized-diags-single-issue.c:3:12: warning: variable 'voodoo' is uninitialized when used here [-Wuninitialized]
// CHECK: Range: {{.*}}serialized-diags-single-issue.c:3:12 {{.*}}serialized-diags-single-issue.c:3:18
// CHECK: +-{{.*}}serialized-diags-single-issue.c:2:13: note: initialize the variable 'voodoo' to silence this warning []
// CHECK: +-FIXIT: {{.*}}serialized-diags-single-issue.c:2:13 - {{.*}}serialized-diags-single-issue.c:2:13): " = 0"
// CHECK: +-Range: {{.*}}serialized-diags-single-issue.c:2:13 {{.*}}serialized-diags-single-issue.c:2:13
// CHECK: +-FIXIT: ({{.*}}serialized-diags-single-issue.c:2:13 - {{.*}}serialized-diags-single-issue.c:2:13): " = 0"
// Test that we handle serializing diagnostics for multiple source files
// RUN: %clang_cc1 -Wall -fsyntax-only %s %s -serialize-diagnostic-file %t
@ -23,11 +24,13 @@ void foo() {
// CHECK-MULT: {{.*}}serialized-diags-single-issue.c:3:12: warning: variable 'voodoo' is uninitialized when used here [-Wuninitialized]
// CHECK-MULT: Range: {{.*}}serialized-diags-single-issue.c:3:12 {{.*}}serialized-diags-single-issue.c:3:18
// CHECK-MULT: +-{{.*}}serialized-diags-single-issue.c:2:13: note: initialize the variable 'voodoo' to silence this warning []
// CHECK-MULT: +-FIXIT: {{.*}}serialized-diags-single-issue.c:2:13 - {{.*}}serialized-diags-single-issue.c:2:13): " = 0"
// CHECK-MULT: +-Range: {{.*}}serialized-diags-single-issue.c:2:13 {{.*}}serialized-diags-single-issue.c:2:13
// CHECK-MULT: +-FIXIT: ({{.*}}serialized-diags-single-issue.c:2:13 - {{.*}}serialized-diags-single-issue.c:2:13): " = 0"
// CHECK-MULT: {{.*}}serialized-diags-single-issue.c:3:12: warning: variable 'voodoo' is uninitialized when used here [-Wuninitialized]
// CHECK-MULT: Range: {{.*}}serialized-diags-single-issue.c:3:12 {{.*}}serialized-diags-single-issue.c:3:18
// CHECK-MULT: +-{{.*}}serialized-diags-single-issue.c:2:13: note: initialize the variable 'voodoo' to silence this warning []
// CHECK-MULT: +-FIXIT: {{.*}}serialized-diags-single-issue.c:2:13 - {{.*}}serialized-diags-single-issue.c:2:13): " = 0"
// CHECK-MULT: +-Range: {{.*}}serialized-diags-single-issue.c:2:13 {{.*}}serialized-diags-single-issue.c:2:13
// CHECK-MULT: +-FIXIT: ({{.*}}serialized-diags-single-issue.c:2:13 - {{.*}}serialized-diags-single-issue.c:2:13): " = 0"
// CHECK-MULT: Number of diagnostics: 2

Просмотреть файл

@ -15,6 +15,16 @@ void qux(int x) {
return;
}
// Test handling of macros.
void taz(int x, int y);
#define false 0
void testMacro() {
taz(0, 0, false);
}
// Test handling of issues from #includes.
#include "serialized-diags.h"
// RUN: rm -f %t
// RUN: %clang -Wall -fsyntax-only %s --serialize-diagnostics %t > /dev/null 2>&1 || true
// RUN: c-index-test -read-diagnostics %t 2>&1 | FileCheck %s
@ -35,5 +45,15 @@ void qux(int x) {
// CHECK: +-FIXIT: ({{.*[/\\]}}serialized-diags.c:14:18 - {{.*[/\\]}}serialized-diags.c:14:19): ""
// CHECK: +-{{.*[/\\]}}serialized-diags.c:14:10: note: use '=' to turn this equality comparison into an assignment []
// CHECK: +-FIXIT: ({{.*[/\\]}}serialized-diags.c:14:10 - {{.*[/\\]}}serialized-diags.c:14:12): "="
// CHECK: Number of diagnostics: 3
// CHECK: {{.*[/\\]}}serialized-diags.c:22:13: error: too many arguments to function call, expected 2, have 3 []
// CHECK: Range: {{.*[/\\]}}serialized-diags.c:22:3 {{.*[/\\]}}serialized-diags.c:22:6
// CHECK: Range: {{.*[/\\]}}serialized-diags.c:22:13 {{.*[/\\]}}serialized-diags.c:22:18
// CHECK: +-{{.*[/\\]}}serialized-diags.c:20:15: note: expanded from macro 'false' []
// CHECK: +-Range: {{.*[/\\]}}serialized-diags.c:22:3 {{.*[/\\]}}serialized-diags.c:22:6
// CHECK: +-Range: {{.*[/\\]}}serialized-diags.c:20:15 {{.*[/\\]}}serialized-diags.c:20:16
// CHECK: +-{{.*[/\\]}}serialized-diags.c:19:1: note: 'taz' declared here []
// CHECK: {{.*[/\\]}}serialized-diags.h:5:7: warning: incompatible integer to pointer conversion initializing 'char *' with an expression of type 'int'; []
// CHECK: Range: {{.*[/\\]}}serialized-diags.h:5:16 {{.*[/\\]}}serialized-diags.h:5:17
// CHECK: +-{{.*[/\\]}}serialized-diags.c:26:10: note: in file included from {{.*[/\\]}}serialized-diags.c:26: []
// CHECK: Number of diagnostics: 5

Просмотреть файл

@ -0,0 +1,5 @@
// This file intentionally has a bug. It is intended
// to be used with serialized-diagnostics.c to show
// how errors are handled with #includes in serialized
// diagnostics.
char *badStr = 1;