Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1810)

Unified Diff: base/logging.h

Issue 1193873004: Make CHECK_EQ and friends work properly in an if/else structure without braces. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Proposed re-working of unit-tests. Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | base/logging_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/logging.h
diff --git a/base/logging.h b/base/logging.h
index ea096d19f729cb9043b0a6fcaea7a935e0d943aa..9a19a447267d80e3c8ad46140ede354eb305e30c 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -480,16 +480,35 @@ const LogSeverity LOG_0 = LOG_ERROR;
#endif // _PREFAST_
+// Captures the result of a CHECK_EQ (for example) and facilitates testing as a
+// boolean.
+class CheckOpResult {
+ public:
+ // |message| must be null if and only if the check failed.
+ CheckOpResult(std::string* message) : message_(message) {}
+ // Returns true if the check succeeded.
+ operator bool() const { return !message_; }
+ // Returns the message.
+ std::string* message() { return message_; }
+
+ private:
+ std::string* message_;
+};
+
// Helper macro for binary operators.
// Don't use this macro directly in your code, use CHECK_EQ et al below.
-//
-// TODO(akalin): Rewrite this so that constructs like if (...)
-// CHECK_EQ(...) else { ... } work properly.
-#define CHECK_OP(name, op, val1, val2) \
- if (std::string* _result = \
- logging::Check##name##Impl((val1), (val2), \
- #val1 " " #op " " #val2)) \
- logging::LogMessage(__FILE__, __LINE__, _result).stream()
+// The 'switch' is used to prevent the 'if' from being ambiguous when the macro
+// is used in an 'if' clause such as:
+// if (a == 1)
+// CHECK_EQ(2, a);
+#define CHECK_OP(name, op, val1, val2) \
+ switch (0) case 0: default: \
+ if (logging::CheckOpResult _result = \
+ logging::Check##name##Impl((val1), (val2), \
+ #val1 " " #op " " #val2)) \
+ ; \
+ else \
+ logging::LogMessage(__FILE__, __LINE__, _result.message()).stream()
Nico 2015/07/14 20:22:41 So if you say DCHECK() << "foo"; won't the <<
erikwright (departed) 2015/07/14 20:33:08 It binds to the else, as desired. Note that CheckO
Nico 2015/07/14 20:47:09 Ah, sorry. This might be too tricky for people wit
#endif
@@ -665,12 +684,20 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
// Helper macro for binary operators.
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
-#define DCHECK_OP(name, op, val1, val2) \
- if (DCHECK_IS_ON()) \
- if (std::string* _result = logging::Check##name##Impl( \
- (val1), (val2), #val1 " " #op " " #val2)) \
- logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, _result) \
- .stream()
+// The 'switch' is used to prevent the 'if' from being ambiguous when the macro
+// is used in an 'if' clause such as:
+// if (a == 1)
+// DCHECK_EQ(2, a);
+#define DCHECK_OP(name, op, val1, val2) \
+ switch (0) case 0: default: \
+ if (logging::CheckOpResult _result = \
+ DCHECK_IS_ON() ? \
+ logging::Check##name##Impl((val1), (val2), \
+ #val1 " " #op " " #val2) : nullptr) \
+ ; \
+ else \
+ logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, \
+ _result.message()).stream()
// Equality/Inequality checks - compare two values, and log a
// LOG_DCHECK message including the two values when the result is not
« no previous file with comments | « no previous file | base/logging_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698