Skip to content
1 change: 1 addition & 0 deletions clang-tools-extra/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ add_subdirectory(clang-doc)
add_subdirectory(clang-include-fixer)
add_subdirectory(clang-move)
add_subdirectory(clang-query)
add_subdirectory(clang-read-diagnostics)
add_subdirectory(include-cleaner)
add_subdirectory(pp-trace)
add_subdirectory(tool-template)
Expand Down
8 changes: 8 additions & 0 deletions clang-tools-extra/clang-read-diagnostics/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
add_clang_tool(clang-read-diagnostics
ClangReadDiagnostics.cpp
)

clang_target_link_libraries(clang-read-diagnostics
PRIVATE
clangFrontend
)
129 changes: 129 additions & 0 deletions clang-tools-extra/clang-read-diagnostics/ClangReadDiagnostics.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//===---- ClangReadDiagnostics.cpp - clang-read-diagnostics tool ----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This tool is for reading clang diagnostics files from -serialize-diagnostics.
//
// Example usage:
//
// $ clang -serialize-diagnostics foo.c.diag foo.c
// $ clang-read-diagnostics foo.c.diag
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/SerializedDiagnosticReader.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Signals.h"

#include <string>

using namespace clang;
using namespace clang::serialized_diags;
using namespace llvm;

static cl::list<std::string> InputFiles(cl::Sink, cl::desc("<input files...>"),
cl::Required);

class BasicSerializedDiagnosticReader : public SerializedDiagnosticReader {
public:
struct DecodedDiagnostics {
unsigned Severity;
StringRef Filename;
unsigned Line;
unsigned Col;
StringRef Category;
StringRef Flag;
StringRef Message;
};

SmallVector<DecodedDiagnostics> getDiagnostics() {
SmallVector<DecodedDiagnostics> Ret;
for (const auto &Diag : Diagnostics_) {
auto Filename = FilenameIdx_.at(Diag.Location.FileID);
auto Category = CategoryIdx_.at(Diag.Category);
auto Flag = Diag.Flag == 0 ? "" : FlagIdx_.at(Diag.Flag);
Ret.emplace_back(DecodedDiagnostics{Diag.Severity, Filename,
Diag.Location.Line, Diag.Location.Col,
Category, Flag, Diag.Message});
}
return Ret;
}

void dump() {
for (const auto &Diag : getDiagnostics()) {
llvm::dbgs() << Diag.Filename << ":" << Diag.Line << ":" << Diag.Col
<< ": " << Diag.Message << " [category=\'" << Diag.Category
<< "'";

if (!Diag.Flag.empty())
llvm::dbgs() << ", flag=" << Diag.Flag;

llvm::dbgs() << "]" << "\n";
}
}

protected:
virtual std::error_code visitCategoryRecord(unsigned ID,
StringRef Name) override {
const auto &[_, Inserted] = CategoryIdx_.try_emplace(ID, Name);
assert(Inserted && "duplicate IDs");
return {};
}

virtual std::error_code visitDiagFlagRecord(unsigned ID,
StringRef Name) override {
const auto &[_, Inserted] = FlagIdx_.try_emplace(ID, Name);
assert(Inserted && "duplicate IDs");
return {};
}

virtual std::error_code visitFilenameRecord(unsigned ID, unsigned Size,
unsigned Timestamp,
StringRef Name) override {
const auto &[_, Inserted] = FilenameIdx_.try_emplace(ID, Name);
assert(Inserted && "duplicate IDs");
return {};
}

virtual std::error_code visitDiagnosticRecord(unsigned Severity,
const Location &Location,
unsigned Category,
unsigned Flag,
StringRef Message) override {
Diagnostics_.emplace_back(
RawDiagnostic{Severity, Location, Category, Flag, Message});
return {};
}

private:
struct RawDiagnostic {
unsigned Severity;
Location Location;
unsigned Category;
unsigned Flag;
StringRef Message;
};

DenseMap<unsigned, StringRef> CategoryIdx_;
DenseMap<unsigned, StringRef> FlagIdx_;
DenseMap<unsigned, StringRef> FilenameIdx_;
std::vector<RawDiagnostic> Diagnostics_;
};

int main(int argc, const char **argv) {
cl::ParseCommandLineOptions(argc, argv);
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);

for (const auto &File : InputFiles) {
BasicSerializedDiagnosticReader BSDR{};
BSDR.readDiagnostics(File);
BSDR.dump();
}

return 0;
}
1 change: 1 addition & 0 deletions clang-tools-extra/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ set(CLANG_TOOLS_TEST_DEPS
clang-include-fixer
clang-move
clang-query
clang-read-diagnostics
clang-reorder-fields
find-all-symbols
modularize
Expand Down
14 changes: 14 additions & 0 deletions clang-tools-extra/test/clang-read-diagnostics/error_and_warning.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// REQUIRES: clang
// RUN: not %clang %s -serialize-diagnostics %t
// RUN: clang-read-diagnostics %t 2>&1 | FileCheck %s

#include <stdio.h>

int forgot_return() {
// CHECK: error_and_warning.c:9:1: non-void function does not return a value [category='Semantic Issue', flag=return-type]
}

int main() {
// CHECK: error_and_warning.c:13:25: expected ';' after expression [category='Parse Issue']
printf("Hello world!")
}
Loading