LogDiagnosticPrinter.cpp revision 64bfbf573e625c04abc3d40faa9b695fe21ebdbb
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 << "{\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"; 72 73 this->OS << OS.str(); 74} 75 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} 116