Clang's DiagnosticError is an llvm::Error payload that stores a partial diagnostic and its location. I'll be using it in D36075.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
Would it be more convenient to extend ErrorInfo instead of creating a new diagnostic wrapper? E.g one benefit of passing around Expected<T>'s is that there's some assurance the diagnostics will be reported.
Possibly, but one issue I found with ErrorInfo is that it gets harder to report diagnostics. E.g. with DiagnosticOr you will be able to write:
DiagnosticOr<...> function(RefactoringOperation &Op) { return Op.Diag(Loc, err::something) << "invalid"; }
But with Expected you'll have to use something like:
Expected<...> function(RefactoringOperation &Op) { return llvm::make_error<DiagnosticError>(Op.Diag(Loc, err::something) << "invalid"); }
I don't think that the assurance about reporting these diagnostics is that important for my case. They will be consumed at most in 3 places (clang-refactor, clangd, and libclang) and clangd and it will obvious to the user if errors aren't getting reported.
Although I guess I could always change the approach completely and use variadic templates instead of <<, e.g.:
template<typename... T> Error RefactoringOperation::error(SourceLocation Loc, unsigned DiagId, const T &... Arguments) { return llvm::make_error<DiagnosticError>(...); } DiagnosticOr<...> function(RefactoringOperation &Op) { return Op.error(Loc, diag::err_something, "invalid"); }
I think I'll try that instead.
Nice! I'd like to get your thoughts on two candidate ergonomic changes:
unittests/Basic/DiagnosticTest.cpp | ||
---|---|---|
81 ↗ | (On Diff #112169) | It might be useful to add an Error-returning wrapper around PDA, e.g: |
90 ↗ | (On Diff #112169) | Creating a null diagnostic before taking an error may become cumbersome. An alternative is to add a static helper in DiagnosticError: static ParitalDiagnosticAt &DiagnosticError::take(Error E) { PartialDiagnosticAt *PDA = nullptr; handleAllErrors(std::move(E), [&](DE) { PDA = &DE.getDiagnostic(); }); assert(PDA && "Expected a DiagnosticError"); return *PDA; } This is more ergonomic, but the downside is that you lose some flexibility (what happens if there are two kinds of errors?, etc). Another alternative is to switch to a callback-driven style (though that might require a lot of refactoring). |