17#include "clang/Basic/Diagnostic.h"
18#include "clang/Basic/SourceLocation.h"
19#include "clang/Basic/SourceManager.h"
20#include "clang/Frontend/CompilerInstance.h"
22#include "llvm/ADT/SmallString.h"
23#include "llvm/Support/raw_ostream.h"
41 return DiagnosticSeverity::Note;
46 return V->Message.c_str();
52 return V->File.c_str();
69DiagnosticSeverity DiagnosticRef::severity()
const {
72const char* DiagnosticRef::message()
const {
83 return E.inlineStatus();
91 if (!S || S->Diagnostics.empty())
98 static thread_local std::vector<DiagnosticRef> Buf;
100 Buf.reserve(S->Diagnostics.size());
102 Buf.push_back(DiagnosticRef{&Dv});
103 return ArrayView<DiagnosticRef>{Buf.data(), Buf.size()};
107Status ErrorRef::status()
const {
return GetStatus(*
this); }
108ArrayView<DiagnosticRef> ErrorRef::diagnostics()
const {
111const char* ErrorRef::producer()
const {
112 const ErrorSlice* S = slice();
113 return S ? S->Producer :
nullptr;
115const char* ErrorRef::producerSignature()
const {
116 const ErrorSlice* S = slice();
117 return S ? S->ProducerSignature :
nullptr;
120ErrorRecord ErrorRef::record()
const {
123 const ErrorSlice* S = slice();
126 R.Diagnostics.reserve(S->Diagnostics.size());
127 for (
const StoredDiagView& Dv : S->Diagnostics) {
129 Di.Severity = Dv.Sev;
130 Di.Message = Dv.Message;
133 Di.Column = Dv.Column;
134 R.Diagnostics.push_back(std::move(Di));
136 R.Producer = S->Producer;
137 R.ProducerSignature = S->ProducerSignature;
145 E.slice()->Refcount.fetch_add(1, std::memory_order_acq_rel);
152 if (S->Refcount.fetch_sub(1, std::memory_order_acq_rel) == 1)
156char StatusError::ID = 0;
158void StatusError::log(llvm::raw_ostream& OS)
const {
159 OS <<
"CppInterOp status error: " << Message;
161std::error_code StatusError::convertToErrorCode()
const {
162 return llvm::inconvertibleErrorCode();
174 std::string Message,
const char* Producer,
175 const char* ProducerSig) {
180 if (!Message.empty()) {
182 Dv.
Message = std::move(Message);
183 Dv.
Sev = DiagnosticSeverity::Error;
189 return ErrorRef::makeSlice(Slc);
193 const char* Producer,
194 const char* ProducerSig) {
200 Status Code = Status::CompileError;
203 llvm::handleAllErrors(
210 [&](
const llvm::ErrorInfoBase& EIB) {
213 llvm::raw_string_ostream OS(Msg);
220 Slc->Producer = Producer;
221 Slc->ProducerSignature = ProducerSig;
225 Dv.
Sev = DiagnosticSeverity::Error;
226 Slc->Diagnostics.push_back(std::move(Dv));
229 return ErrorRef::makeSlice(Slc);
239class CppInteropDiagConsumer :
public clang::DiagnosticConsumer {
241 CppInteropDiagConsumer(InterpreterInfo* II,
242 std::unique_ptr<clang::DiagnosticConsumer> Owned,
243 clang::DiagnosticConsumer* Raw)
244 : II(II), Owned(std::move(Owned)), Raw(Raw) {}
246 void BeginSourceFile(
const clang::LangOptions& LO,
247 const clang::Preprocessor* PP)
override {
249 Raw->BeginSourceFile(LO, PP);
251 void EndSourceFile()
override {
253 Raw->EndSourceFile();
255 void HandleDiagnostic(clang::DiagnosticsEngine::Level Level,
256 const clang::Diagnostic& Info)
override;
260 std::unique_ptr<clang::DiagnosticConsumer> Owned;
261 clang::DiagnosticConsumer* Raw;
264DiagnosticSeverity MapClangSeverity(clang::DiagnosticsEngine::Level L) {
266 case clang::DiagnosticsEngine::Ignored:
267 case clang::DiagnosticsEngine::Note:
268 case clang::DiagnosticsEngine::Remark:
269 return DiagnosticSeverity::Note;
270 case clang::DiagnosticsEngine::Warning:
271 return DiagnosticSeverity::Warning;
272 case clang::DiagnosticsEngine::Error:
273 return DiagnosticSeverity::Error;
274 case clang::DiagnosticsEngine::Fatal:
275 return DiagnosticSeverity::Fatal;
277 return DiagnosticSeverity::Error;
281void CppInteropDiagConsumer::HandleDiagnostic(
282 clang::DiagnosticsEngine::Level Level,
const clang::Diagnostic& Info) {
285 clang::DiagnosticConsumer::HandleDiagnostic(Level, Info);
287 Raw->HandleDiagnostic(Level, Info);
289 llvm::SmallString<128> Buf;
290 Info.FormatDiagnostic(Buf);
293 Dv.Message = Buf.str().str();
294 Dv.Sev = MapClangSeverity(Level);
296 if (Info.hasSourceManager() && Info.getLocation().isValid()) {
297 clang::SourceManager& SM = Info.getSourceManager();
298 clang::PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
299 if (PLoc.isValid()) {
300 if (
const char* F = PLoc.getFilename())
302 Dv.Line = PLoc.getLine();
303 Dv.Column = PLoc.getColumn();
307 II->StoredDiags.push_back(std::move(Dv));
317 clang::DiagnosticsEngine& Diag = II->Interpreter->getCI()->getDiagnostics();
318 std::unique_ptr<clang::DiagnosticConsumer> PrevOwned = Diag.takeClient();
319 clang::DiagnosticConsumer* PrevRaw = Diag.getClient();
320 auto* New =
new CppInteropDiagConsumer(II, std::move(PrevOwned), PrevRaw);
321 Diag.setClient(New,
true);
325 for (
auto& Dv : II->StoredDiags)
326 S->Diagnostics.push_back(std::move(Dv));
327 II->StoredDiags.clear();
331 II->StoredDiags.clear();
340 if (Idx >= II->StoredDiags.size())
341 return DiagnosticRef{};
342 return DiagnosticRef{&II->StoredDiags[Idx]};
351 std::fputs(
"Cpp::Result<T>::value() called on an error-bearing "
352 "Result. Use value_or(fallback) for lenient semantics, "
353 "or branch on .ok() / .error() before calling .value().\n",
361 std::fputs(
"Cpp::Result destroyed without check (likely a dropped "
362 "error). Call .ok() / .error() / .value() to inspect, "
363 "or .ignore() to acknowledge.\n",
void RetainErrorRef(ErrorRef E)
void InstallDiagConsumer(InterpreterInfo *II)
Wire CppInterOp's DiagnosticConsumer into the interpreter's DiagnosticsEngine so parser/sema diagnost...
InterpreterInfo * GetInterpInfo(InterpRef I)
Resolve an InterpRef to the impl-side struct.
Status GetStatus(ErrorRef E)
unsigned GetPendingDiagnosticCount(InterpRef I)
const char * GetDiagnosticFile(DiagnosticRef D)
ErrorRef makeError(Status S)
Build an inline-status ErrorRef (no diagnostics, no payload).
void ResultAbort_UncheckedOnDtor(const ErrorRef &)
unsigned GetDiagnosticLine(DiagnosticRef D)
ErrorRef drainError(InterpreterInfo *II, llvm::Error E, const char *Producer, const char *ProducerSig)
Drain E into a fresh slice, returning the slice via ErrorRef.
DiagnosticSeverity GetDiagnosticSeverity(DiagnosticRef D)
void ClearPendingDiagnostics(InterpRef I)
ArrayView< DiagnosticRef > GetDiagnostics(ErrorRef E)
void DrainPendingInto(InterpreterInfo *II, ErrorSlice *S)
Drain the consumer's per-interp buffer into a slice on failure.
const char * GetDiagnosticMessage(DiagnosticRef D)
ErrorSlice * AllocSlice(InterpreterInfo *Owner)
Allocate a fresh slice on the heap, refcount 0.
void ReleaseErrorRef(ErrorRef E)
void ResultAbort_ValueOnError(const ErrorRef &)
DiagnosticRef GetPendingDiagnostic(unsigned Idx, InterpRef I)
unsigned GetDiagnosticColumn(DiagnosticRef D)
static const StoredDiagView * AsView(DiagnosticRef D)
void ClearPending(InterpreterInfo *II)
Body of a slice-encoded error: drained diagnostics, producer attribution, refcount.
const char * ProducerSignature
std::deque< StoredDiagView > Diagnostics
std::deque< StoredDiagView > StoredDiags
Owning record for one captured diagnostic.