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