cjdb updated this revision to Diff 504309.
cjdb added a comment.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.
merges in D145438 <https://reviews.llvm.org/D145438>. This patch is ready for
review now.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D145284/new/
https://reviews.llvm.org/D145284
Files:
clang/include/clang/Basic/DiagnosticDriverKinds.td
clang/include/clang/Basic/DiagnosticOptions.def
clang/include/clang/Basic/DiagnosticOptions.h
clang/include/clang/Driver/Options.td
clang/include/clang/Frontend/CompilerInstance.h
clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
clang/lib/Driver/ToolChains/Clang.cpp
clang/lib/Frontend/CompilerInstance.cpp
clang/lib/Frontend/FrontendAction.cpp
clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
clang/lib/Frontend/TextDiagnostic.cpp
clang/lib/Tooling/CMakeLists.txt
clang/lib/Tooling/SarifLinker.cpp
clang/lib/Tooling/Tooling.cpp
clang/test/Driver/fdiagnostics-format-sarif.cpp
clang/test/Frontend/sarif-diagnostics.cpp
clang/tools/CMakeLists.txt
clang/tools/driver/CMakeLists.txt
clang/tools/driver/cc1_main.cpp
clang/tools/driver/driver.cpp
clang/tools/sarif-ld/CMakeLists.txt
clang/tools/sarif-ld/SarifLinker.cpp
llvm/include/llvm/ADT/STLExtras.h
Index: llvm/include/llvm/ADT/STLExtras.h
===================================================================
--- llvm/include/llvm/ADT/STLExtras.h
+++ llvm/include/llvm/ADT/STLExtras.h
@@ -1804,6 +1804,34 @@
return std::find(adl_begin(Range), adl_end(Range), Val);
}
+/// std::ranges::find_last means that we don't need to work with
+/// reverse_iterators as often, and can also find the last matching element of a
+/// non-bidirectional range.
+template <typename I, typename T>
+auto find_last(I First, I Last, const T &Val) {
+ using iterator_category = typename std::iterator_traits<I>::iterator_category;
+ static_assert(std::is_base_of_v<std::forward_iterator_tag, iterator_category>,
+ "llvm::find_last requires forward iterators at minimum.");
+ if constexpr (std::is_base_of_v<std::bidirectional_iterator_tag,
+ iterator_category>) {
+ for (auto Current = Last; Current-- != First;)
+ if (*Current == Val)
+ return Current;
+
+ return Last;
+ } else {
+ auto Result = Last;
+ for (; First != Last; ++First)
+ if (*First == Val)
+ Result = First;
+ return Result;
+ }
+}
+
+template <typename R, typename T> auto find_last(R &&Range, const T &Val) {
+ return llvm::find_last(adl_begin(Range), adl_end(Range), Val);
+}
+
/// Provide wrappers to std::find_if which take ranges instead of having to pass
/// begin/end explicitly.
template <typename R, typename UnaryPredicate>
Index: clang/tools/sarif-ld/SarifLinker.cpp
===================================================================
--- /dev/null
+++ clang/tools/sarif-ld/SarifLinker.cpp
@@ -0,0 +1,92 @@
+#include "clang/Basic/Sarif.h"
+#include "clang/Config/config.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/Process.h"
+#include <cassert>
+#include <cstdlib>
+#include <fstream>
+#include <iterator>
+#include <string>
+#include <string_view>
+#include <system_error>
+
+namespace json = llvm::json;
+namespace cl = llvm::cl;
+using llvm::ArrayRef, llvm::StringRef;
+
+static cl::opt<bool> Help("h", cl::desc("Alias for --help"), cl::Hidden);
+static cl::opt<std::string> Target("o", cl::init("<file>"),
+ cl::desc("Write output to <file>.sarif"));
+static cl::list<std::string> Files(cl::Positional, "files",
+ cl::desc("[<file> ...]"));
+
+static void PrintVersion(llvm::raw_ostream &OS) {
+ OS << clang::getClangToolFullVersion("sarif-ld") << '\n';
+}
+
+namespace {
+struct ParseArgsResult {
+ llvm::opt::ArgStringList Input;
+ std::string Output;
+};
+} // namespace
+
+static ParseArgsResult ParseArgs(int argc, char *argv[]) {
+ llvm::cl::ParseCommandLineOptions(
+ argc, argv,
+ "A tool that links separate SARIF files into a single SARIF file.");
+
+ if (Help) {
+ cl::PrintHelpMessage();
+ std::exit(0);
+ }
+
+ if (Files.empty()) {
+ llvm::errs() << argv[0] << ": error: no input files\n";
+ cl::PrintHelpMessage();
+ std::exit(1);
+ }
+
+ if (Target.empty()) {
+ llvm::errs() << argv[0] << ": error: no outpt file\n";
+ cl::PrintHelpMessage();
+ std::exit(2);
+ }
+
+ ParseArgsResult Result{llvm::opt::ArgStringList(), Target.getValue()};
+ llvm::transform(Files, std::back_inserter(Result.Input),
+ [](StringRef File) { return File.data(); });
+ return Result;
+}
+
+namespace llvm::sarif_linker {
+[[noreturn]] void ReportErrorAndExit(llvm::errc error_code, StringRef Message);
+std::error_code LinkSarifDiagnostics(const opt::ArgStringList &InputPaths,
+ StringRef OutputPath);
+} // namespace llvm::sarif_linker
+
+int main(int argc, char *argv[]) {
+ llvm::InitLLVM X(argc, argv);
+ llvm::setBugReportMsg("PLEASE submit a bug report to " BUG_REPORT_URL
+ " and include the crash backtrace, preprocessed "
+ "source, and associated run script.\n");
+
+ if (llvm::sys::Process::FixupStandardFileDescriptors())
+ return 1;
+
+ llvm::cl::SetVersionPrinter(PrintVersion);
+ auto [Input, Output] = ParseArgs(argc, argv);
+
+ std::error_code EC = llvm::sarif_linker::LinkSarifDiagnostics(Input, Output);
+ if (EC)
+ llvm::sarif_linker::ReportErrorAndExit(static_cast<llvm::errc>(EC.value()),
+ EC.message());
+}
Index: clang/tools/sarif-ld/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang/tools/sarif-ld/CMakeLists.txt
@@ -0,0 +1,17 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_tool(
+ sarif-ld
+ SarifLinker.cpp
+)
+
+clang_target_link_libraries(
+ sarif-ld
+ PRIVATE clangTooling
+)
+
+install(
+ PROGRAMS sarif-ld
+ DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ COMPONENT sarif-ld
+)
Index: clang/tools/driver/driver.cpp
===================================================================
--- clang/tools/driver/driver.cpp
+++ clang/tools/driver/driver.cpp
@@ -372,6 +372,12 @@
return 1;
}
+namespace llvm::sarif_linker {
+[[noreturn]] void ReportErrorAndExit(llvm::errc error_code, StringRef Message);
+std::error_code LinkSarifDiagnostics(const opt::ArgStringList &InputPaths,
+ StringRef OutputPath);
+} // namespace llvm::sarif_linker
+
int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
noteBottomOfStack();
llvm::InitLLVM X(Argc, Argv);
@@ -634,6 +640,17 @@
Res = 1;
#endif
+ // Finally, we need to move any SARIF diagnostics into the build directory.
+ const DerivedArgList &ArgList = C->getArgs();
+ if (Arg *DF = ArgList.getLastArg(options::OPT_fdiagnostics_format_EQ);
+ DF && DF->containsValue("sarif-file") && !C->getTempFiles().empty()) {
+ Arg *o = ArgList.getLastArg(options::OPT_o);
+ const char *Out = o ? o->getValue(0) : TheDriver.getDefaultImageName();
+ if (auto EC =
+ llvm::sarif_linker::LinkSarifDiagnostics(C->getTempFiles(), Out)) {
+ }
+ }
+
// If we have multiple failing commands, we return the result of the first
// failing command.
return Res;
Index: clang/tools/driver/cc1_main.cpp
===================================================================
--- clang/tools/driver/cc1_main.cpp
+++ clang/tools/driver/cc1_main.cpp
@@ -230,7 +230,13 @@
CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
// Create the actual diagnostics engine.
- Clang->createDiagnostics();
+ auto DiagnosticsFilePathOption =
+ llvm::find_last(Argv, StringRef("-fdiagnostics-file-path"));
+ std::string DiagnosticsFilePath =
+ std::distance(DiagnosticsFilePathOption, Argv.end()) > 1
+ ? *std::next(DiagnosticsFilePathOption)
+ : Clang->getFrontendOpts().OutputFile;
+ Clang->createDiagnostics(nullptr, true, DiagnosticsFilePath);
if (!Clang->hasDiagnostics())
return 1;
Index: clang/tools/driver/CMakeLists.txt
===================================================================
--- clang/tools/driver/CMakeLists.txt
+++ clang/tools/driver/CMakeLists.txt
@@ -43,6 +43,7 @@
clangFrontend
clangFrontendTool
clangSerialization
+ clangTooling
)
if(WIN32 AND NOT CYGWIN)
Index: clang/tools/CMakeLists.txt
===================================================================
--- clang/tools/CMakeLists.txt
+++ clang/tools/CMakeLists.txt
@@ -51,3 +51,4 @@
add_clang_subdirectory(amdgpu-arch)
add_clang_subdirectory(nvptx-arch)
+add_clang_subdirectory(sarif-ld)
Index: clang/test/Frontend/sarif-diagnostics.cpp
===================================================================
--- clang/test/Frontend/sarif-diagnostics.cpp
+++ clang/test/Frontend/sarif-diagnostics.cpp
@@ -29,10 +29,35 @@
#include "sarif-diagnostics.hpp"
-// RUN: %clang -fsyntax-only -Wall -Wextra -fdiagnostics-format=sarif %s > %t.txt 2>&1 || true
+// RUN: %clang -fsyntax-only -Wall -Wextra -fdiagnostics-format=sarif-stderr %s > %t.txt 2>&1 || true
// RUN: FileCheck -dump-input=always %s --input-file=%t.txt --check-prefixes=STDERR,SARIF
+// RUN: %clang -fsyntax-only -Wall -Wextra -fdiagnostics-format=sarif-file -fdiagnostics-file-path=%t %s > %t.txt 2>&1 || true
+// RUN: FileCheck -dump-input=always --check-prefix=STDERR %s --input-file=%t.txt
+// RUN: FileCheck -dump-input=always --check-prefix=SARIF %s --input-file=%t.sarif
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %clang -Wall -Wextra -fdiagnostics-format=sarif-file %s -o %t/sarif-output > %t.txt 2>&1 || true
+// RUN: FileCheck -dump-input=always --check-prefixes=STDERR,NOFILE %s --input-file=%t.txt
+// RUN: FileCheck -dump-input=always --check-prefix=SARIF %s --input-file=%t/sarif-output.sarif
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %clang -Wall -Wextra -fdiagnostics-format=sarif-file %s %s -o %t/sarif-output > %t.txt 2>&1 || true
+// RUN: FileCheck -dump-input=always --check-prefixes=STDERR,NOFILE %s --input-file=%t.txt
+// RUN: FileCheck -dump-input=always --check-prefix=SARIF %s --input-file=%t/sarif-output.sarif
+// RUN: FileCheck -dump-input=always --check-prefix=SARIF2 %s --input-file=%t/sarif-output.sarif
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %clang -Wall -Wextra -fdiagnostics-format=sarif-file -fdiagnostics-file-path=%t/diags %s -o %t/sarif-output > %t.txt 2>&1 || true
+// RUN: FileCheck -dump-input=always --check-prefix=STDERR %s --input-file=%t.txt
+// RUN: FileCheck -dump-input=always --check-prefix=SARIF %s --input-file=%t/diags.sarif
+// RUN: grep -v "warning: '-fdiagnostics-file-path' should be set when using '-fdiagnostics-format=sarif-file'" %t.txt
+
// STDERR: warning: diagnostic formatting in SARIF mode is currently unstable [-Wsarif-format-unstable]
+// NOFILE: warning: '-fdiagnostics-file-path' should be set when using '-fdiagnostics-format=sarif-file'
// SARIF: {
// SARIF: "$schema":"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json",
// SARIF: "runs":[
@@ -489,6 +514,460 @@
// SARIF: }
// SARIF: }
// SARIF: }
+// SARIF2: ,
+// SARIF2: {
+// SARIF2: "artifacts":[
+// SARIF2: {
+// SARIF2: "length":{{[0-9]+}},
+// SARIF2: "location":{
+// SARIF2: "index":0,
+// SARIF2: "uri":{{"file://[^"]+/clang/test/Frontend/sarif-diagnostics.cpp"}}
+// SARIF2: },
+// SARIF2: "mimeType":"text/plain",
+// SARIF2: "roles":[
+// SARIF2: "resultFile"
+// SARIF2: ]
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "length":{{[0-9]+}},
+// SARIF2: "location":{
+// SARIF2: "index":1,
+// SARIF2: "uri":"file://{{[^"]+test/Frontend/sarif-diagnostics.hpp}}"
+// SARIF2: },
+// SARIF2: "mimeType":"text/plain",
+// SARIF2: "roles":[
+// SARIF2: "resultFile"
+// SARIF2: ]
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "columnKind":"unicodeCodePoints",
+// SARIF2: "results":[
+// SARIF2: {
+// SARIF2: "level":"error",
+// SARIF2: "locations":[
+// SARIF2: {
+// SARIF2: "physicalLocation":{
+// SARIF2: "artifactLocation":{
+// SARIF2: "index":0,
+// SARIF2: "uri":{{"file://[^"]+/clang/test/Frontend/sarif-diagnostics.cpp"}}
+// SARIF2: },
+// SARIF2: "region":{
+// SARIF2: "endColumn":1,
+// SARIF2: "startColumn":1,
+// SARIF2: "startLine":12
+// SARIF2: }
+// SARIF2: }
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "message":{
+// SARIF2: "text":"'main' must return 'int'"
+// SARIF2: },
+// SARIF2: "ruleId":"3485",
+// SARIF2: "ruleIndex":0
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "level":"error",
+// SARIF2: "locations":[
+// SARIF2: {
+// SARIF2: "physicalLocation":{
+// SARIF2: "artifactLocation":{
+// SARIF2: "index":0,
+// SARIF2: "uri":{{"file://[^"]+/clang/test/Frontend/sarif-diagnostics.cpp"}}
+// SARIF2: },
+// SARIF2: "region":{
+// SARIF2: "endColumn":11,
+// SARIF2: "startColumn":11,
+// SARIF2: "startLine":13
+// SARIF2: }
+// SARIF2: }
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "message":{
+// SARIF2: "text":"use of undeclared identifier 'hello'"
+// SARIF2: },
+// SARIF2: "ruleId":"4632",
+// SARIF2: "ruleIndex":1
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "level":"error",
+// SARIF2: "locations":[
+// SARIF2: {
+// SARIF2: "physicalLocation":{
+// SARIF2: "artifactLocation":{
+// SARIF2: "index":0,
+// SARIF2: "uri":{{"file://[^"]+/clang/test/Frontend/sarif-diagnostics.cpp"}}
+// SARIF2: },
+// SARIF2: "region":{
+// SARIF2: "endColumn":17,
+// SARIF2: "startColumn":17,
+// SARIF2: "startLine":15
+// SARIF2: }
+// SARIF2: }
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "message":{
+// SARIF2: "text":"invalid digit 'a' in decimal constant"
+// SARIF2: },
+// SARIF2: "ruleId":"898",
+// SARIF2: "ruleIndex":2
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "level":"warning",
+// SARIF2: "locations":[
+// SARIF2: {
+// SARIF2: "physicalLocation":{
+// SARIF2: "artifactLocation":{
+// SARIF2: "index":0,
+// SARIF2: "uri":{{"file://[^"]+clang/test/Frontend/sarif-diagnostics.cpp"}}
+// SARIF2: },
+// SARIF2: "region":{
+// SARIF2: "endColumn":5,
+// SARIF2: "startColumn":5,
+// SARIF2: "startLine":19
+// SARIF2: }
+// SARIF2: }
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "message":{
+// SARIF2: "text":"misleading indentation; statement is not part of the previous 'if'"
+// SARIF2: },
+// SARIF2: "ruleId":"1826",
+// SARIF2: "ruleIndex":3
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "level":"note",
+// SARIF2: "locations":[
+// SARIF2: {
+// SARIF2: "physicalLocation":{
+// SARIF2: "artifactLocation":{
+// SARIF2: "index":0,
+// SARIF2: "uri":{{"file://[^"]+/clang/test/Frontend/sarif-diagnostics.cpp"}}
+// SARIF2: },
+// SARIF2: "region":{
+// SARIF2: "endColumn":3,
+// SARIF2: "startColumn":3,
+// SARIF2: "startLine":17
+// SARIF2: }
+// SARIF2: }
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "message":{
+// SARIF2: "text":"previous statement is here"
+// SARIF2: },
+// SARIF2: "ruleId":"1746",
+// SARIF2: "ruleIndex":4
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "level":"warning",
+// SARIF2: "locations":[
+// SARIF2: {
+// SARIF2: "physicalLocation":{
+// SARIF2: "artifactLocation":{
+// SARIF2: "index":0,
+// SARIF2: "uri":{{"file://[^"]+clang/test/Frontend/sarif-diagnostics.cpp"}}
+// SARIF2: },
+// SARIF2: "region":{
+// SARIF2: "endColumn":10,
+// SARIF2: "startColumn":10,
+// SARIF2: "startLine":18
+// SARIF2: }
+// SARIF2: }
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "message":{
+// SARIF2: "text":"unused variable 'Yes'"
+// SARIF2: },
+// SARIF2: "ruleId":"6593",
+// SARIF2: "ruleIndex":5
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "level":"error",
+// SARIF2: "locations":[
+// SARIF2: {
+// SARIF2: "physicalLocation":{
+// SARIF2: "artifactLocation":{
+// SARIF2: "index":0,
+// SARIF2: "uri":{{"file://[^"]+clang/test/Frontend/sarif-diagnostics.cpp"}}
+// SARIF2: },
+// SARIF2: "region":{
+// SARIF2: "endColumn":12,
+// SARIF2: "startColumn":12,
+// SARIF2: "startLine":21
+// SARIF2: }
+// SARIF2: }
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "message":{
+// SARIF2: "text":"use of undeclared identifier 'hi'"
+// SARIF2: },
+// SARIF2: "ruleId":"4632",
+// SARIF2: "ruleIndex":6
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "level":"error",
+// SARIF2: "locations":[
+// SARIF2: {
+// SARIF2: "physicalLocation":{
+// SARIF2: "artifactLocation":{
+// SARIF2: "index":0,
+// SARIF2: "uri":{{"file://[^"]+/clang/test/Frontend/sarif-diagnostics.cpp"}}
+// SARIF2: },
+// SARIF2: "region":{
+// SARIF2: "endColumn":1,
+// SARIF2: "startColumn":1,
+// SARIF2: "startLine":23
+// SARIF2: }
+// SARIF2: }
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "message":{
+// SARIF2: "text":"extraneous closing brace ('}')"
+// SARIF2: },
+// SARIF2: "ruleId":"1400",
+// SARIF2: "ruleIndex":7
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "level":"error",
+// SARIF2: "locations":[
+// SARIF2: {
+// SARIF2: "physicalLocation":{
+// SARIF2: "artifactLocation":{
+// SARIF2: "index":0,
+// SARIF2: "uri":{{"file://[^"]+/clang/test/Frontend/sarif-diagnostics.cpp"}}
+// SARIF2: },
+// SARIF2: "region":{
+// SARIF2: "endColumn":6,
+// SARIF2: "endLine":27,
+// SARIF2: "startColumn":5,
+// SARIF2: "startLine":27
+// SARIF2: }
+// SARIF2: }
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "physicalLocation":{
+// SARIF2: "artifactLocation":{
+// SARIF2: "index":0,
+// SARIF2: "uri":{{"file://[^"]+/clang/test/Frontend/sarif-diagnostics.cpp"}}
+// SARIF2: },
+// SARIF2: "region":{
+// SARIF2: "endColumn":10,
+// SARIF2: "endLine":27,
+// SARIF2: "startColumn":9,
+// SARIF2: "startLine":27
+// SARIF2: }
+// SARIF2: }
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "physicalLocation":{
+// SARIF2: "artifactLocation":{
+// SARIF2: "index":0,
+// SARIF2: "uri":{{"file://[^"]+/clang/test/Frontend/sarif-diagnostics.cpp"}}
+// SARIF2: },
+// SARIF2: "region":{
+// SARIF2: "endColumn":7,
+// SARIF2: "startColumn":7,
+// SARIF2: "startLine":27
+// SARIF2: }
+// SARIF2: }
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "message":{
+// SARIF2: "text":"invalid operands to binary expression ('t1' and 't1')"
+// SARIF2: },
+// SARIF2: "ruleId":"4567",
+// SARIF2: "ruleIndex":8
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "level":"note",
+// SARIF2: "locations":[
+// SARIF2: {
+// SARIF2: "physicalLocation":{
+// SARIF2: "artifactLocation":{
+// SARIF2: "index":0,
+// SARIF2: "uri":{{"file://[^"]+/clang/test/Frontend/sarif-diagnostics.cpp"}}
+// SARIF2: },
+// SARIF2: "region":{
+// SARIF2: "endColumn":10,
+// SARIF2: "startColumn":10,
+// SARIF2: "startLine":30
+// SARIF2: }
+// SARIF2: }
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "message":{
+// SARIF2: "text":"in file included from {{[^"]+test/Frontend/sarif-diagnostics.cpp:30:}}\n"
+// SARIF2: },
+// SARIF2: "ruleId":"-1",
+// SARIF2: "ruleIndex":9
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "level":"error",
+// SARIF2: "locations":[
+// SARIF2: {
+// SARIF2: "physicalLocation":{
+// SARIF2: "artifactLocation":{
+// SARIF2: "index":1,
+// SARIF2: "uri":"file:///{{[^"]+/test/Frontend/sarif-diagnostics.hpp}}"
+// SARIF2: },
+// SARIF2: "region":{
+// SARIF2: "endColumn":1,
+// SARIF2: "startColumn":1,
+// SARIF2: "startLine":1
+// SARIF2: }
+// SARIF2: }
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "message":{
+// SARIF2: "text":"unknown type name 'Test'"
+// SARIF2: },
+// SARIF2: "ruleId":"4657",
+// SARIF2: "ruleIndex":10
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "tool":{
+// SARIF2: "driver":{
+// SARIF2: "fullName":"",
+// SARIF2: "informationUri":"https://clang.llvm.org/docs/UsersManual.html",
+// SARIF2: "language":"en-US",
+// SARIF2: "name":"clang",
+// SARIF2: "rules":[
+// SARIF2: {
+// SARIF2: "defaultConfiguration":{
+// SARIF2: "enabled":true,
+// SARIF2: "level":"error",
+// SARIF2: "rank":50
+// SARIF2: },
+// SARIF2: "fullDescription":{
+// SARIF2: "text":""
+// SARIF2: },
+// SARIF2: "id":"3485",
+// SARIF2: "name":""
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "defaultConfiguration":{
+// SARIF2: "enabled":true,
+// SARIF2: "level":"error",
+// SARIF2: "rank":50
+// SARIF2: },
+// SARIF2: "fullDescription":{
+// SARIF2: "text":""
+// SARIF2: },
+// SARIF2: "id":"4632",
+// SARIF2: "name":""
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "defaultConfiguration":{
+// SARIF2: "enabled":true,
+// SARIF2: "level":"error",
+// SARIF2: "rank":50
+// SARIF2: },
+// SARIF2: "fullDescription":{
+// SARIF2: "text":""
+// SARIF2: },
+// SARIF2: "id":"898",
+// SARIF2: "name":""
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "defaultConfiguration":{
+// SARIF2: "enabled":true,
+// SARIF2: "level":"warning",
+// SARIF2: "rank":-1
+// SARIF2: },
+// SARIF2: "fullDescription":{
+// SARIF2: "text":""
+// SARIF2: },
+// SARIF2: "id":"1826",
+// SARIF2: "name":""
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "defaultConfiguration":{
+// SARIF2: "enabled":true,
+// SARIF2: "level":"note",
+// SARIF2: "rank":-1
+// SARIF2: },
+// SARIF2: "fullDescription":{
+// SARIF2: "text":""
+// SARIF2: },
+// SARIF2: "id":"1746",
+// SARIF2: "name":""
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "defaultConfiguration":{
+// SARIF2: "enabled":true,
+// SARIF2: "level":"warning",
+// SARIF2: "rank":-1
+// SARIF2: },
+// SARIF2: "fullDescription":{
+// SARIF2: "text":""
+// SARIF2: },
+// SARIF2: "id":"6593",
+// SARIF2: "name":""
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "defaultConfiguration":{
+// SARIF2: "enabled":true,
+// SARIF2: "level":"error",
+// SARIF2: "rank":50
+// SARIF2: },
+// SARIF2: "fullDescription":{
+// SARIF2: "text":""
+// SARIF2: },
+// SARIF2: "id":"4632",
+// SARIF2: "name":""
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "defaultConfiguration":{
+// SARIF2: "enabled":true,
+// SARIF2: "level":"error",
+// SARIF2: "rank":50
+// SARIF2: },
+// SARIF2: "fullDescription":{
+// SARIF2: "text":""
+// SARIF2: },
+// SARIF2: "id":"1400",
+// SARIF2: "name":""
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "defaultConfiguration":{
+// SARIF2: "enabled":true,
+// SARIF2: "level":"error",
+// SARIF2: "rank":50
+// SARIF2: },
+// SARIF2: "fullDescription":{
+// SARIF2: "text":""
+// SARIF2: },
+// SARIF2: "id":"4567",
+// SARIF2: "name":""
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "defaultConfiguration":{
+// SARIF2: "enabled":true,
+// SARIF2: "level":"note",
+// SARIF2: "rank":-1
+// SARIF2: },
+// SARIF2: "fullDescription":{
+// SARIF2: "text":""
+// SARIF2: },
+// SARIF2: "id":"-1",
+// SARIF2: "name":""
+// SARIF2: },
+// SARIF2: {
+// SARIF2: "defaultConfiguration":{
+// SARIF2: "enabled":true,
+// SARIF2: "level":"error",
+// SARIF2: "rank":50
+// SARIF2: },
+// SARIF2: "fullDescription":{
+// SARIF2: "text":""
+// SARIF2: },
+// SARIF2: "id":"4657",
+// SARIF2: "name":""
+// SARIF2: }
+// SARIF2: ],
+// SARIF2: "version":"17.0.0"
+// SARIF2: }
+// SARIF2: }
+// SARIF2: }
// SARIF: ],
// SARIF: "version":"2.1.0"
// SARIF: }
Index: clang/test/Driver/fdiagnostics-format-sarif.cpp
===================================================================
--- clang/test/Driver/fdiagnostics-format-sarif.cpp
+++ clang/test/Driver/fdiagnostics-format-sarif.cpp
@@ -1,5 +1,6 @@
-// RUN: %clang -fsyntax-only -fdiagnostics-format=sarif %s -### 2>&1 | FileCheck %s --check-prefix=WARN
+// RUN: %clang -fsyntax-only -fdiagnostics-format=sarif-stderr %s -### 2>&1 | FileCheck %s --check-prefix=WARN
+// RUN: %clang -fsyntax-only -fdiagnostics-format=sarif-file %s -### 2>&1 | FileCheck %s --check-prefixes=WARN,ERROR
+// RUN: %clang -fsyntax-only -fdiagnostics-file-path=test %s -### 2>&1 | FileCheck %s --check-prefixes=WARN2
// WARN: warning: diagnostic formatting in SARIF mode is currently unstable [-Wsarif-format-unstable]
-
-// RUN: %clang -fsyntax-only -fdiagnostics-format=SARIF %s -### 2>&1 | FileCheck %s --check-prefix=WARN2
-// WARN2: warning: diagnostic formatting in SARIF mode is currently unstable [-Wsarif-format-unstable]
+// ERROR: error: '-fdiagnostics-file-path' must be set when combining '-fsyntax-only' with '-fdiagnostics-format=sarif-file'
+// WARN2: warning: argument unused during compilation: '-fdiagnostics-file-path=test' [-Wunused-command-line-argument]
Index: clang/lib/Tooling/Tooling.cpp
===================================================================
--- clang/lib/Tooling/Tooling.cpp
+++ clang/lib/Tooling/Tooling.cpp
@@ -684,7 +684,7 @@
if (!Invocation.run())
return nullptr;
-
+
assert(ASTs.size() == 1);
return std::move(ASTs[0]);
}
Index: clang/lib/Tooling/SarifLinker.cpp
===================================================================
--- /dev/null
+++ clang/lib/Tooling/SarifLinker.cpp
@@ -0,0 +1,125 @@
+#include "clang/Basic/Sarif.h"
+#include "clang/Config/config.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/Process.h"
+#include <cassert>
+#include <cstdlib>
+#include <fstream>
+#include <iterator>
+#include <string>
+#include <string_view>
+#include <system_error>
+
+namespace llvm::sarif_linker {
+[[noreturn]] void ReportErrorAndExit(llvm::errc error_code, StringRef Message) {
+ llvm::errs() << "sarif-ld: error: " << Message << '\n';
+ std::exit(static_cast<int>(error_code));
+}
+
+static json::Value ReadSarifDiagnostics(StringRef Path) {
+ std::ifstream in(Path.data());
+ if (!in) {
+ ReportErrorAndExit(llvm::errc::io_error, (Path + " not found").str());
+ }
+
+ in >> std::noskipws;
+ std::string data(std::istream_iterator<char>(in), {});
+ assert(!in);
+ if (!in.eof()) {
+ ReportErrorAndExit(llvm::errc::io_error, "Unable to read " + Path.str());
+ }
+
+ llvm::Expected<json::Value> value = json::parse(data);
+ if (!value) {
+ ReportErrorAndExit(llvm::errc::invalid_argument,
+ "SARIF requires a valid JSON format");
+ }
+
+ // FIXME: we should eventually replace this with a proper SARIF validation
+ // algorithm. For now, we're just checking that a few fields are present
+ // (namely to ensure it "looks" like a SARIF file, and to check the fields
+ // we need are around).
+ json::Object *object = value->getAsObject();
+ if (object == nullptr) {
+ ReportErrorAndExit(llvm::errc::invalid_argument,
+ "SARIF requires the top-level value to be an object");
+ }
+
+ if (object->getString("$schema") == std::nullopt) {
+ ReportErrorAndExit(llvm::errc::invalid_argument,
+ "SARIF requires there to be a `$schema` string field");
+ }
+
+ if (object->getString("version") == std::nullopt) {
+ ReportErrorAndExit(llvm::errc::invalid_argument,
+ "SARIF requires there to be a `version` string field");
+ }
+
+ if (object->getArray("runs") == nullptr) {
+ ReportErrorAndExit(llvm::errc::invalid_argument,
+ "SARIF requires there to be a `runs` array field");
+ }
+
+ return *value;
+}
+
+template <class JsonValue> static auto &getRuns(JsonValue &value) {
+ return *value.getAsObject()->getArray("runs")->front().getAsObject();
+}
+
+static json::Value ReduceSarif(json::Value Init,
+ ArrayRef<json::Value> SarifObjects) {
+ json::Object &FirstRuns = getRuns(Init);
+ json::Array &FirstArtifacts = *FirstRuns.getArray("artifacts");
+ json::Array &FirstResults = *FirstRuns.getArray("results");
+
+ for (const json::Value &Other : SarifObjects) {
+ const json::Object &OtherRuns = getRuns(Other);
+ const json::Array &Artifacts = *OtherRuns.getArray("artifacts");
+ FirstArtifacts.insert(FirstArtifacts.end(), Artifacts.begin(),
+ Artifacts.end());
+
+ const json::Array &Results = *OtherRuns.getArray("results");
+ FirstResults.insert(FirstResults.end(), Results.begin(), Results.end());
+ }
+
+ return Init;
+}
+
+std::error_code LinkSarifDiagnostics(const opt::ArgStringList &InputPaths,
+ StringRef OutputPath) {
+ assert(InputPaths.size() > 0 && "There needs to be at least one Input path.");
+ std::vector<std::string> SarifDiagnosticPaths;
+ llvm::copy_if(InputPaths, std::back_inserter(SarifDiagnosticPaths),
+ [](StringRef File) { return File.ends_with(".o"); });
+ llvm::transform(SarifDiagnosticPaths, SarifDiagnosticPaths.begin(),
+ [](const std::string &Temp) { return Temp + ".sarif"; });
+
+ std::vector<json::Value> JSONData;
+ llvm::transform(SarifDiagnosticPaths, std::back_inserter(JSONData),
+ [](StringRef Path) {
+ json::Value SarifDiagnostics = ReadSarifDiagnostics(Path);
+ return SarifDiagnostics;
+ });
+
+ json::Value Output = ReduceSarif(
+ std::move(JSONData[0]), ArrayRef<json::Value>(JSONData).drop_front());
+
+ std::error_code EC;
+ llvm::raw_fd_ostream Out(OutputPath.str() + ".sarif", EC);
+ if (EC) {
+ return EC;
+ }
+
+ Out << Output;
+ return EC;
+}
+} // namespace llvm::sarif_linker
Index: clang/lib/Tooling/CMakeLists.txt
===================================================================
--- clang/lib/Tooling/CMakeLists.txt
+++ clang/lib/Tooling/CMakeLists.txt
@@ -113,6 +113,7 @@
JSONCompilationDatabase.cpp
Refactoring.cpp
RefactoringCallbacks.cpp
+ SarifLinker.cpp
StandaloneExecution.cpp
NodeIntrospection.cpp
${BINARY_INCLUDE_DIR}/NodeIntrospection.inc
Index: clang/lib/Frontend/TextDiagnostic.cpp
===================================================================
--- clang/lib/Frontend/TextDiagnostic.cpp
+++ clang/lib/Frontend/TextDiagnostic.cpp
@@ -815,7 +815,8 @@
emitFilename(PLoc.getFilename(), Loc.getManager());
switch (DiagOpts->getFormat()) {
- case DiagnosticOptions::SARIF:
+ case DiagnosticOptions::SARIFStderr:
+ case DiagnosticOptions::SARIFFile:
case DiagnosticOptions::Clang:
if (DiagOpts->ShowLine)
OS << ':' << LineNo;
@@ -838,7 +839,8 @@
OS << ColNo;
}
switch (DiagOpts->getFormat()) {
- case DiagnosticOptions::SARIF:
+ case DiagnosticOptions::SARIFStderr:
+ case DiagnosticOptions::SARIFFile:
case DiagnosticOptions::Clang:
case DiagnosticOptions::Vi: OS << ':'; break;
case DiagnosticOptions::MSVC:
Index: clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
===================================================================
--- clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
+++ clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
@@ -22,19 +22,37 @@
#include "llvm/Support/JSON.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <memory>
namespace clang {
SARIFDiagnosticPrinter::SARIFDiagnosticPrinter(raw_ostream &OS,
DiagnosticOptions *Diags)
- : OS(OS), DiagOpts(Diags) {}
+ : OS(&OS), DiagOpts(Diags) {}
+
+static std::unique_ptr<llvm::raw_ostream>
+OpenDiagnosticFile(StringRef TargetPath, std::error_code &EC) {
+ assert(!TargetPath.empty());
+ return std::make_unique<llvm::raw_fd_ostream>(
+ std::string(TargetPath) + ".sarif", EC);
+}
+
+SARIFDiagnosticPrinter::SARIFDiagnosticPrinter(StringRef TargetPath,
+ DiagnosticOptions *Diags)
+ : EC(std::error_code()), OS(OpenDiagnosticFile(TargetPath, *EC)),
+ DiagOpts(Diags) {
+ if (*EC) {
+ assert(false and "not implemented yet: not even sure what to do");
+ }
+}
void SARIFDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
const Preprocessor *PP) {
// Build the SARIFDiagnostic utility.
assert(hasSarifWriter() && "Writer not set!");
assert(!SARIFDiag && "SARIFDiagnostic already set.");
- SARIFDiag = std::make_unique<SARIFDiagnostic>(OS, LO, &*DiagOpts, &*Writer);
+ SARIFDiag =
+ std::make_unique<SARIFDiagnostic>(getOS(), LO, &*DiagOpts, &*Writer);
// Initialize the SARIF object.
Writer->createRun("clang", Prefix);
}
@@ -43,8 +61,13 @@
assert(SARIFDiag && "SARIFDiagnostic has not been set.");
Writer->endRun();
llvm::json::Value Value(Writer->createDocument());
- OS << "\n" << Value << "\n\n";
- OS.flush();
+ getOS() << '\n' << Value << '\n';
+ getOS().flush();
+ if (EC and *EC) {
+ llvm::errs() << "error: " << EC->message() << '\n';
+ llvm::errs() << "outputting to stderr as a backup\n";
+ llvm::errs() << Value << '\n';
+ }
SARIFDiag.reset();
}
Index: clang/lib/Frontend/FrontendAction.cpp
===================================================================
--- clang/lib/Frontend/FrontendAction.cpp
+++ clang/lib/Frontend/FrontendAction.cpp
@@ -724,7 +724,9 @@
}
if (!CI.hasSourceManager()) {
CI.createSourceManager(CI.getFileManager());
- if (CI.getDiagnosticOpts().getFormat() == DiagnosticOptions::SARIF) {
+ if (TextDiagnosticFormat Format = CI.getDiagnosticOpts().getFormat();
+ Format == DiagnosticOptions::SARIFStderr ||
+ Format == DiagnosticOptions::SARIFFile) {
static_cast<SARIFDiagnosticPrinter *>(&CI.getDiagnosticClient())
->setSarifWriter(
std::make_unique<SarifDocumentWriter>(CI.getSourceManager()));
Index: clang/lib/Frontend/CompilerInstance.cpp
===================================================================
--- clang/lib/Frontend/CompilerInstance.cpp
+++ clang/lib/Frontend/CompilerInstance.cpp
@@ -333,16 +333,15 @@
}
void CompilerInstance::createDiagnostics(DiagnosticConsumer *Client,
- bool ShouldOwnClient) {
- Diagnostics = createDiagnostics(&getDiagnosticOpts(), Client,
- ShouldOwnClient, &getCodeGenOpts());
+ bool ShouldOwnClient,
+ StringRef Output) {
+ Diagnostics = createDiagnostics(&getDiagnosticOpts(), Client, ShouldOwnClient,
+ &getCodeGenOpts(), Output);
}
-IntrusiveRefCntPtr<DiagnosticsEngine>
-CompilerInstance::createDiagnostics(DiagnosticOptions *Opts,
- DiagnosticConsumer *Client,
- bool ShouldOwnClient,
- const CodeGenOptions *CodeGenOpts) {
+IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics(
+ DiagnosticOptions *Opts, DiagnosticConsumer *Client, bool ShouldOwnClient,
+ const CodeGenOptions *CodeGenOpts, StringRef OutputPath) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine>
Diags(new DiagnosticsEngine(DiagID, Opts));
@@ -351,10 +350,16 @@
// implementing -verify.
if (Client) {
Diags->setClient(Client, ShouldOwnClient);
- } else if (Opts->getFormat() == DiagnosticOptions::SARIF) {
+ } else if (Opts->getFormat() == DiagnosticOptions::SARIFStderr) {
Diags->setClient(new SARIFDiagnosticPrinter(llvm::errs(), Opts));
- } else
+ } else if (Opts->getFormat() == DiagnosticOptions::SARIFFile) {
+ if (OutputPath.empty())
+ goto Default;
+ Diags->setClient(new SARIFDiagnosticPrinter(OutputPath, Opts));
+ } else {
+ Default:
Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
+ }
// Chain in -verify checker, if requested.
if (Opts->VerifyDiagnostics)
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -4029,12 +4029,26 @@
CmdArgs.push_back(Args.MakeArgString(Opt));
}
- if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
+ if (const Arg *Format =
+ Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
CmdArgs.push_back("-fdiagnostics-format");
- CmdArgs.push_back(A->getValue());
- if (StringRef(A->getValue()) == "sarif" ||
- StringRef(A->getValue()) == "SARIF")
+ CmdArgs.push_back(Format->getValue());
+ if (StringRef(Format->getValue()).starts_with("sarif"))
D.Diag(diag::warn_drv_sarif_format_unstable);
+
+ const Arg *Path = Args.getLastArg(options::OPT_fdiagnostics_file_path_EQ);
+ if (StringRef(Format->getValue()).ends_with("-file")) {
+ if (Path != nullptr) {
+ CmdArgs.push_back("-fdiagnostics-file-path");
+ CmdArgs.push_back(Path->getValue());
+ } else if (const Arg *SyntaxOnly =
+ Args.getLastArg(options::OPT_fsyntax_only))
+ D.Diag(diag::err_drv_diagnostics_format_file_fsyntax_only)
+ << Format->getValue();
+ else
+ D.Diag(diag::warn_drv_implicit_diagnostics_format_file)
+ << Format->getValue();
+ }
}
if (const Arg *A = Args.getLastArg(
Index: clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
===================================================================
--- clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
+++ clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
@@ -20,6 +20,8 @@
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
#include <memory>
+#include <optional>
+#include <variant>
namespace clang {
class DiagnosticOptions;
@@ -30,6 +32,12 @@
class SARIFDiagnosticPrinter : public DiagnosticConsumer {
public:
SARIFDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions *Diags);
+
+ /// Constructs a SARIFDiagnosticPrinter so that it writes to a file mimicing
+ /// Clang's current output target. The diagnostics file target has the same
+ /// name suffixed with `.sarif`.
+ SARIFDiagnosticPrinter(StringRef TargetPath, DiagnosticOptions *Diags);
+
~SARIFDiagnosticPrinter() = default;
SARIFDiagnosticPrinter &operator=(const SARIFDiagnosticPrinter &&) = delete;
@@ -59,7 +67,8 @@
const Diagnostic &Info) override;
private:
- raw_ostream &OS;
+ std::optional<std::error_code> EC;
+ std::variant<raw_ostream *, std::unique_ptr<raw_ostream>> OS;
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
/// Handle to the currently active SARIF diagnostic emitter.
@@ -69,6 +78,16 @@
std::string Prefix;
std::unique_ptr<SarifDocumentWriter> Writer;
+
+ raw_ostream &getOS() {
+ // Deliberately not using std::visit due to there being exactly two known
+ // types.
+ if (std::holds_alternative<raw_ostream *>(OS)) {
+ return *std::get<raw_ostream *>(OS);
+ } else {
+ return *std::get<std::unique_ptr<raw_ostream>>(OS);
+ }
+ }
};
} // end namespace clang
Index: clang/include/clang/Frontend/CompilerInstance.h
===================================================================
--- clang/include/clang/Frontend/CompilerInstance.h
+++ clang/include/clang/Frontend/CompilerInstance.h
@@ -606,8 +606,10 @@
///
/// \param ShouldOwnClient If Client is non-NULL, specifies whether
/// the diagnostic object should take ownership of the client.
+ ///
+ /// \param ToFile Determines if Clang should write diagnostics to a file.
void createDiagnostics(DiagnosticConsumer *Client = nullptr,
- bool ShouldOwnClient = true);
+ bool ShouldOwnClient = true, StringRef Output = "");
/// Create a DiagnosticsEngine object with a the TextDiagnosticPrinter.
///
@@ -626,12 +628,16 @@
/// \param CodeGenOpts If non-NULL, the code gen options in use, which may be
/// used by some diagnostics printers (for logging purposes only).
///
+ /// \param TargetPath Path to the target that Clang is currently producing.
+ /// This will be used as the prefix of any file that Clang may write
+ /// diagnostics to (e.g. `-fdiagnostics-format=sarif-file -o /tmp/hello` would
+ /// lead to there being a file called `/tmp/hello.sarif`).
+ ///
/// \return The new object on success, or null on failure.
- static IntrusiveRefCntPtr<DiagnosticsEngine>
- createDiagnostics(DiagnosticOptions *Opts,
- DiagnosticConsumer *Client = nullptr,
- bool ShouldOwnClient = true,
- const CodeGenOptions *CodeGenOpts = nullptr);
+ static IntrusiveRefCntPtr<DiagnosticsEngine> createDiagnostics(
+ DiagnosticOptions *Opts, DiagnosticConsumer *Client = nullptr,
+ bool ShouldOwnClient = true, const CodeGenOptions *CodeGenOpts = nullptr,
+ StringRef TargetPath = "");
/// Create the file manager and replace any existing one with it.
///
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1555,6 +1555,7 @@
PosFlag<SetTrue, [], "Display include stacks for diagnostic notes">,
NegFlag<SetFalse>, BothFlags<[CC1Option]>>;
def fdiagnostics_format_EQ : Joined<["-"], "fdiagnostics-format=">, Group<f_clang_Group>;
+def fdiagnostics_file_path_EQ : Joined<["-"], "fdiagnostics-file-path=">, Group<f_clang_Group>;
def fdiagnostics_show_category_EQ : Joined<["-"], "fdiagnostics-show-category=">, Group<f_clang_Group>;
def fdiagnostics_show_template_tree : Flag<["-"], "fdiagnostics-show-template-tree">,
Group<f_Group>, Flags<[CC1Option]>,
@@ -5843,9 +5844,12 @@
def fdiagnostics_format : Separate<["-"], "fdiagnostics-format">,
HelpText<"Change diagnostic formatting to match IDE and command line tools">,
- Values<"clang,msvc,vi,sarif,SARIF">,
- NormalizedValuesScope<"DiagnosticOptions">, NormalizedValues<["Clang", "MSVC", "Vi", "SARIF", "SARIF"]>,
+ Values<"clang,msvc,vi,sarif-stderr,sarif-file">,
+ NormalizedValuesScope<"DiagnosticOptions">, NormalizedValues<["Clang", "MSVC", "Vi", "SARIFStderr", "SARIFFile"]>,
MarshallingInfoEnum<DiagnosticOpts<"Format">, "Clang">;
+def fdiagnostics_file_path : Separate<["-"], "fdiagnostics-file-path">,
+ HelpText<"FIX BEFORE MERGING">,
+ MarshallingInfoString<DiagnosticOpts<"FilePath">>;
def fdiagnostics_show_category : Separate<["-"], "fdiagnostics-show-category">,
HelpText<"Print diagnostic category">,
Values<"none,id,name">,
Index: clang/include/clang/Basic/DiagnosticOptions.h
===================================================================
--- clang/include/clang/Basic/DiagnosticOptions.h
+++ clang/include/clang/Basic/DiagnosticOptions.h
@@ -74,7 +74,7 @@
friend class CompilerInvocation;
public:
- enum TextDiagnosticFormat { Clang, MSVC, Vi, SARIF };
+ enum TextDiagnosticFormat { Clang, MSVC, Vi, SARIFStderr, SARIFFile };
// Default values.
enum {
@@ -106,6 +106,9 @@
/// The file to serialize diagnostics to (non-appending).
std::string DiagnosticSerializationFile;
+ /// The file to serialise text diagnostics to (non-appending).
+ std::string FilePath;
+
/// The list of -W... options used to alter the diagnostic mappings, with the
/// prefixes removed.
std::vector<std::string> Warnings;
Index: clang/include/clang/Basic/DiagnosticOptions.def
===================================================================
--- clang/include/clang/Basic/DiagnosticOptions.def
+++ clang/include/clang/Basic/DiagnosticOptions.def
@@ -63,7 +63,7 @@
VALUE_DIAGOPT(ShowCategories, 2, 0) /// Show categories: 0 -> none, 1 -> Number,
/// 2 -> Full Name.
-ENUM_DIAGOPT(Format, TextDiagnosticFormat, 2, Clang) /// Format for diagnostics:
+ENUM_DIAGOPT(Format, TextDiagnosticFormat, 3, Clang) /// Format for diagnostics:
DIAGOPT(ShowColors, 1, 0) /// Show diagnostics with ANSI color sequences.
DIAGOPT(UseANSIEscapeCodes, 1, 0)
Index: clang/include/clang/Basic/DiagnosticDriverKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -710,6 +710,12 @@
def warn_drv_sarif_format_unstable : Warning<
"diagnostic formatting in SARIF mode is currently unstable">,
InGroup<DiagGroup<"sarif-format-unstable">>;
+def warn_drv_implicit_diagnostics_format_file : Warning<
+ "'-fdiagnostics-file-path' should be set when using '-fdiagnostics-format=%0'">,
+ InGroup<DiagGroup<"implicit-diagnostics-format-file">>;
+def err_drv_diagnostics_format_file_fsyntax_only : Error<
+ "'-fdiagnostics-file-path' must be set when combining '-fsyntax-only' with "
+ "'-fdiagnostics-format=%0'">;
def err_drv_riscv_unsupported_with_linker_relaxation : Error<
"%0 is unsupported with RISC-V linker relaxation (-mrelax)">;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits