reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
//===- DiagnosticRenderer.h - Diagnostic Pretty-Printing --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This is a utility class that provides support for pretty-printing of
// diagnostics. It is used to implement the different code paths which require
// such functionality in a consistent way.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_FRONTEND_DIAGNOSTICRENDERER_H
#define LLVM_CLANG_FRONTEND_DIAGNOSTICRENDERER_H

#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/StringRef.h"

namespace clang {

class LangOptions;
class SourceManager;

using DiagOrStoredDiag =
    llvm::PointerUnion<const Diagnostic *, const StoredDiagnostic *>;

/// Class to encapsulate the logic for formatting a diagnostic message.
///
/// Actual "printing" logic is implemented by subclasses.
///
/// This class provides an interface for building and emitting
/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt
/// Hints, and code snippets. In the presence of macros this involves
/// a recursive process, synthesizing notes for each macro expansion.
///
/// A brief worklist:
/// FIXME: Sink the recursive printing of template instantiations into this
/// class.
class DiagnosticRenderer {
protected:
  const LangOptions &LangOpts;
  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;

  /// The location of the previous diagnostic if known.
  ///
  /// This will be invalid in cases where there is no (known) previous
  /// diagnostic location, or that location itself is invalid or comes from
  /// a different source manager than SM.
  SourceLocation LastLoc;

  /// The location of the last include whose stack was printed if known.
  ///
  /// Same restriction as LastLoc essentially, but tracking include stack
  /// root locations rather than diagnostic locations.
  SourceLocation LastIncludeLoc;

  /// The level of the last diagnostic emitted.
  ///
  /// The level of the last diagnostic emitted. Used to detect level changes
  /// which change the amount of information displayed.
  DiagnosticsEngine::Level LastLevel = DiagnosticsEngine::Ignored;

  DiagnosticRenderer(const LangOptions &LangOpts,
                     DiagnosticOptions *DiagOpts);

  virtual ~DiagnosticRenderer();

  virtual void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
                                     DiagnosticsEngine::Level Level,
                                     StringRef Message,
                                     ArrayRef<CharSourceRange> Ranges,
                                     DiagOrStoredDiag Info) = 0;

  virtual void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
                                 DiagnosticsEngine::Level Level,
                                 ArrayRef<CharSourceRange> Ranges) = 0;

  virtual void emitCodeContext(FullSourceLoc Loc,
                               DiagnosticsEngine::Level Level,
                               SmallVectorImpl<CharSourceRange> &Ranges,
                               ArrayRef<FixItHint> Hints) = 0;

  virtual void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) = 0;
  virtual void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
                                  StringRef ModuleName) = 0;
  virtual void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc,
                                          StringRef ModuleName) = 0;

  virtual void beginDiagnostic(DiagOrStoredDiag D,
                               DiagnosticsEngine::Level Level) {}
  virtual void endDiagnostic(DiagOrStoredDiag D,
                             DiagnosticsEngine::Level Level) {}

private:
  void emitBasicNote(StringRef Message);
  void emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc,
                        DiagnosticsEngine::Level Level);
  void emitIncludeStackRecursively(FullSourceLoc Loc);
  void emitImportStack(FullSourceLoc Loc);
  void emitImportStackRecursively(FullSourceLoc Loc, StringRef ModuleName);
  void emitModuleBuildStack(const SourceManager &SM);
  void emitCaret(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
                 ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> Hints);
  void emitSingleMacroExpansion(FullSourceLoc Loc,
                                DiagnosticsEngine::Level Level,
                                ArrayRef<CharSourceRange> Ranges);
  void emitMacroExpansions(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
                           ArrayRef<CharSourceRange> Ranges,
                           ArrayRef<FixItHint> Hints);

public:
  /// Emit a diagnostic.
  ///
  /// This is the primary entry point for emitting diagnostic messages.
  /// It handles formatting and rendering the message as well as any ancillary
  /// information needed based on macros whose expansions impact the
  /// diagnostic.
  ///
  /// \param Loc The location for this caret.
  /// \param Level The level of the diagnostic to be emitted.
  /// \param Message The diagnostic message to emit.
  /// \param Ranges The underlined ranges for this code snippet.
  /// \param FixItHints The FixIt hints active for this diagnostic.
  void emitDiagnostic(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
                      StringRef Message, ArrayRef<CharSourceRange> Ranges,
                      ArrayRef<FixItHint> FixItHints,
                      DiagOrStoredDiag D = (Diagnostic *)nullptr);

  void emitStoredDiagnostic(StoredDiagnostic &Diag);
};

/// Subclass of DiagnosticRender that turns all subdiagostics into explicit
/// notes.  It is up to subclasses to further define the behavior.
class DiagnosticNoteRenderer : public DiagnosticRenderer {
public:
  DiagnosticNoteRenderer(const LangOptions &LangOpts,
                         DiagnosticOptions *DiagOpts)
      : DiagnosticRenderer(LangOpts, DiagOpts) {}

  ~DiagnosticNoteRenderer() override;

  void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override;

  void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
                          StringRef ModuleName) override;

  void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc,
                                  StringRef ModuleName) override;

  virtual void emitNote(FullSourceLoc Loc, StringRef Message) = 0;
};

} // namespace clang

#endif // LLVM_CLANG_FRONTEND_DIAGNOSTICRENDERER_H