blob: ca661a6af7f0c8c0fa919e54e4d36a89ae6bdd0f [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 Dunbar64bfbf52011-04-07 18:37:34 +000055 OS << "{\n";
56 // FIXME: Output main translation unit file name.
57 // FIXME: Include the invocation, if dwarf-debug-flags is available.
58 OS << " \"diagnostics\" : [\n";
59 for (unsigned i = 0, e = Entries.size(); i != e; ++i) {
60 DiagEntry &DE = Entries[i];
61
62 OS << " {\n";
63 OS << " \"filename\" : \"" << DE.Filename << "\",\n";
64 OS << " \"line\" : " << DE.Line << ",\n";
65 OS << " \"column\" : " << DE.Column << ",\n";
66 OS << " \"message\" : \"" << DE.Message << "\",\n";
67 OS << " \"level\" : \"" << getLevelName(DE.DiagnosticLevel) << "\"\n";
68 OS << " }" << ((i + 1 != e) ? "," : "") << '\n';
69 }
70 OS << " ]\n";
71 OS << "},\n";
Daniel Dunbar9df23492011-04-07 18:31:10 +000072
73 this->OS << OS.str();
74}
Daniel Dunbar64bfbf52011-04-07 18:37:34 +000075
76void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
77 const DiagnosticInfo &Info) {
78 // Default implementation (Warnings/errors count).
79 DiagnosticClient::HandleDiagnostic(Level, Info);
80
81 // Create the diag entry.
82 DiagEntry DE;
83 DE.DiagnosticID = Info.getID();
84 DE.DiagnosticLevel = Level;
85
86 // Format the message.
87 llvm::SmallString<100> MessageStr;
88 Info.FormatDiagnostic(MessageStr);
89 DE.Message = MessageStr.str();
90
91 // Set the location information.
92 DE.Filename = "";
93 DE.Line = DE.Column = 0;
94 if (Info.getLocation().isValid()) {
95 const SourceManager &SM = Info.getSourceManager();
96 PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
97
98 if (PLoc.isInvalid()) {
99 // At least print the file name if available:
100 FileID FID = SM.getFileID(Info.getLocation());
101 if (!FID.isInvalid()) {
102 const FileEntry *FE = SM.getFileEntryForID(FID);
103 if (FE && FE->getName())
104 DE.Filename = FE->getName();
105 }
106 } else {
107 DE.Filename = PLoc.getFilename();
108 DE.Line = PLoc.getLine();
109 DE.Column = PLoc.getColumn();
110 }
111 }
112
113 // Record the diagnostic entry.
114 Entries.push_back(DE);
115}