SARIFDiagnosticPrinter.cpp 3.3 KB

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