Check Errorf()/ErrnoErrorf() format string at compile time

fmtlib provides compile time checking of format strings that we're not
currently using.  This change makes Errorf() and ErrnoErrorf() into
macros such that we can take advantage of this capability.

Test: build successfully normally
Test: fail the build if using an invalid format string
Change-Id: Icb8ba8cb973bbd1fa4755a62e7598bdbb0113757
This commit is contained in:
Tom Cherry 2020-02-04 15:18:29 -08:00
parent c19b08a66a
commit f8e6bf6d81
3 changed files with 17 additions and 11 deletions

View file

@ -156,11 +156,11 @@ class Error {
Error& operator=(const Error&) = delete;
Error& operator=(Error&&) = delete;
template <typename... Args>
friend Error Errorf(const char* fmt, const Args&... args);
template <typename T, typename... Args>
friend Error ErrorfImpl(const T&& fmt, const Args&... args);
template <typename... Args>
friend Error ErrnoErrorf(const char* fmt, const Args&... args);
template <typename T, typename... Args>
friend Error ErrnoErrorfImpl(const T&& fmt, const Args&... args);
private:
Error(bool append_errno, int errno_to_append, const std::string& message)
@ -191,16 +191,24 @@ inline int ErrorCode(int code, T&& t, const Args&... args) {
return ErrorCode(code, args...);
}
template <typename... Args>
inline Error Errorf(const char* fmt, const Args&... args) {
// TODO(tomcherry): Remove this once we've removed all `using android::base::Errorf` and `using
// android::base::ErrnoErrorf` lines.
enum Errorf {};
enum ErrnoErrorf {};
template <typename T, typename... Args>
inline Error ErrorfImpl(const T&& fmt, const Args&... args) {
return Error(false, ErrorCode(0, args...), fmt::format(fmt, args...));
}
template <typename... Args>
inline Error ErrnoErrorf(const char* fmt, const Args&... args) {
template <typename T, typename... Args>
inline Error ErrnoErrorfImpl(const T&& fmt, const Args&... args) {
return Error(true, errno, fmt::format(fmt, args...));
}
#define Errorf(fmt, ...) android::base::ErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__)
#define ErrnoErrorf(fmt, ...) android::base::ErrnoErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__)
template <typename T>
using Result = android::base::expected<T, ResultError>;

View file

@ -362,7 +362,7 @@ TEST(result, error_with_fmt) {
result = Errorf("{} {}!", std::string("hello"), std::string("world"));
EXPECT_EQ("hello world!", result.error().message());
result = Errorf("{h} {w}!", fmt::arg("w", "world"), fmt::arg("h", "hello"));
result = Errorf("{1} {0}!", "world", "hello");
EXPECT_EQ("hello world!", result.error().message());
result = Errorf("hello world!");

View file

@ -22,8 +22,6 @@
#include <android-base/result.h>
using android::base::ErrnoError;
using android::base::ErrnoErrorf;
using android::base::Error;
using android::base::Errorf;
using android::base::Result;
using android::base::ResultError;