/src/llvm-project/clang/lib/Frontend/LogDiagnosticPrinter.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- LogDiagnosticPrinter.cpp - Log Diagnostic Printer ----------------===// |
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 "clang/Frontend/LogDiagnosticPrinter.h" |
10 | | #include "clang/Basic/DiagnosticOptions.h" |
11 | | #include "clang/Basic/FileManager.h" |
12 | | #include "clang/Basic/PlistSupport.h" |
13 | | #include "clang/Basic/SourceManager.h" |
14 | | #include "llvm/ADT/SmallString.h" |
15 | | #include "llvm/Support/ErrorHandling.h" |
16 | | #include "llvm/Support/raw_ostream.h" |
17 | | using namespace clang; |
18 | | using namespace markup; |
19 | | |
20 | | LogDiagnosticPrinter::LogDiagnosticPrinter( |
21 | | raw_ostream &os, DiagnosticOptions *diags, |
22 | | std::unique_ptr<raw_ostream> StreamOwner) |
23 | | : OS(os), StreamOwner(std::move(StreamOwner)), LangOpts(nullptr), |
24 | 0 | DiagOpts(diags) {} |
25 | | |
26 | 0 | static StringRef getLevelName(DiagnosticsEngine::Level Level) { |
27 | 0 | switch (Level) { |
28 | 0 | case DiagnosticsEngine::Ignored: return "ignored"; |
29 | 0 | case DiagnosticsEngine::Remark: return "remark"; |
30 | 0 | case DiagnosticsEngine::Note: return "note"; |
31 | 0 | case DiagnosticsEngine::Warning: return "warning"; |
32 | 0 | case DiagnosticsEngine::Error: return "error"; |
33 | 0 | case DiagnosticsEngine::Fatal: return "fatal error"; |
34 | 0 | } |
35 | 0 | llvm_unreachable("Invalid DiagnosticsEngine level!"); |
36 | 0 | } |
37 | | |
38 | | void |
39 | | LogDiagnosticPrinter::EmitDiagEntry(llvm::raw_ostream &OS, |
40 | 0 | const LogDiagnosticPrinter::DiagEntry &DE) { |
41 | 0 | OS << " <dict>\n"; |
42 | 0 | OS << " <key>level</key>\n" |
43 | 0 | << " "; |
44 | 0 | EmitString(OS, getLevelName(DE.DiagnosticLevel)) << '\n'; |
45 | 0 | if (!DE.Filename.empty()) { |
46 | 0 | OS << " <key>filename</key>\n" |
47 | 0 | << " "; |
48 | 0 | EmitString(OS, DE.Filename) << '\n'; |
49 | 0 | } |
50 | 0 | if (DE.Line != 0) { |
51 | 0 | OS << " <key>line</key>\n" |
52 | 0 | << " "; |
53 | 0 | EmitInteger(OS, DE.Line) << '\n'; |
54 | 0 | } |
55 | 0 | if (DE.Column != 0) { |
56 | 0 | OS << " <key>column</key>\n" |
57 | 0 | << " "; |
58 | 0 | EmitInteger(OS, DE.Column) << '\n'; |
59 | 0 | } |
60 | 0 | if (!DE.Message.empty()) { |
61 | 0 | OS << " <key>message</key>\n" |
62 | 0 | << " "; |
63 | 0 | EmitString(OS, DE.Message) << '\n'; |
64 | 0 | } |
65 | 0 | OS << " <key>ID</key>\n" |
66 | 0 | << " "; |
67 | 0 | EmitInteger(OS, DE.DiagnosticID) << '\n'; |
68 | 0 | if (!DE.WarningOption.empty()) { |
69 | 0 | OS << " <key>WarningOption</key>\n" |
70 | 0 | << " "; |
71 | 0 | EmitString(OS, DE.WarningOption) << '\n'; |
72 | 0 | } |
73 | 0 | OS << " </dict>\n"; |
74 | 0 | } |
75 | | |
76 | 0 | void LogDiagnosticPrinter::EndSourceFile() { |
77 | | // We emit all the diagnostics in EndSourceFile. However, we don't emit any |
78 | | // entry if no diagnostics were present. |
79 | | // |
80 | | // Note that DiagnosticConsumer has no "end-of-compilation" callback, so we |
81 | | // will miss any diagnostics which are emitted after and outside the |
82 | | // translation unit processing. |
83 | 0 | if (Entries.empty()) |
84 | 0 | return; |
85 | | |
86 | | // Write to a temporary string to ensure atomic write of diagnostic object. |
87 | 0 | SmallString<512> Msg; |
88 | 0 | llvm::raw_svector_ostream OS(Msg); |
89 | |
|
90 | 0 | OS << "<dict>\n"; |
91 | 0 | if (!MainFilename.empty()) { |
92 | 0 | OS << " <key>main-file</key>\n" |
93 | 0 | << " "; |
94 | 0 | EmitString(OS, MainFilename) << '\n'; |
95 | 0 | } |
96 | 0 | if (!DwarfDebugFlags.empty()) { |
97 | 0 | OS << " <key>dwarf-debug-flags</key>\n" |
98 | 0 | << " "; |
99 | 0 | EmitString(OS, DwarfDebugFlags) << '\n'; |
100 | 0 | } |
101 | 0 | OS << " <key>diagnostics</key>\n"; |
102 | 0 | OS << " <array>\n"; |
103 | 0 | for (auto &DE : Entries) |
104 | 0 | EmitDiagEntry(OS, DE); |
105 | 0 | OS << " </array>\n"; |
106 | 0 | OS << "</dict>\n"; |
107 | |
|
108 | 0 | this->OS << OS.str(); |
109 | 0 | } |
110 | | |
111 | | void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, |
112 | 0 | const Diagnostic &Info) { |
113 | | // Default implementation (Warnings/errors count). |
114 | 0 | DiagnosticConsumer::HandleDiagnostic(Level, Info); |
115 | | |
116 | | // Initialize the main file name, if we haven't already fetched it. |
117 | 0 | if (MainFilename.empty() && Info.hasSourceManager()) { |
118 | 0 | const SourceManager &SM = Info.getSourceManager(); |
119 | 0 | FileID FID = SM.getMainFileID(); |
120 | 0 | if (FID.isValid()) { |
121 | 0 | if (OptionalFileEntryRef FE = SM.getFileEntryRefForID(FID)) |
122 | 0 | MainFilename = std::string(FE->getName()); |
123 | 0 | } |
124 | 0 | } |
125 | | |
126 | | // Create the diag entry. |
127 | 0 | DiagEntry DE; |
128 | 0 | DE.DiagnosticID = Info.getID(); |
129 | 0 | DE.DiagnosticLevel = Level; |
130 | |
|
131 | 0 | DE.WarningOption = |
132 | 0 | std::string(DiagnosticIDs::getWarningOptionForDiag(DE.DiagnosticID)); |
133 | | |
134 | | // Format the message. |
135 | 0 | SmallString<100> MessageStr; |
136 | 0 | Info.FormatDiagnostic(MessageStr); |
137 | 0 | DE.Message = std::string(MessageStr.str()); |
138 | | |
139 | | // Set the location information. |
140 | 0 | DE.Filename = ""; |
141 | 0 | DE.Line = DE.Column = 0; |
142 | 0 | if (Info.getLocation().isValid() && Info.hasSourceManager()) { |
143 | 0 | const SourceManager &SM = Info.getSourceManager(); |
144 | 0 | PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation()); |
145 | |
|
146 | 0 | if (PLoc.isInvalid()) { |
147 | | // At least print the file name if available: |
148 | 0 | FileID FID = SM.getFileID(Info.getLocation()); |
149 | 0 | if (FID.isValid()) { |
150 | 0 | if (OptionalFileEntryRef FE = SM.getFileEntryRefForID(FID)) |
151 | 0 | DE.Filename = std::string(FE->getName()); |
152 | 0 | } |
153 | 0 | } else { |
154 | 0 | DE.Filename = PLoc.getFilename(); |
155 | 0 | DE.Line = PLoc.getLine(); |
156 | 0 | DE.Column = PLoc.getColumn(); |
157 | 0 | } |
158 | 0 | } |
159 | | |
160 | | // Record the diagnostic entry. |
161 | 0 | Entries.push_back(DE); |
162 | 0 | } |
163 | | |