blob: 954bad4e7c54957a817799c08c09bb80b6392be7 [file] [log] [blame]
Daniel Dunbar9df23492011-04-07 18:31:10 +00001//===--- 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"
Daniel Dunbar64bfbf52011-04-07 18:37:34 +000011#include "clang/Basic/FileManager.h"
12#include "clang/Basic/SourceManager.h"
Daniel Dunbar9df23492011-04-07 18:31:10 +000013#include "llvm/ADT/SmallString.h"
14#include "llvm/Support/raw_ostream.h"
15using namespace clang;
16
17LogDiagnosticPrinter::LogDiagnosticPrinter(llvm::raw_ostream &os,
18 const DiagnosticOptions &diags,
19 bool _OwnsOutputStream)
20 : OS(os), LangOpts(0), DiagOpts(&diags),
21 OwnsOutputStream(_OwnsOutputStream) {
22}
23
24LogDiagnosticPrinter::~LogDiagnosticPrinter() {
25 if (OwnsOutputStream)
26 delete &OS;
27}
28
Daniel Dunbar64bfbf52011-04-07 18:37:34 +000029static 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
41void 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;
Daniel Dunbar9df23492011-04-07 18:31:10 +000050
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
Daniel Dunbar5dccf572011-04-07 18:44:15 +000055 OS << "<dict>\n";
Daniel Dunbar28f14932011-04-07 18:51:54 +000056 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 }
Daniel Dunbar5dccf572011-04-07 18:44:15 +000064 OS << " <key>diagnostics</key>\n";
65 OS << " <array>\n";
Daniel Dunbar64bfbf52011-04-07 18:37:34 +000066 for (unsigned i = 0, e = Entries.size(); i != e; ++i) {
67 DiagEntry &DE = Entries[i];
68
Daniel Dunbar5dccf572011-04-07 18:44:15 +000069 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";
Daniel Dunbar64bfbf52011-04-07 18:37:34 +000089 }
Daniel Dunbar5dccf572011-04-07 18:44:15 +000090 OS << " </array>\n";
91 OS << "</dict>\n";
Daniel Dunbar9df23492011-04-07 18:31:10 +000092
93 this->OS << OS.str();
94}
Daniel Dunbar64bfbf52011-04-07 18:37:34 +000095
96void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
97 const DiagnosticInfo &Info) {
98 // Default implementation (Warnings/errors count).
99 DiagnosticClient::HandleDiagnostic(Level, Info);
100
Daniel Dunbar28f14932011-04-07 18:51:54 +0000101 // Initialize the main file name, if we haven't already fetched it.
102 if (MainFilename.empty()) {
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
Daniel Dunbar64bfbf52011-04-07 18:37:34 +0000112 // 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()) {
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}