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