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