1 //===--- PlistReporter.cpp - ARC Migrate Tool Plist Reporter ----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Internals.h"
10 #include "clang/Basic/FileManager.h"
11 #include "clang/Basic/PlistSupport.h"
12 #include "clang/Basic/SourceManager.h"
13 #include "clang/Lex/Lexer.h"
14 using namespace clang;
15 using namespace arcmt;
16 using namespace markup;
17 
getLevelName(DiagnosticsEngine::Level Level)18 static StringRef getLevelName(DiagnosticsEngine::Level Level) {
19   switch (Level) {
20   case DiagnosticsEngine::Ignored:
21     llvm_unreachable("ignored");
22   case DiagnosticsEngine::Note:
23     return "note";
24   case DiagnosticsEngine::Remark:
25   case DiagnosticsEngine::Warning:
26     return "warning";
27   case DiagnosticsEngine::Fatal:
28   case DiagnosticsEngine::Error:
29     return "error";
30   }
31   llvm_unreachable("Invalid DiagnosticsEngine level!");
32 }
33 
writeARCDiagsToPlist(const std::string & outPath,ArrayRef<StoredDiagnostic> diags,SourceManager & SM,const LangOptions & LangOpts)34 void arcmt::writeARCDiagsToPlist(const std::string &outPath,
35                                  ArrayRef<StoredDiagnostic> diags,
36                                  SourceManager &SM,
37                                  const LangOptions &LangOpts) {
38   DiagnosticIDs DiagIDs;
39 
40   // Build up a set of FIDs that we use by scanning the locations and
41   // ranges of the diagnostics.
42   FIDMap FM;
43   SmallVector<FileID, 10> Fids;
44 
45   for (ArrayRef<StoredDiagnostic>::iterator
46          I = diags.begin(), E = diags.end(); I != E; ++I) {
47     const StoredDiagnostic &D = *I;
48 
49     AddFID(FM, Fids, SM, D.getLocation());
50 
51     for (StoredDiagnostic::range_iterator
52            RI = D.range_begin(), RE = D.range_end(); RI != RE; ++RI) {
53       AddFID(FM, Fids, SM, RI->getBegin());
54       AddFID(FM, Fids, SM, RI->getEnd());
55     }
56   }
57 
58   std::error_code EC;
59   llvm::raw_fd_ostream o(outPath, EC, llvm::sys::fs::OF_Text);
60   if (EC) {
61     llvm::errs() << "error: could not create file: " << outPath << '\n';
62     return;
63   }
64 
65   EmitPlistHeader(o);
66 
67   // Write the root object: a <dict> containing...
68   //  - "files", an <array> mapping from FIDs to file names
69   //  - "diagnostics", an <array> containing the diagnostics
70   o << "<dict>\n"
71        " <key>files</key>\n"
72        " <array>\n";
73 
74   for (FileID FID : Fids)
75     EmitString(o << "  ", SM.getFileEntryForID(FID)->getName()) << '\n';
76 
77   o << " </array>\n"
78        " <key>diagnostics</key>\n"
79        " <array>\n";
80 
81   for (ArrayRef<StoredDiagnostic>::iterator
82          DI = diags.begin(), DE = diags.end(); DI != DE; ++DI) {
83 
84     const StoredDiagnostic &D = *DI;
85 
86     if (D.getLevel() == DiagnosticsEngine::Ignored)
87       continue;
88 
89     o << "  <dict>\n";
90 
91     // Output the diagnostic.
92     o << "   <key>description</key>";
93     EmitString(o, D.getMessage()) << '\n';
94     o << "   <key>category</key>";
95     EmitString(o, DiagIDs.getCategoryNameFromID(
96                           DiagIDs.getCategoryNumberForDiag(D.getID()))) << '\n';
97     o << "   <key>type</key>";
98     EmitString(o, getLevelName(D.getLevel())) << '\n';
99 
100     // Output the location of the bug.
101     o << "  <key>location</key>\n";
102     EmitLocation(o, SM, D.getLocation(), FM, 2);
103 
104     // Output the ranges (if any).
105     if (!D.getRanges().empty()) {
106       o << "   <key>ranges</key>\n";
107       o << "   <array>\n";
108       for (auto &R : D.getRanges()) {
109         CharSourceRange ExpansionRange = SM.getExpansionRange(R);
110         EmitRange(o, SM, Lexer::getAsCharRange(ExpansionRange, SM, LangOpts),
111                   FM, 4);
112       }
113       o << "   </array>\n";
114     }
115 
116     // Close up the entry.
117     o << "  </dict>\n";
118   }
119 
120   o << " </array>\n";
121 
122   // Finish.
123   o << "</dict>\n</plist>\n";
124 }
125