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