]> granicus.if.org Git - clang/commitdiff
[Basic] Add a DiagnosticError llvm::ErrorInfo subclass
authorAlex Lorenz <arphaman@gmail.com>
Fri, 25 Aug 2017 15:48:00 +0000 (15:48 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Fri, 25 Aug 2017 15:48:00 +0000 (15:48 +0000)
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 [new file with mode: 0644]
lib/Basic/Diagnostic.cpp
unittests/Basic/DiagnosticTest.cpp

diff --git a/include/clang/Basic/DiagnosticError.h b/include/clang/Basic/DiagnosticError.h
new file mode 100644 (file)
index 0000000..6b4b073
--- /dev/null
@@ -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<DiagnosticError> {
+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<DiagnosticError>(
+        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<PartialDiagnosticAt> take(llvm::Error &Err) {
+    Optional<PartialDiagnosticAt> 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
index c355445dc1e715d052bd8725ba94ba628e61fe34..47f6a139b15ab4d5d069e56320355afb20a1038d 100644 (file)
@@ -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;
index 0111b172472b8bfc3c7998ab8f90ec08f68263e1..3068e1c34050d4653ef79e7d0c910b78dc3cba43 100644 (file)
@@ -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<std::pair<int, int>> Value = DiagnosticError::create(
+      SourceLocation(), PartialDiagnostic(diag::err_cannot_open_file, Alloc)
+                            << "file"
+                            << "error");
+  ASSERT_TRUE(!Value);
+  llvm::Error Err = Value.takeError();
+  Optional<PartialDiagnosticAt> 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);
+}
 }