| 1 | //===-- DiagnosticManager.h -------------------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef LLDB_EXPRESSION_DIAGNOSTICMANAGER_H |
| 10 | #define LLDB_EXPRESSION_DIAGNOSTICMANAGER_H |
| 11 | |
| 12 | #include "lldb/lldb-defines.h" |
| 13 | #include "lldb/lldb-types.h" |
| 14 | |
| 15 | #include "lldb/Utility/DiagnosticsRendering.h" |
| 16 | #include "lldb/Utility/FileSpec.h" |
| 17 | #include "lldb/Utility/Status.h" |
| 18 | |
| 19 | #include "llvm/ADT/STLExtras.h" |
| 20 | #include "llvm/ADT/StringRef.h" |
| 21 | |
| 22 | #include <string> |
| 23 | #include <vector> |
| 24 | |
| 25 | namespace lldb_private { |
| 26 | |
| 27 | /// An llvm::Error used to communicate diagnostics in Status. Multiple |
| 28 | /// diagnostics may be chained in an llvm::ErrorList. |
| 29 | class ExpressionError |
| 30 | : public llvm::ErrorInfo<ExpressionError, DiagnosticError> { |
| 31 | std::string m_message; |
| 32 | std::vector<DiagnosticDetail> m_details; |
| 33 | |
| 34 | public: |
| 35 | static char ID; |
| 36 | using llvm::ErrorInfo<ExpressionError, DiagnosticError>::ErrorInfo; |
| 37 | ExpressionError(lldb::ExpressionResults result, std::string msg, |
| 38 | std::vector<DiagnosticDetail> details = {}); |
| 39 | std::string message() const override; |
| 40 | llvm::ArrayRef<DiagnosticDetail> GetDetails() const override { |
| 41 | return m_details; |
| 42 | } |
| 43 | std::error_code convertToErrorCode() const override; |
| 44 | void log(llvm::raw_ostream &OS) const override; |
| 45 | std::unique_ptr<CloneableError> Clone() const override; |
| 46 | }; |
| 47 | |
| 48 | enum DiagnosticOrigin { |
| 49 | eDiagnosticOriginUnknown = 0, |
| 50 | eDiagnosticOriginLLDB, |
| 51 | eDiagnosticOriginClang, |
| 52 | eDiagnosticOriginSwift, |
| 53 | eDiagnosticOriginLLVM |
| 54 | }; |
| 55 | |
| 56 | const uint32_t LLDB_INVALID_COMPILER_ID = UINT32_MAX; |
| 57 | |
| 58 | class Diagnostic { |
| 59 | friend class DiagnosticManager; |
| 60 | |
| 61 | public: |
| 62 | DiagnosticOrigin getKind() const { return m_origin; } |
| 63 | |
| 64 | static bool classof(const Diagnostic *diag) { |
| 65 | DiagnosticOrigin kind = diag->getKind(); |
| 66 | switch (kind) { |
| 67 | case eDiagnosticOriginUnknown: |
| 68 | case eDiagnosticOriginLLDB: |
| 69 | case eDiagnosticOriginLLVM: |
| 70 | return true; |
| 71 | case eDiagnosticOriginClang: |
| 72 | case eDiagnosticOriginSwift: |
| 73 | return false; |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | Diagnostic(DiagnosticOrigin origin, uint32_t compiler_id, |
| 78 | DiagnosticDetail detail) |
| 79 | : m_origin(origin), m_compiler_id(compiler_id), m_detail(detail) {} |
| 80 | |
| 81 | virtual ~Diagnostic() = default; |
| 82 | |
| 83 | virtual bool HasFixIts() const { return false; } |
| 84 | |
| 85 | lldb::Severity GetSeverity() const { return m_detail.severity; } |
| 86 | |
| 87 | uint32_t GetCompilerID() const { return m_compiler_id; } |
| 88 | |
| 89 | llvm::StringRef GetMessage() const { return m_detail.message; } |
| 90 | const DiagnosticDetail &GetDetail() const { return m_detail; } |
| 91 | |
| 92 | void AppendMessage(llvm::StringRef message, bool precede_with_newline = true); |
| 93 | |
| 94 | protected: |
| 95 | DiagnosticOrigin m_origin; |
| 96 | /// Compiler-specific diagnostic ID. |
| 97 | uint32_t m_compiler_id; |
| 98 | DiagnosticDetail m_detail; |
| 99 | }; |
| 100 | |
| 101 | typedef std::vector<std::unique_ptr<Diagnostic>> DiagnosticList; |
| 102 | |
| 103 | class DiagnosticManager { |
| 104 | public: |
| 105 | void Clear() { |
| 106 | m_diagnostics.clear(); |
| 107 | m_fixed_expression.clear(); |
| 108 | } |
| 109 | |
| 110 | const DiagnosticList &Diagnostics() const { return m_diagnostics; } |
| 111 | DiagnosticList &Diagnostics() { return m_diagnostics; } |
| 112 | |
| 113 | bool HasFixIts() const { |
| 114 | return llvm::any_of(Range: m_diagnostics, |
| 115 | P: [](const std::unique_ptr<Diagnostic> &diag) { |
| 116 | return diag->HasFixIts(); |
| 117 | }); |
| 118 | } |
| 119 | |
| 120 | void AddDiagnostic(llvm::StringRef message, lldb::Severity severity, |
| 121 | DiagnosticOrigin origin, |
| 122 | uint32_t compiler_id = LLDB_INVALID_COMPILER_ID); |
| 123 | |
| 124 | void AddDiagnostic(std::unique_ptr<Diagnostic> diagnostic) { |
| 125 | if (diagnostic) |
| 126 | m_diagnostics.push_back(x: std::move(diagnostic)); |
| 127 | } |
| 128 | |
| 129 | /// Moves over the contents of a second diagnostic manager over. Leaves other |
| 130 | /// diagnostic manager in an empty state. |
| 131 | void Consume(DiagnosticManager &&other) { |
| 132 | std::move(first: other.m_diagnostics.begin(), last: other.m_diagnostics.end(), |
| 133 | result: std::back_inserter(x&: m_diagnostics)); |
| 134 | m_fixed_expression = std::move(other.m_fixed_expression); |
| 135 | other.Clear(); |
| 136 | } |
| 137 | |
| 138 | size_t Printf(lldb::Severity severity, const char *format, ...) |
| 139 | __attribute__((format(printf, 3, 4))); |
| 140 | void PutString(lldb::Severity severity, llvm::StringRef str); |
| 141 | |
| 142 | void AppendMessageToDiagnostic(llvm::StringRef str) { |
| 143 | if (!m_diagnostics.empty()) |
| 144 | m_diagnostics.back()->AppendMessage(message: str); |
| 145 | } |
| 146 | |
| 147 | /// Returns an \ref ExpressionError with \c arg as error code. |
| 148 | llvm::Error GetAsError(lldb::ExpressionResults result, |
| 149 | llvm::Twine message = {}) const; |
| 150 | |
| 151 | // Returns a string containing errors in this format: |
| 152 | // |
| 153 | // "error: error text\n |
| 154 | // warning: warning text\n |
| 155 | // remark text\n" |
| 156 | std::string GetString(char separator = '\n'); |
| 157 | |
| 158 | void Dump(Log *log); |
| 159 | |
| 160 | const std::string &GetFixedExpression() { return m_fixed_expression; } |
| 161 | |
| 162 | // Moves fixed_expression to the internal storage. |
| 163 | void SetFixedExpression(std::string fixed_expression) { |
| 164 | m_fixed_expression = std::move(fixed_expression); |
| 165 | } |
| 166 | |
| 167 | protected: |
| 168 | DiagnosticList m_diagnostics; |
| 169 | std::string m_fixed_expression; |
| 170 | }; |
| 171 | } |
| 172 | |
| 173 | #endif // LLDB_EXPRESSION_DIAGNOSTICMANAGER_H |
| 174 | |