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-exception 6 // 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 23 namespace clang { 24 25 SARIFDiagnosticPrinter::SARIFDiagnosticPrinter(raw_ostream &OS, 26 DiagnosticOptions &DiagOpts) 27 : OS(OS), DiagOpts(DiagOpts) {} 28 29 void 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 39 void 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 48 void 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 the 52 // number of errors. 53 DiagnosticConsumer::HandleDiagnostic(Level, Info); 54 55 // Render the diagnostic message into a temporary buffer eagerly. We'll use 56 // 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 emitting 64 // diagnostics in a context that lacks language options, a source manager, or 65 // other infrastructure necessary when emitting more rich diagnostics. 66 if (Info.getLocation().isInvalid()) { 67 // FIXME: Enable diagnostics without a source manager 68 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 clang 80