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() { return m_diagnostics; } 111 112 bool HasFixIts() const { 113 return llvm::any_of(m_diagnostics, 114 [](const std::unique_ptr<Diagnostic> &diag) { 115 return diag->HasFixIts(); 116 }); 117 } 118 119 void AddDiagnostic(llvm::StringRef message, lldb::Severity severity, 120 DiagnosticOrigin origin, 121 uint32_t compiler_id = LLDB_INVALID_COMPILER_ID); 122 123 void AddDiagnostic(std::unique_ptr<Diagnostic> diagnostic) { 124 if (diagnostic) 125 m_diagnostics.push_back(std::move(diagnostic)); 126 } 127 128 /// Moves over the contents of a second diagnostic manager over. Leaves other 129 /// diagnostic manager in an empty state. 130 void Consume(DiagnosticManager &&other) { 131 std::move(other.m_diagnostics.begin(), other.m_diagnostics.end(), 132 std::back_inserter(m_diagnostics)); 133 m_fixed_expression = std::move(other.m_fixed_expression); 134 other.Clear(); 135 } 136 137 size_t Printf(lldb::Severity severity, const char *format, ...) 138 __attribute__((format(printf, 3, 4))); 139 void PutString(lldb::Severity severity, llvm::StringRef str); 140 141 void AppendMessageToDiagnostic(llvm::StringRef str) { 142 if (!m_diagnostics.empty()) 143 m_diagnostics.back()->AppendMessage(str); 144 } 145 146 /// Returns an \ref ExpressionError with \c arg as error code. 147 llvm::Error GetAsError(lldb::ExpressionResults result, 148 llvm::Twine message = {}) const; 149 150 // Returns a string containing errors in this format: 151 // 152 // "error: error text\n 153 // warning: warning text\n 154 // remark text\n" 155 std::string GetString(char separator = '\n'); 156 157 void Dump(Log *log); 158 159 const std::string &GetFixedExpression() { return m_fixed_expression; } 160 161 // Moves fixed_expression to the internal storage. 162 void SetFixedExpression(std::string fixed_expression) { 163 m_fixed_expression = std::move(fixed_expression); 164 } 165 166 protected: 167 DiagnosticList m_diagnostics; 168 std::string m_fixed_expression; 169 }; 170 } 171 172 #endif // LLDB_EXPRESSION_DIAGNOSTICMANAGER_H 173