From 494ef6fbebeba1d68dab968806e2e7adfd2788ec Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Fri, 25 Aug 2017 15:48:00 +0000 Subject: [PATCH] [Basic] Add a DiagnosticError llvm::ErrorInfo subclass Clang's DiagnosticError is an llvm::Error payload that stores a partial diagnostic and its location. I'll be using it in the refactoring engine. Differential Revision: https://reviews.llvm.org/D36969 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@311778 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticError.h | 61 +++++++++++++++++++++++++++ lib/Basic/Diagnostic.cpp | 5 ++- unittests/Basic/DiagnosticTest.cpp | 22 ++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 include/clang/Basic/DiagnosticError.h diff --git a/include/clang/Basic/DiagnosticError.h b/include/clang/Basic/DiagnosticError.h new file mode 100644 index 0000000000..6b4b073736 --- /dev/null +++ b/include/clang/Basic/DiagnosticError.h @@ -0,0 +1,61 @@ +//===--- DiagnosticError.h - Diagnostic payload for llvm::Error -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H +#define LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H + +#include "clang/Basic/PartialDiagnostic.h" +#include "llvm/Support/Error.h" + +namespace clang { + +/// \brief Carries a Clang diagnostic in an llvm::Error. +/// +/// Users should emit the stored diagnostic using the DiagnosticsEngine. +class DiagnosticError : public llvm::ErrorInfo { +public: + DiagnosticError(PartialDiagnosticAt Diag) : Diag(std::move(Diag)) {} + + void log(raw_ostream &OS) const override { OS << "clang diagnostic"; } + + PartialDiagnosticAt &getDiagnostic() { return Diag; } + const PartialDiagnosticAt &getDiagnostic() const { return Diag; } + + /// Creates a new \c DiagnosticError that contains the given diagnostic at + /// the given location. + static llvm::Error create(SourceLocation Loc, PartialDiagnostic Diag) { + return llvm::make_error( + PartialDiagnosticAt(Loc, std::move(Diag))); + } + + /// Extracts and returns the diagnostic payload from the given \c Error if + /// the error is a \c DiagnosticError. Returns none if the given error is not + /// a \c DiagnosticError. + static Optional take(llvm::Error &Err) { + Optional Result; + Err = llvm::handleErrors(std::move(Err), [&](DiagnosticError &E) { + Result = std::move(E.getDiagnostic()); + }); + return Result; + } + + static char ID; + +private: + // Users are not expected to use error_code. + std::error_code convertToErrorCode() const override { + return llvm::inconvertibleErrorCode(); + } + + PartialDiagnosticAt Diag; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_DIAGNOSTIC_ERROR_H diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index c355445dc1..47f6a139b1 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -11,8 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/DiagnosticError.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/PartialDiagnostic.h" @@ -1050,3 +1051,5 @@ PartialDiagnostic::StorageAllocator::~StorageAllocator() { llvm::CrashRecoveryContext::isRecoveringFromCrash()) && "A partial is on the lam"); } + +char DiagnosticError::ID; diff --git a/unittests/Basic/DiagnosticTest.cpp b/unittests/Basic/DiagnosticTest.cpp index 0111b17247..3068e1c340 100644 --- a/unittests/Basic/DiagnosticTest.cpp +++ b/unittests/Basic/DiagnosticTest.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticError.h" #include "clang/Basic/DiagnosticIDs.h" #include "gtest/gtest.h" @@ -72,4 +73,25 @@ TEST(DiagnosticTest, suppressAfterFatalError) { } } +TEST(DiagnosticTest, diagnosticError) { + DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions, + new IgnoringDiagConsumer()); + PartialDiagnostic::StorageAllocator Alloc; + llvm::Expected> Value = DiagnosticError::create( + SourceLocation(), PartialDiagnostic(diag::err_cannot_open_file, Alloc) + << "file" + << "error"); + ASSERT_TRUE(!Value); + llvm::Error Err = Value.takeError(); + Optional ErrDiag = DiagnosticError::take(Err); + llvm::cantFail(std::move(Err)); + ASSERT_FALSE(!ErrDiag); + EXPECT_EQ(ErrDiag->first, SourceLocation()); + EXPECT_EQ(ErrDiag->second.getDiagID(), diag::err_cannot_open_file); + + Value = std::make_pair(20, 1); + ASSERT_FALSE(!Value); + EXPECT_EQ(*Value, std::make_pair(20, 1)); + EXPECT_EQ(Value->first, 20); +} } -- 2.40.0