19df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar//===--- LogDiagnosticPrinter.cpp - Log Diagnostic Printer ----------------===// 29df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar// 39df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar// The LLVM Compiler Infrastructure 49df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar// 59df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar// This file is distributed under the University of Illinois Open Source 69df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar// License. See LICENSE.TXT for details. 79df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar// 89df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar//===----------------------------------------------------------------------===// 99df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar 109df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar#include "clang/Frontend/LogDiagnosticPrinter.h" 1164bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar#include "clang/Basic/FileManager.h" 1264bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar#include "clang/Basic/SourceManager.h" 139df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar#include "llvm/ADT/SmallString.h" 149df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar#include "llvm/Support/raw_ostream.h" 15561d3abc881033776ece385a01a510e1cbc1fa92David Blaikie#include "llvm/Support/ErrorHandling.h" 169df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbarusing namespace clang; 179df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar 185f9e272e632e951b1efe824cd16acb4d96077930Chris LattnerLogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os, 199df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar const DiagnosticOptions &diags, 209df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar bool _OwnsOutputStream) 219df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar : OS(os), LangOpts(0), DiagOpts(&diags), 229df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar OwnsOutputStream(_OwnsOutputStream) { 239df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar} 249df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar 259df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel DunbarLogDiagnosticPrinter::~LogDiagnosticPrinter() { 269df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar if (OwnsOutputStream) 279df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar delete &OS; 289df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar} 299df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar 30d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikiestatic StringRef getLevelName(DiagnosticsEngine::Level Level) { 3164bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar switch (Level) { 32d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie case DiagnosticsEngine::Ignored: return "ignored"; 33d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie case DiagnosticsEngine::Note: return "note"; 34d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie case DiagnosticsEngine::Warning: return "warning"; 35d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie case DiagnosticsEngine::Error: return "error"; 36d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie case DiagnosticsEngine::Fatal: return "fatal error"; 3764bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar } 38561d3abc881033776ece385a01a510e1cbc1fa92David Blaikie llvm_unreachable("Invalid DiagnosticsEngine level!"); 3964bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar} 4064bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar 41cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier// Escape XML characters inside the raw string. 42cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosierstatic void emitString(llvm::raw_svector_ostream &OS, const StringRef Raw) { 43cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier for (StringRef::iterator I = Raw.begin(), E = Raw.end(); I != E; ++I) { 44cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier char c = *I; 45cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier switch (c) { 46cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier default: OS << c; break; 47cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier case '&': OS << "&"; break; 48cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier case '<': OS << "<"; break; 49cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier case '>': OS << ">"; break; 50cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier case '\'': OS << "'"; break; 51cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier case '\"': OS << """; break; 52cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier } 53cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier } 54cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier} 55cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier 5664bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbarvoid LogDiagnosticPrinter::EndSourceFile() { 5764bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar // We emit all the diagnostics in EndSourceFile. However, we don't emit any 5864bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar // entry if no diagnostics were present. 5964bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar // 6078ad0b98848c17a0a11847fa1d456e2dfec8aa2fDavid Blaikie // Note that DiagnosticConsumer has no "end-of-compilation" callback, so we 6178ad0b98848c17a0a11847fa1d456e2dfec8aa2fDavid Blaikie // will miss any diagnostics which are emitted after and outside the 6278ad0b98848c17a0a11847fa1d456e2dfec8aa2fDavid Blaikie // translation unit processing. 6364bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar if (Entries.empty()) 6464bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar return; 659df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar 669df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar // Write to a temporary string to ensure atomic write of diagnostic object. 67f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith SmallString<512> Msg; 689df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar llvm::raw_svector_ostream OS(Msg); 699df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar 705dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar OS << "<dict>\n"; 7128f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar if (!MainFilename.empty()) { 7228f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar OS << " <key>main-file</key>\n" 73cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier << " <string>"; 74cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier emitString(OS, MainFilename); 75cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier OS << "</string>\n"; 7628f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar } 7728f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar if (!DwarfDebugFlags.empty()) { 7828f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar OS << " <key>dwarf-debug-flags</key>\n" 79cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier << " <string>"; 80cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier emitString(OS, DwarfDebugFlags); 81cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier OS << "</string>\n"; 8228f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar } 835dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar OS << " <key>diagnostics</key>\n"; 845dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar OS << " <array>\n"; 8564bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar for (unsigned i = 0, e = Entries.size(); i != e; ++i) { 8664bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar DiagEntry &DE = Entries[i]; 8764bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar 885dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar OS << " <dict>\n"; 895dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar OS << " <key>level</key>\n" 90cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier << " <string>"; 91cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier emitString(OS, getLevelName(DE.DiagnosticLevel)); 92cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier OS << "</string>\n"; 935dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar if (!DE.Filename.empty()) { 945dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar OS << " <key>filename</key>\n" 95cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier << " <string>"; 96cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier emitString(OS, DE.Filename); 97cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier OS << "</string>\n"; 985dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar } 995dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar if (DE.Line != 0) { 1005dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar OS << " <key>line</key>\n" 1015dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar << " <integer>" << DE.Line << "</integer>\n"; 1025dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar } 1035dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar if (DE.Column != 0) { 1045dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar OS << " <key>column</key>\n" 1055dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar << " <integer>" << DE.Column << "</integer>\n"; 1065dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar } 1075dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar if (!DE.Message.empty()) { 1085dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar OS << " <key>message</key>\n" 109cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier << " <string>"; 110cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier emitString(OS, DE.Message); 111cc78c6c6152b6c30b069769b45716e0ae6519211Chad Rosier OS << "</string>\n"; 1125dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar } 1135dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar OS << " </dict>\n"; 11464bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar } 1155dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar OS << " </array>\n"; 1165dccf575ad0b45a268d4026047234a6872440c95Daniel Dunbar OS << "</dict>\n"; 1179df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar 1189df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar this->OS << OS.str(); 1199df23493f5b8a223dfbc491e4b7de3850797c2e7Daniel Dunbar} 12064bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar 121d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikievoid LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, 12240847cfb58acc3cac7d68727df9455ac45f2e118David Blaikie const Diagnostic &Info) { 12364bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar // Default implementation (Warnings/errors count). 12478ad0b98848c17a0a11847fa1d456e2dfec8aa2fDavid Blaikie DiagnosticConsumer::HandleDiagnostic(Level, Info); 12564bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar 12628f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar // Initialize the main file name, if we haven't already fetched it. 1277665ad83d8eff7b8b2c5f3b893b6b7ece38f847cDaniel Dunbar if (MainFilename.empty() && Info.hasSourceManager()) { 12828f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar const SourceManager &SM = Info.getSourceManager(); 12928f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar FileID FID = SM.getMainFileID(); 13028f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar if (!FID.isInvalid()) { 13128f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar const FileEntry *FE = SM.getFileEntryForID(FID); 13228f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar if (FE && FE->getName()) 13328f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar MainFilename = FE->getName(); 13428f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar } 13528f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar } 13628f14933edc863821e4f2ffa3663835c62440dcbDaniel Dunbar 13764bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar // Create the diag entry. 13864bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar DiagEntry DE; 13964bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar DE.DiagnosticID = Info.getID(); 14064bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar DE.DiagnosticLevel = Level; 14164bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar 14264bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar // Format the message. 143f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith SmallString<100> MessageStr; 14464bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar Info.FormatDiagnostic(MessageStr); 14564bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar DE.Message = MessageStr.str(); 14664bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar 14764bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar // Set the location information. 14864bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar DE.Filename = ""; 14964bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar DE.Line = DE.Column = 0; 1507665ad83d8eff7b8b2c5f3b893b6b7ece38f847cDaniel Dunbar if (Info.getLocation().isValid() && Info.hasSourceManager()) { 15164bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar const SourceManager &SM = Info.getSourceManager(); 15264bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation()); 15364bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar 15464bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar if (PLoc.isInvalid()) { 15564bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar // At least print the file name if available: 15664bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar FileID FID = SM.getFileID(Info.getLocation()); 15764bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar if (!FID.isInvalid()) { 15864bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar const FileEntry *FE = SM.getFileEntryForID(FID); 15964bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar if (FE && FE->getName()) 16064bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar DE.Filename = FE->getName(); 16164bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar } 16264bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar } else { 16364bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar DE.Filename = PLoc.getFilename(); 16464bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar DE.Line = PLoc.getLine(); 16564bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar DE.Column = PLoc.getColumn(); 16664bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar } 16764bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar } 16864bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar 16964bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar // Record the diagnostic entry. 17064bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar Entries.push_back(DE); 17164bfbf573e625c04abc3d40faa9b695fe21ebdbbDaniel Dunbar} 172aee526e77657afd1600276450e9c346953ad51d7Douglas Gregor 173aee526e77657afd1600276450e9c346953ad51d7Douglas GregorDiagnosticConsumer * 174aee526e77657afd1600276450e9c346953ad51d7Douglas GregorLogDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { 175aee526e77657afd1600276450e9c346953ad51d7Douglas Gregor return new LogDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false); 176aee526e77657afd1600276450e9c346953ad51d7Douglas Gregor} 177aee526e77657afd1600276450e9c346953ad51d7Douglas Gregor 178