diff --git a/clang-tools-extra/CMakeLists.txt b/clang-tools-extra/CMakeLists.txt index 6b6f2b1ca2276..7ff17fa489693 100644 --- a/clang-tools-extra/CMakeLists.txt +++ b/clang-tools-extra/CMakeLists.txt @@ -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) diff --git a/clang-tools-extra/clang-read-diagnostics/CMakeLists.txt b/clang-tools-extra/clang-read-diagnostics/CMakeLists.txt new file mode 100644 index 0000000000000..922465ad3e098 --- /dev/null +++ b/clang-tools-extra/clang-read-diagnostics/CMakeLists.txt @@ -0,0 +1,8 @@ +add_clang_tool(clang-read-diagnostics + ClangReadDiagnostics.cpp + ) + +clang_target_link_libraries(clang-read-diagnostics + PRIVATE + clangFrontend + ) diff --git a/clang-tools-extra/clang-read-diagnostics/ClangReadDiagnostics.cpp b/clang-tools-extra/clang-read-diagnostics/ClangReadDiagnostics.cpp new file mode 100644 index 0000000000000..6dd7fd532b0ab --- /dev/null +++ b/clang-tools-extra/clang-read-diagnostics/ClangReadDiagnostics.cpp @@ -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 + +using namespace clang; +using namespace clang::serialized_diags; +using namespace llvm; + +static cl::list InputFiles(cl::Sink, cl::desc(""), + cl::Required); + +class BasicSerializedDiagnosticReader : public SerializedDiagnosticReader { +public: + struct DecodedDiagnostics { + unsigned Severity; + StringRef Filename; + unsigned Line; + unsigned Col; + StringRef Category; + StringRef Flag; + StringRef Message; + }; + + SmallVector getDiagnostics() { + SmallVector 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 CategoryIdx_; + DenseMap FlagIdx_; + DenseMap FilenameIdx_; + std::vector 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; +} diff --git a/clang-tools-extra/test/CMakeLists.txt b/clang-tools-extra/test/CMakeLists.txt index 7e4d99d8cfc1d..84426c9a56b7f 100644 --- a/clang-tools-extra/test/CMakeLists.txt +++ b/clang-tools-extra/test/CMakeLists.txt @@ -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 diff --git a/clang-tools-extra/test/clang-read-diagnostics/error_and_warning.c b/clang-tools-extra/test/clang-read-diagnostics/error_and_warning.c new file mode 100644 index 0000000000000..5d9263f2dea72 --- /dev/null +++ b/clang-tools-extra/test/clang-read-diagnostics/error_and_warning.c @@ -0,0 +1,14 @@ +// REQUIRES: clang +// RUN: not %clang %s -serialize-diagnostics %t +// RUN: clang-read-diagnostics %t 2>&1 | FileCheck %s + +#include + +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!") +}