xref: /minix3/external/bsd/llvm/dist/clang/lib/Frontend/LogDiagnosticPrinter.cpp (revision f4a2713ac843a11c696ec80c0a5e3e5d80b4d338)
1*f4a2713aSLionel Sambuc //===--- LogDiagnosticPrinter.cpp - Log Diagnostic Printer ----------------===//
2*f4a2713aSLionel Sambuc //
3*f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4*f4a2713aSLionel Sambuc //
5*f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6*f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7*f4a2713aSLionel Sambuc //
8*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9*f4a2713aSLionel Sambuc 
10*f4a2713aSLionel Sambuc #include "clang/Frontend/LogDiagnosticPrinter.h"
11*f4a2713aSLionel Sambuc #include "clang/Basic/DiagnosticOptions.h"
12*f4a2713aSLionel Sambuc #include "clang/Basic/FileManager.h"
13*f4a2713aSLionel Sambuc #include "clang/Basic/SourceManager.h"
14*f4a2713aSLionel Sambuc #include "llvm/ADT/SmallString.h"
15*f4a2713aSLionel Sambuc #include "llvm/Support/ErrorHandling.h"
16*f4a2713aSLionel Sambuc #include "llvm/Support/raw_ostream.h"
17*f4a2713aSLionel Sambuc using namespace clang;
18*f4a2713aSLionel Sambuc 
19*f4a2713aSLionel Sambuc LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os,
20*f4a2713aSLionel Sambuc                                            DiagnosticOptions *diags,
21*f4a2713aSLionel Sambuc                                            bool _OwnsOutputStream)
22*f4a2713aSLionel Sambuc   : OS(os), LangOpts(0), DiagOpts(diags),
23*f4a2713aSLionel Sambuc     OwnsOutputStream(_OwnsOutputStream) {
24*f4a2713aSLionel Sambuc }
25*f4a2713aSLionel Sambuc 
26*f4a2713aSLionel Sambuc LogDiagnosticPrinter::~LogDiagnosticPrinter() {
27*f4a2713aSLionel Sambuc   if (OwnsOutputStream)
28*f4a2713aSLionel Sambuc     delete &OS;
29*f4a2713aSLionel Sambuc }
30*f4a2713aSLionel Sambuc 
31*f4a2713aSLionel Sambuc static StringRef getLevelName(DiagnosticsEngine::Level Level) {
32*f4a2713aSLionel Sambuc   switch (Level) {
33*f4a2713aSLionel Sambuc   case DiagnosticsEngine::Ignored: return "ignored";
34*f4a2713aSLionel Sambuc   case DiagnosticsEngine::Note:    return "note";
35*f4a2713aSLionel Sambuc   case DiagnosticsEngine::Warning: return "warning";
36*f4a2713aSLionel Sambuc   case DiagnosticsEngine::Error:   return "error";
37*f4a2713aSLionel Sambuc   case DiagnosticsEngine::Fatal:   return "fatal error";
38*f4a2713aSLionel Sambuc   }
39*f4a2713aSLionel Sambuc   llvm_unreachable("Invalid DiagnosticsEngine level!");
40*f4a2713aSLionel Sambuc }
41*f4a2713aSLionel Sambuc 
42*f4a2713aSLionel Sambuc // Escape XML characters inside the raw string.
43*f4a2713aSLionel Sambuc static void emitString(llvm::raw_svector_ostream &OS, const StringRef Raw) {
44*f4a2713aSLionel Sambuc   for (StringRef::iterator I = Raw.begin(), E = Raw.end(); I != E; ++I) {
45*f4a2713aSLionel Sambuc     char c = *I;
46*f4a2713aSLionel Sambuc     switch (c) {
47*f4a2713aSLionel Sambuc     default:   OS << c; break;
48*f4a2713aSLionel Sambuc     case '&':  OS << "&amp;"; break;
49*f4a2713aSLionel Sambuc     case '<':  OS << "&lt;"; break;
50*f4a2713aSLionel Sambuc     case '>':  OS << "&gt;"; break;
51*f4a2713aSLionel Sambuc     case '\'': OS << "&apos;"; break;
52*f4a2713aSLionel Sambuc     case '\"': OS << "&quot;"; break;
53*f4a2713aSLionel Sambuc     }
54*f4a2713aSLionel Sambuc   }
55*f4a2713aSLionel Sambuc }
56*f4a2713aSLionel Sambuc 
57*f4a2713aSLionel Sambuc void LogDiagnosticPrinter::EndSourceFile() {
58*f4a2713aSLionel Sambuc   // We emit all the diagnostics in EndSourceFile. However, we don't emit any
59*f4a2713aSLionel Sambuc   // entry if no diagnostics were present.
60*f4a2713aSLionel Sambuc   //
61*f4a2713aSLionel Sambuc   // Note that DiagnosticConsumer has no "end-of-compilation" callback, so we
62*f4a2713aSLionel Sambuc   // will miss any diagnostics which are emitted after and outside the
63*f4a2713aSLionel Sambuc   // translation unit processing.
64*f4a2713aSLionel Sambuc   if (Entries.empty())
65*f4a2713aSLionel Sambuc     return;
66*f4a2713aSLionel Sambuc 
67*f4a2713aSLionel Sambuc   // Write to a temporary string to ensure atomic write of diagnostic object.
68*f4a2713aSLionel Sambuc   SmallString<512> Msg;
69*f4a2713aSLionel Sambuc   llvm::raw_svector_ostream OS(Msg);
70*f4a2713aSLionel Sambuc 
71*f4a2713aSLionel Sambuc   OS << "<dict>\n";
72*f4a2713aSLionel Sambuc   if (!MainFilename.empty()) {
73*f4a2713aSLionel Sambuc     OS << "  <key>main-file</key>\n"
74*f4a2713aSLionel Sambuc        << "  <string>";
75*f4a2713aSLionel Sambuc     emitString(OS, MainFilename);
76*f4a2713aSLionel Sambuc     OS << "</string>\n";
77*f4a2713aSLionel Sambuc   }
78*f4a2713aSLionel Sambuc   if (!DwarfDebugFlags.empty()) {
79*f4a2713aSLionel Sambuc     OS << "  <key>dwarf-debug-flags</key>\n"
80*f4a2713aSLionel Sambuc        << "  <string>";
81*f4a2713aSLionel Sambuc     emitString(OS, DwarfDebugFlags);
82*f4a2713aSLionel Sambuc     OS << "</string>\n";
83*f4a2713aSLionel Sambuc   }
84*f4a2713aSLionel Sambuc   OS << "  <key>diagnostics</key>\n";
85*f4a2713aSLionel Sambuc   OS << "  <array>\n";
86*f4a2713aSLionel Sambuc   for (unsigned i = 0, e = Entries.size(); i != e; ++i) {
87*f4a2713aSLionel Sambuc     DiagEntry &DE = Entries[i];
88*f4a2713aSLionel Sambuc 
89*f4a2713aSLionel Sambuc     OS << "    <dict>\n";
90*f4a2713aSLionel Sambuc     OS << "      <key>level</key>\n"
91*f4a2713aSLionel Sambuc        << "      <string>";
92*f4a2713aSLionel Sambuc     emitString(OS, getLevelName(DE.DiagnosticLevel));
93*f4a2713aSLionel Sambuc     OS << "</string>\n";
94*f4a2713aSLionel Sambuc     if (!DE.Filename.empty()) {
95*f4a2713aSLionel Sambuc       OS << "      <key>filename</key>\n"
96*f4a2713aSLionel Sambuc          << "      <string>";
97*f4a2713aSLionel Sambuc       emitString(OS, DE.Filename);
98*f4a2713aSLionel Sambuc       OS << "</string>\n";
99*f4a2713aSLionel Sambuc     }
100*f4a2713aSLionel Sambuc     if (DE.Line != 0) {
101*f4a2713aSLionel Sambuc       OS << "      <key>line</key>\n"
102*f4a2713aSLionel Sambuc          << "      <integer>" << DE.Line << "</integer>\n";
103*f4a2713aSLionel Sambuc     }
104*f4a2713aSLionel Sambuc     if (DE.Column != 0) {
105*f4a2713aSLionel Sambuc       OS << "      <key>column</key>\n"
106*f4a2713aSLionel Sambuc          << "      <integer>" << DE.Column << "</integer>\n";
107*f4a2713aSLionel Sambuc     }
108*f4a2713aSLionel Sambuc     if (!DE.Message.empty()) {
109*f4a2713aSLionel Sambuc       OS << "      <key>message</key>\n"
110*f4a2713aSLionel Sambuc          << "      <string>";
111*f4a2713aSLionel Sambuc       emitString(OS, DE.Message);
112*f4a2713aSLionel Sambuc       OS << "</string>\n";
113*f4a2713aSLionel Sambuc     }
114*f4a2713aSLionel Sambuc     OS << "    </dict>\n";
115*f4a2713aSLionel Sambuc   }
116*f4a2713aSLionel Sambuc   OS << "  </array>\n";
117*f4a2713aSLionel Sambuc   OS << "</dict>\n";
118*f4a2713aSLionel Sambuc 
119*f4a2713aSLionel Sambuc   this->OS << OS.str();
120*f4a2713aSLionel Sambuc }
121*f4a2713aSLionel Sambuc 
122*f4a2713aSLionel Sambuc void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
123*f4a2713aSLionel Sambuc                                             const Diagnostic &Info) {
124*f4a2713aSLionel Sambuc   // Default implementation (Warnings/errors count).
125*f4a2713aSLionel Sambuc   DiagnosticConsumer::HandleDiagnostic(Level, Info);
126*f4a2713aSLionel Sambuc 
127*f4a2713aSLionel Sambuc   // Initialize the main file name, if we haven't already fetched it.
128*f4a2713aSLionel Sambuc   if (MainFilename.empty() && Info.hasSourceManager()) {
129*f4a2713aSLionel Sambuc     const SourceManager &SM = Info.getSourceManager();
130*f4a2713aSLionel Sambuc     FileID FID = SM.getMainFileID();
131*f4a2713aSLionel Sambuc     if (!FID.isInvalid()) {
132*f4a2713aSLionel Sambuc       const FileEntry *FE = SM.getFileEntryForID(FID);
133*f4a2713aSLionel Sambuc       if (FE && FE->getName())
134*f4a2713aSLionel Sambuc         MainFilename = FE->getName();
135*f4a2713aSLionel Sambuc     }
136*f4a2713aSLionel Sambuc   }
137*f4a2713aSLionel Sambuc 
138*f4a2713aSLionel Sambuc   // Create the diag entry.
139*f4a2713aSLionel Sambuc   DiagEntry DE;
140*f4a2713aSLionel Sambuc   DE.DiagnosticID = Info.getID();
141*f4a2713aSLionel Sambuc   DE.DiagnosticLevel = Level;
142*f4a2713aSLionel Sambuc 
143*f4a2713aSLionel Sambuc   // Format the message.
144*f4a2713aSLionel Sambuc   SmallString<100> MessageStr;
145*f4a2713aSLionel Sambuc   Info.FormatDiagnostic(MessageStr);
146*f4a2713aSLionel Sambuc   DE.Message = MessageStr.str();
147*f4a2713aSLionel Sambuc 
148*f4a2713aSLionel Sambuc   // Set the location information.
149*f4a2713aSLionel Sambuc   DE.Filename = "";
150*f4a2713aSLionel Sambuc   DE.Line = DE.Column = 0;
151*f4a2713aSLionel Sambuc   if (Info.getLocation().isValid() && Info.hasSourceManager()) {
152*f4a2713aSLionel Sambuc     const SourceManager &SM = Info.getSourceManager();
153*f4a2713aSLionel Sambuc     PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
154*f4a2713aSLionel Sambuc 
155*f4a2713aSLionel Sambuc     if (PLoc.isInvalid()) {
156*f4a2713aSLionel Sambuc       // At least print the file name if available:
157*f4a2713aSLionel Sambuc       FileID FID = SM.getFileID(Info.getLocation());
158*f4a2713aSLionel Sambuc       if (!FID.isInvalid()) {
159*f4a2713aSLionel Sambuc         const FileEntry *FE = SM.getFileEntryForID(FID);
160*f4a2713aSLionel Sambuc         if (FE && FE->getName())
161*f4a2713aSLionel Sambuc           DE.Filename = FE->getName();
162*f4a2713aSLionel Sambuc       }
163*f4a2713aSLionel Sambuc     } else {
164*f4a2713aSLionel Sambuc       DE.Filename = PLoc.getFilename();
165*f4a2713aSLionel Sambuc       DE.Line = PLoc.getLine();
166*f4a2713aSLionel Sambuc       DE.Column = PLoc.getColumn();
167*f4a2713aSLionel Sambuc     }
168*f4a2713aSLionel Sambuc   }
169*f4a2713aSLionel Sambuc 
170*f4a2713aSLionel Sambuc   // Record the diagnostic entry.
171*f4a2713aSLionel Sambuc   Entries.push_back(DE);
172*f4a2713aSLionel Sambuc }
173*f4a2713aSLionel Sambuc 
174