blob: 9eee843dbe5c38c2461fe6be56ebdc06c6ba0b30 [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 Dunbar64bfbf52011-04-07 18:37:34 +000056 // FIXME: Output main translation unit file name.
57 // FIXME: Include the invocation, if dwarf-debug-flags is available.
Daniel Dunbar5dccf572011-04-07 18:44:15 +000058 OS << " <key>diagnostics</key>\n";
59 OS << " <array>\n";
Daniel Dunbar64bfbf52011-04-07 18:37:34 +000060 for (unsigned i = 0, e = Entries.size(); i != e; ++i) {
61 DiagEntry &DE = Entries[i];
62
Daniel Dunbar5dccf572011-04-07 18:44:15 +000063 OS << " <dict>\n";
64 OS << " <key>level</key>\n"
65 << " <string>" << getLevelName(DE.DiagnosticLevel) << "</string>\n";
66 if (!DE.Filename.empty()) {
67 OS << " <key>filename</key>\n"
68 << " <string>" << DE.Filename << "</string>\n";
69 }
70 if (DE.Line != 0) {
71 OS << " <key>line</key>\n"
72 << " <integer>" << DE.Line << "</integer>\n";
73 }
74 if (DE.Column != 0) {
75 OS << " <key>column</key>\n"
76 << " <integer>" << DE.Column << "</integer>\n";
77 }
78 if (!DE.Message.empty()) {
79 OS << " <key>message</key>\n"
80 << " <string>" << DE.Message << "</string>\n";
81 }
82 OS << " </dict>\n";
Daniel Dunbar64bfbf52011-04-07 18:37:34 +000083 }
Daniel Dunbar5dccf572011-04-07 18:44:15 +000084 OS << " </array>\n";
85 OS << "</dict>\n";
Daniel Dunbar9df23492011-04-07 18:31:10 +000086
87 this->OS << OS.str();
88}
Daniel Dunbar64bfbf52011-04-07 18:37:34 +000089
90void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
91 const DiagnosticInfo &Info) {
92 // Default implementation (Warnings/errors count).
93 DiagnosticClient::HandleDiagnostic(Level, Info);
94
95 // Create the diag entry.
96 DiagEntry DE;
97 DE.DiagnosticID = Info.getID();
98 DE.DiagnosticLevel = Level;
99
100 // Format the message.
101 llvm::SmallString<100> MessageStr;
102 Info.FormatDiagnostic(MessageStr);
103 DE.Message = MessageStr.str();
104
105 // Set the location information.
106 DE.Filename = "";
107 DE.Line = DE.Column = 0;
108 if (Info.getLocation().isValid()) {
109 const SourceManager &SM = Info.getSourceManager();
110 PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
111
112 if (PLoc.isInvalid()) {
113 // At least print the file name if available:
114 FileID FID = SM.getFileID(Info.getLocation());
115 if (!FID.isInvalid()) {
116 const FileEntry *FE = SM.getFileEntryForID(FID);
117 if (FE && FE->getName())
118 DE.Filename = FE->getName();
119 }
120 } else {
121 DE.Filename = PLoc.getFilename();
122 DE.Line = PLoc.getLine();
123 DE.Column = PLoc.getColumn();
124 }
125 }
126
127 // Record the diagnostic entry.
128 Entries.push_back(DE);
129}