/Users/buildslave/jenkins/workspace/coverage/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 | 11 | DiagOpts(diags) {} |
25 | | |
26 | 18 | static StringRef getLevelName(DiagnosticsEngine::Level Level) { |
27 | 18 | switch (Level) { |
28 | 0 | case DiagnosticsEngine::Ignored: return "ignored"; |
29 | 0 | case DiagnosticsEngine::Remark: return "remark"; |
30 | 0 | case DiagnosticsEngine::Note: return "note"; |
31 | 18 | case DiagnosticsEngine::Warning: return "warning"; |
32 | 0 | case DiagnosticsEngine::Error: return "error"; |
33 | 0 | case DiagnosticsEngine::Fatal: return "fatal error"; |
34 | 18 | } |
35 | 0 | llvm_unreachable("Invalid DiagnosticsEngine level!"); |
36 | 0 | } |
37 | | |
38 | | void |
39 | | LogDiagnosticPrinter::EmitDiagEntry(llvm::raw_ostream &OS, |
40 | 18 | const LogDiagnosticPrinter::DiagEntry &DE) { |
41 | 18 | OS << " <dict>\n"; |
42 | 18 | OS << " <key>level</key>\n" |
43 | 18 | << " "; |
44 | 18 | EmitString(OS, getLevelName(DE.DiagnosticLevel)) << '\n'; |
45 | 18 | if (!DE.Filename.empty()) { |
46 | 17 | OS << " <key>filename</key>\n" |
47 | 17 | << " "; |
48 | 17 | EmitString(OS, DE.Filename) << '\n'; |
49 | 17 | } |
50 | 18 | if (DE.Line != 0) { |
51 | 17 | OS << " <key>line</key>\n" |
52 | 17 | << " "; |
53 | 17 | EmitInteger(OS, DE.Line) << '\n'; |
54 | 17 | } |
55 | 18 | if (DE.Column != 0) { |
56 | 17 | OS << " <key>column</key>\n" |
57 | 17 | << " "; |
58 | 17 | EmitInteger(OS, DE.Column) << '\n'; |
59 | 17 | } |
60 | 18 | if (!DE.Message.empty()) { |
61 | 18 | OS << " <key>message</key>\n" |
62 | 18 | << " "; |
63 | 18 | EmitString(OS, DE.Message) << '\n'; |
64 | 18 | } |
65 | 18 | OS << " <key>ID</key>\n" |
66 | 18 | << " "; |
67 | 18 | EmitInteger(OS, DE.DiagnosticID) << '\n'; |
68 | 18 | if (!DE.WarningOption.empty()) { |
69 | 18 | OS << " <key>WarningOption</key>\n" |
70 | 18 | << " "; |
71 | 18 | EmitString(OS, DE.WarningOption) << '\n'; |
72 | 18 | } |
73 | 18 | OS << " </dict>\n"; |
74 | 18 | } |
75 | | |
76 | 2 | 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 | 2 | if (Entries.empty()) |
84 | 0 | return; |
85 | | |
86 | | // Write to a temporary string to ensure atomic write of diagnostic object. |
87 | 2 | SmallString<512> Msg; |
88 | 2 | llvm::raw_svector_ostream OS(Msg); |
89 | | |
90 | 2 | OS << "<dict>\n"; |
91 | 2 | if (!MainFilename.empty()) { |
92 | 2 | OS << " <key>main-file</key>\n" |
93 | 2 | << " "; |
94 | 2 | EmitString(OS, MainFilename) << '\n'; |
95 | 2 | } |
96 | 2 | if (!DwarfDebugFlags.empty()) { |
97 | 2 | OS << " <key>dwarf-debug-flags</key>\n" |
98 | 2 | << " "; |
99 | 2 | EmitString(OS, DwarfDebugFlags) << '\n'; |
100 | 2 | } |
101 | 2 | OS << " <key>diagnostics</key>\n"; |
102 | 2 | OS << " <array>\n"; |
103 | 2 | for (auto &DE : Entries) |
104 | 18 | EmitDiagEntry(OS, DE); |
105 | 2 | OS << " </array>\n"; |
106 | 2 | OS << "</dict>\n"; |
107 | | |
108 | 2 | this->OS << OS.str(); |
109 | 2 | } |
110 | | |
111 | | void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, |
112 | 20 | const Diagnostic &Info) { |
113 | | // Default implementation (Warnings/errors count). |
114 | 20 | DiagnosticConsumer::HandleDiagnostic(Level, Info); |
115 | | |
116 | | // Initialize the main file name, if we haven't already fetched it. |
117 | 20 | if (MainFilename.empty() && Info.hasSourceManager()5 ) { |
118 | 3 | const SourceManager &SM = Info.getSourceManager(); |
119 | 3 | FileID FID = SM.getMainFileID(); |
120 | 3 | if (FID.isValid()) { |
121 | 3 | if (const FileEntry *FE = SM.getFileEntryForID(FID)) |
122 | 3 | MainFilename = std::string(FE->getName()); |
123 | 3 | } |
124 | 3 | } |
125 | | |
126 | | // Create the diag entry. |
127 | 20 | DiagEntry DE; |
128 | 20 | DE.DiagnosticID = Info.getID(); |
129 | 20 | DE.DiagnosticLevel = Level; |
130 | | |
131 | 20 | DE.WarningOption = |
132 | 20 | std::string(DiagnosticIDs::getWarningOptionForDiag(DE.DiagnosticID)); |
133 | | |
134 | | // Format the message. |
135 | 20 | SmallString<100> MessageStr; |
136 | 20 | Info.FormatDiagnostic(MessageStr); |
137 | 20 | DE.Message = std::string(MessageStr.str()); |
138 | | |
139 | | // Set the location information. |
140 | 20 | DE.Filename = ""; |
141 | 20 | DE.Line = DE.Column = 0; |
142 | 20 | if (Info.getLocation().isValid() && Info.hasSourceManager()17 ) { |
143 | 17 | const SourceManager &SM = Info.getSourceManager(); |
144 | 17 | PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation()); |
145 | | |
146 | 17 | 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 (const FileEntry *FE = SM.getFileEntryForID(FID)) |
151 | 0 | DE.Filename = std::string(FE->getName()); |
152 | 0 | } |
153 | 17 | } else { |
154 | 17 | DE.Filename = PLoc.getFilename(); |
155 | 17 | DE.Line = PLoc.getLine(); |
156 | 17 | DE.Column = PLoc.getColumn(); |
157 | 17 | } |
158 | 17 | } |
159 | | |
160 | | // Record the diagnostic entry. |
161 | 20 | Entries.push_back(DE); |
162 | 20 | } |
163 | | |