1 //===--- LogDiagnosticPrinter.cpp - Log Diagnostic Printer ----------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "clang/Frontend/LogDiagnosticPrinter.h"
11 #include "clang/Basic/FileManager.h"
12 #include "clang/Basic/SourceManager.h"
13 #include "llvm/ADT/SmallString.h"
14 #include "llvm/Support/raw_ostream.h"
15 using namespace clang
;
17 LogDiagnosticPrinter::LogDiagnosticPrinter(llvm::raw_ostream
&os
,
18 const DiagnosticOptions
&diags
,
19 bool _OwnsOutputStream
)
20 : OS(os
), LangOpts(0), DiagOpts(&diags
),
21 OwnsOutputStream(_OwnsOutputStream
) {
24 LogDiagnosticPrinter::~LogDiagnosticPrinter() {
29 static llvm::StringRef
getLevelName(Diagnostic::Level Level
) {
33 case Diagnostic::Ignored
: return "ignored";
34 case Diagnostic::Note
: return "note";
35 case Diagnostic::Warning
: return "warning";
36 case Diagnostic::Error
: return "error";
37 case Diagnostic::Fatal
: return "fatal error";
41 void LogDiagnosticPrinter::EndSourceFile() {
42 // We emit all the diagnostics in EndSourceFile. However, we don't emit any
43 // entry if no diagnostics were present.
45 // Note that DiagnosticClient has no "end-of-compilation" callback, so we will
46 // miss any diagnostics which are emitted after and outside the translation
51 // Write to a temporary string to ensure atomic write of diagnostic object.
52 llvm::SmallString
<512> Msg
;
53 llvm::raw_svector_ostream
OS(Msg
);
56 if (!MainFilename
.empty()) {
57 OS
<< " <key>main-file</key>\n"
58 << " <string>" << MainFilename
<< "</string>\n";
60 if (!DwarfDebugFlags
.empty()) {
61 OS
<< " <key>dwarf-debug-flags</key>\n"
62 << " <string>" << DwarfDebugFlags
<< "</string>\n";
64 OS
<< " <key>diagnostics</key>\n";
66 for (unsigned i
= 0, e
= Entries
.size(); i
!= e
; ++i
) {
67 DiagEntry
&DE
= Entries
[i
];
70 OS
<< " <key>level</key>\n"
71 << " <string>" << getLevelName(DE
.DiagnosticLevel
) << "</string>\n";
72 if (!DE
.Filename
.empty()) {
73 OS
<< " <key>filename</key>\n"
74 << " <string>" << DE
.Filename
<< "</string>\n";
77 OS
<< " <key>line</key>\n"
78 << " <integer>" << DE
.Line
<< "</integer>\n";
81 OS
<< " <key>column</key>\n"
82 << " <integer>" << DE
.Column
<< "</integer>\n";
84 if (!DE
.Message
.empty()) {
85 OS
<< " <key>message</key>\n"
86 << " <string>" << DE
.Message
<< "</string>\n";
96 void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level
,
97 const DiagnosticInfo
&Info
) {
98 // Default implementation (Warnings/errors count).
99 DiagnosticClient::HandleDiagnostic(Level
, Info
);
101 // Initialize the main file name, if we haven't already fetched it.
102 if (MainFilename
.empty() && Info
.hasSourceManager()) {
103 const SourceManager
&SM
= Info
.getSourceManager();
104 FileID FID
= SM
.getMainFileID();
105 if (!FID
.isInvalid()) {
106 const FileEntry
*FE
= SM
.getFileEntryForID(FID
);
107 if (FE
&& FE
->getName())
108 MainFilename
= FE
->getName();
112 // Create the diag entry.
114 DE
.DiagnosticID
= Info
.getID();
115 DE
.DiagnosticLevel
= Level
;
117 // Format the message.
118 llvm::SmallString
<100> MessageStr
;
119 Info
.FormatDiagnostic(MessageStr
);
120 DE
.Message
= MessageStr
.str();
122 // Set the location information.
124 DE
.Line
= DE
.Column
= 0;
125 if (Info
.getLocation().isValid() && Info
.hasSourceManager()) {
126 const SourceManager
&SM
= Info
.getSourceManager();
127 PresumedLoc PLoc
= SM
.getPresumedLoc(Info
.getLocation());
129 if (PLoc
.isInvalid()) {
130 // At least print the file name if available:
131 FileID FID
= SM
.getFileID(Info
.getLocation());
132 if (!FID
.isInvalid()) {
133 const FileEntry
*FE
= SM
.getFileEntryForID(FID
);
134 if (FE
&& FE
->getName())
135 DE
.Filename
= FE
->getName();
138 DE
.Filename
= PLoc
.getFilename();
139 DE
.Line
= PLoc
.getLine();
140 DE
.Column
= PLoc
.getColumn();
144 // Record the diagnostic entry.
145 Entries
.push_back(DE
);