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/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" 24 #include <algorithm> 25 26 namespace clang { 27 28 SARIFDiagnosticPrinter::SARIFDiagnosticPrinter(raw_ostream &OS, 29 DiagnosticOptions *Diags) 30 : OS(OS), DiagOpts(Diags) {} 31 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); 40 } 41 42 void SARIFDiagnosticPrinter::EndSourceFile() { 43 assert(SARIFDiag && "SARIFDiagnostic has not been set."); 44 Writer->endRun(); 45 llvm::json::Value Value(Writer->createDocument()); 46 OS << "\n" << Value << "\n\n"; 47 OS.flush(); 48 SARIFDiag.reset(); 49 } 50 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 55 // number of errors. 56 DiagnosticConsumer::HandleDiagnostic(Level, Info); 57 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); 62 63 llvm::raw_svector_ostream DiagMessageStream(OutStr); 64 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 71 return; 72 } 73 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"); 78 79 SARIFDiag->emitDiagnostic( 80 FullSourceLoc(Info.getLocation(), Info.getSourceManager()), Level, 81 DiagMessageStream.str(), Info.getRanges(), Info.getFixItHints(), &Info); 82 } 83 } // namespace clang 84