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