clang  3.7.0
LogDiagnosticPrinter.cpp
Go to the documentation of this file.
1 //===--- LogDiagnosticPrinter.cpp - Log Diagnostic Printer ----------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
15 #include "llvm/ADT/SmallString.h"
16 #include "llvm/Support/ErrorHandling.h"
17 #include "llvm/Support/raw_ostream.h"
18 using namespace clang;
19 using namespace markup;
20 
22  raw_ostream &os, DiagnosticOptions *diags,
23  std::unique_ptr<raw_ostream> StreamOwner)
24  : OS(os), StreamOwner(std::move(StreamOwner)), LangOpts(nullptr),
25  DiagOpts(diags) {}
26 
28  switch (Level) {
29  case DiagnosticsEngine::Ignored: return "ignored";
30  case DiagnosticsEngine::Remark: return "remark";
31  case DiagnosticsEngine::Note: return "note";
32  case DiagnosticsEngine::Warning: return "warning";
33  case DiagnosticsEngine::Error: return "error";
34  case DiagnosticsEngine::Fatal: return "fatal error";
35  }
36  llvm_unreachable("Invalid DiagnosticsEngine level!");
37 }
38 
39 void
40 LogDiagnosticPrinter::EmitDiagEntry(llvm::raw_ostream &OS,
41  const LogDiagnosticPrinter::DiagEntry &DE) {
42  OS << " <dict>\n";
43  OS << " <key>level</key>\n"
44  << " ";
45  EmitString(OS, getLevelName(DE.DiagnosticLevel)) << '\n';
46  if (!DE.Filename.empty()) {
47  OS << " <key>filename</key>\n"
48  << " ";
49  EmitString(OS, DE.Filename) << '\n';
50  }
51  if (DE.Line != 0) {
52  OS << " <key>line</key>\n"
53  << " ";
54  EmitInteger(OS, DE.Line) << '\n';
55  }
56  if (DE.Column != 0) {
57  OS << " <key>column</key>\n"
58  << " ";
59  EmitInteger(OS, DE.Column) << '\n';
60  }
61  if (!DE.Message.empty()) {
62  OS << " <key>message</key>\n"
63  << " ";
64  EmitString(OS, DE.Message) << '\n';
65  }
66  OS << " <key>ID</key>\n"
67  << " ";
68  EmitInteger(OS, DE.DiagnosticID) << '\n';
69  if (!DE.WarningOption.empty()) {
70  OS << " <key>WarningOption</key>\n"
71  << " ";
72  EmitString(OS, DE.WarningOption) << '\n';
73  }
74  OS << " </dict>\n";
75 }
76 
78  // We emit all the diagnostics in EndSourceFile. However, we don't emit any
79  // entry if no diagnostics were present.
80  //
81  // Note that DiagnosticConsumer has no "end-of-compilation" callback, so we
82  // will miss any diagnostics which are emitted after and outside the
83  // translation unit processing.
84  if (Entries.empty())
85  return;
86 
87  // Write to a temporary string to ensure atomic write of diagnostic object.
88  SmallString<512> Msg;
89  llvm::raw_svector_ostream OS(Msg);
90 
91  OS << "<dict>\n";
92  if (!MainFilename.empty()) {
93  OS << " <key>main-file</key>\n"
94  << " ";
95  EmitString(OS, MainFilename) << '\n';
96  }
97  if (!DwarfDebugFlags.empty()) {
98  OS << " <key>dwarf-debug-flags</key>\n"
99  << " ";
100  EmitString(OS, DwarfDebugFlags) << '\n';
101  }
102  OS << " <key>diagnostics</key>\n";
103  OS << " <array>\n";
104  for (auto &DE : Entries)
105  EmitDiagEntry(OS, DE);
106  OS << " </array>\n";
107  OS << "</dict>\n";
108 
109  this->OS << OS.str();
110 }
111 
113  const Diagnostic &Info) {
114  // Default implementation (Warnings/errors count).
116 
117  // Initialize the main file name, if we haven't already fetched it.
118  if (MainFilename.empty() && Info.hasSourceManager()) {
119  const SourceManager &SM = Info.getSourceManager();
120  FileID FID = SM.getMainFileID();
121  if (!FID.isInvalid()) {
122  const FileEntry *FE = SM.getFileEntryForID(FID);
123  if (FE && FE->isValid())
124  MainFilename = FE->getName();
125  }
126  }
127 
128  // Create the diag entry.
129  DiagEntry DE;
130  DE.DiagnosticID = Info.getID();
131  DE.DiagnosticLevel = Level;
132 
133  DE.WarningOption = DiagnosticIDs::getWarningOptionForDiag(DE.DiagnosticID);
134 
135  // Format the message.
136  SmallString<100> MessageStr;
137  Info.FormatDiagnostic(MessageStr);
138  DE.Message = MessageStr.str();
139 
140  // Set the location information.
141  DE.Filename = "";
142  DE.Line = DE.Column = 0;
143  if (Info.getLocation().isValid() && Info.hasSourceManager()) {
144  const SourceManager &SM = Info.getSourceManager();
145  PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
146 
147  if (PLoc.isInvalid()) {
148  // At least print the file name if available:
149  FileID FID = SM.getFileID(Info.getLocation());
150  if (!FID.isInvalid()) {
151  const FileEntry *FE = SM.getFileEntryForID(FID);
152  if (FE && FE->isValid())
153  DE.Filename = FE->getName();
154  }
155  } else {
156  DE.Filename = PLoc.getFilename();
157  DE.Line = PLoc.getLine();
158  DE.Column = PLoc.getColumn();
159  }
160  }
161 
162  // Record the diagnostic entry.
163  Entries.push_back(DE);
164 }
165 
unsigned getColumn() const
Return the presumed column number of this location.
Defines the clang::FileManager interface and associated types.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
Defines the SourceManager interface.
void EndSourceFile() override
Callback to inform the diagnostic client that processing of a source file has ended.
bool isValid() const
Definition: FileManager.h:85
unsigned getID() const
Definition: Diagnostic.h:1147
raw_ostream & EmitInteger(raw_ostream &o, int64_t value)
Definition: PlistSupport.h:54
const SourceLocation & getLocation() const
Definition: Diagnostic.h:1148
unsigned getLine() const
Return the presumed line number of this location.
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
SourceManager & SM
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
static StringRef getWarningOptionForDiag(unsigned DiagID)
Return the lowest-level warning option that enables the specified diagnostic.
Represents an unpacked "presumed" location which can be presented to the user.
const char * getFilename() const
Return the presumed filename of this location.
const char * getName() const
Definition: FileManager.h:84
bool isValid() const
Return true if this is a valid SourceLocation object.
Options for controlling the compiler diagnostics engine.
Cached information about one file (either on disk or in the virtual file system). ...
Definition: FileManager.h:53
static StringRef getLevelName(DiagnosticsEngine::Level Level)
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info)
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
Definition: Diagnostic.cpp:398
FileID getMainFileID() const
Returns the FileID of the main source file.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool hasSourceManager() const
Definition: Diagnostic.h:1149
LogDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions *Diags, std::unique_ptr< raw_ostream > StreamOwner)
SourceManager & getSourceManager() const
Definition: Diagnostic.h:1150
bool isInvalid() const
raw_ostream & EmitString(raw_ostream &o, StringRef s)
Definition: PlistSupport.h:61
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:141
void FormatDiagnostic(SmallVectorImpl< char > &OutStr) const
Format this diagnostic into a string, substituting the formal arguments into the %0 slots...
Definition: Diagnostic.cpp:630
This class handles loading and caching of source files into memory.
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.