|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 /* Implementation of macros to ensure correct use of RAII Auto* objects. */ |
|
8 |
|
9 #ifndef mozilla_GuardObjects_h |
|
10 #define mozilla_GuardObjects_h |
|
11 |
|
12 #include "mozilla/Assertions.h" |
|
13 #include "mozilla/NullPtr.h" |
|
14 #include "mozilla/Types.h" |
|
15 |
|
16 #ifdef __cplusplus |
|
17 |
|
18 #ifdef DEBUG |
|
19 |
|
20 namespace mozilla { |
|
21 namespace detail { |
|
22 |
|
23 /* |
|
24 * The following classes are designed to cause assertions to detect |
|
25 * inadvertent use of guard objects as temporaries. In other words, |
|
26 * when we have a guard object whose only purpose is its constructor and |
|
27 * destructor (and is never otherwise referenced), the intended use |
|
28 * might be: |
|
29 * |
|
30 * AutoRestore savePainting(mIsPainting); |
|
31 * |
|
32 * but is is easy to accidentally write: |
|
33 * |
|
34 * AutoRestore(mIsPainting); |
|
35 * |
|
36 * which compiles just fine, but runs the destructor well before the |
|
37 * intended time. |
|
38 * |
|
39 * They work by adding (#ifdef DEBUG) an additional parameter to the |
|
40 * guard object's constructor, with a default value, so that users of |
|
41 * the guard object's API do not need to do anything. The default value |
|
42 * of this parameter is a temporary object. C++ (ISO/IEC 14882:1998), |
|
43 * section 12.2 [class.temporary], clauses 4 and 5 seem to assume a |
|
44 * guarantee that temporaries are destroyed in the reverse of their |
|
45 * construction order, but I actually can't find a statement that that |
|
46 * is true in the general case (beyond the two specific cases mentioned |
|
47 * there). However, it seems to be true. |
|
48 * |
|
49 * These classes are intended to be used only via the macros immediately |
|
50 * below them: |
|
51 * |
|
52 * MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER declares (ifdef DEBUG) a member |
|
53 * variable, and should be put where a declaration of a private |
|
54 * member variable would be placed. |
|
55 * MOZ_GUARD_OBJECT_NOTIFIER_PARAM should be placed at the end of the |
|
56 * parameters to each constructor of the guard object; it declares |
|
57 * (ifdef DEBUG) an additional parameter. (But use the *_ONLY_PARAM |
|
58 * variant for constructors that take no other parameters.) |
|
59 * MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL should likewise be used in |
|
60 * the implementation of such constructors when they are not inline. |
|
61 * MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT should be used in |
|
62 * the implementation of such constructors to pass the parameter to |
|
63 * a base class that also uses these macros |
|
64 * MOZ_GUARD_OBJECT_NOTIFIER_INIT is a statement that belongs in each |
|
65 * constructor. It uses the parameter declared by |
|
66 * MOZ_GUARD_OBJECT_NOTIFIER_PARAM. |
|
67 * |
|
68 * For more details, and examples of using these macros, see |
|
69 * https://developer.mozilla.org/en/Using_RAII_classes_in_Mozilla |
|
70 */ |
|
71 class GuardObjectNotifier |
|
72 { |
|
73 private: |
|
74 bool* statementDone; |
|
75 |
|
76 public: |
|
77 GuardObjectNotifier() : statementDone(nullptr) { } |
|
78 |
|
79 ~GuardObjectNotifier() { |
|
80 *statementDone = true; |
|
81 } |
|
82 |
|
83 void setStatementDone(bool* statementIsDone) { |
|
84 statementDone = statementIsDone; |
|
85 } |
|
86 }; |
|
87 |
|
88 class GuardObjectNotificationReceiver |
|
89 { |
|
90 private: |
|
91 bool statementDone; |
|
92 |
|
93 public: |
|
94 GuardObjectNotificationReceiver() : statementDone(false) { } |
|
95 |
|
96 ~GuardObjectNotificationReceiver() { |
|
97 /* |
|
98 * Assert that the guard object was not used as a temporary. (Note that |
|
99 * this assert might also fire if init is not called because the guard |
|
100 * object's implementation is not using the above macros correctly.) |
|
101 */ |
|
102 MOZ_ASSERT(statementDone); |
|
103 } |
|
104 |
|
105 void init(const GuardObjectNotifier& constNotifier) { |
|
106 /* |
|
107 * constNotifier is passed as a const reference so that we can pass a |
|
108 * temporary, but we really intend it as non-const. |
|
109 */ |
|
110 GuardObjectNotifier& notifier = const_cast<GuardObjectNotifier&>(constNotifier); |
|
111 notifier.setStatementDone(&statementDone); |
|
112 } |
|
113 }; |
|
114 |
|
115 } /* namespace detail */ |
|
116 } /* namespace mozilla */ |
|
117 |
|
118 #endif /* DEBUG */ |
|
119 |
|
120 #ifdef DEBUG |
|
121 # define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER \ |
|
122 mozilla::detail::GuardObjectNotificationReceiver _mCheckNotUsedAsTemporary; |
|
123 # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM \ |
|
124 , const mozilla::detail::GuardObjectNotifier& _notifier = \ |
|
125 mozilla::detail::GuardObjectNotifier() |
|
126 # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM \ |
|
127 const mozilla::detail::GuardObjectNotifier& _notifier = \ |
|
128 mozilla::detail::GuardObjectNotifier() |
|
129 # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL \ |
|
130 , const mozilla::detail::GuardObjectNotifier& _notifier |
|
131 # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL \ |
|
132 const mozilla::detail::GuardObjectNotifier& _notifier |
|
133 # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT \ |
|
134 , _notifier |
|
135 # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT \ |
|
136 _notifier |
|
137 # define MOZ_GUARD_OBJECT_NOTIFIER_INIT \ |
|
138 do { _mCheckNotUsedAsTemporary.init(_notifier); } while (0) |
|
139 #else |
|
140 # define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
|
141 # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM |
|
142 # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM |
|
143 # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL |
|
144 # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL |
|
145 # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT |
|
146 # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT |
|
147 # define MOZ_GUARD_OBJECT_NOTIFIER_INIT do { } while (0) |
|
148 #endif |
|
149 |
|
150 #endif /* __cplusplus */ |
|
151 |
|
152 #endif /* mozilla_GuardObjects_h */ |