1 //===--- LogDiagnosticPrinter.cpp - Log Diagnostic Printer ----------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
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;
16
LogDiagnosticPrinter(llvm::raw_ostream & os,const DiagnosticOptions & diags,bool _OwnsOutputStream)17 LogDiagnosticPrinter::LogDiagnosticPrinter(llvm::raw_ostream &os,
18 const DiagnosticOptions &diags,
19 bool _OwnsOutputStream)
20 : OS(os), LangOpts(0), DiagOpts(&diags),
21 OwnsOutputStream(_OwnsOutputStream) {
22 }
23
~LogDiagnosticPrinter()24 LogDiagnosticPrinter::~LogDiagnosticPrinter() {
25 if (OwnsOutputStream)
26 delete &OS;
27 }
28
getLevelName(Diagnostic::Level Level)29 static llvm::StringRef getLevelName(Diagnostic::Level Level) {
30 switch (Level) {
31 default:
32 return "<unknown>";
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";
38 }
39 }
40
EndSourceFile()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.
44 //
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
47 // unit processing.
48 if (Entries.empty())
49 return;
50
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);
54
55 OS << "<dict>\n";
56 if (!MainFilename.empty()) {
57 OS << " <key>main-file</key>\n"
58 << " <string>" << MainFilename << "</string>\n";
59 }
60 if (!DwarfDebugFlags.empty()) {
61 OS << " <key>dwarf-debug-flags</key>\n"
62 << " <string>" << DwarfDebugFlags << "</string>\n";
63 }
64 OS << " <key>diagnostics</key>\n";
65 OS << " <array>\n";
66 for (unsigned i = 0, e = Entries.size(); i != e; ++i) {
67 DiagEntry &DE = Entries[i];
68
69 OS << " <dict>\n";
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";
75 }
76 if (DE.Line != 0) {
77 OS << " <key>line</key>\n"
78 << " <integer>" << DE.Line << "</integer>\n";
79 }
80 if (DE.Column != 0) {
81 OS << " <key>column</key>\n"
82 << " <integer>" << DE.Column << "</integer>\n";
83 }
84 if (!DE.Message.empty()) {
85 OS << " <key>message</key>\n"
86 << " <string>" << DE.Message << "</string>\n";
87 }
88 OS << " </dict>\n";
89 }
90 OS << " </array>\n";
91 OS << "</dict>\n";
92
93 this->OS << OS.str();
94 }
95
HandleDiagnostic(Diagnostic::Level Level,const DiagnosticInfo & Info)96 void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
97 const DiagnosticInfo &Info) {
98 // Default implementation (Warnings/errors count).
99 DiagnosticClient::HandleDiagnostic(Level, Info);
100
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();
109 }
110 }
111
112 // Create the diag entry.
113 DiagEntry DE;
114 DE.DiagnosticID = Info.getID();
115 DE.DiagnosticLevel = Level;
116
117 // Format the message.
118 llvm::SmallString<100> MessageStr;
119 Info.FormatDiagnostic(MessageStr);
120 DE.Message = MessageStr.str();
121
122 // Set the location information.
123 DE.Filename = "";
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());
128
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();
136 }
137 } else {
138 DE.Filename = PLoc.getFilename();
139 DE.Line = PLoc.getLine();
140 DE.Column = PLoc.getColumn();
141 }
142 }
143
144 // Record the diagnostic entry.
145 Entries.push_back(DE);
146 }
147