clang  19.0.0git
LogDiagnosticPrinter.cpp
Go to the documentation of this file.
1 //===--- LogDiagnosticPrinter.cpp - Log 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 
14 #include "llvm/ADT/SmallString.h"
15 #include "llvm/Support/ErrorHandling.h"
16 #include "llvm/Support/raw_ostream.h"
17 using namespace clang;
18 using namespace markup;
19 
21  raw_ostream &os, DiagnosticOptions *diags,
22  std::unique_ptr<raw_ostream> StreamOwner)
23  : OS(os), StreamOwner(std::move(StreamOwner)), LangOpts(nullptr),
24  DiagOpts(diags) {}
25 
27  switch (Level) {
28  case DiagnosticsEngine::Ignored: return "ignored";
29  case DiagnosticsEngine::Remark: return "remark";
30  case DiagnosticsEngine::Note: return "note";
31  case DiagnosticsEngine::Warning: return "warning";
32  case DiagnosticsEngine::Error: return "error";
33  case DiagnosticsEngine::Fatal: return "fatal error";
34  }
35  llvm_unreachable("Invalid DiagnosticsEngine level!");
36 }
37 
38 void
39 LogDiagnosticPrinter::EmitDiagEntry(llvm::raw_ostream &OS,
40  const LogDiagnosticPrinter::DiagEntry &DE) {
41  OS << " <dict>\n";
42  OS << " <key>level</key>\n"
43  << " ";
44  EmitString(OS, getLevelName(DE.DiagnosticLevel)) << '\n';
45  if (!DE.Filename.empty()) {
46  OS << " <key>filename</key>\n"
47  << " ";
48  EmitString(OS, DE.Filename) << '\n';
49  }
50  if (DE.Line != 0) {
51  OS << " <key>line</key>\n"
52  << " ";
53  EmitInteger(OS, DE.Line) << '\n';
54  }
55  if (DE.Column != 0) {
56  OS << " <key>column</key>\n"
57  << " ";
58  EmitInteger(OS, DE.Column) << '\n';
59  }
60  if (!DE.Message.empty()) {
61  OS << " <key>message</key>\n"
62  << " ";
63  EmitString(OS, DE.Message) << '\n';
64  }
65  OS << " <key>ID</key>\n"
66  << " ";
67  EmitInteger(OS, DE.DiagnosticID) << '\n';
68  if (!DE.WarningOption.empty()) {
69  OS << " <key>WarningOption</key>\n"
70  << " ";
71  EmitString(OS, DE.WarningOption) << '\n';
72  }
73  OS << " </dict>\n";
74 }
75 
77  // We emit all the diagnostics in EndSourceFile. However, we don't emit any
78  // entry if no diagnostics were present.
79  //
80  // Note that DiagnosticConsumer has no "end-of-compilation" callback, so we
81  // will miss any diagnostics which are emitted after and outside the
82  // translation unit processing.
83  if (Entries.empty())
84  return;
85 
86  // Write to a temporary string to ensure atomic write of diagnostic object.
87  SmallString<512> Msg;
88  llvm::raw_svector_ostream OS(Msg);
89 
90  OS << "<dict>\n";
91  if (!MainFilename.empty()) {
92  OS << " <key>main-file</key>\n"
93  << " ";
94  EmitString(OS, MainFilename) << '\n';
95  }
96  if (!DwarfDebugFlags.empty()) {
97  OS << " <key>dwarf-debug-flags</key>\n"
98  << " ";
99  EmitString(OS, DwarfDebugFlags) << '\n';
100  }
101  OS << " <key>diagnostics</key>\n";
102  OS << " <array>\n";
103  for (auto &DE : Entries)
104  EmitDiagEntry(OS, DE);
105  OS << " </array>\n";
106  OS << "</dict>\n";
107 
108  this->OS << OS.str();
109 }
110 
112  const Diagnostic &Info) {
113  // Default implementation (Warnings/errors count).
115 
116  // Initialize the main file name, if we haven't already fetched it.
117  if (MainFilename.empty() && Info.hasSourceManager()) {
118  const SourceManager &SM = Info.getSourceManager();
119  FileID FID = SM.getMainFileID();
120  if (FID.isValid()) {
121  if (OptionalFileEntryRef FE = SM.getFileEntryRefForID(FID))
122  MainFilename = std::string(FE->getName());
123  }
124  }
125 
126  // Create the diag entry.
127  DiagEntry DE;
128  DE.DiagnosticID = Info.getID();
129  DE.DiagnosticLevel = Level;
130 
131  DE.WarningOption =
132  std::string(DiagnosticIDs::getWarningOptionForDiag(DE.DiagnosticID));
133 
134  // Format the message.
135  SmallString<100> MessageStr;
136  Info.FormatDiagnostic(MessageStr);
137  DE.Message = std::string(MessageStr);
138 
139  // Set the location information.
140  DE.Filename = "";
141  DE.Line = DE.Column = 0;
142  if (Info.getLocation().isValid() && Info.hasSourceManager()) {
143  const SourceManager &SM = Info.getSourceManager();
144  PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
145 
146  if (PLoc.isInvalid()) {
147  // At least print the file name if available:
148  FileID FID = SM.getFileID(Info.getLocation());
149  if (FID.isValid()) {
150  if (OptionalFileEntryRef FE = SM.getFileEntryRefForID(FID))
151  DE.Filename = std::string(FE->getName());
152  }
153  } else {
154  DE.Filename = PLoc.getFilename();
155  DE.Line = PLoc.getLine();
156  DE.Column = PLoc.getColumn();
157  }
158  }
159 
160  // Record the diagnostic entry.
161  Entries.push_back(DE);
162 }
163 
#define SM(sm)
Definition: Cuda.cpp:83
Defines the clang::FileManager interface and associated types.
static StringRef getLevelName(DiagnosticsEngine::Level Level)
Defines the SourceManager interface.
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info)
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
Definition: Diagnostic.cpp:560
static StringRef getWarningOptionForDiag(unsigned DiagID)
Return the lowest-level warning option that enables the specified diagnostic.
Options for controlling the compiler diagnostics engine.
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
Definition: Diagnostic.h:1577
SourceManager & getSourceManager() const
Definition: Diagnostic.h:1590
void FormatDiagnostic(SmallVectorImpl< char > &OutStr) const
Format this diagnostic into a string, substituting the formal arguments into the %0 slots.
Definition: Diagnostic.cpp:791
bool hasSourceManager() const
Definition: Diagnostic.h:1589
unsigned getID() const
Definition: Diagnostic.h:1587
const SourceLocation & getLocation() const
Definition: Diagnostic.h:1588
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:196
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool isValid() const
LogDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions *Diags, std::unique_ptr< raw_ostream > StreamOwner)
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
void EndSourceFile() override
Callback to inform the diagnostic client that processing of a source file has ended.
Represents an unpacked "presumed" location which can be presented to the user.
unsigned getColumn() const
Return the presumed column number of this location.
const char * getFilename() const
Return the presumed filename of this location.
unsigned getLine() const
Return the presumed line number of this location.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
raw_ostream & EmitString(raw_ostream &o, StringRef s)
Definition: PlistSupport.h:78
raw_ostream & EmitInteger(raw_ostream &o, int64_t value)
Definition: PlistSupport.h:71
The JSON file list parser is used to communicate input to InstallAPI.
Definition: Format.h:5433