1 //===------- SARIFDiagnosticPrinter.cpp - Diagnostic Printer---------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This diagnostic client prints out their diagnostic messages in SARIF format.
11 //===----------------------------------------------------------------------===//
13 #include "clang/Frontend/SARIFDiagnosticPrinter.h"
14 #include "clang/Basic/DiagnosticOptions.h"
15 #include "clang/Basic/Sarif.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "clang/Frontend/DiagnosticRenderer.h"
18 #include "clang/Frontend/SARIFDiagnostic.h"
19 #include "clang/Lex/Lexer.h"
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Support/JSON.h"
23 #include "llvm/Support/raw_ostream.h"
28 SARIFDiagnosticPrinter::SARIFDiagnosticPrinter(raw_ostream
&OS
,
29 DiagnosticOptions
*Diags
)
30 : OS(OS
), DiagOpts(Diags
) {}
32 void SARIFDiagnosticPrinter::BeginSourceFile(const LangOptions
&LO
,
33 const Preprocessor
*PP
) {
34 // Build the SARIFDiagnostic utility.
35 assert(hasSarifWriter() && "Writer not set!");
36 assert(!SARIFDiag
&& "SARIFDiagnostic already set.");
37 SARIFDiag
= std::make_unique
<SARIFDiagnostic
>(OS
, LO
, &*DiagOpts
, &*Writer
);
38 // Initialize the SARIF object.
39 Writer
->createRun("clang", Prefix
);
42 void SARIFDiagnosticPrinter::EndSourceFile() {
43 assert(SARIFDiag
&& "SARIFDiagnostic has not been set.");
45 llvm::json::Value
Value(Writer
->createDocument());
46 OS
<< "\n" << Value
<< "\n\n";
51 void SARIFDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level
,
52 const Diagnostic
&Info
) {
53 assert(SARIFDiag
&& "SARIFDiagnostic has not been set.");
54 // Default implementation (Warnings/errors count). Keeps track of the
56 DiagnosticConsumer::HandleDiagnostic(Level
, Info
);
58 // Render the diagnostic message into a temporary buffer eagerly. We'll use
59 // this later as we add the diagnostic to the SARIF object.
60 SmallString
<100> OutStr
;
61 Info
.FormatDiagnostic(OutStr
);
63 llvm::raw_svector_ostream
DiagMessageStream(OutStr
);
65 // Use a dedicated, simpler path for diagnostics without a valid location.
66 // This is important as if the location is missing, we may be emitting
67 // diagnostics in a context that lacks language options, a source manager, or
68 // other infrastructure necessary when emitting more rich diagnostics.
69 if (Info
.getLocation().isInvalid()) {
70 // FIXME: Enable diagnostics without a source manager
74 // Assert that the rest of our infrastructure is setup properly.
75 assert(DiagOpts
&& "Unexpected diagnostic without options set");
76 assert(Info
.hasSourceManager() &&
77 "Unexpected diagnostic with no source manager");
79 SARIFDiag
->emitDiagnostic(
80 FullSourceLoc(Info
.getLocation(), Info
.getSourceManager()), Level
,
81 DiagMessageStream
.str(), Info
.getRanges(), Info
.getFixItHints(), &Info
);