1 /*
   2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #ifndef ErrorHandling_h
  27 #define ErrorHandling_h
  28 
  29 
  30 #include <stdexcept>
  31 
  32 #include "SourceCodePos.h"
  33 #include "tstrings.h"
  34 
  35 
  36 //
  37 // Exception handling helpers. Allow transparent exception logging.
  38 // Use as follows:
  39 //
  40 //  void foo () {
  41 //      JP_TRY;
  42 //
  43 //      if (!do_something()) {
  44 //          JP_THROW("do_something() failed");
  45 //      }
  46 //
  47 //      JP_CATCH_ALL;
  48 //  }
  49 //
  50 
  51 
  52 // Logs std::exception caught at 'pos'.
  53 void reportError(const SourceCodePos& pos, const std::exception& e);
  54 // Logs unknown exception caught at 'pos'.
  55 // Assumed to be called from catch (...) {}
  56 void reportUnknownError(const SourceCodePos& pos);
  57 
  58 std::string makeMessage(const std::exception& e, const SourceCodePos& pos);
  59 
  60 std::string joinErrorMessages(const std::string& a, const std::string& b);
  61 
  62 
  63 template <class Base>
  64 class JpError: public Base {
  65 public:
  66     JpError(const Base& e, const SourceCodePos& pos):
  67                                         Base(e), msg(::makeMessage(e, pos)) {
  68     }
  69 
  70     ~JpError() throw() {
  71     }
  72 
  73     // override Base::what()
  74     const char* what() const throw() {
  75         return msg.c_str();
  76     }
  77 private:
  78     // Assert Base is derived from std::exception
  79     enum { isDerivedFromStdException =
  80                         sizeof(static_cast<std::exception*>((Base*)0)) };
  81 
  82     std::string msg;
  83 };
  84 
  85 template <class T>
  86 inline JpError<T> makeException(const T& obj, const SourceCodePos& p) {
  87     return JpError<T>(obj, p);
  88 }
  89 
  90 inline JpError<std::runtime_error> makeException(
  91                             const std::string& msg, const SourceCodePos& p) {
  92     return JpError<std::runtime_error>(std::runtime_error(msg), p);
  93 }
  94 
  95 inline JpError<std::runtime_error> makeException(
  96                         const tstrings::any& msg, const SourceCodePos& p) {
  97     return makeException(msg.str(), p);
  98 }
  99 
 100 inline JpError<std::runtime_error> makeException(
 101                     std::string::const_pointer msg, const SourceCodePos& p) {
 102     return makeException(std::string(msg), p);
 103 }
 104 
 105 
 106 #define JP_REPORT_ERROR(e)          reportError(JP_SOURCE_CODE_POS, e)
 107 #define JP_REPORT_UNKNOWN_ERROR     reportUnknownError(JP_SOURCE_CODE_POS)
 108 
 109 // Redefine locally in cpp file(s) if need more handling than just reporting
 110 #define JP_HANDLE_ERROR(e)          JP_REPORT_ERROR(e)
 111 #define JP_HANDLE_UNKNOWN_ERROR     JP_REPORT_UNKNOWN_ERROR
 112 
 113 
 114 #define JP_TRY                              \
 115         try                                 \
 116         {                                   \
 117             do {} while(0)
 118 
 119 #define JP_DEFAULT_CATCH_EXCEPTIONS         \
 120         JP_CATCH_STD_EXCEPTION              \
 121         JP_CATCH_UNKNOWN_EXCEPTION
 122 
 123 #define JP_CATCH_EXCEPTIONS                 \
 124         JP_DEFAULT_CATCH_EXCEPTIONS
 125 
 126 #define JP_CATCH_ALL                        \
 127         }                                   \
 128         JP_CATCH_EXCEPTIONS                 \
 129         do {} while(0)
 130 
 131 #define JP_CATCH_STD_EXCEPTION              \
 132         catch (const std::exception& e)     \
 133         {                                   \
 134             JP_HANDLE_ERROR(e);             \
 135         }
 136 
 137 #define JP_CATCH_UNKNOWN_EXCEPTION          \
 138         catch (...)                         \
 139         {                                   \
 140             JP_HANDLE_UNKNOWN_ERROR;        \
 141         }
 142 
 143 
 144 #define JP_THROW(e) throw makeException((e), JP_SOURCE_CODE_POS)
 145 
 146 #define JP_NO_THROW(expr) \
 147     JP_TRY; \
 148     expr; \
 149     JP_CATCH_ALL
 150 
 151 #endif // #ifndef ErrorHandling_h