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