1341825Sdim//===- Diagnostic.h - C Language Family Diagnostic Handling -----*- C++ -*-===//
2193326Sed//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6193326Sed//
7193326Sed//===----------------------------------------------------------------------===//
8341825Sdim//
9239462Sdim/// \file
10341825Sdim/// Defines the Diagnostic-related interfaces.
11341825Sdim//
12193326Sed//===----------------------------------------------------------------------===//
13193326Sed
14280031Sdim#ifndef LLVM_CLANG_BASIC_DIAGNOSTIC_H
15280031Sdim#define LLVM_CLANG_BASIC_DIAGNOSTIC_H
16193326Sed
17218893Sdim#include "clang/Basic/DiagnosticIDs.h"
18243830Sdim#include "clang/Basic/DiagnosticOptions.h"
19193326Sed#include "clang/Basic/SourceLocation.h"
20288943Sdim#include "clang/Basic/Specifiers.h"
21226633Sdim#include "llvm/ADT/ArrayRef.h"
22218893Sdim#include "llvm/ADT/DenseMap.h"
23206275Srdivacky#include "llvm/ADT/IntrusiveRefCntPtr.h"
24314564Sdim#include "llvm/ADT/SmallVector.h"
25314564Sdim#include "llvm/ADT/StringRef.h"
26341825Sdim#include "llvm/ADT/iterator_range.h"
27341825Sdim#include "llvm/Support/Compiler.h"
28353358Sdim#include "llvm/Support/Error.h"
29314564Sdim#include <cassert>
30314564Sdim#include <cstdint>
31341825Sdim#include <limits>
32249423Sdim#include <list>
33321369Sdim#include <map>
34314564Sdim#include <memory>
35314564Sdim#include <string>
36314564Sdim#include <type_traits>
37314564Sdim#include <utility>
38198092Srdivacky#include <vector>
39193326Sed
40193326Sednamespace clang {
41314564Sdim
42314564Sdimclass DeclContext;
43314564Sdimclass DiagnosticBuilder;
44314564Sdimclass DiagnosticConsumer;
45314564Sdimclass IdentifierInfo;
46314564Sdimclass LangOptions;
47314564Sdimclass Preprocessor;
48341825Sdimclass SourceManager;
49314564Sdimclass StoredDiagnostic;
50314564Sdim
51314564Sdimnamespace tok {
52314564Sdim
53341825Sdimenum TokenKind : unsigned short;
54198092Srdivacky
55341825Sdim} // namespace tok
56314564Sdim
57341825Sdim/// Annotates a diagnostic with some code that should be
58193326Sed/// inserted, removed, or replaced to fix the problem.
59193326Sed///
60193326Sed/// This kind of hint should be used when we are certain that the
61193326Sed/// introduction, removal, or modification of a particular (small!)
62193326Sed/// amount of code will correct a compilation error. The compiler
63193326Sed/// should also provide full recovery from such errors, such that
64193326Sed/// suppressing the diagnostic output can still result in successful
65193326Sed/// compilation.
66206084Srdivackyclass FixItHint {
67193326Sedpublic:
68341825Sdim  /// Code that should be replaced to correct the error. Empty for an
69212904Sdim  /// insertion hint.
70210299Sed  CharSourceRange RemoveRange;
71193326Sed
72341825Sdim  /// Code in the specific range that should be inserted in the insertion
73234353Sdim  /// location.
74234353Sdim  CharSourceRange InsertFromRange;
75234353Sdim
76341825Sdim  /// The actual code to insert at the insertion location, as a
77193326Sed  /// string.
78193326Sed  std::string CodeToInsert;
79193326Sed
80341825Sdim  bool BeforePreviousInsertions = false;
81234353Sdim
82341825Sdim  /// Empty code modification hint, indicating that no code
83193326Sed  /// modification is known.
84341825Sdim  FixItHint() = default;
85193326Sed
86199482Srdivacky  bool isNull() const {
87212904Sdim    return !RemoveRange.isValid();
88199482Srdivacky  }
89341825Sdim
90341825Sdim  /// Create a code modification hint that inserts the given
91193326Sed  /// code string at a specific location.
92206084Srdivacky  static FixItHint CreateInsertion(SourceLocation InsertionLoc,
93234353Sdim                                   StringRef Code,
94234353Sdim                                   bool BeforePreviousInsertions = false) {
95206084Srdivacky    FixItHint Hint;
96212904Sdim    Hint.RemoveRange =
97249423Sdim      CharSourceRange::getCharRange(InsertionLoc, InsertionLoc);
98193326Sed    Hint.CodeToInsert = Code;
99234353Sdim    Hint.BeforePreviousInsertions = BeforePreviousInsertions;
100193326Sed    return Hint;
101193326Sed  }
102341825Sdim
103341825Sdim  /// Create a code modification hint that inserts the given
104239462Sdim  /// code from \p FromRange at a specific location.
105234353Sdim  static FixItHint CreateInsertionFromRange(SourceLocation InsertionLoc,
106234353Sdim                                            CharSourceRange FromRange,
107234353Sdim                                        bool BeforePreviousInsertions = false) {
108234353Sdim    FixItHint Hint;
109234353Sdim    Hint.RemoveRange =
110249423Sdim      CharSourceRange::getCharRange(InsertionLoc, InsertionLoc);
111234353Sdim    Hint.InsertFromRange = FromRange;
112234353Sdim    Hint.BeforePreviousInsertions = BeforePreviousInsertions;
113234353Sdim    return Hint;
114234353Sdim  }
115193326Sed
116341825Sdim  /// Create a code modification hint that removes the given
117193326Sed  /// source range.
118210299Sed  static FixItHint CreateRemoval(CharSourceRange RemoveRange) {
119206084Srdivacky    FixItHint Hint;
120193326Sed    Hint.RemoveRange = RemoveRange;
121193326Sed    return Hint;
122193326Sed  }
123210299Sed  static FixItHint CreateRemoval(SourceRange RemoveRange) {
124210299Sed    return CreateRemoval(CharSourceRange::getTokenRange(RemoveRange));
125210299Sed  }
126341825Sdim
127341825Sdim  /// Create a code modification hint that replaces the given
128193326Sed  /// source range with the given code string.
129210299Sed  static FixItHint CreateReplacement(CharSourceRange RemoveRange,
130226633Sdim                                     StringRef Code) {
131206084Srdivacky    FixItHint Hint;
132193326Sed    Hint.RemoveRange = RemoveRange;
133193326Sed    Hint.CodeToInsert = Code;
134193326Sed    return Hint;
135193326Sed  }
136341825Sdim
137210299Sed  static FixItHint CreateReplacement(SourceRange RemoveRange,
138226633Sdim                                     StringRef Code) {
139210299Sed    return CreateReplacement(CharSourceRange::getTokenRange(RemoveRange), Code);
140210299Sed  }
141193326Sed};
142193326Sed
143341825Sdim/// Concrete class used by the front-end to report problems and issues.
144239462Sdim///
145239462Sdim/// This massages the diagnostics (e.g. handling things like "report warnings
146239462Sdim/// as errors" and passes them off to the DiagnosticConsumer for reporting to
147239462Sdim/// the user. DiagnosticsEngine is tied to one translation unit and one
148239462Sdim/// SourceManager.
149234353Sdimclass DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
150193326Sedpublic:
151341825Sdim  /// The level of the diagnostic, after it has been through mapping.
152193326Sed  enum Level {
153218893Sdim    Ignored = DiagnosticIDs::Ignored,
154218893Sdim    Note = DiagnosticIDs::Note,
155276479Sdim    Remark = DiagnosticIDs::Remark,
156218893Sdim    Warning = DiagnosticIDs::Warning,
157218893Sdim    Error = DiagnosticIDs::Error,
158218893Sdim    Fatal = DiagnosticIDs::Fatal
159193326Sed  };
160198092Srdivacky
161193326Sed  enum ArgumentKind {
162341825Sdim    /// std::string
163341825Sdim    ak_std_string,
164341825Sdim
165341825Sdim    /// const char *
166341825Sdim    ak_c_string,
167341825Sdim
168341825Sdim    /// int
169341825Sdim    ak_sint,
170341825Sdim
171341825Sdim    /// unsigned
172341825Sdim    ak_uint,
173341825Sdim
174341825Sdim    /// enum TokenKind : unsigned
175341825Sdim    ak_tokenkind,
176341825Sdim
177341825Sdim    /// IdentifierInfo
178341825Sdim    ak_identifierinfo,
179341825Sdim
180360784Sdim    /// address space
181360784Sdim    ak_addrspace,
182360784Sdim
183344779Sdim    /// Qualifiers
184344779Sdim    ak_qual,
185344779Sdim
186341825Sdim    /// QualType
187341825Sdim    ak_qualtype,
188341825Sdim
189341825Sdim    /// DeclarationName
190341825Sdim    ak_declarationname,
191341825Sdim
192341825Sdim    /// NamedDecl *
193341825Sdim    ak_nameddecl,
194341825Sdim
195341825Sdim    /// NestedNameSpecifier *
196341825Sdim    ak_nestednamespec,
197341825Sdim
198341825Sdim    /// DeclContext *
199341825Sdim    ak_declcontext,
200341825Sdim
201341825Sdim    /// pair<QualType, QualType>
202341825Sdim    ak_qualtype_pair,
203341825Sdim
204341825Sdim    /// Attr *
205341825Sdim    ak_attr
206193326Sed  };
207210299Sed
208341825Sdim  /// Represents on argument value, which is a union discriminated
209239462Sdim  /// by ArgumentKind, with a value.
210341825Sdim  using ArgumentValue = std::pair<ArgumentKind, intptr_t>;
211193326Sed
212198092Srdivackyprivate:
213341825Sdim  // Used by __extension__
214341825Sdim  unsigned char AllExtensionsSilenced = 0;
215341825Sdim
216353358Sdim  // Treat fatal errors like errors.
217353358Sdim  bool FatalsAsError = false;
218341825Sdim
219341825Sdim  // Suppress all diagnostics.
220341825Sdim  bool SuppressAllDiagnostics = false;
221341825Sdim
222341825Sdim  // Elide common types of templates.
223341825Sdim  bool ElideType = true;
224341825Sdim
225341825Sdim  // Print a tree when comparing templates.
226341825Sdim  bool PrintTemplateTree = false;
227341825Sdim
228341825Sdim  // Color printing is enabled.
229341825Sdim  bool ShowColors = false;
230341825Sdim
231341825Sdim  // Which overload candidates to show.
232341825Sdim  OverloadsShown ShowOverloads = Ovl_All;
233341825Sdim
234341825Sdim  // Cap of # errors emitted, 0 -> no limit.
235341825Sdim  unsigned ErrorLimit = 0;
236341825Sdim
237341825Sdim  // Cap on depth of template backtrace stack, 0 -> no limit.
238341825Sdim  unsigned TemplateBacktraceLimit = 0;
239341825Sdim
240341825Sdim  // Cap on depth of constexpr evaluation backtrace stack, 0 -> no limit.
241341825Sdim  unsigned ConstexprBacktraceLimit = 0;
242341825Sdim
243234353Sdim  IntrusiveRefCntPtr<DiagnosticIDs> Diags;
244243830Sdim  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
245341825Sdim  DiagnosticConsumer *Client = nullptr;
246280031Sdim  std::unique_ptr<DiagnosticConsumer> Owner;
247341825Sdim  SourceManager *SourceMgr = nullptr;
248218893Sdim
249341825Sdim  /// Mapping information for diagnostics.
250218893Sdim  ///
251239462Sdim  /// Mapping info is packed into four bits per diagnostic.  The low three
252276479Sdim  /// bits are the mapping (an instance of diag::Severity), or zero if unset.
253239462Sdim  /// The high bit is set when the mapping was established as a user mapping.
254239462Sdim  /// If the high bit is clear, then the low bits are set to the default
255239462Sdim  /// value, and should be mapped with -pedantic, -Werror, etc.
256239462Sdim  ///
257218893Sdim  /// A new DiagState is created and kept around when diagnostic pragmas modify
258218893Sdim  /// the state so that we know what is the diagnostic state at any given
259218893Sdim  /// source location.
260218893Sdim  class DiagState {
261276479Sdim    llvm::DenseMap<unsigned, DiagnosticMapping> DiagMap;
262198092Srdivacky
263212904Sdim  public:
264321369Sdim    // "Global" configuration state that can actually vary between modules.
265321369Sdim
266341825Sdim    // Ignore all warnings: -w
267341825Sdim    unsigned IgnoreAllWarnings : 1;
268341825Sdim
269341825Sdim    // Enable all warnings.
270341825Sdim    unsigned EnableAllWarnings : 1;
271341825Sdim
272341825Sdim    // Treat warnings like errors.
273341825Sdim    unsigned WarningsAsErrors : 1;
274341825Sdim
275341825Sdim    // Treat errors like fatal errors.
276341825Sdim    unsigned ErrorsAsFatal : 1;
277341825Sdim
278341825Sdim    // Suppress warnings in system headers.
279341825Sdim    unsigned SuppressSystemWarnings : 1;
280341825Sdim
281341825Sdim    // Map extensions to warnings or errors?
282341825Sdim    diag::Severity ExtBehavior = diag::Severity::Ignored;
283341825Sdim
284321369Sdim    DiagState()
285321369Sdim        : IgnoreAllWarnings(false), EnableAllWarnings(false),
286321369Sdim          WarningsAsErrors(false), ErrorsAsFatal(false),
287341825Sdim          SuppressSystemWarnings(false) {}
288321369Sdim
289341825Sdim    using iterator = llvm::DenseMap<unsigned, DiagnosticMapping>::iterator;
290341825Sdim    using const_iterator =
291341825Sdim        llvm::DenseMap<unsigned, DiagnosticMapping>::const_iterator;
292212904Sdim
293276479Sdim    void setMapping(diag::kind Diag, DiagnosticMapping Info) {
294226633Sdim      DiagMap[Diag] = Info;
295212904Sdim    }
296341825Sdim
297321369Sdim    DiagnosticMapping lookupMapping(diag::kind Diag) const {
298321369Sdim      return DiagMap.lookup(Diag);
299321369Sdim    }
300218893Sdim
301276479Sdim    DiagnosticMapping &getOrAddMapping(diag::kind Diag);
302226633Sdim
303226633Sdim    const_iterator begin() const { return DiagMap.begin(); }
304226633Sdim    const_iterator end() const { return DiagMap.end(); }
305212904Sdim  };
306212904Sdim
307341825Sdim  /// Keeps and automatically disposes all DiagStates that we create.
308218893Sdim  std::list<DiagState> DiagStates;
309198092Srdivacky
310321369Sdim  /// A mapping from files to the diagnostic states for those files. Lazily
311321369Sdim  /// built on demand for files in which the diagnostic state has not changed.
312321369Sdim  class DiagStateMap {
313321369Sdim  public:
314321369Sdim    /// Add an initial diagnostic state.
315321369Sdim    void appendFirst(DiagState *State);
316341825Sdim
317321369Sdim    /// Add a new latest state point.
318321369Sdim    void append(SourceManager &SrcMgr, SourceLocation Loc, DiagState *State);
319341825Sdim
320321369Sdim    /// Look up the diagnostic state at a given source location.
321321369Sdim    DiagState *lookup(SourceManager &SrcMgr, SourceLocation Loc) const;
322341825Sdim
323321369Sdim    /// Determine whether this map is empty.
324321369Sdim    bool empty() const { return Files.empty(); }
325341825Sdim
326321369Sdim    /// Clear out this map.
327321369Sdim    void clear() {
328321369Sdim      Files.clear();
329321369Sdim      FirstDiagState = CurDiagState = nullptr;
330321369Sdim      CurDiagStateLoc = SourceLocation();
331218893Sdim    }
332321369Sdim
333341825Sdim    /// Produce a debugging dump of the diagnostic state.
334341825Sdim    LLVM_DUMP_METHOD void dump(SourceManager &SrcMgr,
335341825Sdim                               StringRef DiagName = StringRef()) const;
336341825Sdim
337321369Sdim    /// Grab the most-recently-added state point.
338321369Sdim    DiagState *getCurDiagState() const { return CurDiagState; }
339341825Sdim
340321369Sdim    /// Get the location at which a diagnostic state was last added.
341321369Sdim    SourceLocation getCurDiagStateLoc() const { return CurDiagStateLoc; }
342321369Sdim
343321369Sdim  private:
344341825Sdim    friend class ASTReader;
345341825Sdim    friend class ASTWriter;
346341825Sdim
347341825Sdim    /// Represents a point in source where the diagnostic state was
348321369Sdim    /// modified because of a pragma.
349321369Sdim    ///
350321369Sdim    /// 'Loc' can be null if the point represents the diagnostic state
351321369Sdim    /// modifications done through the command-line.
352321369Sdim    struct DiagStatePoint {
353321369Sdim      DiagState *State;
354321369Sdim      unsigned Offset;
355341825Sdim
356321369Sdim      DiagStatePoint(DiagState *State, unsigned Offset)
357341825Sdim          : State(State), Offset(Offset) {}
358321369Sdim    };
359321369Sdim
360321369Sdim    /// Description of the diagnostic states and state transitions for a
361321369Sdim    /// particular FileID.
362321369Sdim    struct File {
363321369Sdim      /// The diagnostic state for the parent file. This is strictly redundant,
364321369Sdim      /// as looking up the DecomposedIncludedLoc for the FileID in the Files
365321369Sdim      /// map would give us this, but we cache it here for performance.
366321369Sdim      File *Parent = nullptr;
367341825Sdim
368321369Sdim      /// The offset of this file within its parent.
369321369Sdim      unsigned ParentOffset = 0;
370341825Sdim
371321369Sdim      /// Whether this file has any local (not imported from an AST file)
372321369Sdim      /// diagnostic state transitions.
373321369Sdim      bool HasLocalTransitions = false;
374341825Sdim
375321369Sdim      /// The points within the file where the state changes. There will always
376321369Sdim      /// be at least one of these (the state on entry to the file).
377321369Sdim      llvm::SmallVector<DiagStatePoint, 4> StateTransitions;
378321369Sdim
379321369Sdim      DiagState *lookup(unsigned Offset) const;
380321369Sdim    };
381321369Sdim
382321369Sdim    /// The diagnostic states for each file.
383321369Sdim    mutable std::map<FileID, File> Files;
384321369Sdim
385321369Sdim    /// The initial diagnostic state.
386321369Sdim    DiagState *FirstDiagState;
387341825Sdim
388321369Sdim    /// The current diagnostic state.
389321369Sdim    DiagState *CurDiagState;
390341825Sdim
391321369Sdim    /// The location at which the current diagnostic state was established.
392321369Sdim    SourceLocation CurDiagStateLoc;
393321369Sdim
394321369Sdim    /// Get the diagnostic state information for a file.
395321369Sdim    File *getFile(SourceManager &SrcMgr, FileID ID) const;
396218893Sdim  };
397218893Sdim
398321369Sdim  DiagStateMap DiagStatesByLoc;
399218893Sdim
400341825Sdim  /// Keeps the DiagState that was active during each diagnostic 'push'
401218893Sdim  /// so we can get back at it when we 'pop'.
402218893Sdim  std::vector<DiagState *> DiagStateOnPushStack;
403218893Sdim
404218893Sdim  DiagState *GetCurDiagState() const {
405321369Sdim    return DiagStatesByLoc.getCurDiagState();
406218893Sdim  }
407218893Sdim
408321369Sdim  void PushDiagStatePoint(DiagState *State, SourceLocation L);
409218893Sdim
410341825Sdim  /// Finds the DiagStatePoint that contains the diagnostic state of
411218893Sdim  /// the given source location.
412321369Sdim  DiagState *GetDiagStateForLoc(SourceLocation Loc) const {
413321369Sdim    return SourceMgr ? DiagStatesByLoc.lookup(*SourceMgr, Loc)
414321369Sdim                     : DiagStatesByLoc.getCurDiagState();
415321369Sdim  }
416218893Sdim
417341825Sdim  /// Sticky flag set to \c true when an error is emitted.
418193326Sed  bool ErrorOccurred;
419239462Sdim
420341825Sdim  /// Sticky flag set to \c true when an "uncompilable error" occurs.
421249423Sdim  /// I.e. an error that was not upgraded from a warning by -Werror.
422249423Sdim  bool UncompilableErrorOccurred;
423249423Sdim
424341825Sdim  /// Sticky flag set to \c true when a fatal error is emitted.
425193326Sed  bool FatalErrorOccurred;
426198092Srdivacky
427341825Sdim  /// Indicates that an unrecoverable error has occurred.
428224145Sdim  bool UnrecoverableErrorOccurred;
429341825Sdim
430341825Sdim  /// Counts for DiagnosticErrorTrap to check whether an error occurred
431224145Sdim  /// during a parsing section, e.g. during parsing a function.
432226633Sdim  unsigned TrapNumErrorsOccurred;
433226633Sdim  unsigned TrapNumUnrecoverableErrorsOccurred;
434224145Sdim
435341825Sdim  /// The level of the last diagnostic emitted.
436239462Sdim  ///
437239462Sdim  /// This is used to emit continuation diagnostics with the same level as the
438193326Sed  /// diagnostic that they follow.
439218893Sdim  DiagnosticIDs::Level LastDiagLevel;
440193326Sed
441341825Sdim  /// Number of warnings reported
442341825Sdim  unsigned NumWarnings;
443193326Sed
444341825Sdim  /// Number of errors reported
445341825Sdim  unsigned NumErrors;
446341825Sdim
447341825Sdim  /// A function pointer that converts an opaque diagnostic
448239462Sdim  /// argument to a strings.
449198398Srdivacky  ///
450239462Sdim  /// This takes the modifiers and argument that was present in the diagnostic.
451239462Sdim  ///
452276479Sdim  /// The PrevArgs array indicates the previous arguments formatted for this
453276479Sdim  /// diagnostic.  Implementations of this function can use this information to
454276479Sdim  /// avoid redundancy across arguments.
455198398Srdivacky  ///
456193326Sed  /// This is a hack to avoid a layering violation between libbasic and libsema.
457341825Sdim  using ArgToStringFnTy = void (*)(
458224145Sdim      ArgumentKind Kind, intptr_t Val,
459276479Sdim      StringRef Modifier, StringRef Argument,
460276479Sdim      ArrayRef<ArgumentValue> PrevArgs,
461226633Sdim      SmallVectorImpl<char> &Output,
462224145Sdim      void *Cookie,
463234353Sdim      ArrayRef<intptr_t> QualTypeVals);
464341825Sdim
465341825Sdim  void *ArgToStringCookie = nullptr;
466193326Sed  ArgToStringFnTy ArgToStringFn;
467206084Srdivacky
468341825Sdim  /// ID of the "delayed" diagnostic, which is a (typically
469206084Srdivacky  /// fatal) diagnostic that had to be delayed because it was found
470206084Srdivacky  /// while emitting another diagnostic.
471206084Srdivacky  unsigned DelayedDiagID;
472206084Srdivacky
473341825Sdim  /// First string argument for the delayed diagnostic.
474206084Srdivacky  std::string DelayedDiagArg1;
475206084Srdivacky
476341825Sdim  /// Second string argument for the delayed diagnostic.
477206084Srdivacky  std::string DelayedDiagArg2;
478206084Srdivacky
479360784Sdim  /// Third string argument for the delayed diagnostic.
480360784Sdim  std::string DelayedDiagArg3;
481360784Sdim
482341825Sdim  /// Optional flag value.
483276479Sdim  ///
484276479Sdim  /// Some flags accept values, for instance: -Wframe-larger-than=<value> and
485276479Sdim  /// -Rpass=<value>. The content of this string is emitted after the flag name
486276479Sdim  /// and '='.
487276479Sdim  std::string FlagValue;
488276479Sdim
489193326Sedpublic:
490314564Sdim  explicit DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> Diags,
491341825Sdim                             IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
492314564Sdim                             DiagnosticConsumer *client = nullptr,
493314564Sdim                             bool ShouldOwnClient = true);
494314564Sdim  DiagnosticsEngine(const DiagnosticsEngine &) = delete;
495314564Sdim  DiagnosticsEngine &operator=(const DiagnosticsEngine &) = delete;
496226633Sdim  ~DiagnosticsEngine();
497198092Srdivacky
498344779Sdim  LLVM_DUMP_METHOD void dump() const;
499344779Sdim  LLVM_DUMP_METHOD void dump(StringRef DiagName) const;
500341825Sdim
501234353Sdim  const IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const {
502218893Sdim    return Diags;
503218893Sdim  }
504218893Sdim
505341825Sdim  /// Retrieve the diagnostic options.
506243830Sdim  DiagnosticOptions &getDiagnosticOptions() const { return *DiagOpts; }
507243830Sdim
508341825Sdim  using diag_mapping_range = llvm::iterator_range<DiagState::const_iterator>;
509276479Sdim
510341825Sdim  /// Get the current set of diagnostic mappings.
511276479Sdim  diag_mapping_range getDiagnosticMappings() const {
512276479Sdim    const DiagState &DS = *GetCurDiagState();
513276479Sdim    return diag_mapping_range(DS.begin(), DS.end());
514276479Sdim  }
515276479Sdim
516226633Sdim  DiagnosticConsumer *getClient() { return Client; }
517226633Sdim  const DiagnosticConsumer *getClient() const { return Client; }
518218893Sdim
519341825Sdim  /// Determine whether this \c DiagnosticsEngine object own its client.
520280031Sdim  bool ownsClient() const { return Owner != nullptr; }
521280031Sdim
522341825Sdim  /// Return the current diagnostic client along with ownership of that
523218893Sdim  /// client.
524280031Sdim  std::unique_ptr<DiagnosticConsumer> takeClient() { return std::move(Owner); }
525218893Sdim
526276479Sdim  bool hasSourceManager() const { return SourceMgr != nullptr; }
527341825Sdim
528218893Sdim  SourceManager &getSourceManager() const {
529218893Sdim    assert(SourceMgr && "SourceManager not set!");
530218893Sdim    return *SourceMgr;
531218893Sdim  }
532341825Sdim
533321369Sdim  void setSourceManager(SourceManager *SrcMgr) {
534321369Sdim    assert(DiagStatesByLoc.empty() &&
535321369Sdim           "Leftover diag state from a different SourceManager.");
536321369Sdim    SourceMgr = SrcMgr;
537321369Sdim  }
538218893Sdim
539193326Sed  //===--------------------------------------------------------------------===//
540226633Sdim  //  DiagnosticsEngine characterization methods, used by a client to customize
541226633Sdim  //  how diagnostics are emitted.
542193326Sed  //
543198092Srdivacky
544341825Sdim  /// Copies the current DiagMappings and pushes the new copy
545198092Srdivacky  /// onto the top of the stack.
546218893Sdim  void pushMappings(SourceLocation Loc);
547198092Srdivacky
548341825Sdim  /// Pops the current DiagMappings off the top of the stack,
549239462Sdim  /// causing the new top of the stack to be the active mappings.
550239462Sdim  ///
551239462Sdim  /// \returns \c true if the pop happens, \c false if there is only one
552239462Sdim  /// DiagMapping on the stack.
553218893Sdim  bool popMappings(SourceLocation Loc);
554198092Srdivacky
555341825Sdim  /// Set the diagnostic client associated with this diagnostic object.
556212904Sdim  ///
557218893Sdim  /// \param ShouldOwnClient true if the diagnostic object should take
558218893Sdim  /// ownership of \c client.
559226633Sdim  void setClient(DiagnosticConsumer *client, bool ShouldOwnClient = true);
560193326Sed
561341825Sdim  /// Specify a limit for the number of errors we should
562239462Sdim  /// emit before giving up.
563239462Sdim  ///
564239462Sdim  /// Zero disables the limit.
565207619Srdivacky  void setErrorLimit(unsigned Limit) { ErrorLimit = Limit; }
566341825Sdim
567341825Sdim  /// Specify the maximum number of template instantiation
568207619Srdivacky  /// notes to emit along with a given diagnostic.
569207619Srdivacky  void setTemplateBacktraceLimit(unsigned Limit) {
570207619Srdivacky    TemplateBacktraceLimit = Limit;
571207619Srdivacky  }
572234353Sdim
573341825Sdim  /// Retrieve the maximum number of template instantiation
574234353Sdim  /// notes to emit along with a given diagnostic.
575207619Srdivacky  unsigned getTemplateBacktraceLimit() const {
576207619Srdivacky    return TemplateBacktraceLimit;
577207619Srdivacky  }
578234353Sdim
579341825Sdim  /// Specify the maximum number of constexpr evaluation
580234353Sdim  /// notes to emit along with a given diagnostic.
581234353Sdim  void setConstexprBacktraceLimit(unsigned Limit) {
582234353Sdim    ConstexprBacktraceLimit = Limit;
583234353Sdim  }
584234353Sdim
585341825Sdim  /// Retrieve the maximum number of constexpr evaluation
586234353Sdim  /// notes to emit along with a given diagnostic.
587234353Sdim  unsigned getConstexprBacktraceLimit() const {
588234353Sdim    return ConstexprBacktraceLimit;
589234353Sdim  }
590234353Sdim
591341825Sdim  /// When set to true, any unmapped warnings are ignored.
592239462Sdim  ///
593239462Sdim  /// If this and WarningsAsErrors are both set, then this one wins.
594321369Sdim  void setIgnoreAllWarnings(bool Val) {
595321369Sdim    GetCurDiagState()->IgnoreAllWarnings = Val;
596321369Sdim  }
597321369Sdim  bool getIgnoreAllWarnings() const {
598321369Sdim    return GetCurDiagState()->IgnoreAllWarnings;
599321369Sdim  }
600198092Srdivacky
601341825Sdim  /// When set to true, any unmapped ignored warnings are no longer
602239462Sdim  /// ignored.
603239462Sdim  ///
604239462Sdim  /// If this and IgnoreAllWarnings are both set, then that one wins.
605321369Sdim  void setEnableAllWarnings(bool Val) {
606321369Sdim    GetCurDiagState()->EnableAllWarnings = Val;
607321369Sdim  }
608321369Sdim  bool getEnableAllWarnings() const {
609321369Sdim    return GetCurDiagState()->EnableAllWarnings;
610321369Sdim  }
611249423Sdim
612341825Sdim  /// When set to true, any warnings reported are issued as errors.
613321369Sdim  void setWarningsAsErrors(bool Val) {
614321369Sdim    GetCurDiagState()->WarningsAsErrors = Val;
615321369Sdim  }
616321369Sdim  bool getWarningsAsErrors() const {
617321369Sdim    return GetCurDiagState()->WarningsAsErrors;
618321369Sdim  }
619198092Srdivacky
620341825Sdim  /// When set to true, any error reported is made a fatal error.
621321369Sdim  void setErrorsAsFatal(bool Val) { GetCurDiagState()->ErrorsAsFatal = Val; }
622321369Sdim  bool getErrorsAsFatal() const { return GetCurDiagState()->ErrorsAsFatal; }
623201361Srdivacky
624353358Sdim  /// \brief When set to true, any fatal error reported is made an error.
625353358Sdim  ///
626353358Sdim  /// This setting takes precedence over the setErrorsAsFatal setting above.
627353358Sdim  void setFatalsAsError(bool Val) { FatalsAsError = Val; }
628353358Sdim  bool getFatalsAsError() const { return FatalsAsError; }
629309124Sdim
630341825Sdim  /// When set to true mask warnings that come from system headers.
631321369Sdim  void setSuppressSystemWarnings(bool Val) {
632321369Sdim    GetCurDiagState()->SuppressSystemWarnings = Val;
633321369Sdim  }
634321369Sdim  bool getSuppressSystemWarnings() const {
635321369Sdim    return GetCurDiagState()->SuppressSystemWarnings;
636321369Sdim  }
637193326Sed
638341825Sdim  /// Suppress all diagnostics, to silence the front end when we
639198092Srdivacky  /// know that we don't want any more diagnostics to be passed along to the
640198092Srdivacky  /// client
641360784Sdim  void setSuppressAllDiagnostics(bool Val) { SuppressAllDiagnostics = Val; }
642198092Srdivacky  bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; }
643239462Sdim
644341825Sdim  /// Set type eliding, to skip outputting same types occurring in
645239462Sdim  /// template types.
646360784Sdim  void setElideType(bool Val) { ElideType = Val; }
647239462Sdim  bool getElideType() { return ElideType; }
648341825Sdim
649341825Sdim  /// Set tree printing, to outputting the template difference in a
650239462Sdim  /// tree format.
651360784Sdim  void setPrintTemplateTree(bool Val) { PrintTemplateTree = Val; }
652239462Sdim  bool getPrintTemplateTree() { return PrintTemplateTree; }
653341825Sdim
654341825Sdim  /// Set color printing, so the type diffing will inject color markers
655239462Sdim  /// into the output.
656360784Sdim  void setShowColors(bool Val) { ShowColors = Val; }
657239462Sdim  bool getShowColors() { return ShowColors; }
658239462Sdim
659341825Sdim  /// Specify which overload candidates to show when overload resolution
660239462Sdim  /// fails.
661239462Sdim  ///
662239462Sdim  /// By default, we show all candidates.
663210299Sed  void setShowOverloads(OverloadsShown Val) {
664210299Sed    ShowOverloads = Val;
665210299Sed  }
666210299Sed  OverloadsShown getShowOverloads() const { return ShowOverloads; }
667341825Sdim
668341825Sdim  /// Pretend that the last diagnostic issued was ignored, so any
669327952Sdim  /// subsequent notes will be suppressed, or restore a prior ignoring
670327952Sdim  /// state after ignoring some diagnostics and their notes, possibly in
671327952Sdim  /// the middle of another diagnostic.
672239462Sdim  ///
673239462Sdim  /// This can be used by clients who suppress diagnostics themselves.
674360784Sdim  void setLastDiagnosticIgnored(bool Ignored) {
675243830Sdim    if (LastDiagLevel == DiagnosticIDs::Fatal)
676243830Sdim      FatalErrorOccurred = true;
677327952Sdim    LastDiagLevel = Ignored ? DiagnosticIDs::Ignored : DiagnosticIDs::Warning;
678198092Srdivacky  }
679261991Sdim
680341825Sdim  /// Determine whether the previous diagnostic was ignored. This can
681261991Sdim  /// be used by clients that want to determine whether notes attached to a
682261991Sdim  /// diagnostic will be suppressed.
683261991Sdim  bool isLastDiagnosticIgnored() const {
684261991Sdim    return LastDiagLevel == DiagnosticIDs::Ignored;
685261991Sdim  }
686261991Sdim
687341825Sdim  /// Controls whether otherwise-unmapped extension diagnostics are
688321369Sdim  /// mapped onto ignore/warning/error.
689239462Sdim  ///
690239462Sdim  /// This corresponds to the GCC -pedantic and -pedantic-errors option.
691321369Sdim  void setExtensionHandlingBehavior(diag::Severity H) {
692321369Sdim    GetCurDiagState()->ExtBehavior = H;
693321369Sdim  }
694321369Sdim  diag::Severity getExtensionHandlingBehavior() const {
695321369Sdim    return GetCurDiagState()->ExtBehavior;
696321369Sdim  }
697198092Srdivacky
698341825Sdim  /// Counter bumped when an __extension__  block is/ encountered.
699239462Sdim  ///
700239462Sdim  /// When non-zero, all extension diagnostics are entirely silenced, no
701239462Sdim  /// matter how they are mapped.
702193326Sed  void IncrementAllExtensionsSilenced() { ++AllExtensionsSilenced; }
703193326Sed  void DecrementAllExtensionsSilenced() { --AllExtensionsSilenced; }
704198092Srdivacky  bool hasAllExtensionsSilenced() { return AllExtensionsSilenced != 0; }
705198092Srdivacky
706341825Sdim  /// This allows the client to specify that certain warnings are
707239462Sdim  /// ignored.
708218893Sdim  ///
709239462Sdim  /// Notes can never be mapped, errors can only be mapped to fatal, and
710239462Sdim  /// WARNINGs and EXTENSIONs can be mapped arbitrarily.
711239462Sdim  ///
712218893Sdim  /// \param Loc The source location that this change of diagnostic state should
713218893Sdim  /// take affect. It can be null if we are setting the latest state.
714276479Sdim  void setSeverity(diag::kind Diag, diag::Severity Map, SourceLocation Loc);
715198092Srdivacky
716341825Sdim  /// Change an entire diagnostic group (e.g. "unknown-pragmas") to
717239462Sdim  /// have the specified mapping.
718218893Sdim  ///
719239462Sdim  /// \returns true (and ignores the request) if "Group" was unknown, false
720239462Sdim  /// otherwise.
721239462Sdim  ///
722276479Sdim  /// \param Flavor The flavor of group to affect. -Rfoo does not affect the
723276479Sdim  /// state of the -Wfoo group and vice versa.
724276479Sdim  ///
725239462Sdim  /// \param Loc The source location that this change of diagnostic state should
726218893Sdim  /// take affect. It can be null if we are setting the state from command-line.
727276479Sdim  bool setSeverityForGroup(diag::Flavor Flavor, StringRef Group,
728276479Sdim                           diag::Severity Map,
729276479Sdim                           SourceLocation Loc = SourceLocation());
730193326Sed
731341825Sdim  /// Set the warning-as-error flag for the given diagnostic group.
732226633Sdim  ///
733239462Sdim  /// This function always only operates on the current diagnostic state.
734239462Sdim  ///
735226633Sdim  /// \returns True if the given group is unknown, false otherwise.
736226633Sdim  bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled);
737226633Sdim
738341825Sdim  /// Set the error-as-fatal flag for the given diagnostic group.
739226633Sdim  ///
740239462Sdim  /// This function always only operates on the current diagnostic state.
741239462Sdim  ///
742226633Sdim  /// \returns True if the given group is unknown, false otherwise.
743226633Sdim  bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled);
744226633Sdim
745341825Sdim  /// Add the specified mapping to all diagnostics of the specified
746276479Sdim  /// flavor.
747239462Sdim  ///
748239462Sdim  /// Mainly to be used by -Wno-everything to disable all warnings but allow
749239462Sdim  /// subsequent -W options to enable specific warnings.
750276479Sdim  void setSeverityForAll(diag::Flavor Flavor, diag::Severity Map,
751276479Sdim                         SourceLocation Loc = SourceLocation());
752234353Sdim
753193326Sed  bool hasErrorOccurred() const { return ErrorOccurred; }
754249423Sdim
755341825Sdim  /// Errors that actually prevent compilation, not those that are
756249423Sdim  /// upgraded from a warning by -Werror.
757249423Sdim  bool hasUncompilableErrorOccurred() const {
758249423Sdim    return UncompilableErrorOccurred;
759249423Sdim  }
760193326Sed  bool hasFatalErrorOccurred() const { return FatalErrorOccurred; }
761341825Sdim
762341825Sdim  /// Determine whether any kind of unrecoverable error has occurred.
763224145Sdim  bool hasUnrecoverableErrorOccurred() const {
764224145Sdim    return FatalErrorOccurred || UnrecoverableErrorOccurred;
765224145Sdim  }
766341825Sdim
767207619Srdivacky  unsigned getNumWarnings() const { return NumWarnings; }
768198092Srdivacky
769212904Sdim  void setNumWarnings(unsigned NumWarnings) {
770212904Sdim    this->NumWarnings = NumWarnings;
771212904Sdim  }
772212904Sdim
773341825Sdim  /// Return an ID for a diagnostic with the specified format string and
774276479Sdim  /// level.
775239462Sdim  ///
776249423Sdim  /// If this is the first request for this diagnostic, it is registered and
777239462Sdim  /// created, otherwise the existing ID is returned.
778276479Sdim  ///
779276479Sdim  /// \param FormatString A fixed diagnostic format string that will be hashed
780276479Sdim  /// and mapped to a unique DiagID.
781276479Sdim  template <unsigned N>
782276479Sdim  unsigned getCustomDiagID(Level L, const char (&FormatString)[N]) {
783276479Sdim    return Diags->getCustomDiagID((DiagnosticIDs::Level)L,
784276479Sdim                                  StringRef(FormatString, N - 1));
785218893Sdim  }
786198092Srdivacky
787341825Sdim  /// Converts a diagnostic argument (as an intptr_t) into the string
788239462Sdim  /// that represents it.
789193326Sed  void ConvertArgToString(ArgumentKind Kind, intptr_t Val,
790276479Sdim                          StringRef Modifier, StringRef Argument,
791276479Sdim                          ArrayRef<ArgumentValue> PrevArgs,
792226633Sdim                          SmallVectorImpl<char> &Output,
793243830Sdim                          ArrayRef<intptr_t> QualTypeVals) const {
794276479Sdim    ArgToStringFn(Kind, Val, Modifier, Argument, PrevArgs, Output,
795276479Sdim                  ArgToStringCookie, QualTypeVals);
796193326Sed  }
797198092Srdivacky
798193326Sed  void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) {
799193326Sed    ArgToStringFn = Fn;
800193326Sed    ArgToStringCookie = Cookie;
801193326Sed  }
802198092Srdivacky
803341825Sdim  /// Note that the prior diagnostic was emitted by some other
804249423Sdim  /// \c DiagnosticsEngine, and we may be attaching a note to that diagnostic.
805249423Sdim  void notePriorDiagnosticFrom(const DiagnosticsEngine &Other) {
806249423Sdim    LastDiagLevel = Other.LastDiagLevel;
807249423Sdim  }
808249423Sdim
809341825Sdim  /// Reset the state of the diagnostic object to its initial
810212904Sdim  /// configuration.
811212904Sdim  void Reset();
812341825Sdim
813193326Sed  //===--------------------------------------------------------------------===//
814226633Sdim  // DiagnosticsEngine classification and reporting interfaces.
815193326Sed  //
816193326Sed
817341825Sdim  /// Determine whether the diagnostic is known to be ignored.
818276479Sdim  ///
819276479Sdim  /// This can be used to opportunistically avoid expensive checks when it's
820276479Sdim  /// known for certain that the diagnostic has been suppressed at the
821276479Sdim  /// specified location \p Loc.
822276479Sdim  ///
823276479Sdim  /// \param Loc The source location we are interested in finding out the
824276479Sdim  /// diagnostic state. Can be null in order to query the latest state.
825276479Sdim  bool isIgnored(unsigned DiagID, SourceLocation Loc) const {
826276479Sdim    return Diags->getDiagnosticSeverity(DiagID, Loc, *this) ==
827276479Sdim           diag::Severity::Ignored;
828276479Sdim  }
829276479Sdim
830341825Sdim  /// Based on the way the client configured the DiagnosticsEngine
831218893Sdim  /// object, classify the specified diagnostic ID into a Level, consumable by
832226633Sdim  /// the DiagnosticConsumer.
833193326Sed  ///
834276479Sdim  /// To preserve invariant assumptions, this function should not be used to
835276479Sdim  /// influence parse or semantic analysis actions. Instead consider using
836276479Sdim  /// \c isIgnored().
837276479Sdim  ///
838218893Sdim  /// \param Loc The source location we are interested in finding out the
839218893Sdim  /// diagnostic state. Can be null in order to query the latest state.
840226633Sdim  Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const {
841226633Sdim    return (Level)Diags->getDiagnosticLevel(DiagID, Loc, *this);
842207619Srdivacky  }
843198092Srdivacky
844341825Sdim  /// Issue the message to the client.
845239462Sdim  ///
846239462Sdim  /// This actually returns an instance of DiagnosticBuilder which emits the
847239462Sdim  /// diagnostics (through @c ProcessDiag) when it is destroyed.
848239462Sdim  ///
849239462Sdim  /// \param DiagID A member of the @c diag::kind enum.
850239462Sdim  /// \param Loc Represents the source location associated with the diagnostic,
851193326Sed  /// which can be an invalid location if no position information is available.
852239462Sdim  inline DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID);
853199482Srdivacky  inline DiagnosticBuilder Report(unsigned DiagID);
854193326Sed
855223017Sdim  void Report(const StoredDiagnostic &storedDiag);
856223017Sdim
857341825Sdim  /// Determine whethere there is already a diagnostic in flight.
858341825Sdim  bool isDiagnosticInFlight() const {
859341825Sdim    return CurDiagID != std::numeric_limits<unsigned>::max();
860341825Sdim  }
861206084Srdivacky
862341825Sdim  /// Set the "delayed" diagnostic that will be emitted once
863206084Srdivacky  /// the current diagnostic completes.
864206084Srdivacky  ///
865206084Srdivacky  ///  If a diagnostic is already in-flight but the front end must
866206084Srdivacky  ///  report a problem (e.g., with an inconsistent file system
867206084Srdivacky  ///  state), this routine sets a "delayed" diagnostic that will be
868206084Srdivacky  ///  emitted after the current diagnostic completes. This should
869206084Srdivacky  ///  only be used for fatal errors detected at inconvenient
870206084Srdivacky  ///  times. If emitting a delayed diagnostic causes a second delayed
871206084Srdivacky  ///  diagnostic to be introduced, that second delayed diagnostic
872206084Srdivacky  ///  will be ignored.
873206084Srdivacky  ///
874206084Srdivacky  /// \param DiagID The ID of the diagnostic being delayed.
875206084Srdivacky  ///
876206084Srdivacky  /// \param Arg1 A string argument that will be provided to the
877206084Srdivacky  /// diagnostic. A copy of this string will be stored in the
878226633Sdim  /// DiagnosticsEngine object itself.
879206084Srdivacky  ///
880206084Srdivacky  /// \param Arg2 A string argument that will be provided to the
881206084Srdivacky  /// diagnostic. A copy of this string will be stored in the
882226633Sdim  /// DiagnosticsEngine object itself.
883360784Sdim  ///
884360784Sdim  /// \param Arg3 A string argument that will be provided to the
885360784Sdim  /// diagnostic. A copy of this string will be stored in the
886360784Sdim  /// DiagnosticsEngine object itself.
887226633Sdim  void SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1 = "",
888360784Sdim                            StringRef Arg2 = "", StringRef Arg3 = "");
889198092Srdivacky
890341825Sdim  /// Clear out the current diagnostic.
891341825Sdim  void Clear() { CurDiagID = std::numeric_limits<unsigned>::max(); }
892341825Sdim
893341825Sdim  /// Return the value associated with this diagnostic flag.
894276479Sdim  StringRef getFlagValue() const { return FlagValue; }
895276479Sdim
896193326Sedprivate:
897193326Sed  // This is private state used by DiagnosticBuilder.  We put it here instead of
898193326Sed  // in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight
899193326Sed  // object.  This implementation choice means that we can only have one
900193326Sed  // diagnostic "in flight" at a time, but this seems to be a reasonable
901193326Sed  // tradeoff to keep these objects small.  Assertions verify that only one
902193326Sed  // diagnostic is in flight at a time.
903341825Sdim  friend class Diagnostic;
904341825Sdim  friend class DiagnosticBuilder;
905341825Sdim  friend class DiagnosticErrorTrap;
906218893Sdim  friend class DiagnosticIDs;
907218893Sdim  friend class PartialDiagnostic;
908341825Sdim
909341825Sdim  /// Report the delayed diagnostic.
910341825Sdim  void ReportDelayed();
911341825Sdim
912341825Sdim  /// The location of the current diagnostic that is in flight.
913218893Sdim  SourceLocation CurDiagLoc;
914198092Srdivacky
915341825Sdim  /// The ID of the current diagnostic that is in flight.
916239462Sdim  ///
917341825Sdim  /// This is set to std::numeric_limits<unsigned>::max() when there is no
918341825Sdim  /// diagnostic in flight.
919193326Sed  unsigned CurDiagID;
920193326Sed
921193326Sed  enum {
922341825Sdim    /// The maximum number of arguments we can hold.
923239462Sdim    ///
924239462Sdim    /// We currently only support up to 10 arguments (%0-%9).  A single
925239462Sdim    /// diagnostic with more than that almost certainly has to be simplified
926239462Sdim    /// anyway.
927234353Sdim    MaxArguments = 10,
928193326Sed  };
929198092Srdivacky
930341825Sdim  /// The number of entries in Arguments.
931193326Sed  signed char NumDiagArgs;
932193326Sed
933341825Sdim  /// Specifies whether an argument is in DiagArgumentsStr or
934239462Sdim  /// in DiagArguments.
935239462Sdim  ///
936239462Sdim  /// This is an array of ArgumentKind::ArgumentKind enum values, one for each
937239462Sdim  /// argument.
938193326Sed  unsigned char DiagArgumentsKind[MaxArguments];
939198092Srdivacky
940341825Sdim  /// Holds the values of each string argument for the current
941239462Sdim  /// diagnostic.
942239462Sdim  ///
943239462Sdim  /// This is only used when the corresponding ArgumentKind is ak_std_string.
944193326Sed  std::string DiagArgumentsStr[MaxArguments];
945193326Sed
946341825Sdim  /// The values for the various substitution positions.
947239462Sdim  ///
948239462Sdim  /// This is used when the argument is not an std::string.  The specific
949239462Sdim  /// value is mangled into an intptr_t and the interpretation depends on
950239462Sdim  /// exactly what sort of argument kind it is.
951193326Sed  intptr_t DiagArgumentsVal[MaxArguments];
952198092Srdivacky
953341825Sdim  /// The list of ranges added to this diagnostic.
954276479Sdim  SmallVector<CharSourceRange, 8> DiagRanges;
955198092Srdivacky
956341825Sdim  /// If valid, provides a hint with some code to insert, remove,
957234353Sdim  /// or modify at a particular position.
958276479Sdim  SmallVector<FixItHint, 8> DiagFixItHints;
959193326Sed
960276479Sdim  DiagnosticMapping makeUserMapping(diag::Severity Map, SourceLocation L) {
961234353Sdim    bool isPragma = L.isValid();
962276479Sdim    DiagnosticMapping Mapping =
963276479Sdim        DiagnosticMapping::Make(Map, /*IsUser=*/true, isPragma);
964193326Sed
965234353Sdim    // If this is a pragma mapping, then set the diagnostic mapping flags so
966234353Sdim    // that we override command line options.
967234353Sdim    if (isPragma) {
968276479Sdim      Mapping.setNoWarningAsError(true);
969276479Sdim      Mapping.setNoErrorAsFatal(true);
970234353Sdim    }
971234353Sdim
972276479Sdim    return Mapping;
973234353Sdim  }
974234353Sdim
975341825Sdim  /// Used to report a diagnostic that is finally fully formed.
976194179Sed  ///
977239462Sdim  /// \returns true if the diagnostic was emitted, false if it was suppressed.
978218893Sdim  bool ProcessDiag() {
979218893Sdim    return Diags->ProcessDiag(*this);
980218893Sdim  }
981218893Sdim
982234353Sdim  /// @name Diagnostic Emission
983234353Sdim  /// @{
984234353Sdimprotected:
985341825Sdim  friend class ASTReader;
986341825Sdim  friend class ASTWriter;
987341825Sdim
988234353Sdim  // Sema requires access to the following functions because the current design
989234353Sdim  // of SFINAE requires it to use its own SemaDiagnosticBuilder, which needs to
990234353Sdim  // access us directly to ensure we minimize the emitted code for the common
991234353Sdim  // Sema::Diag() patterns.
992234353Sdim  friend class Sema;
993234353Sdim
994341825Sdim  /// Emit the current diagnostic and clear the diagnostic state.
995239462Sdim  ///
996239462Sdim  /// \param Force Emit the diagnostic regardless of suppression settings.
997239462Sdim  bool EmitCurrentDiagnostic(bool Force = false);
998234353Sdim
999234353Sdim  unsigned getCurrentDiagID() const { return CurDiagID; }
1000234353Sdim
1001234353Sdim  SourceLocation getCurrentDiagLoc() const { return CurDiagLoc; }
1002234353Sdim
1003234353Sdim  /// @}
1004193326Sed};
1005193326Sed
1006341825Sdim/// RAII class that determines when any errors have occurred
1007218893Sdim/// between the time the instance was created and the time it was
1008218893Sdim/// queried.
1009218893Sdimclass DiagnosticErrorTrap {
1010226633Sdim  DiagnosticsEngine &Diag;
1011226633Sdim  unsigned NumErrors;
1012226633Sdim  unsigned NumUnrecoverableErrors;
1013218893Sdim
1014218893Sdimpublic:
1015226633Sdim  explicit DiagnosticErrorTrap(DiagnosticsEngine &Diag)
1016341825Sdim      : Diag(Diag) { reset(); }
1017218893Sdim
1018341825Sdim  /// Determine whether any errors have occurred since this
1019218893Sdim  /// object instance was created.
1020218893Sdim  bool hasErrorOccurred() const {
1021226633Sdim    return Diag.TrapNumErrorsOccurred > NumErrors;
1022218893Sdim  }
1023218893Sdim
1024341825Sdim  /// Determine whether any unrecoverable errors have occurred since this
1025224145Sdim  /// object instance was created.
1026224145Sdim  bool hasUnrecoverableErrorOccurred() const {
1027226633Sdim    return Diag.TrapNumUnrecoverableErrorsOccurred > NumUnrecoverableErrors;
1028224145Sdim  }
1029224145Sdim
1030341825Sdim  /// Set to initial state of "no errors occurred".
1031224145Sdim  void reset() {
1032226633Sdim    NumErrors = Diag.TrapNumErrorsOccurred;
1033226633Sdim    NumUnrecoverableErrors = Diag.TrapNumUnrecoverableErrorsOccurred;
1034224145Sdim  }
1035218893Sdim};
1036218893Sdim
1037193326Sed//===----------------------------------------------------------------------===//
1038193326Sed// DiagnosticBuilder
1039193326Sed//===----------------------------------------------------------------------===//
1040193326Sed
1041341825Sdim/// A little helper class used to produce diagnostics.
1042193326Sed///
1043239462Sdim/// This is constructed by the DiagnosticsEngine::Report method, and
1044239462Sdim/// allows insertion of extra information (arguments and source ranges) into
1045239462Sdim/// the currently "in flight" diagnostic.  When the temporary for the builder
1046239462Sdim/// is destroyed, the diagnostic is issued.
1047239462Sdim///
1048193326Sed/// Note that many of these will be created as temporary objects (many call
1049193326Sed/// sites), so we want them to be small and we never want their address taken.
1050193326Sed/// This ensures that compilers with somewhat reasonable optimizers will promote
1051193326Sed/// the common fields to registers, eliminating increments of the NumArgs field,
1052193326Sed/// for example.
1053193326Sedclass DiagnosticBuilder {
1054341825Sdim  friend class DiagnosticsEngine;
1055341825Sdim  friend class PartialDiagnostic;
1056341825Sdim
1057296417Sdim  mutable DiagnosticsEngine *DiagObj = nullptr;
1058296417Sdim  mutable unsigned NumArgs = 0;
1059198092Srdivacky
1060341825Sdim  /// Status variable indicating if this diagnostic is still active.
1061234353Sdim  ///
1062234353Sdim  // NOTE: This field is redundant with DiagObj (IsActive iff (DiagObj == 0)),
1063234353Sdim  // but LLVM is not currently smart enough to eliminate the null check that
1064234353Sdim  // Emit() would end up with if we used that as our status variable.
1065296417Sdim  mutable bool IsActive = false;
1066234353Sdim
1067341825Sdim  /// Flag indicating that this diagnostic is being emitted via a
1068239462Sdim  /// call to ForceEmit.
1069296417Sdim  mutable bool IsForceEmit = false;
1070239462Sdim
1071296417Sdim  DiagnosticBuilder() = default;
1072239462Sdim
1073226633Sdim  explicit DiagnosticBuilder(DiagnosticsEngine *diagObj)
1074296417Sdim      : DiagObj(diagObj), IsActive(true) {
1075234353Sdim    assert(diagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!");
1076276479Sdim    diagObj->DiagRanges.clear();
1077276479Sdim    diagObj->DiagFixItHints.clear();
1078234353Sdim  }
1079193326Sed
1080218893Sdimprotected:
1081234353Sdim  void FlushCounts() {
1082234353Sdim    DiagObj->NumDiagArgs = NumArgs;
1083193326Sed  }
1084193326Sed
1085341825Sdim  /// Clear out the current diagnostic.
1086234353Sdim  void Clear() const {
1087276479Sdim    DiagObj = nullptr;
1088234353Sdim    IsActive = false;
1089239462Sdim    IsForceEmit = false;
1090234353Sdim  }
1091194179Sed
1092341825Sdim  /// Determine whether this diagnostic is still active.
1093234353Sdim  bool isActive() const { return IsActive; }
1094194179Sed
1095341825Sdim  /// Force the diagnostic builder to emit the diagnostic now.
1096193326Sed  ///
1097193326Sed  /// Once this function has been called, the DiagnosticBuilder object
1098193326Sed  /// should not be used again before it is destroyed.
1099194179Sed  ///
1100194179Sed  /// \returns true if a diagnostic was emitted, false if the
1101194179Sed  /// diagnostic was suppressed.
1102234353Sdim  bool Emit() {
1103234353Sdim    // If this diagnostic is inactive, then its soul was stolen by the copy ctor
1104234353Sdim    // (or by a subclass, as in SemaDiagnosticBuilder).
1105234353Sdim    if (!isActive()) return false;
1106193326Sed
1107234353Sdim    // When emitting diagnostics, we set the final argument count into
1108234353Sdim    // the DiagnosticsEngine object.
1109234353Sdim    FlushCounts();
1110198092Srdivacky
1111234353Sdim    // Process the diagnostic.
1112239462Sdim    bool Result = DiagObj->EmitCurrentDiagnostic(IsForceEmit);
1113203955Srdivacky
1114234353Sdim    // This diagnostic is dead.
1115234353Sdim    Clear();
1116234353Sdim
1117234353Sdim    return Result;
1118218893Sdim  }
1119341825Sdim
1120234353Sdimpublic:
1121234353Sdim  /// Copy constructor.  When copied, this "takes" the diagnostic info from the
1122234353Sdim  /// input and neuters it.
1123234353Sdim  DiagnosticBuilder(const DiagnosticBuilder &D) {
1124234353Sdim    DiagObj = D.DiagObj;
1125234353Sdim    IsActive = D.IsActive;
1126239462Sdim    IsForceEmit = D.IsForceEmit;
1127234353Sdim    D.Clear();
1128234353Sdim    NumArgs = D.NumArgs;
1129234353Sdim  }
1130234353Sdim
1131314564Sdim  DiagnosticBuilder &operator=(const DiagnosticBuilder &) = delete;
1132314564Sdim
1133341825Sdim  /// Emits the diagnostic.
1134314564Sdim  ~DiagnosticBuilder() {
1135314564Sdim    Emit();
1136314564Sdim  }
1137314564Sdim
1138341825Sdim  /// Forces the diagnostic to be emitted.
1139239462Sdim  const DiagnosticBuilder &setForceEmit() const {
1140239462Sdim    IsForceEmit = true;
1141239462Sdim    return *this;
1142239462Sdim  }
1143239462Sdim
1144341825Sdim  /// Conversion of DiagnosticBuilder to bool always returns \c true.
1145239462Sdim  ///
1146239462Sdim  /// This allows is to be used in boolean error contexts (where \c true is
1147239462Sdim  /// used to indicate that an error has occurred), like:
1148239462Sdim  /// \code
1149193326Sed  /// return Diag(...);
1150239462Sdim  /// \endcode
1151193326Sed  operator bool() const { return true; }
1152193326Sed
1153226633Sdim  void AddString(StringRef S) const {
1154234353Sdim    assert(isActive() && "Clients must not add to cleared diagnostic!");
1155226633Sdim    assert(NumArgs < DiagnosticsEngine::MaxArguments &&
1156193326Sed           "Too many arguments to diagnostic!");
1157234353Sdim    DiagObj->DiagArgumentsKind[NumArgs] = DiagnosticsEngine::ak_std_string;
1158234353Sdim    DiagObj->DiagArgumentsStr[NumArgs++] = S;
1159193326Sed  }
1160198092Srdivacky
1161226633Sdim  void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const {
1162234353Sdim    assert(isActive() && "Clients must not add to cleared diagnostic!");
1163226633Sdim    assert(NumArgs < DiagnosticsEngine::MaxArguments &&
1164193326Sed           "Too many arguments to diagnostic!");
1165234353Sdim    DiagObj->DiagArgumentsKind[NumArgs] = Kind;
1166234353Sdim    DiagObj->DiagArgumentsVal[NumArgs++] = V;
1167193326Sed  }
1168198092Srdivacky
1169210299Sed  void AddSourceRange(const CharSourceRange &R) const {
1170234353Sdim    assert(isActive() && "Clients must not add to cleared diagnostic!");
1171276479Sdim    DiagObj->DiagRanges.push_back(R);
1172198092Srdivacky  }
1173193326Sed
1174206084Srdivacky  void AddFixItHint(const FixItHint &Hint) const {
1175234353Sdim    assert(isActive() && "Clients must not add to cleared diagnostic!");
1176288943Sdim    if (!Hint.isNull())
1177288943Sdim      DiagObj->DiagFixItHints.push_back(Hint);
1178193326Sed  }
1179243830Sdim
1180276479Sdim  void addFlagValue(StringRef V) const { DiagObj->FlagValue = V; }
1181276479Sdim};
1182261991Sdim
1183276479Sdimstruct AddFlagValue {
1184341825Sdim  StringRef Val;
1185341825Sdim
1186276479Sdim  explicit AddFlagValue(StringRef V) : Val(V) {}
1187193326Sed};
1188193326Sed
1189341825Sdim/// Register a value for the flag in the current diagnostic. This
1190276479Sdim/// value will be shown as the suffix "=value" after the flag name. It is
1191276479Sdim/// useful in cases where the diagnostic flag accepts values (e.g.,
1192276479Sdim/// -Rpass or -Wframe-larger-than).
1193193326Sedinline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1194276479Sdim                                           const AddFlagValue V) {
1195276479Sdim  DB.addFlagValue(V.Val);
1196276479Sdim  return DB;
1197276479Sdim}
1198276479Sdim
1199276479Sdiminline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1200226633Sdim                                           StringRef S) {
1201193326Sed  DB.AddString(S);
1202193326Sed  return DB;
1203193326Sed}
1204193326Sed
1205193326Sedinline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1206193326Sed                                           const char *Str) {
1207193326Sed  DB.AddTaggedVal(reinterpret_cast<intptr_t>(Str),
1208226633Sdim                  DiagnosticsEngine::ak_c_string);
1209193326Sed  return DB;
1210193326Sed}
1211193326Sed
1212193326Sedinline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, int I) {
1213226633Sdim  DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
1214193326Sed  return DB;
1215193326Sed}
1216193326Sed
1217276479Sdim// We use enable_if here to prevent that this overload is selected for
1218276479Sdim// pointers or other arguments that are implicitly convertible to bool.
1219276479Sdimtemplate <typename T>
1220276479Sdiminline
1221276479Sdimtypename std::enable_if<std::is_same<T, bool>::value,
1222276479Sdim                        const DiagnosticBuilder &>::type
1223276479Sdimoperator<<(const DiagnosticBuilder &DB, T I) {
1224226633Sdim  DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
1225193326Sed  return DB;
1226193326Sed}
1227193326Sed
1228193326Sedinline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1229193326Sed                                           unsigned I) {
1230226633Sdim  DB.AddTaggedVal(I, DiagnosticsEngine::ak_uint);
1231193326Sed  return DB;
1232193326Sed}
1233193326Sed
1234193326Sedinline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1235276479Sdim                                           tok::TokenKind I) {
1236276479Sdim  DB.AddTaggedVal(static_cast<unsigned>(I), DiagnosticsEngine::ak_tokenkind);
1237276479Sdim  return DB;
1238276479Sdim}
1239276479Sdim
1240276479Sdiminline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1241193326Sed                                           const IdentifierInfo *II) {
1242193326Sed  DB.AddTaggedVal(reinterpret_cast<intptr_t>(II),
1243226633Sdim                  DiagnosticsEngine::ak_identifierinfo);
1244193326Sed  return DB;
1245193326Sed}
1246198092Srdivacky
1247198092Srdivacky// Adds a DeclContext to the diagnostic. The enable_if template magic is here
1248198092Srdivacky// so that we only match those arguments that are (statically) DeclContexts;
1249198092Srdivacky// other arguments that derive from DeclContext (e.g., RecordDecls) will not
1250198092Srdivacky// match.
1251309124Sdimtemplate <typename T>
1252309124Sdiminline typename std::enable_if<
1253309124Sdim    std::is_same<typename std::remove_const<T>::type, DeclContext>::value,
1254309124Sdim    const DiagnosticBuilder &>::type
1255198092Srdivackyoperator<<(const DiagnosticBuilder &DB, T *DC) {
1256198092Srdivacky  DB.AddTaggedVal(reinterpret_cast<intptr_t>(DC),
1257226633Sdim                  DiagnosticsEngine::ak_declcontext);
1258198092Srdivacky  return DB;
1259198092Srdivacky}
1260276479Sdim
1261193326Sedinline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1262296417Sdim                                           SourceRange R) {
1263210299Sed  DB.AddSourceRange(CharSourceRange::getTokenRange(R));
1264193326Sed  return DB;
1265193326Sed}
1266193326Sed
1267193326Sedinline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1268276479Sdim                                           ArrayRef<SourceRange> Ranges) {
1269296417Sdim  for (SourceRange R : Ranges)
1270276479Sdim    DB.AddSourceRange(CharSourceRange::getTokenRange(R));
1271276479Sdim  return DB;
1272276479Sdim}
1273276479Sdim
1274276479Sdiminline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1275210299Sed                                           const CharSourceRange &R) {
1276210299Sed  DB.AddSourceRange(R);
1277210299Sed  return DB;
1278210299Sed}
1279276479Sdim
1280210299Sedinline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1281206084Srdivacky                                           const FixItHint &Hint) {
1282288943Sdim  DB.AddFixItHint(Hint);
1283288943Sdim  return DB;
1284288943Sdim}
1285288943Sdim
1286288943Sdiminline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1287288943Sdim                                           ArrayRef<FixItHint> Hints) {
1288288943Sdim  for (const FixItHint &Hint : Hints)
1289234353Sdim    DB.AddFixItHint(Hint);
1290193326Sed  return DB;
1291193326Sed}
1292193326Sed
1293288943Sdim/// A nullability kind paired with a bit indicating whether it used a
1294288943Sdim/// context-sensitive keyword.
1295341825Sdimusing DiagNullabilityKind = std::pair<NullabilityKind, bool>;
1296288943Sdim
1297288943Sdimconst DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1298288943Sdim                                    DiagNullabilityKind nullability);
1299288943Sdim
1300226633Sdiminline DiagnosticBuilder DiagnosticsEngine::Report(SourceLocation Loc,
1301276479Sdim                                                   unsigned DiagID) {
1302341825Sdim  assert(CurDiagID == std::numeric_limits<unsigned>::max() &&
1303341825Sdim         "Multiple diagnostics in flight at once!");
1304193326Sed  CurDiagLoc = Loc;
1305193326Sed  CurDiagID = DiagID;
1306276479Sdim  FlagValue.clear();
1307193326Sed  return DiagnosticBuilder(this);
1308193326Sed}
1309276479Sdim
1310353358Sdiminline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
1311353358Sdim                                           llvm::Error &&E) {
1312353358Sdim  DB.AddString(toString(std::move(E)));
1313353358Sdim  return DB;
1314353358Sdim}
1315353358Sdim
1316226633Sdiminline DiagnosticBuilder DiagnosticsEngine::Report(unsigned DiagID) {
1317218893Sdim  return Report(SourceLocation(), DiagID);
1318199482Srdivacky}
1319193326Sed
1320193326Sed//===----------------------------------------------------------------------===//
1321226633Sdim// Diagnostic
1322193326Sed//===----------------------------------------------------------------------===//
1323198092Srdivacky
1324239462Sdim/// A little helper class (which is basically a smart pointer that forwards
1325239462Sdim/// info from DiagnosticsEngine) that allows clients to enquire about the
1326239462Sdim/// currently in-flight diagnostic.
1327226633Sdimclass Diagnostic {
1328226633Sdim  const DiagnosticsEngine *DiagObj;
1329226633Sdim  StringRef StoredDiagMessage;
1330314564Sdim
1331193326Sedpublic:
1332226633Sdim  explicit Diagnostic(const DiagnosticsEngine *DO) : DiagObj(DO) {}
1333226633Sdim  Diagnostic(const DiagnosticsEngine *DO, StringRef storedDiagMessage)
1334341825Sdim      : DiagObj(DO), StoredDiagMessage(storedDiagMessage) {}
1335198092Srdivacky
1336226633Sdim  const DiagnosticsEngine *getDiags() const { return DiagObj; }
1337193326Sed  unsigned getID() const { return DiagObj->CurDiagID; }
1338218893Sdim  const SourceLocation &getLocation() const { return DiagObj->CurDiagLoc; }
1339218893Sdim  bool hasSourceManager() const { return DiagObj->hasSourceManager(); }
1340218893Sdim  SourceManager &getSourceManager() const { return DiagObj->getSourceManager();}
1341198092Srdivacky
1342193326Sed  unsigned getNumArgs() const { return DiagObj->NumDiagArgs; }
1343198092Srdivacky
1344341825Sdim  /// Return the kind of the specified index.
1345239462Sdim  ///
1346239462Sdim  /// Based on the kind of argument, the accessors below can be used to get
1347239462Sdim  /// the value.
1348239462Sdim  ///
1349239462Sdim  /// \pre Idx < getNumArgs()
1350226633Sdim  DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const {
1351193326Sed    assert(Idx < getNumArgs() && "Argument index out of range!");
1352226633Sdim    return (DiagnosticsEngine::ArgumentKind)DiagObj->DiagArgumentsKind[Idx];
1353193326Sed  }
1354198092Srdivacky
1355341825Sdim  /// Return the provided argument string specified by \p Idx.
1356239462Sdim  /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_std_string
1357193326Sed  const std::string &getArgStdStr(unsigned Idx) const {
1358226633Sdim    assert(getArgKind(Idx) == DiagnosticsEngine::ak_std_string &&
1359193326Sed           "invalid argument accessor!");
1360193326Sed    return DiagObj->DiagArgumentsStr[Idx];
1361193326Sed  }
1362198092Srdivacky
1363341825Sdim  /// Return the specified C string argument.
1364239462Sdim  /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_c_string
1365193326Sed  const char *getArgCStr(unsigned Idx) const {
1366226633Sdim    assert(getArgKind(Idx) == DiagnosticsEngine::ak_c_string &&
1367193326Sed           "invalid argument accessor!");
1368193326Sed    return reinterpret_cast<const char*>(DiagObj->DiagArgumentsVal[Idx]);
1369193326Sed  }
1370198092Srdivacky
1371341825Sdim  /// Return the specified signed integer argument.
1372239462Sdim  /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_sint
1373193326Sed  int getArgSInt(unsigned Idx) const {
1374226633Sdim    assert(getArgKind(Idx) == DiagnosticsEngine::ak_sint &&
1375193326Sed           "invalid argument accessor!");
1376193326Sed    return (int)DiagObj->DiagArgumentsVal[Idx];
1377193326Sed  }
1378198092Srdivacky
1379341825Sdim  /// Return the specified unsigned integer argument.
1380239462Sdim  /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_uint
1381193326Sed  unsigned getArgUInt(unsigned Idx) const {
1382226633Sdim    assert(getArgKind(Idx) == DiagnosticsEngine::ak_uint &&
1383193326Sed           "invalid argument accessor!");
1384193326Sed    return (unsigned)DiagObj->DiagArgumentsVal[Idx];
1385193326Sed  }
1386198092Srdivacky
1387341825Sdim  /// Return the specified IdentifierInfo argument.
1388239462Sdim  /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo
1389193326Sed  const IdentifierInfo *getArgIdentifier(unsigned Idx) const {
1390226633Sdim    assert(getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo &&
1391193326Sed           "invalid argument accessor!");
1392193326Sed    return reinterpret_cast<IdentifierInfo*>(DiagObj->DiagArgumentsVal[Idx]);
1393193326Sed  }
1394198092Srdivacky
1395341825Sdim  /// Return the specified non-string argument in an opaque form.
1396239462Sdim  /// \pre getArgKind(Idx) != DiagnosticsEngine::ak_std_string
1397193326Sed  intptr_t getRawArg(unsigned Idx) const {
1398226633Sdim    assert(getArgKind(Idx) != DiagnosticsEngine::ak_std_string &&
1399193326Sed           "invalid argument accessor!");
1400193326Sed    return DiagObj->DiagArgumentsVal[Idx];
1401193326Sed  }
1402198092Srdivacky
1403341825Sdim  /// Return the number of source ranges associated with this diagnostic.
1404193326Sed  unsigned getNumRanges() const {
1405276479Sdim    return DiagObj->DiagRanges.size();
1406193326Sed  }
1407198092Srdivacky
1408239462Sdim  /// \pre Idx < getNumRanges()
1409210299Sed  const CharSourceRange &getRange(unsigned Idx) const {
1410276479Sdim    assert(Idx < getNumRanges() && "Invalid diagnostic range index!");
1411203955Srdivacky    return DiagObj->DiagRanges[Idx];
1412193326Sed  }
1413198092Srdivacky
1414341825Sdim  /// Return an array reference for this diagnostic's ranges.
1415234353Sdim  ArrayRef<CharSourceRange> getRanges() const {
1416276479Sdim    return DiagObj->DiagRanges;
1417234353Sdim  }
1418234353Sdim
1419206084Srdivacky  unsigned getNumFixItHints() const {
1420276479Sdim    return DiagObj->DiagFixItHints.size();
1421193326Sed  }
1422193326Sed
1423206084Srdivacky  const FixItHint &getFixItHint(unsigned Idx) const {
1424234353Sdim    assert(Idx < getNumFixItHints() && "Invalid index!");
1425234353Sdim    return DiagObj->DiagFixItHints[Idx];
1426193326Sed  }
1427193326Sed
1428276479Sdim  ArrayRef<FixItHint> getFixItHints() const {
1429276479Sdim    return DiagObj->DiagFixItHints;
1430193326Sed  }
1431193326Sed
1432341825Sdim  /// Format this diagnostic into a string, substituting the
1433239462Sdim  /// formal arguments into the %0 slots.
1434239462Sdim  ///
1435239462Sdim  /// The result is appended onto the \p OutStr array.
1436226633Sdim  void FormatDiagnostic(SmallVectorImpl<char> &OutStr) const;
1437202379Srdivacky
1438341825Sdim  /// Format the given format-string into the output buffer using the
1439239462Sdim  /// arguments stored in this diagnostic.
1440202379Srdivacky  void FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
1441226633Sdim                        SmallVectorImpl<char> &OutStr) const;
1442204643Srdivacky};
1443203955Srdivacky
1444204643Srdivacky/**
1445341825Sdim * Represents a diagnostic in a form that can be retained until its
1446341825Sdim * corresponding source manager is destroyed.
1447204643Srdivacky */
1448204643Srdivackyclass StoredDiagnostic {
1449218893Sdim  unsigned ID;
1450226633Sdim  DiagnosticsEngine::Level Level;
1451204643Srdivacky  FullSourceLoc Loc;
1452204643Srdivacky  std::string Message;
1453210299Sed  std::vector<CharSourceRange> Ranges;
1454206084Srdivacky  std::vector<FixItHint> FixIts;
1455204643Srdivacky
1456204643Srdivackypublic:
1457296417Sdim  StoredDiagnostic() = default;
1458226633Sdim  StoredDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info);
1459341825Sdim  StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
1460226633Sdim                   StringRef Message);
1461341825Sdim  StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
1462226633Sdim                   StringRef Message, FullSourceLoc Loc,
1463226633Sdim                   ArrayRef<CharSourceRange> Ranges,
1464226633Sdim                   ArrayRef<FixItHint> Fixits);
1465204643Srdivacky
1466341825Sdim  /// Evaluates true when this object stores a diagnostic.
1467314564Sdim  explicit operator bool() const { return !Message.empty(); }
1468204643Srdivacky
1469218893Sdim  unsigned getID() const { return ID; }
1470226633Sdim  DiagnosticsEngine::Level getLevel() const { return Level; }
1471204643Srdivacky  const FullSourceLoc &getLocation() const { return Loc; }
1472226633Sdim  StringRef getMessage() const { return Message; }
1473212904Sdim
1474212904Sdim  void setLocation(FullSourceLoc Loc) { this->Loc = Loc; }
1475212904Sdim
1476341825Sdim  using range_iterator = std::vector<CharSourceRange>::const_iterator;
1477341825Sdim
1478204643Srdivacky  range_iterator range_begin() const { return Ranges.begin(); }
1479204643Srdivacky  range_iterator range_end() const { return Ranges.end(); }
1480204643Srdivacky  unsigned range_size() const { return Ranges.size(); }
1481341825Sdim
1482234353Sdim  ArrayRef<CharSourceRange> getRanges() const {
1483234353Sdim    return llvm::makeArrayRef(Ranges);
1484234353Sdim  }
1485204643Srdivacky
1486341825Sdim  using fixit_iterator = std::vector<FixItHint>::const_iterator;
1487341825Sdim
1488204643Srdivacky  fixit_iterator fixit_begin() const { return FixIts.begin(); }
1489204643Srdivacky  fixit_iterator fixit_end() const { return FixIts.end(); }
1490204643Srdivacky  unsigned fixit_size() const { return FixIts.size(); }
1491341825Sdim
1492234353Sdim  ArrayRef<FixItHint> getFixIts() const {
1493234353Sdim    return llvm::makeArrayRef(FixIts);
1494234353Sdim  }
1495193326Sed};
1496198092Srdivacky
1497341825Sdim/// Abstract interface, implemented by clients of the front-end, which
1498239462Sdim/// formats and prints fully processed diagnostics.
1499226633Sdimclass DiagnosticConsumer {
1500218893Sdimprotected:
1501314564Sdim  unsigned NumWarnings = 0;       ///< Number of warnings reported
1502314564Sdim  unsigned NumErrors = 0;         ///< Number of errors reported
1503341825Sdim
1504193326Sedpublic:
1505314564Sdim  DiagnosticConsumer() = default;
1506314564Sdim  virtual ~DiagnosticConsumer();
1507314564Sdim
1508218893Sdim  unsigned getNumErrors() const { return NumErrors; }
1509218893Sdim  unsigned getNumWarnings() const { return NumWarnings; }
1510234353Sdim  virtual void clear() { NumWarnings = NumErrors = 0; }
1511218893Sdim
1512341825Sdim  /// Callback to inform the diagnostic client that processing
1513198954Srdivacky  /// of a source file is beginning.
1514198954Srdivacky  ///
1515198954Srdivacky  /// Note that diagnostics may be emitted outside the processing of a source
1516198954Srdivacky  /// file, for example during the parsing of command line options. However,
1517198954Srdivacky  /// diagnostics with source range information are required to only be emitted
1518198954Srdivacky  /// in between BeginSourceFile() and EndSourceFile().
1519198954Srdivacky  ///
1520239462Sdim  /// \param LangOpts The language options for the source file being processed.
1521341825Sdim  /// \param PP The preprocessor object being used for the source; this is
1522239462Sdim  /// optional, e.g., it may not be present when processing AST source files.
1523199482Srdivacky  virtual void BeginSourceFile(const LangOptions &LangOpts,
1524276479Sdim                               const Preprocessor *PP = nullptr) {}
1525198092Srdivacky
1526341825Sdim  /// Callback to inform the diagnostic client that processing
1527239462Sdim  /// of a source file has ended.
1528239462Sdim  ///
1529239462Sdim  /// The diagnostic client should assume that any objects made available via
1530239462Sdim  /// BeginSourceFile() are inaccessible.
1531198954Srdivacky  virtual void EndSourceFile() {}
1532198954Srdivacky
1533341825Sdim  /// Callback to inform the diagnostic client that processing of all
1534234353Sdim  /// source files has ended.
1535234353Sdim  virtual void finish() {}
1536234353Sdim
1537341825Sdim  /// Indicates whether the diagnostics handled by this
1538226633Sdim  /// DiagnosticConsumer should be included in the number of diagnostics
1539226633Sdim  /// reported by DiagnosticsEngine.
1540239462Sdim  ///
1541239462Sdim  /// The default implementation returns true.
1542193326Sed  virtual bool IncludeInDiagnosticCounts() const;
1543193326Sed
1544341825Sdim  /// Handle this diagnostic, reporting it to the user or
1545193326Sed  /// capturing it to a log as needed.
1546218893Sdim  ///
1547239462Sdim  /// The default implementation just keeps track of the total number of
1548239462Sdim  /// warnings and errors.
1549226633Sdim  virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
1550226633Sdim                                const Diagnostic &Info);
1551193326Sed};
1552193326Sed
1553341825Sdim/// A diagnostic client that ignores all diagnostics.
1554226633Sdimclass IgnoringDiagConsumer : public DiagnosticConsumer {
1555234353Sdim  virtual void anchor();
1556314564Sdim
1557226633Sdim  void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
1558276479Sdim                        const Diagnostic &Info) override {
1559226633Sdim    // Just ignore it.
1560226633Sdim  }
1561226633Sdim};
1562226633Sdim
1563341825Sdim/// Diagnostic consumer that forwards diagnostics along to an
1564251662Sdim/// existing, already-initialized diagnostic consumer.
1565251662Sdim///
1566251662Sdimclass ForwardingDiagnosticConsumer : public DiagnosticConsumer {
1567251662Sdim  DiagnosticConsumer &Target;
1568251662Sdim
1569251662Sdimpublic:
1570251662Sdim  ForwardingDiagnosticConsumer(DiagnosticConsumer &Target) : Target(Target) {}
1571288943Sdim  ~ForwardingDiagnosticConsumer() override;
1572251662Sdim
1573276479Sdim  void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
1574276479Sdim                        const Diagnostic &Info) override;
1575276479Sdim  void clear() override;
1576251662Sdim
1577276479Sdim  bool IncludeInDiagnosticCounts() const override;
1578251662Sdim};
1579251662Sdim
1580239462Sdim// Struct used for sending info about how a type should be printed.
1581239462Sdimstruct TemplateDiffTypes {
1582239462Sdim  intptr_t FromType;
1583239462Sdim  intptr_t ToType;
1584239462Sdim  unsigned PrintTree : 1;
1585239462Sdim  unsigned PrintFromType : 1;
1586239462Sdim  unsigned ElideType : 1;
1587239462Sdim  unsigned ShowColors : 1;
1588341825Sdim
1589239462Sdim  // The printer sets this variable to true if the template diff was used.
1590239462Sdim  unsigned TemplateDiffUsed : 1;
1591239462Sdim};
1592239462Sdim
1593239462Sdim/// Special character that the diagnostic printer will use to toggle the bold
1594239462Sdim/// attribute.  The character itself will be not be printed.
1595239462Sdimconst char ToggleHighlight = 127;
1596239462Sdim
1597276479Sdim/// ProcessWarningOptions - Initialize the diagnostic client and process the
1598276479Sdim/// warning options specified on the command line.
1599276479Sdimvoid ProcessWarningOptions(DiagnosticsEngine &Diags,
1600276479Sdim                           const DiagnosticOptions &Opts,
1601276479Sdim                           bool ReportDiags = true);
1602276479Sdim
1603341825Sdim} // namespace clang
1604193326Sed
1605314564Sdim#endif // LLVM_CLANG_BASIC_DIAGNOSTIC_H
1606