LogDiagnosticPrinter.cpp revision 28f14933edc863821e4f2ffa3663835c62440dcb
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" 11#include "clang/Basic/FileManager.h" 12#include "clang/Basic/SourceManager.h" 13#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 29static 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; 50 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 55 OS << "<dict>\n"; 56 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 } 64 OS << " <key>diagnostics</key>\n"; 65 OS << " <array>\n"; 66 for (unsigned i = 0, e = Entries.size(); i != e; ++i) { 67 DiagEntry &DE = Entries[i]; 68 69 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"; 89 } 90 OS << " </array>\n"; 91 OS << "</dict>\n"; 92 93 this->OS << OS.str(); 94} 95 96void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, 97 const DiagnosticInfo &Info) { 98 // Default implementation (Warnings/errors count). 99 DiagnosticClient::HandleDiagnostic(Level, Info); 100 101 // 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 112 // 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} 147