FreeCAD / src /Base /Exception.h
AbdulElahGwaith's picture
Upload folder using huggingface_hub
985c397 verified
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License (LGPL) *
* as published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* for detail see the LICENCE text file. *
* *
* FreeCAD is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with FreeCAD; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
* *
***************************************************************************/
#ifndef BASE_EXCEPTION_H
#define BASE_EXCEPTION_H
#include <FCConfig.h>
#include <csignal>
#include <source_location>
#include <string>
#include "BaseClass.h"
#include "FileInfo.h"
using PyObject = struct _object; // NOLINT
// Remove once all used compilers support this
#if defined(__cpp_lib_source_location)
# define HAVE_STD_SOURCE_LOCATION 1
#else
# undef HAVE_STD_SOURCE_LOCATION
#endif
// std::source_location is implemented, but buggy in Clang 15
#if defined(__clang__) && __clang_major__ <= 15
# undef HAVE_STD_SOURCE_LOCATION
#endif
/// The macros do NOT mark any message for translation
/// If you want to mark text for translation, use the QT_TRANSLATE_NOOP macro
/// with the context "Exceptions" and the right throwing macro from below (the one ending with T)
/// example:
/// THROWMT(Base::ValueError,QT_TRANSLATE_NOOP("Exceptions","The multiplicity cannot be increased
/// beyond the degree of the B-Spline."));
///
/// N.B.: The QT_TRANSLATE_NOOP macro won't translate your string. It will just allow lupdate to
/// identify that string for translation so that if you ask for a translation (and the translator
/// have provided one) at that time it gets translated (e.g. in the UI before showing the message
/// of the exception).
#if defined(HAVE_STD_SOURCE_LOCATION)
// NOLINTBEGIN(*-macro-usage)
# define THROWM(exc, msg) Base::setupAndThrowException<exc>((msg), std::source_location::current());
# define THROWMT(exc, msg) \
Base::setupAndThrowException<exc>((msg), std::source_location::current(), true);
# define FC_THROWM(exception, msg) \
do { \
std::stringstream ss; \
ss << msg; \
THROWM(exception, ss.str()); \
} while (0)
// NOLINTEND(*-macro-usage)
namespace Base
{
template<typename ExceptionType>
[[noreturn]] void setupAndThrowException(
const std::string message,
const std::source_location location,
const bool translatable = false
)
{
ExceptionType exception {message};
exception.setTranslatable(translatable);
exception.setDebugInformation(location);
throw exception;
} // NOLINT // unreachable
} // namespace Base
#else // HAVE_STD_SOURCE_LOCATION
# ifdef _MSC_VER
# define FC_THROW_INFO __FILE__, __LINE__, __FUNCSIG__
# elif __GNUC__
# define FC_THROW_INFO __FILE__, __LINE__, __PRETTY_FUNCTION__
# else
# define FC_THROW_INFO __FILE__, __LINE__, __func__
# endif
# define THROWM(exc, msg) Base::setupAndThrowException<exc>(msg, FC_THROW_INFO);
# define THROWMT(exc, msg) Base::setupAndThrowException<exc>(msg, FC_THROW_INFO, true);
# define FC_THROWM(exception, msg) \
do { \
std::stringstream ss; \
ss << msg; \
THROWM(exception, ss.str()); \
} while (0)
namespace Base
{
template<typename ExceptionType>
[[noreturn]] void setupAndThrowException(
const std::string message,
const char* file,
const int line,
const char* func,
const bool translatable = false
)
{
ExceptionType exception {message};
exception.setTranslatable(translatable);
exception.setDebugInformation(file, line, func);
throw exception;
} // NOLINT // unreachable
} // namespace Base
#endif // HAVE_STD_SOURCE_LOCATION
//--------------------------------------------------------------------------------------------------
template<typename Exception>
constexpr void THROWM_(
const std::string& msg,
const std::source_location location = std::source_location::current()
)
{
Base::setupAndThrowException<Exception>(msg, location);
}
template<typename Exception>
constexpr void THROWMT_(
const std::string& msg,
const std::source_location location = std::source_location::current()
)
{
Base::setupAndThrowException<Exception>(msg, location, true);
}
template<typename Exception>
constexpr void FC_THROWM_(
const std::string& raw_msg,
const std::source_location location = std::source_location::current()
)
{
THROWM_<Exception>(raw_msg, location);
}
namespace Base
{
class BaseExport Exception: public BaseClass
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
explicit Exception(std::string message = "FreeCAD Exception");
~Exception() noexcept override = default;
Exception& operator=(const Exception& inst);
Exception& operator=(Exception&& inst) noexcept;
virtual const char* what() const noexcept;
virtual void reportException() const; // once only
inline void setMessage(const std::string& message);
// what may differ from the message given by the user in
// derived classes
inline std::string getMessage() const;
inline std::string getFile() const;
inline int getLine() const;
inline std::string getFunction() const;
inline bool getTranslatable() const;
inline bool getReported() const;
inline void setReported(bool reported) const;
#if defined(HAVE_STD_SOURCE_LOCATION)
inline void setDebugInformation(const std::source_location& location);
#else
inline void setDebugInformation(const char* file, int line, const char* func);
#endif
inline void setTranslatable(bool translatable);
PyObject* getPyObject() override; // exception data
void setPyObject(PyObject* pydict) override; // set the exception data
virtual PyObject* getPyExceptionType() const;
virtual void setPyException() const;
protected:
Exception(const Exception& inst);
Exception(Exception&& inst) noexcept;
private:
std::string errorMessage;
std::string fileName;
int lineNum {0};
std::string functionName;
bool isTranslatable {false};
mutable bool hasBeenReported {false};
};
class BaseExport AbortException: public Exception
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
explicit AbortException(const std::string& message = "Aborted operation");
const char* what() const noexcept override;
PyObject* getPyExceptionType() const override;
};
class BaseExport XMLBaseException: public Exception
{
public:
explicit XMLBaseException(const std::string& message = "XML base exception");
PyObject* getPyExceptionType() const override;
};
class BaseExport XMLParseException: public XMLBaseException
{
public:
explicit XMLParseException(const std::string& message = "XML parse exception");
const char* what() const noexcept override;
PyObject* getPyExceptionType() const override;
};
class BaseExport XMLAttributeError: public XMLBaseException
{
public:
explicit XMLAttributeError(const std::string& message = "XML attribute error");
const char* what() const noexcept override;
PyObject* getPyExceptionType() const override;
};
class BaseExport FileException: public Exception
{
public:
explicit FileException(
const std::string& message = "Unknown file exception happened",
const std::string& fileName = ""
);
FileException(const std::string& message, const FileInfo& File);
const char* what() const noexcept override;
void reportException() const override;
std::string getFileName() const;
PyObject* getPyObject() override;
void setPyObject(PyObject* pydict) override;
PyObject* getPyExceptionType() const override;
private:
FileInfo file;
// necessary for what() legacy behaviour as it returns a buffer that
// can not be of a temporary object to be destroyed at end of what()
std::string _sErrMsgAndFileName;
void setFileName(const std::string& fileName);
};
class BaseExport FileSystemError: public Exception
{
public:
explicit FileSystemError(const std::string& message = "File system error");
FileSystemError(const FileSystemError&) = default;
FileSystemError(FileSystemError&&) = default;
~FileSystemError() noexcept override = default;
FileSystemError& operator=(const FileSystemError&) = default;
FileSystemError& operator=(FileSystemError&&) = default;
PyObject* getPyExceptionType() const override;
};
/** errors in a data structure */
class BaseExport BadFormatError: public Exception
{
public:
explicit BadFormatError(const std::string& message = "Bad format error");
BadFormatError(const BadFormatError&) = default;
BadFormatError(BadFormatError&&) = default;
~BadFormatError() noexcept override = default;
BadFormatError& operator=(const BadFormatError&) = default;
BadFormatError& operator=(BadFormatError&&) = default;
PyObject* getPyExceptionType() const override;
};
#if defined(__GNUC__)
// calling instance of our new handler expects a bad_alloc exception
class BaseExport MemoryException: public Exception, virtual public std::bad_alloc
#else
class BaseExport MemoryException: public Exception
#endif
{
public:
explicit MemoryException(const std::string& = "Not enough memory available");
#if defined(__GNUC__)
const char* what() const noexcept override;
#endif
PyObject* getPyExceptionType() const override;
};
/** can be used in an own signal handler */
class BaseExport AccessViolation: public Exception
{
public:
explicit AccessViolation(const std::string& message = "Access violation");
PyObject* getPyExceptionType() const override;
};
/** can be used in an own signal handler */
class BaseExport AbnormalProgramTermination: public Exception
{
public:
explicit AbnormalProgramTermination(const std::string& message = "Abnormal program termination");
PyObject* getPyExceptionType() const override;
};
class BaseExport UnknownProgramOption: public Exception
{
public:
explicit UnknownProgramOption(const std::string& message = "Unknown program option");
PyObject* getPyExceptionType() const override;
};
class BaseExport ProgramInformation: public Exception
{
public:
explicit ProgramInformation(const std::string& message = "Program information");
};
class BaseExport TypeError: public Exception
{
public:
explicit TypeError(const std::string& message = "Type error");
PyObject* getPyExceptionType() const override;
};
class BaseExport ValueError: public Exception
{
public:
explicit ValueError(const std::string& message = "Value error");
PyObject* getPyExceptionType() const override;
};
/** sequence subscript is out of range */
class BaseExport IndexError: public Exception
{
public:
explicit IndexError(const std::string& message = "Index error");
PyObject* getPyExceptionType() const override;
};
class BaseExport NameError: public Exception
{
public:
explicit NameError(const std::string& message = "Name error");
PyObject* getPyExceptionType() const override;
};
class BaseExport ImportError: public Exception
{
public:
explicit ImportError(const std::string& message = "Import error");
PyObject* getPyExceptionType() const override;
};
class BaseExport AttributeError: public Exception
{
public:
explicit AttributeError(const std::string& message = "Attribute error");
PyObject* getPyExceptionType() const override;
};
class BaseExport PropertyError: public AttributeError
{
public:
explicit PropertyError(const std::string& message = "Property error");
PyObject* getPyExceptionType() const override;
};
class BaseExport RuntimeError: public Exception
{
public:
explicit RuntimeError(const std::string& message = "Runtime error");
PyObject* getPyExceptionType() const override;
};
class BaseExport BadGraphError: public RuntimeError
{
public:
explicit BadGraphError(const std::string& message = "Bad graph error");
PyObject* getPyExceptionType() const override;
};
class BaseExport NotImplementedError: public Exception
{
public:
explicit NotImplementedError(const std::string& message = "Not implemented error");
PyObject* getPyExceptionType() const override;
};
class BaseExport ZeroDivisionError: public Exception
{
public:
explicit ZeroDivisionError(const std::string& message = "Zero division error");
PyObject* getPyExceptionType() const override;
};
class BaseExport ReferenceError: public Exception
{
public:
explicit ReferenceError(const std::string& message = "Reference error");
PyObject* getPyExceptionType() const override;
};
class BaseExport ExpressionError: public Exception
{
public:
explicit ExpressionError(const std::string& message = "Expression error");
PyObject* getPyExceptionType() const override;
};
class BaseExport ParserError: public Exception
{
public:
explicit ParserError(const std::string& message = "Parser error");
PyObject* getPyExceptionType() const override;
};
class BaseExport UnicodeError: public Exception
{
public:
explicit UnicodeError(const std::string& message = "Unicode error");
PyObject* getPyExceptionType() const override;
};
class BaseExport OverflowError: public Exception
{
public:
explicit OverflowError(const std::string& message = "Overflow error");
PyObject* getPyExceptionType() const override;
};
class BaseExport UnderflowError: public Exception
{
public:
explicit UnderflowError(const std::string& message = "Underflow error");
PyObject* getPyExceptionType() const override;
};
class BaseExport UnitsMismatchError: public Exception
{
public:
explicit UnitsMismatchError(const std::string& message = "Units mismatch error");
PyObject* getPyExceptionType() const override;
};
class BaseExport CADKernelError: public Exception
{
public:
explicit CADKernelError(const std::string& message = "CAD kernel error");
PyObject* getPyExceptionType() const override;
};
class BaseExport RestoreError: public Exception
{
public:
explicit RestoreError(const std::string& message = "Restore error");
PyObject* getPyExceptionType() const override;
};
inline void Exception::setMessage(const std::string& message)
{
errorMessage = message;
}
inline std::string Exception::getMessage() const
{
return errorMessage;
}
inline std::string Exception::getFile() const
{
return fileName;
}
inline int Exception::getLine() const
{
return lineNum;
}
inline std::string Exception::getFunction() const
{
return functionName;
}
inline bool Exception::getTranslatable() const
{
return isTranslatable;
}
inline bool Exception::getReported() const
{
return hasBeenReported;
}
inline void Exception::setReported(const bool reported) const
{
hasBeenReported = reported;
}
#if defined(HAVE_STD_SOURCE_LOCATION)
inline void Exception::setDebugInformation(const std::source_location& location)
{
fileName = location.file_name();
lineNum = static_cast<int>(location.line());
functionName = location.function_name();
}
#else
inline void Exception::setDebugInformation(const char* file, int line, const char* func)
{
fileName = file;
lineNum = line;
functionName = func;
}
#endif
inline void Exception::setTranslatable(const bool translatable)
{
isTranslatable = translatable;
}
#if defined(__GNUC__) && defined(FC_OS_LINUX)
class SignalException
{
public:
SignalException();
~SignalException();
private:
static void throw_signal(int signum);
struct sigaction new_action {}; // NOLINT (keep struct)
struct sigaction old_action {}; // NOLINT (keep struct)
bool ok {false};
};
#endif
} // namespace Base
#endif // BASE_EXCEPTION_H