1 //===--- PlistReporter.cpp - ARC Migrate Tool Plist Reporter ----*- C++ -*-===// 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 "Internals.h" 11 #include "clang/Basic/FileManager.h" 12 #include "clang/Basic/PlistSupport.h" 13 #include "clang/Basic/SourceManager.h" 14 #include "clang/Lex/Lexer.h" 15 using namespace clang; 16 using namespace arcmt; 17 using namespace markup; 18 19 void arcmt::writeARCDiagsToPlist(const std::string &outPath, 20 ArrayRef<StoredDiagnostic> diags, 21 SourceManager &SM, 22 const LangOptions &LangOpts) { 23 DiagnosticIDs DiagIDs; 24 25 // Build up a set of FIDs that we use by scanning the locations and 26 // ranges of the diagnostics. 27 FIDMap FM; 28 SmallVector<FileID, 10> Fids; 29 30 for (ArrayRef<StoredDiagnostic>::iterator 31 I = diags.begin(), E = diags.end(); I != E; ++I) { 32 const StoredDiagnostic &D = *I; 33 34 AddFID(FM, Fids, SM, D.getLocation()); 35 36 for (StoredDiagnostic::range_iterator 37 RI = D.range_begin(), RE = D.range_end(); RI != RE; ++RI) { 38 AddFID(FM, Fids, SM, RI->getBegin()); 39 AddFID(FM, Fids, SM, RI->getEnd()); 40 } 41 } 42 43 std::string errMsg; 44 llvm::raw_fd_ostream o(outPath.c_str(), errMsg, llvm::sys::fs::F_Text); 45 if (!errMsg.empty()) { 46 llvm::errs() << "error: could not create file: " << outPath << '\n'; 47 return; 48 } 49 50 // Write the plist header. 51 o << PlistHeader; 52 53 // Write the root object: a <dict> containing... 54 // - "files", an <array> mapping from FIDs to file names 55 // - "diagnostics", an <array> containing the diagnostics 56 o << "<dict>\n" 57 " <key>files</key>\n" 58 " <array>\n"; 59 60 for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end(); 61 I!=E; ++I) { 62 o << " "; 63 EmitString(o, SM.getFileEntryForID(*I)->getName()) << '\n'; 64 } 65 66 o << " </array>\n" 67 " <key>diagnostics</key>\n" 68 " <array>\n"; 69 70 for (ArrayRef<StoredDiagnostic>::iterator 71 DI = diags.begin(), DE = diags.end(); DI != DE; ++DI) { 72 73 const StoredDiagnostic &D = *DI; 74 75 if (D.getLevel() == DiagnosticsEngine::Ignored) 76 continue; 77 78 o << " <dict>\n"; 79 80 // Output the diagnostic. 81 o << " <key>description</key>"; 82 EmitString(o, D.getMessage()) << '\n'; 83 o << " <key>category</key>"; 84 EmitString(o, DiagIDs.getCategoryNameFromID( 85 DiagIDs.getCategoryNumberForDiag(D.getID()))) << '\n'; 86 o << " <key>type</key>"; 87 if (D.getLevel() >= DiagnosticsEngine::Error) 88 EmitString(o, "error") << '\n'; 89 else if (D.getLevel() == DiagnosticsEngine::Warning) 90 EmitString(o, "warning") << '\n'; 91 else 92 EmitString(o, "note") << '\n'; 93 94 // Output the location of the bug. 95 o << " <key>location</key>\n"; 96 EmitLocation(o, SM, LangOpts, D.getLocation(), FM, 2); 97 98 // Output the ranges (if any). 99 StoredDiagnostic::range_iterator RI = D.range_begin(), RE = D.range_end(); 100 101 if (RI != RE) { 102 o << " <key>ranges</key>\n"; 103 o << " <array>\n"; 104 for (; RI != RE; ++RI) 105 EmitRange(o, SM, LangOpts, *RI, FM, 4); 106 o << " </array>\n"; 107 } 108 109 // Close up the entry. 110 o << " </dict>\n"; 111 } 112 113 o << " </array>\n"; 114 115 // Finish. 116 o << "</dict>\n</plist>"; 117 } 118