LogDiagnosticPrinter.cpp revision 5dccf575ad0b45a268d4026047234a6872440c95
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 // FIXME: Output main translation unit file name. 57 // FIXME: Include the invocation, if dwarf-debug-flags is available. 58 OS << " <key>diagnostics</key>\n"; 59 OS << " <array>\n"; 60 for (unsigned i = 0, e = Entries.size(); i != e; ++i) { 61 DiagEntry &DE = Entries[i]; 62 63 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"; 83 } 84 OS << " </array>\n"; 85 OS << "</dict>\n"; 86 87 this->OS << OS.str(); 88} 89 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} 130