blob: ce1dc9046557b8c3d20297485cf82c3791bbda1e [file] [log] [blame]
//===--- DiagnosticRenderer.h - Diagnostic Pretty-Printing ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// 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_DIAGNOSTIC_RENDERER_H_
#define LLVM_CLANG_FRONTEND_DIAGNOSTIC_RENDERER_H_
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
namespace clang {
class DiagnosticOptions;
class LangOptions;
class SourceManager;
typedef llvm::PointerUnion<const Diagnostic *,
const StoredDiagnostic *> DiagOrStoredDiag;
/// \brief 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;
/// \brief 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;
/// \brief 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;
/// \brief 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;
DiagnosticRenderer(const LangOptions &LangOpts,
DiagnosticOptions *DiagOpts);
virtual ~DiagnosticRenderer();
virtual void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
StringRef Message,
ArrayRef<CharSourceRange> Ranges,
const SourceManager *SM,
DiagOrStoredDiag Info) = 0;
virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges,
const SourceManager &SM) = 0;
virtual void emitCodeContext(SourceLocation Loc,
DiagnosticsEngine::Level Level,
SmallVectorImpl<CharSourceRange>& Ranges,
ArrayRef<FixItHint> Hints,
const SourceManager &SM) = 0;
virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
const SourceManager &SM) = 0;
virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
StringRef ModuleName,
const SourceManager &SM) = 0;
virtual void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
StringRef ModuleName,
const SourceManager &SM) = 0;
virtual void beginDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) {}
virtual void endDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) {}
private:
void emitBasicNote(StringRef Message);
void emitIncludeStack(SourceLocation Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level, const SourceManager &SM);
void emitIncludeStackRecursively(SourceLocation Loc, const SourceManager &SM);
void emitImportStack(SourceLocation Loc, const SourceManager &SM);
void emitImportStackRecursively(SourceLocation Loc, StringRef ModuleName,
const SourceManager &SM);
void emitModuleBuildStack(const SourceManager &SM);
void emitCaret(SourceLocation Loc, DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> Hints,
const SourceManager &SM);
void emitMacroExpansions(SourceLocation Loc,
DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges,
ArrayRef<FixItHint> Hints,
const SourceManager &SM,
unsigned &MacroDepth,
unsigned OnMacroInst = 0);
public:
/// \brief 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.
/// \param SM The SourceManager; will be null if the diagnostic came from the
/// frontend, thus \p Loc will be invalid.
void emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level,
StringRef Message, ArrayRef<CharSourceRange> Ranges,
ArrayRef<FixItHint> FixItHints,
const SourceManager *SM,
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) {}
virtual ~DiagnosticNoteRenderer();
void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
const SourceManager &SM) override;
void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
StringRef ModuleName,
const SourceManager &SM) override;
void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
StringRef ModuleName,
const SourceManager &SM) override;
virtual void emitNote(SourceLocation Loc, StringRef Message,
const SourceManager *SM) = 0;
};
} // end clang namespace
#endif