1//===- llvm/Support/DiagnosticInfo.h - Diagnostic Declaration ---*- C++ -*-===//
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//
10// This file declares the different classes involved in low level diagnostics.
11//
12// Diagnostics reporting is still done as part of the LLVMContext.
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_SUPPORT_DIAGNOSTICINFO_H
16#define LLVM_SUPPORT_DIAGNOSTICINFO_H
17
18#include "llvm-c/Core.h"
19#include "llvm/ADT/ArrayRef.h"
20#include "llvm/IR/DebugLoc.h"
21#include "llvm/Support/Casting.h"
22
23namespace llvm {
24
25// Forward declarations.
26class DiagnosticPrinter;
27class Function;
28class Instruction;
29class LLVMContextImpl;
30class Twine;
31class Value;
32class DebugLoc;
33
34/// \brief Defines the different supported severity of a diagnostic.
35enum DiagnosticSeverity {
36  DS_Error,
37  DS_Warning,
38  DS_Remark,
39  // A note attaches additional information to one of the previous diagnostic
40  // types.
41  DS_Note
42};
43
44/// \brief Defines the different supported kind of a diagnostic.
45/// This enum should be extended with a new ID for each added concrete subclass.
46enum DiagnosticKind {
47  DK_InlineAsm,
48  DK_StackSize,
49  DK_DebugMetadataVersion,
50  DK_SampleProfile,
51  DK_OptimizationRemark,
52  DK_OptimizationRemarkMissed,
53  DK_OptimizationRemarkAnalysis,
54  DK_FirstPluginKind
55};
56
57/// \brief Get the next available kind ID for a plugin diagnostic.
58/// Each time this function is called, it returns a different number.
59/// Therefore, a plugin that wants to "identify" its own classes
60/// with a dynamic identifier, just have to use this method to get a new ID
61/// and assign it to each of its classes.
62/// The returned ID will be greater than or equal to DK_FirstPluginKind.
63/// Thus, the plugin identifiers will not conflict with the
64/// DiagnosticKind values.
65int getNextAvailablePluginDiagnosticKind();
66
67/// \brief This is the base abstract class for diagnostic reporting in
68/// the backend.
69/// The print method must be overloaded by the subclasses to print a
70/// user-friendly message in the client of the backend (let us call it a
71/// frontend).
72class DiagnosticInfo {
73private:
74  /// Kind defines the kind of report this is about.
75  const /* DiagnosticKind */ int Kind;
76  /// Severity gives the severity of the diagnostic.
77  const DiagnosticSeverity Severity;
78
79public:
80  DiagnosticInfo(/* DiagnosticKind */ int Kind, DiagnosticSeverity Severity)
81      : Kind(Kind), Severity(Severity) {}
82
83  virtual ~DiagnosticInfo() {}
84
85  /* DiagnosticKind */ int getKind() const { return Kind; }
86  DiagnosticSeverity getSeverity() const { return Severity; }
87
88  /// Print using the given \p DP a user-friendly message.
89  /// This is the default message that will be printed to the user.
90  /// It is used when the frontend does not directly take advantage
91  /// of the information contained in fields of the subclasses.
92  /// The printed message must not end with '.' nor start with a severity
93  /// keyword.
94  virtual void print(DiagnosticPrinter &DP) const = 0;
95};
96
97/// Diagnostic information for inline asm reporting.
98/// This is basically a message and an optional location.
99class DiagnosticInfoInlineAsm : public DiagnosticInfo {
100private:
101  /// Optional line information. 0 if not set.
102  unsigned LocCookie;
103  /// Message to be reported.
104  const Twine &MsgStr;
105  /// Optional origin of the problem.
106  const Instruction *Instr;
107
108public:
109  /// \p MsgStr is the message to be reported to the frontend.
110  /// This class does not copy \p MsgStr, therefore the reference must be valid
111  /// for the whole life time of the Diagnostic.
112  DiagnosticInfoInlineAsm(const Twine &MsgStr,
113                          DiagnosticSeverity Severity = DS_Error)
114      : DiagnosticInfo(DK_InlineAsm, Severity), LocCookie(0), MsgStr(MsgStr),
115        Instr(nullptr) {}
116
117  /// \p LocCookie if non-zero gives the line number for this report.
118  /// \p MsgStr gives the message.
119  /// This class does not copy \p MsgStr, therefore the reference must be valid
120  /// for the whole life time of the Diagnostic.
121  DiagnosticInfoInlineAsm(unsigned LocCookie, const Twine &MsgStr,
122                          DiagnosticSeverity Severity = DS_Error)
123      : DiagnosticInfo(DK_InlineAsm, Severity), LocCookie(LocCookie),
124        MsgStr(MsgStr), Instr(nullptr) {}
125
126  /// \p Instr gives the original instruction that triggered the diagnostic.
127  /// \p MsgStr gives the message.
128  /// This class does not copy \p MsgStr, therefore the reference must be valid
129  /// for the whole life time of the Diagnostic.
130  /// Same for \p I.
131  DiagnosticInfoInlineAsm(const Instruction &I, const Twine &MsgStr,
132                          DiagnosticSeverity Severity = DS_Error);
133
134  unsigned getLocCookie() const { return LocCookie; }
135  const Twine &getMsgStr() const { return MsgStr; }
136  const Instruction *getInstruction() const { return Instr; }
137
138  /// \see DiagnosticInfo::print.
139  void print(DiagnosticPrinter &DP) const override;
140
141  static bool classof(const DiagnosticInfo *DI) {
142    return DI->getKind() == DK_InlineAsm;
143  }
144};
145
146/// Diagnostic information for stack size reporting.
147/// This is basically a function and a size.
148class DiagnosticInfoStackSize : public DiagnosticInfo {
149private:
150  /// The function that is concerned by this stack size diagnostic.
151  const Function &Fn;
152  /// The computed stack size.
153  unsigned StackSize;
154
155public:
156  /// \p The function that is concerned by this stack size diagnostic.
157  /// \p The computed stack size.
158  DiagnosticInfoStackSize(const Function &Fn, unsigned StackSize,
159                          DiagnosticSeverity Severity = DS_Warning)
160      : DiagnosticInfo(DK_StackSize, Severity), Fn(Fn), StackSize(StackSize) {}
161
162  const Function &getFunction() const { return Fn; }
163  unsigned getStackSize() const { return StackSize; }
164
165  /// \see DiagnosticInfo::print.
166  void print(DiagnosticPrinter &DP) const override;
167
168  static bool classof(const DiagnosticInfo *DI) {
169    return DI->getKind() == DK_StackSize;
170  }
171};
172
173/// Diagnostic information for debug metadata version reporting.
174/// This is basically a module and a version.
175class DiagnosticInfoDebugMetadataVersion : public DiagnosticInfo {
176private:
177  /// The module that is concerned by this debug metadata version diagnostic.
178  const Module &M;
179  /// The actual metadata version.
180  unsigned MetadataVersion;
181
182public:
183  /// \p The module that is concerned by this debug metadata version diagnostic.
184  /// \p The actual metadata version.
185  DiagnosticInfoDebugMetadataVersion(const Module &M, unsigned MetadataVersion,
186                          DiagnosticSeverity Severity = DS_Warning)
187      : DiagnosticInfo(DK_DebugMetadataVersion, Severity), M(M),
188        MetadataVersion(MetadataVersion) {}
189
190  const Module &getModule() const { return M; }
191  unsigned getMetadataVersion() const { return MetadataVersion; }
192
193  /// \see DiagnosticInfo::print.
194  void print(DiagnosticPrinter &DP) const override;
195
196  static bool classof(const DiagnosticInfo *DI) {
197    return DI->getKind() == DK_DebugMetadataVersion;
198  }
199};
200
201/// Diagnostic information for the sample profiler.
202class DiagnosticInfoSampleProfile : public DiagnosticInfo {
203public:
204  DiagnosticInfoSampleProfile(const char *FileName, unsigned LineNum,
205                              const Twine &Msg,
206                              DiagnosticSeverity Severity = DS_Error)
207      : DiagnosticInfo(DK_SampleProfile, Severity), FileName(FileName),
208        LineNum(LineNum), Msg(Msg) {}
209  DiagnosticInfoSampleProfile(const char *FileName, const Twine &Msg,
210                              DiagnosticSeverity Severity = DS_Error)
211      : DiagnosticInfo(DK_SampleProfile, Severity), FileName(FileName),
212        LineNum(0), Msg(Msg) {}
213  DiagnosticInfoSampleProfile(const Twine &Msg,
214                              DiagnosticSeverity Severity = DS_Error)
215      : DiagnosticInfo(DK_SampleProfile, Severity), FileName(nullptr),
216        LineNum(0), Msg(Msg) {}
217
218  /// \see DiagnosticInfo::print.
219  void print(DiagnosticPrinter &DP) const override;
220
221  static bool classof(const DiagnosticInfo *DI) {
222    return DI->getKind() == DK_SampleProfile;
223  }
224
225  const char *getFileName() const { return FileName; }
226  unsigned getLineNum() const { return LineNum; }
227  const Twine &getMsg() const { return Msg; }
228
229private:
230  /// Name of the input file associated with this diagnostic.
231  const char *FileName;
232
233  /// Line number where the diagnostic occurred. If 0, no line number will
234  /// be emitted in the message.
235  unsigned LineNum;
236
237  /// Message to report.
238  const Twine &Msg;
239};
240
241/// Common features for diagnostics dealing with optimization remarks.
242class DiagnosticInfoOptimizationRemarkBase : public DiagnosticInfo {
243public:
244  /// \p PassName is the name of the pass emitting this diagnostic.
245  /// \p Fn is the function where the diagnostic is being emitted. \p DLoc is
246  /// the location information to use in the diagnostic. If line table
247  /// information is available, the diagnostic will include the source code
248  /// location. \p Msg is the message to show. Note that this class does not
249  /// copy this message, so this reference must be valid for the whole life time
250  /// of the diagnostic.
251  DiagnosticInfoOptimizationRemarkBase(enum DiagnosticKind Kind,
252                                       const char *PassName, const Function &Fn,
253                                       const DebugLoc &DLoc, const Twine &Msg)
254      : DiagnosticInfo(Kind, DS_Remark), PassName(PassName), Fn(Fn), DLoc(DLoc),
255        Msg(Msg) {}
256
257  /// \see DiagnosticInfo::print.
258  void print(DiagnosticPrinter &DP) const override;
259
260  static bool classof(const DiagnosticInfo *DI) {
261    return DI->getKind() == DK_OptimizationRemark;
262  }
263
264  /// Return true if this optimization remark is enabled by one of
265  /// of the LLVM command line flags (-pass-remarks, -pass-remarks-missed,
266  /// or -pass-remarks-analysis). Note that this only handles the LLVM
267  /// flags. We cannot access Clang flags from here (they are handled
268  /// in BackendConsumer::OptimizationRemarkHandler).
269  virtual bool isEnabled() const = 0;
270
271  /// Return true if location information is available for this diagnostic.
272  bool isLocationAvailable() const;
273
274  /// Return a string with the location information for this diagnostic
275  /// in the format "file:line:col". If location information is not available,
276  /// it returns "<unknown>:0:0".
277  const std::string getLocationStr() const;
278
279  /// Return location information for this diagnostic in three parts:
280  /// the source file name, line number and column.
281  void getLocation(StringRef *Filename, unsigned *Line, unsigned *Column) const;
282
283  const char *getPassName() const { return PassName; }
284  const Function &getFunction() const { return Fn; }
285  const DebugLoc &getDebugLoc() const { return DLoc; }
286  const Twine &getMsg() const { return Msg; }
287
288private:
289  /// Name of the pass that triggers this report. If this matches the
290  /// regular expression given in -Rpass=regexp, then the remark will
291  /// be emitted.
292  const char *PassName;
293
294  /// Function where this diagnostic is triggered.
295  const Function &Fn;
296
297  /// Debug location where this diagnostic is triggered.
298  DebugLoc DLoc;
299
300  /// Message to report.
301  const Twine &Msg;
302};
303
304/// Diagnostic information for applied optimization remarks.
305class DiagnosticInfoOptimizationRemark
306    : public DiagnosticInfoOptimizationRemarkBase {
307public:
308  /// \p PassName is the name of the pass emitting this diagnostic. If
309  /// this name matches the regular expression given in -Rpass=, then the
310  /// diagnostic will be emitted. \p Fn is the function where the diagnostic
311  /// is being emitted. \p DLoc is the location information to use in the
312  /// diagnostic. If line table information is available, the diagnostic
313  /// will include the source code location. \p Msg is the message to show.
314  /// Note that this class does not copy this message, so this reference
315  /// must be valid for the whole life time of the diagnostic.
316  DiagnosticInfoOptimizationRemark(const char *PassName, const Function &Fn,
317                                   const DebugLoc &DLoc, const Twine &Msg)
318      : DiagnosticInfoOptimizationRemarkBase(DK_OptimizationRemark, PassName,
319                                             Fn, DLoc, Msg) {}
320
321  static bool classof(const DiagnosticInfo *DI) {
322    return DI->getKind() == DK_OptimizationRemark;
323  }
324
325  /// \see DiagnosticInfoOptimizationRemarkBase::isEnabled.
326  virtual bool isEnabled() const override;
327};
328
329/// Diagnostic information for missed-optimization remarks.
330class DiagnosticInfoOptimizationRemarkMissed
331    : public DiagnosticInfoOptimizationRemarkBase {
332public:
333  /// \p PassName is the name of the pass emitting this diagnostic. If
334  /// this name matches the regular expression given in -Rpass-missed=, then the
335  /// diagnostic will be emitted. \p Fn is the function where the diagnostic
336  /// is being emitted. \p DLoc is the location information to use in the
337  /// diagnostic. If line table information is available, the diagnostic
338  /// will include the source code location. \p Msg is the message to show.
339  /// Note that this class does not copy this message, so this reference
340  /// must be valid for the whole life time of the diagnostic.
341  DiagnosticInfoOptimizationRemarkMissed(const char *PassName,
342                                         const Function &Fn,
343                                         const DebugLoc &DLoc, const Twine &Msg)
344      : DiagnosticInfoOptimizationRemarkBase(DK_OptimizationRemarkMissed,
345                                             PassName, Fn, DLoc, Msg) {}
346
347  static bool classof(const DiagnosticInfo *DI) {
348    return DI->getKind() == DK_OptimizationRemarkMissed;
349  }
350
351  /// \see DiagnosticInfoOptimizationRemarkBase::isEnabled.
352  virtual bool isEnabled() const override;
353};
354
355/// Diagnostic information for optimization analysis remarks.
356class DiagnosticInfoOptimizationRemarkAnalysis
357    : public DiagnosticInfoOptimizationRemarkBase {
358public:
359  /// \p PassName is the name of the pass emitting this diagnostic. If
360  /// this name matches the regular expression given in -Rpass-analysis=, then
361  /// the diagnostic will be emitted. \p Fn is the function where the diagnostic
362  /// is being emitted. \p DLoc is the location information to use in the
363  /// diagnostic. If line table information is available, the diagnostic will
364  /// include the source code location. \p Msg is the message to show. Note that
365  /// this class does not copy this message, so this reference must be valid for
366  /// the whole life time of the diagnostic.
367  DiagnosticInfoOptimizationRemarkAnalysis(const char *PassName,
368                                           const Function &Fn,
369                                           const DebugLoc &DLoc,
370                                           const Twine &Msg)
371      : DiagnosticInfoOptimizationRemarkBase(DK_OptimizationRemarkAnalysis,
372                                             PassName, Fn, DLoc, Msg) {}
373
374  static bool classof(const DiagnosticInfo *DI) {
375    return DI->getKind() == DK_OptimizationRemarkAnalysis;
376  }
377
378  /// \see DiagnosticInfoOptimizationRemarkBase::isEnabled.
379  virtual bool isEnabled() const override;
380};
381
382// Create wrappers for C Binding types (see CBindingWrapping.h).
383DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DiagnosticInfo, LLVMDiagnosticInfoRef)
384
385/// Emit an optimization-applied message. \p PassName is the name of the pass
386/// emitting the message. If -Rpass= is given and \p PassName matches the
387/// regular expression in -Rpass, then the remark will be emitted. \p Fn is
388/// the function triggering the remark, \p DLoc is the debug location where
389/// the diagnostic is generated. \p Msg is the message string to use.
390void emitOptimizationRemark(LLVMContext &Ctx, const char *PassName,
391                            const Function &Fn, const DebugLoc &DLoc,
392                            const Twine &Msg);
393
394/// Emit an optimization-missed message. \p PassName is the name of the
395/// pass emitting the message. If -Rpass-missed= is given and \p PassName
396/// matches the regular expression in -Rpass, then the remark will be
397/// emitted. \p Fn is the function triggering the remark, \p DLoc is the
398/// debug location where the diagnostic is generated. \p Msg is the
399/// message string to use.
400void emitOptimizationRemarkMissed(LLVMContext &Ctx, const char *PassName,
401                                  const Function &Fn, const DebugLoc &DLoc,
402                                  const Twine &Msg);
403
404/// Emit an optimization analysis remark message. \p PassName is the name of
405/// the pass emitting the message. If -Rpass-analysis= is given and \p
406/// PassName matches the regular expression in -Rpass, then the remark will be
407/// emitted. \p Fn is the function triggering the remark, \p DLoc is the debug
408/// location where the diagnostic is generated. \p Msg is the message string
409/// to use.
410void emitOptimizationRemarkAnalysis(LLVMContext &Ctx, const char *PassName,
411                                    const Function &Fn, const DebugLoc &DLoc,
412                                    const Twine &Msg);
413
414} // End namespace llvm
415
416#endif
417