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