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 #ifndef nsCOMPtr_h___
8 #define nsCOMPtr_h___
9
10 /*
11 * Having problems?
12 *
13 * See the User Manual at:
14 * https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Using_nsCOMPtr
15 *
16 *
17 * nsCOMPtr
18 * better than a raw pointer
19 * for owning objects
20 * -- scc
21 */
22
23 #include <type_traits>
24
25 #include "mozilla/AlreadyAddRefed.h"
26 #include "mozilla/Assertions.h"
27 #include "mozilla/Attributes.h"
28 #include "mozilla/RefPtr.h"
29 #include "nsCycleCollectionNoteChild.h"
30 #include "nsDebug.h" // for |NS_ASSERTION|
31 #include "nsISupportsUtils.h" // for |nsresult|, |NS_ADDREF|, |NS_GET_TEMPLATE_IID| et al
32
33 /*
34 * WARNING: This file defines several macros for internal use only. These
35 * macros begin with the prefix |NSCAP_|. Do not use these macros in your own
36 * code. They are for internal use only for cross-platform compatibility, and
37 * are subject to change without notice.
38 */
39
40 #ifdef _MSC_VER
41 // Under VC++, we win by inlining StartAssignment.
42 # define NSCAP_FEATURE_INLINE_STARTASSIGNMENT
43
44 // Also under VC++, at the highest warning level, we are overwhelmed with
45 // warnings about (unused) inline functions being removed. This is to be
46 // expected with templates, so we disable the warning.
47 # pragma warning(disable : 4514)
48 #endif
49
50 #define NSCAP_FEATURE_USE_BASE
51
52 #ifdef DEBUG
53 # define NSCAP_FEATURE_TEST_DONTQUERY_CASES
54 # undef NSCAP_FEATURE_USE_BASE
55 #endif
56
57 #ifdef __GNUC__
58 // Our use of nsCOMPtr_base::mRawPtr violates the C++ standard's aliasing
59 // rules. Mark it with the may_alias attribute so that gcc 3.3 and higher
60 // don't reorder instructions based on aliasing assumptions for
61 // this variable. Fortunately, gcc versions < 3.3 do not do any
62 // optimizations that break nsCOMPtr.
63
64 # define NS_MAY_ALIAS_PTR(t) t* __attribute__((__may_alias__))
65 #else
66 # define NS_MAY_ALIAS_PTR(t) t*
67 #endif
68
69 #if defined(NSCAP_DISABLE_DEBUG_PTR_TYPES)
70 # define NSCAP_FEATURE_USE_BASE
71 #endif
72
73 /*
74 * The following three macros (NSCAP_ADDREF, NSCAP_RELEASE, and
75 * NSCAP_LOG_ASSIGNMENT) allow external clients the ability to add logging or
76 * other interesting debug facilities. In fact, if you want |nsCOMPtr| to
77 * participate in the standard logging facility, you provide
78 * (e.g., in "nsISupportsImpl.h") suitable definitions
79 *
80 * #define NSCAP_ADDREF(this, ptr) NS_ADDREF(ptr)
81 * #define NSCAP_RELEASE(this, ptr) NS_RELEASE(ptr)
82 */
83
84 #ifndef NSCAP_ADDREF
85 # define NSCAP_ADDREF(this, ptr) (ptr)->AddRef()
86 #endif
87
88 #ifndef NSCAP_RELEASE
89 # define NSCAP_RELEASE(this, ptr) (ptr)->Release()
90 #endif
91
92 // Clients can define |NSCAP_LOG_ASSIGNMENT| to perform logging.
93 #ifdef NSCAP_LOG_ASSIGNMENT
94 // Remember that |NSCAP_LOG_ASSIGNMENT| was defined by some client so that we
95 // know to instantiate |~nsGetterAddRefs| in turn to note the external
96 // assignment into the |nsCOMPtr|.
97 # define NSCAP_LOG_EXTERNAL_ASSIGNMENT
98 #else
99 // ...otherwise, just strip it out of the code
100 # define NSCAP_LOG_ASSIGNMENT(this, ptr)
101 #endif
102
103 #ifndef NSCAP_LOG_RELEASE
104 # define NSCAP_LOG_RELEASE(this, ptr)
105 #endif
106
107 namespace mozilla {
108 template <class T>
109 class OwningNonNull;
110 } // namespace mozilla
111
112 template <class T>
dont_AddRef(T * aRawPtr)113 inline already_AddRefed<T> dont_AddRef(T* aRawPtr) {
114 return already_AddRefed<T>(aRawPtr);
115 }
116
117 template <class T>
dont_AddRef(already_AddRefed<T> && aAlreadyAddRefedPtr)118 inline already_AddRefed<T>&& dont_AddRef(
119 already_AddRefed<T>&& aAlreadyAddRefedPtr) {
120 return std::move(aAlreadyAddRefedPtr);
121 }
122
123 /*
124 * An nsCOMPtr_helper transforms commonly called getters into typesafe forms
125 * that are more convenient to call, and more efficient to use with |nsCOMPtr|s.
126 * Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc.
127 *
128 * Here are the rules for a helper:
129 * - it implements |operator()| to produce an interface pointer
130 * - (except for its name) |operator()| is a valid [XP]COM `getter'
131 * - the interface pointer that it returns is already |AddRef()|ed (as from
132 * any good getter)
133 * - it matches the type requested with the supplied |nsIID| argument
134 * - its constructor provides an optional |nsresult*| that |operator()| can
135 * fill in with an error when it is executed
136 *
137 * See |class nsGetInterface| for an example.
138 */
139 class MOZ_STACK_CLASS nsCOMPtr_helper {
140 public:
141 virtual nsresult NS_FASTCALL operator()(const nsIID&, void**) const = 0;
142 };
143
144 /*
145 * nsQueryInterface could have been implemented as an nsCOMPtr_helper to avoid
146 * adding specialized machinery in nsCOMPtr, but do_QueryInterface is called
147 * often enough that the codesize savings are big enough to warrant the
148 * specialcasing.
149 */
150 class MOZ_STACK_CLASS nsQueryInterfaceISupports {
151 public:
nsQueryInterfaceISupports(nsISupports * aRawPtr)152 explicit nsQueryInterfaceISupports(nsISupports* aRawPtr) : mRawPtr(aRawPtr) {}
153
154 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
155
156 private:
157 nsISupports* MOZ_OWNING_REF mRawPtr;
158 };
159
160 #ifndef NSCAP_FEATURE_USE_BASE
161 template <typename T>
162 class MOZ_STACK_CLASS nsQueryInterface final
163 : public nsQueryInterfaceISupports {
164 public:
nsQueryInterface(T * aRawPtr)165 explicit nsQueryInterface(T* aRawPtr)
166 : nsQueryInterfaceISupports(ToSupports(aRawPtr)) {}
167
operator()168 nsresult NS_FASTCALL operator()(const nsIID& aIID, void** aAnswer) const {
169 return nsQueryInterfaceISupports::operator()(aIID, aAnswer);
170 }
171 };
172 #endif // #ifndef NSCAP_FEATURE_USE_BASE
173
174 class MOZ_STACK_CLASS nsQueryInterfaceISupportsWithError {
175 public:
nsQueryInterfaceISupportsWithError(nsISupports * aRawPtr,nsresult * aError)176 nsQueryInterfaceISupportsWithError(nsISupports* aRawPtr, nsresult* aError)
177 : mRawPtr(aRawPtr), mErrorPtr(aError) {}
178
179 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
180
181 private:
182 nsISupports* MOZ_OWNING_REF mRawPtr;
183 nsresult* mErrorPtr;
184 };
185
186 #ifndef NSCAP_FEATURE_USE_BASE
187 template <typename T>
188 class MOZ_STACK_CLASS nsQueryInterfaceWithError final
189 : public nsQueryInterfaceISupportsWithError {
190 public:
nsQueryInterfaceWithError(T * aRawPtr,nsresult * aError)191 explicit nsQueryInterfaceWithError(T* aRawPtr, nsresult* aError)
192 : nsQueryInterfaceISupportsWithError(ToSupports(aRawPtr), aError) {}
193
operator()194 nsresult NS_FASTCALL operator()(const nsIID& aIID, void** aAnswer) const {
195 return nsQueryInterfaceISupportsWithError::operator()(aIID, aAnswer);
196 }
197 };
198 #endif // #ifndef NSCAP_FEATURE_USE_BASE
199
200 namespace mozilla {
201 // PointedToType<> is needed so that do_QueryInterface() will work with a
202 // variety of smart pointer types in addition to raw pointers. These types
203 // include RefPtr<>, nsCOMPtr<>, and OwningNonNull<>.
204 template <class T>
205 using PointedToType = std::remove_pointer_t<decltype(&*std::declval<T>())>;
206 } // namespace mozilla
207
208 #ifdef NSCAP_FEATURE_USE_BASE
209 template <class T>
do_QueryInterface(T aPtr)210 inline nsQueryInterfaceISupports do_QueryInterface(T aPtr) {
211 return nsQueryInterfaceISupports(
212 ToSupports(static_cast<mozilla::PointedToType<T>*>(aPtr)));
213 }
214
215 template <class T>
do_QueryInterface(T aPtr,nsresult * aError)216 inline nsQueryInterfaceISupportsWithError do_QueryInterface(T aPtr,
217 nsresult* aError) {
218 return nsQueryInterfaceISupportsWithError(
219 ToSupports(static_cast<mozilla::PointedToType<T>*>(aPtr)), aError);
220 }
221 #else
222 template <class T>
do_QueryInterface(T aPtr)223 inline nsQueryInterface<mozilla::PointedToType<T>> do_QueryInterface(T aPtr) {
224 return nsQueryInterface<mozilla::PointedToType<T>>(aPtr);
225 }
226
227 template <class T>
do_QueryInterface(T aRawPtr,nsresult * aError)228 inline nsQueryInterfaceWithError<mozilla::PointedToType<T>> do_QueryInterface(
229 T aRawPtr, nsresult* aError) {
230 return nsQueryInterfaceWithError<mozilla::PointedToType<T>>(aRawPtr, aError);
231 }
232
233 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
234
235 template <class T>
do_QueryInterface(already_AddRefed<T> &)236 inline void do_QueryInterface(already_AddRefed<T>&) {
237 // This signature exists solely to _stop_ you from doing the bad thing.
238 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
239 // someone else is an automatic leak. See bug 8221.
240 }
241
242 template <class T>
do_QueryInterface(already_AddRefed<T> &,nsresult *)243 inline void do_QueryInterface(already_AddRefed<T>&, nsresult*) {
244 // This signature exists solely to _stop_ you from doing the bad thing.
245 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
246 // someone else is an automatic leak. See bug 8221.
247 }
248
249 ////////////////////////////////////////////////////////////////////////////
250 // Using servicemanager with COMPtrs
251 class nsGetServiceByCID final {
252 public:
nsGetServiceByCID(const nsCID & aCID)253 explicit nsGetServiceByCID(const nsCID& aCID) : mCID(aCID) {}
254
255 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
256
257 private:
258 const nsCID& mCID;
259 };
260
261 class nsGetServiceByCIDWithError final {
262 public:
nsGetServiceByCIDWithError(const nsCID & aCID,nsresult * aErrorPtr)263 nsGetServiceByCIDWithError(const nsCID& aCID, nsresult* aErrorPtr)
264 : mCID(aCID), mErrorPtr(aErrorPtr) {}
265
266 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
267
268 private:
269 const nsCID& mCID;
270 nsresult* mErrorPtr;
271 };
272
273 class nsGetServiceByContractID final {
274 public:
nsGetServiceByContractID(const char * aContractID)275 explicit nsGetServiceByContractID(const char* aContractID)
276 : mContractID(aContractID) {}
277
278 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
279
280 private:
281 const char* mContractID;
282 };
283
284 class nsGetServiceByContractIDWithError final {
285 public:
nsGetServiceByContractIDWithError(const char * aContractID,nsresult * aErrorPtr)286 nsGetServiceByContractIDWithError(const char* aContractID,
287 nsresult* aErrorPtr)
288 : mContractID(aContractID), mErrorPtr(aErrorPtr) {}
289
290 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
291
292 private:
293 const char* mContractID;
294 nsresult* mErrorPtr;
295 };
296
297 class nsIWeakReference;
298
299 // Weak references
300 class MOZ_STACK_CLASS nsQueryReferent final {
301 public:
nsQueryReferent(nsIWeakReference * aWeakPtr,nsresult * aError)302 nsQueryReferent(nsIWeakReference* aWeakPtr, nsresult* aError)
303 : mWeakPtr(aWeakPtr), mErrorPtr(aError) {}
304
305 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
306
307 private:
308 nsIWeakReference* MOZ_NON_OWNING_REF mWeakPtr;
309 nsresult* mErrorPtr;
310 };
311
312 /**
313 * Factors implementation for all template versions of nsCOMPtr.
314 *
315 * Here's the way people normally do things like this:
316 *
317 * template<class T> class Foo { ... };
318 * template<> class Foo<void*> { ... };
319 * template<class T> class Foo<T*> : private Foo<void*> { ... };
320 */
321 class nsCOMPtr_base {
322 public:
mRawPtr(aRawPtr)323 explicit nsCOMPtr_base(nsISupports* aRawPtr = nullptr) : mRawPtr(aRawPtr) {}
324
~nsCOMPtr_base()325 NS_CONSTRUCTOR_FASTCALL ~nsCOMPtr_base() {
326 NSCAP_LOG_RELEASE(this, mRawPtr);
327 if (mRawPtr) {
328 NSCAP_RELEASE(this, mRawPtr);
329 }
330 }
331
332 void NS_FASTCALL assign_with_AddRef(nsISupports*);
333 void NS_FASTCALL assign_from_qi(const nsQueryInterfaceISupports,
334 const nsIID&);
335 void NS_FASTCALL assign_from_qi_with_error(
336 const nsQueryInterfaceISupportsWithError&, const nsIID&);
337 void NS_FASTCALL assign_from_gs_cid(const nsGetServiceByCID, const nsIID&);
338 void NS_FASTCALL assign_from_gs_cid_with_error(
339 const nsGetServiceByCIDWithError&, const nsIID&);
340 void NS_FASTCALL assign_from_gs_contractid(const nsGetServiceByContractID,
341 const nsIID&);
342 void NS_FASTCALL assign_from_gs_contractid_with_error(
343 const nsGetServiceByContractIDWithError&, const nsIID&);
344 void NS_FASTCALL assign_from_query_referent(const nsQueryReferent&,
345 const nsIID&);
346 void NS_FASTCALL assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
347 // Since in most cases, begin_assignment is called on a default-constructed
348 // nsCOMPtr, the call to assign_assuming_AddRef becomes a no-op in release
349 // builds. However, the compiler does not always optimize this away and emits a
350 // call to begin_assignment without MOZ_ALWAYS_INLINE. When logging is enabled,
351 // this might cause code bloat, so we MOZ_NEVER_INLINE in that case.
352 #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
353 MOZ_NEVER_INLINE
354 #else
355 MOZ_ALWAYS_INLINE
356 #endif
begin_assignment()357 void** NS_FASTCALL begin_assignment() {
358 assign_assuming_AddRef(nullptr);
359 return reinterpret_cast<void**>(&mRawPtr);
360 }
361
362 protected:
NS_MAY_ALIAS_PTR(nsISupports)363 NS_MAY_ALIAS_PTR(nsISupports) MOZ_OWNING_REF mRawPtr;
364
365 void assign_assuming_AddRef(nsISupports* aNewPtr) {
366 // |AddRef()|ing the new value (before entering this function) before
367 // |Release()|ing the old lets us safely ignore the self-assignment case.
368 // We must, however, be careful only to |Release()| _after_ doing the
369 // assignment, in case the |Release()| leads to our _own_ destruction,
370 // which would, in turn, cause an incorrect second |Release()| of our old
371 // pointer. Thank <waterson@netscape.com> for discovering this.
372 nsISupports* oldPtr = mRawPtr;
373 mRawPtr = aNewPtr;
374 NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
375 NSCAP_LOG_RELEASE(this, oldPtr);
376 if (oldPtr) {
377 NSCAP_RELEASE(this, oldPtr);
378 }
379 }
380 };
381
382 // template<class T> class nsGetterAddRefs;
383
384 // Helper for assert_validity method
385 template <class T>
386 char (&TestForIID(decltype(&NS_GET_TEMPLATE_IID(T))))[2];
387 template <class T>
388 char TestForIID(...);
389
390 template <class T>
391 class MOZ_IS_REFPTR nsCOMPtr final
392 #ifdef NSCAP_FEATURE_USE_BASE
393 : private nsCOMPtr_base
394 #endif
395 {
396 private:
397 #ifdef NSCAP_FEATURE_USE_BASE
398 # define NSCAP_CTOR_BASE(x) nsCOMPtr_base(ToSupports(x))
assign_assuming_AddRef(T * aNewPtr)399 void assign_assuming_AddRef(T* aNewPtr) {
400 nsCOMPtr_base::assign_assuming_AddRef(ToSupports(aNewPtr));
401 }
402 #else
403 # define NSCAP_CTOR_BASE(x) mRawPtr(x)
404
405 void assign_with_AddRef(nsISupports*);
406 template <typename U>
407 void assign_from_qi(const nsQueryInterface<U>, const nsIID&);
408 template <typename U>
409 void assign_from_qi_with_error(const nsQueryInterfaceWithError<U>&,
410 const nsIID&);
411 void assign_from_gs_cid(const nsGetServiceByCID, const nsIID&);
412 void assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError&,
413 const nsIID&);
414 void assign_from_gs_contractid(const nsGetServiceByContractID, const nsIID&);
415 void assign_from_gs_contractid_with_error(
416 const nsGetServiceByContractIDWithError&, const nsIID&);
417 void assign_from_query_referent(const nsQueryReferent&, const nsIID&);
418 void assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
419 void** begin_assignment();
420
421 void assign_assuming_AddRef(T* aNewPtr) {
422 T* oldPtr = mRawPtr;
423 mRawPtr = aNewPtr;
424 NSCAP_LOG_ASSIGNMENT(this, aNewPtr);
425 NSCAP_LOG_RELEASE(this, oldPtr);
426 if (oldPtr) {
427 NSCAP_RELEASE(this, oldPtr);
428 }
429 }
430
431 private:
432 T* MOZ_OWNING_REF mRawPtr;
433 #endif
434
assert_validity()435 void assert_validity() {
436 static_assert(1 < sizeof(TestForIID<T>(nullptr)),
437 "nsCOMPtr only works "
438 "for types with IIDs. Either use RefPtr; add an IID to "
439 "your type with NS_DECLARE_STATIC_IID_ACCESSOR/"
440 "NS_DEFINE_STATIC_IID_ACCESSOR; or make the nsCOMPtr point "
441 "to a base class with an IID.");
442 }
443
444 public:
445 typedef T element_type;
446
447 #ifndef NSCAP_FEATURE_USE_BASE
~nsCOMPtr()448 ~nsCOMPtr() {
449 NSCAP_LOG_RELEASE(this, mRawPtr);
450 if (mRawPtr) {
451 NSCAP_RELEASE(this, mRawPtr);
452 }
453 }
454 #endif
455
456 #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
Assert_NoQueryNeeded()457 void Assert_NoQueryNeeded() {
458 if (mRawPtr) {
459 // This can't be defined in terms of do_QueryInterface because
460 // that bans casts from a class to itself.
461 void* out = nullptr;
462 mRawPtr->QueryInterface(NS_GET_TEMPLATE_IID(T), &out);
463 T* query_result = static_cast<T*>(out);
464 MOZ_ASSERT(query_result == mRawPtr, "QueryInterface needed");
465 NS_RELEASE(query_result);
466 }
467 }
468
469 # define NSCAP_ASSERT_NO_QUERY_NEEDED() Assert_NoQueryNeeded();
470 #else
471 # define NSCAP_ASSERT_NO_QUERY_NEEDED()
472 #endif
473
474 // Constructors
475
nsCOMPtr()476 nsCOMPtr() : NSCAP_CTOR_BASE(nullptr) {
477 assert_validity();
478 NSCAP_LOG_ASSIGNMENT(this, nullptr);
479 }
480
nsCOMPtr(decltype (nullptr))481 MOZ_IMPLICIT nsCOMPtr(decltype(nullptr)) : NSCAP_CTOR_BASE(nullptr) {
482 assert_validity();
483 NSCAP_LOG_ASSIGNMENT(this, nullptr);
484 }
485
nsCOMPtr(const nsCOMPtr<T> & aSmartPtr)486 nsCOMPtr(const nsCOMPtr<T>& aSmartPtr) : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) {
487 assert_validity();
488 if (mRawPtr) {
489 NSCAP_ADDREF(this, mRawPtr);
490 }
491 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
492 }
493
494 template <class U>
nsCOMPtr(const nsCOMPtr<U> & aSmartPtr)495 MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr<U>& aSmartPtr)
496 : NSCAP_CTOR_BASE(aSmartPtr.get()) {
497 // Make sure that U actually inherits from T
498 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
499 assert_validity();
500 if (mRawPtr) {
501 NSCAP_ADDREF(this, mRawPtr);
502 }
503 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.get());
504 }
505
nsCOMPtr(nsCOMPtr<T> && aSmartPtr)506 nsCOMPtr(nsCOMPtr<T>&& aSmartPtr) : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) {
507 assert_validity();
508 aSmartPtr.mRawPtr = nullptr;
509 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
510 }
511
512 template <class U>
nsCOMPtr(nsCOMPtr<U> && aSmartPtr)513 MOZ_IMPLICIT nsCOMPtr(nsCOMPtr<U>&& aSmartPtr)
514 : NSCAP_CTOR_BASE(aSmartPtr.forget().template downcast<T>().take()) {
515 // Make sure that U actually inherits from T
516 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
517 assert_validity();
518 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
519 NSCAP_ASSERT_NO_QUERY_NEEDED();
520 }
521
nsCOMPtr(T * aRawPtr)522 MOZ_IMPLICIT nsCOMPtr(T* aRawPtr) : NSCAP_CTOR_BASE(aRawPtr) {
523 assert_validity();
524 if (mRawPtr) {
525 NSCAP_ADDREF(this, mRawPtr);
526 }
527 NSCAP_LOG_ASSIGNMENT(this, aRawPtr);
528 NSCAP_ASSERT_NO_QUERY_NEEDED();
529 }
530
nsCOMPtr(already_AddRefed<T> & aSmartPtr)531 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>& aSmartPtr)
532 : NSCAP_CTOR_BASE(aSmartPtr.take()) {
533 assert_validity();
534 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
535 NSCAP_ASSERT_NO_QUERY_NEEDED();
536 }
537
538 // Construct from |otherComPtr.forget()|.
nsCOMPtr(already_AddRefed<T> && aSmartPtr)539 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>&& aSmartPtr)
540 : NSCAP_CTOR_BASE(aSmartPtr.take()) {
541 assert_validity();
542 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
543 NSCAP_ASSERT_NO_QUERY_NEEDED();
544 }
545
546 // Construct from |std::move(otherRefPtr)|.
547 template <typename U>
nsCOMPtr(RefPtr<U> && aSmartPtr)548 MOZ_IMPLICIT nsCOMPtr(RefPtr<U>&& aSmartPtr)
549 : NSCAP_CTOR_BASE(
550 static_cast<already_AddRefed<T>>(aSmartPtr.forget()).take()) {
551 assert_validity();
552 // Make sure that U actually inherits from T
553 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
554 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
555 NSCAP_ASSERT_NO_QUERY_NEEDED();
556 }
557
558 // Construct from |already_AddRefed|.
559 template <typename U>
nsCOMPtr(already_AddRefed<U> & aSmartPtr)560 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>& aSmartPtr)
561 : NSCAP_CTOR_BASE(static_cast<T*>(aSmartPtr.take())) {
562 assert_validity();
563 // But make sure that U actually inherits from T.
564 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
565 NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr));
566 NSCAP_ASSERT_NO_QUERY_NEEDED();
567 }
568
569 // Construct from |otherComPtr.forget()|.
570 template <typename U>
nsCOMPtr(already_AddRefed<U> && aSmartPtr)571 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>&& aSmartPtr)
572 : NSCAP_CTOR_BASE(static_cast<T*>(aSmartPtr.take())) {
573 assert_validity();
574 // But make sure that U actually inherits from T.
575 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
576 NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr));
577 NSCAP_ASSERT_NO_QUERY_NEEDED();
578 }
579
580 // Construct from |do_QueryInterface(expr)|.
581 #ifdef NSCAP_FEATURE_USE_BASE
nsCOMPtr(const nsQueryInterfaceISupports aQI)582 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupports aQI)
583 #else
584 template <typename U>
585 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterface<U> aQI)
586 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
587 : NSCAP_CTOR_BASE(nullptr) {
588 assert_validity();
589 NSCAP_LOG_ASSIGNMENT(this, nullptr);
590 assign_from_qi(aQI, NS_GET_TEMPLATE_IID(T));
591 }
592
593 // Construct from |do_QueryInterface(expr, &rv)|.
594 #ifdef NSCAP_FEATURE_USE_BASE
nsCOMPtr(const nsQueryInterfaceISupportsWithError & aQI)595 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupportsWithError& aQI)
596 #else
597 template <typename U>
598 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceWithError<U>& aQI)
599 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
600 : NSCAP_CTOR_BASE(nullptr) {
601 assert_validity();
602 NSCAP_LOG_ASSIGNMENT(this, nullptr);
603 assign_from_qi_with_error(aQI, NS_GET_TEMPLATE_IID(T));
604 }
605
606 // Construct from |do_GetService(cid_expr)|.
nsCOMPtr(const nsGetServiceByCID aGS)607 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCID aGS)
608 : NSCAP_CTOR_BASE(nullptr) {
609 assert_validity();
610 NSCAP_LOG_ASSIGNMENT(this, nullptr);
611 assign_from_gs_cid(aGS, NS_GET_TEMPLATE_IID(T));
612 }
613
614 // Construct from |do_GetService(cid_expr, &rv)|.
nsCOMPtr(const nsGetServiceByCIDWithError & aGS)615 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCIDWithError& aGS)
616 : NSCAP_CTOR_BASE(nullptr) {
617 assert_validity();
618 NSCAP_LOG_ASSIGNMENT(this, nullptr);
619 assign_from_gs_cid_with_error(aGS, NS_GET_TEMPLATE_IID(T));
620 }
621
622 // Construct from |do_GetService(contractid_expr)|.
nsCOMPtr(const nsGetServiceByContractID aGS)623 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractID aGS)
624 : NSCAP_CTOR_BASE(nullptr) {
625 assert_validity();
626 NSCAP_LOG_ASSIGNMENT(this, nullptr);
627 assign_from_gs_contractid(aGS, NS_GET_TEMPLATE_IID(T));
628 }
629
630 // Construct from |do_GetService(contractid_expr, &rv)|.
nsCOMPtr(const nsGetServiceByContractIDWithError & aGS)631 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
632 : NSCAP_CTOR_BASE(nullptr) {
633 assert_validity();
634 NSCAP_LOG_ASSIGNMENT(this, nullptr);
635 assign_from_gs_contractid_with_error(aGS, NS_GET_TEMPLATE_IID(T));
636 }
637
638 // Construct from |do_QueryReferent(ptr)|
nsCOMPtr(const nsQueryReferent & aQueryReferent)639 MOZ_IMPLICIT nsCOMPtr(const nsQueryReferent& aQueryReferent)
640 : NSCAP_CTOR_BASE(nullptr) {
641 assert_validity();
642 NSCAP_LOG_ASSIGNMENT(this, nullptr);
643 assign_from_query_referent(aQueryReferent, NS_GET_TEMPLATE_IID(T));
644 }
645
646 // And finally, anything else we might need to construct from can exploit the
647 // nsCOMPtr_helper facility.
nsCOMPtr(const nsCOMPtr_helper & aHelper)648 MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper)
649 : NSCAP_CTOR_BASE(nullptr) {
650 assert_validity();
651 NSCAP_LOG_ASSIGNMENT(this, nullptr);
652 assign_from_helper(aHelper, NS_GET_TEMPLATE_IID(T));
653 NSCAP_ASSERT_NO_QUERY_NEEDED();
654 }
655
656 // Defined in OwningNonNull.h
657 template <class U>
658 MOZ_IMPLICIT nsCOMPtr(const mozilla::OwningNonNull<U>& aOther);
659
660 // Assignment operators
661
662 nsCOMPtr<T>& operator=(const nsCOMPtr<T>& aRhs) {
663 assign_with_AddRef(ToSupports(aRhs.mRawPtr));
664 return *this;
665 }
666
667 template <class U>
668 nsCOMPtr<T>& operator=(const nsCOMPtr<U>& aRhs) {
669 // Make sure that U actually inherits from T
670 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
671 assign_with_AddRef(ToSupports(static_cast<T*>(aRhs.get())));
672 return *this;
673 }
674
675 nsCOMPtr<T>& operator=(nsCOMPtr<T>&& aRhs) {
676 assign_assuming_AddRef(aRhs.forget().take());
677 return *this;
678 }
679
680 template <class U>
681 nsCOMPtr<T>& operator=(nsCOMPtr<U>&& aRhs) {
682 // Make sure that U actually inherits from T
683 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
684 assign_assuming_AddRef(aRhs.forget().template downcast<T>().take());
685 NSCAP_ASSERT_NO_QUERY_NEEDED();
686 return *this;
687 }
688
689 nsCOMPtr<T>& operator=(T* aRhs) {
690 assign_with_AddRef(ToSupports(aRhs));
691 NSCAP_ASSERT_NO_QUERY_NEEDED();
692 return *this;
693 }
694
decltype(nullptr)695 nsCOMPtr<T>& operator=(decltype(nullptr)) {
696 assign_assuming_AddRef(nullptr);
697 return *this;
698 }
699
700 // Assign from |already_AddRefed|.
701 template <typename U>
702 nsCOMPtr<T>& operator=(already_AddRefed<U>& aRhs) {
703 // Make sure that U actually inherits from T
704 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
705 assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
706 NSCAP_ASSERT_NO_QUERY_NEEDED();
707 return *this;
708 }
709
710 // Assign from |otherComPtr.forget()|.
711 template <typename U>
712 nsCOMPtr<T>& operator=(already_AddRefed<U>&& aRhs) {
713 // Make sure that U actually inherits from T
714 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
715 assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
716 NSCAP_ASSERT_NO_QUERY_NEEDED();
717 return *this;
718 }
719
720 // Assign from |std::move(otherRefPtr)|.
721 template <typename U>
722 nsCOMPtr<T>& operator=(RefPtr<U>&& aRhs) {
723 // Make sure that U actually inherits from T
724 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
725 assign_assuming_AddRef(static_cast<T*>(aRhs.forget().take()));
726 NSCAP_ASSERT_NO_QUERY_NEEDED();
727 return *this;
728 }
729
730 // Assign from |do_QueryInterface(expr)|.
731 #ifdef NSCAP_FEATURE_USE_BASE
732 nsCOMPtr<T>& operator=(const nsQueryInterfaceISupports aRhs)
733 #else
734 template <typename U>
735 nsCOMPtr<T>& operator=(const nsQueryInterface<U> aRhs)
736 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
737 {
738 assign_from_qi(aRhs, NS_GET_TEMPLATE_IID(T));
739 return *this;
740 }
741
742 // Assign from |do_QueryInterface(expr, &rv)|.
743 #ifdef NSCAP_FEATURE_USE_BASE
744 nsCOMPtr<T>& operator=(const nsQueryInterfaceISupportsWithError& aRhs)
745 #else
746 template <typename U>
747 nsCOMPtr<T>& operator=(const nsQueryInterfaceWithError<U>& aRhs)
748 #endif // ! #ifdef NSCAP_FEATURE_USE_BASE
749 {
750 assign_from_qi_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
751 return *this;
752 }
753
754 // Assign from |do_GetService(cid_expr)|.
755 nsCOMPtr<T>& operator=(const nsGetServiceByCID aRhs) {
756 assign_from_gs_cid(aRhs, NS_GET_TEMPLATE_IID(T));
757 return *this;
758 }
759
760 // Assign from |do_GetService(cid_expr, &rv)|.
761 nsCOMPtr<T>& operator=(const nsGetServiceByCIDWithError& aRhs) {
762 assign_from_gs_cid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
763 return *this;
764 }
765
766 // Assign from |do_GetService(contractid_expr)|.
767 nsCOMPtr<T>& operator=(const nsGetServiceByContractID aRhs) {
768 assign_from_gs_contractid(aRhs, NS_GET_TEMPLATE_IID(T));
769 return *this;
770 }
771
772 // Assign from |do_GetService(contractid_expr, &rv)|.
773 nsCOMPtr<T>& operator=(const nsGetServiceByContractIDWithError& aRhs) {
774 assign_from_gs_contractid_with_error(aRhs, NS_GET_TEMPLATE_IID(T));
775 return *this;
776 }
777
778 // Assign from |do_QueryReferent(ptr)|.
779 nsCOMPtr<T>& operator=(const nsQueryReferent& aRhs) {
780 assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(T));
781 return *this;
782 }
783
784 // And finally, anything else we might need to assign from can exploit the
785 // nsCOMPtr_helper facility.
786 nsCOMPtr<T>& operator=(const nsCOMPtr_helper& aRhs) {
787 assign_from_helper(aRhs, NS_GET_TEMPLATE_IID(T));
788 NSCAP_ASSERT_NO_QUERY_NEEDED();
789 return *this;
790 }
791
792 // Defined in OwningNonNull.h
793 template <class U>
794 nsCOMPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
795
796 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
swap(nsCOMPtr<T> & aRhs)797 void swap(nsCOMPtr<T>& aRhs) {
798 #ifdef NSCAP_FEATURE_USE_BASE
799 nsISupports* temp = aRhs.mRawPtr;
800 #else
801 T* temp = aRhs.mRawPtr;
802 #endif
803 NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr);
804 NSCAP_LOG_ASSIGNMENT(this, temp);
805 NSCAP_LOG_RELEASE(this, mRawPtr);
806 NSCAP_LOG_RELEASE(&aRhs, temp);
807 aRhs.mRawPtr = mRawPtr;
808 mRawPtr = temp;
809 // |aRhs| maintains the same invariants, so we don't need to
810 // |NSCAP_ASSERT_NO_QUERY_NEEDED|
811 }
812
813 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
swap(T * & aRhs)814 void swap(T*& aRhs) {
815 #ifdef NSCAP_FEATURE_USE_BASE
816 nsISupports* temp = ToSupports(aRhs);
817 #else
818 T* temp = aRhs;
819 #endif
820 NSCAP_LOG_ASSIGNMENT(this, temp);
821 NSCAP_LOG_RELEASE(this, mRawPtr);
822 aRhs = reinterpret_cast<T*>(mRawPtr);
823 mRawPtr = temp;
824 NSCAP_ASSERT_NO_QUERY_NEEDED();
825 }
826
827 // Other pointer operators
828
829 // Return the value of mRawPtr and null out mRawPtr. Useful for
830 // already_AddRefed return values.
forget()831 already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget() {
832 T* temp = nullptr;
833 swap(temp);
834 return already_AddRefed<T>(temp);
835 }
836
837 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
838 // Useful to avoid unnecessary AddRef/Release pairs with "out" parameters
839 // where aRhs bay be a T** or an I** where I is a base class of T.
840 template <typename I>
forget(I ** aRhs)841 void forget(I** aRhs) {
842 NS_ASSERTION(aRhs, "Null pointer passed to forget!");
843 NSCAP_LOG_RELEASE(this, mRawPtr);
844 *aRhs = get();
845 mRawPtr = nullptr;
846 }
847
848 // Prefer the implicit conversion provided automatically by
849 // |operator T*() const|. Use |get()| to resolve ambiguity or to get a
850 // castable pointer.
get()851 T* get() const { return reinterpret_cast<T*>(mRawPtr); }
852
853 // Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
854 // used in a context where a raw pointer is expected. It is this operator
855 // that makes an nsCOMPtr substitutable for a raw pointer.
856 //
857 // Prefer the implicit use of this operator to calling |get()|, except where
858 // necessary to resolve ambiguity.
859 operator T*() const& { return get(); }
860
861 // Don't allow implicit conversion of temporary nsCOMPtr to raw pointer,
862 // because the refcount might be one and the pointer will immediately become
863 // invalid.
864 operator T*() const&& = delete;
865
866 // Needed to avoid the deleted operator above
867 explicit operator bool() const { return !!mRawPtr; }
868
869 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
870 MOZ_ASSERT(mRawPtr != nullptr,
871 "You can't dereference a NULL nsCOMPtr with operator->().");
872 return get();
873 }
874
875 // These are not intended to be used by clients. See |address_of| below.
get_address()876 nsCOMPtr<T>* get_address() { return this; }
get_address()877 const nsCOMPtr<T>* get_address() const { return this; }
878
879 public:
880 T& operator*() const {
881 MOZ_ASSERT(mRawPtr != nullptr,
882 "You can't dereference a NULL nsCOMPtr with operator*().");
883 return *get();
884 }
885
StartAssignment()886 T** StartAssignment() {
887 #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
888 return reinterpret_cast<T**>(begin_assignment());
889 #else
890 assign_assuming_AddRef(nullptr);
891 return reinterpret_cast<T**>(&mRawPtr);
892 #endif
893 }
894 };
895
896 /*
897 * Specializing nsCOMPtr for nsISupports allows us to use nsCOMPtr<nsISupports>
898 * the same way people use nsISupports* and void*, i.e., as a `catch-all'
899 * pointing to any valid [XP]COM interface. Otherwise, an nsCOMPtr<nsISupports>
900 * would only be able to point to the single [XP]COM-correct nsISupports
901 * instance within an object; extra querying ensues. Clients need to be able to
902 * pass around arbitrary interface pointers, without hassles, through
903 * intermediary code that doesn't know the exact type.
904 */
905 template <>
906 class MOZ_IS_REFPTR nsCOMPtr<nsISupports> : private nsCOMPtr_base {
907 public:
908 typedef nsISupports element_type;
909
910 // Constructors
911
nsCOMPtr()912 nsCOMPtr() : nsCOMPtr_base(nullptr) { NSCAP_LOG_ASSIGNMENT(this, nullptr); }
913
nsCOMPtr(decltype (nullptr))914 MOZ_IMPLICIT nsCOMPtr(decltype(nullptr)) : nsCOMPtr_base(nullptr) {
915 NSCAP_LOG_ASSIGNMENT(this, nullptr);
916 }
917
nsCOMPtr(const nsCOMPtr<nsISupports> & aSmartPtr)918 nsCOMPtr(const nsCOMPtr<nsISupports>& aSmartPtr)
919 : nsCOMPtr_base(aSmartPtr.mRawPtr) {
920 if (mRawPtr) {
921 NSCAP_ADDREF(this, mRawPtr);
922 }
923 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr);
924 }
925
nsCOMPtr(nsISupports * aRawPtr)926 MOZ_IMPLICIT nsCOMPtr(nsISupports* aRawPtr) : nsCOMPtr_base(aRawPtr) {
927 if (mRawPtr) {
928 NSCAP_ADDREF(this, mRawPtr);
929 }
930 NSCAP_LOG_ASSIGNMENT(this, aRawPtr);
931 }
932
933 // Construct from |already_AddRefed|.
nsCOMPtr(already_AddRefed<nsISupports> & aSmartPtr)934 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<nsISupports>& aSmartPtr)
935 : nsCOMPtr_base(aSmartPtr.take()) {
936 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
937 }
938
939 // Construct from |otherComPtr.forget()|.
nsCOMPtr(already_AddRefed<nsISupports> && aSmartPtr)940 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<nsISupports>&& aSmartPtr)
941 : nsCOMPtr_base(aSmartPtr.take()) {
942 NSCAP_LOG_ASSIGNMENT(this, mRawPtr);
943 }
944
945 // Construct from |do_QueryInterface(expr)|.
nsCOMPtr(const nsQueryInterfaceISupports aQI)946 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupports aQI)
947 : nsCOMPtr_base(nullptr) {
948 NSCAP_LOG_ASSIGNMENT(this, nullptr);
949 assign_from_qi(aQI, NS_GET_IID(nsISupports));
950 }
951
952 // Construct from |do_QueryInterface(expr, &rv)|.
nsCOMPtr(const nsQueryInterfaceISupportsWithError & aQI)953 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceISupportsWithError& aQI)
954 : nsCOMPtr_base(nullptr) {
955 NSCAP_LOG_ASSIGNMENT(this, nullptr);
956 assign_from_qi_with_error(aQI, NS_GET_IID(nsISupports));
957 }
958
959 // Construct from |do_GetService(cid_expr)|.
nsCOMPtr(const nsGetServiceByCID aGS)960 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCID aGS) : nsCOMPtr_base(nullptr) {
961 NSCAP_LOG_ASSIGNMENT(this, nullptr);
962 assign_from_gs_cid(aGS, NS_GET_IID(nsISupports));
963 }
964
965 // Construct from |do_GetService(cid_expr, &rv)|.
nsCOMPtr(const nsGetServiceByCIDWithError & aGS)966 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCIDWithError& aGS)
967 : nsCOMPtr_base(nullptr) {
968 NSCAP_LOG_ASSIGNMENT(this, nullptr);
969 assign_from_gs_cid_with_error(aGS, NS_GET_IID(nsISupports));
970 }
971
972 // Construct from |do_GetService(contractid_expr)|.
nsCOMPtr(const nsGetServiceByContractID aGS)973 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractID aGS)
974 : nsCOMPtr_base(nullptr) {
975 NSCAP_LOG_ASSIGNMENT(this, nullptr);
976 assign_from_gs_contractid(aGS, NS_GET_IID(nsISupports));
977 }
978
979 // Construct from |do_GetService(contractid_expr, &rv)|.
nsCOMPtr(const nsGetServiceByContractIDWithError & aGS)980 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
981 : nsCOMPtr_base(nullptr) {
982 NSCAP_LOG_ASSIGNMENT(this, nullptr);
983 assign_from_gs_contractid_with_error(aGS, NS_GET_IID(nsISupports));
984 }
985
986 // Construct from |do_QueryReferent(ptr)|
nsCOMPtr(const nsQueryReferent & aQueryReferent)987 MOZ_IMPLICIT nsCOMPtr(const nsQueryReferent& aQueryReferent)
988 : nsCOMPtr_base(nullptr) {
989 NSCAP_LOG_ASSIGNMENT(this, nullptr);
990 assign_from_query_referent(aQueryReferent,
991 NS_GET_TEMPLATE_IID(nsISupports));
992 }
993
994 // And finally, anything else we might need to construct from can exploit
995 // the |nsCOMPtr_helper| facility
nsCOMPtr(const nsCOMPtr_helper & aHelper)996 MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper)
997 : nsCOMPtr_base(nullptr) {
998 NSCAP_LOG_ASSIGNMENT(this, nullptr);
999 assign_from_helper(aHelper, NS_GET_IID(nsISupports));
1000 }
1001
1002 // Assignment operators
1003
1004 nsCOMPtr<nsISupports>& operator=(const nsCOMPtr<nsISupports>& aRhs) {
1005 assign_with_AddRef(aRhs.mRawPtr);
1006 return *this;
1007 }
1008
1009 nsCOMPtr<nsISupports>& operator=(nsISupports* aRhs) {
1010 assign_with_AddRef(aRhs);
1011 return *this;
1012 }
1013
decltype(nullptr)1014 nsCOMPtr<nsISupports>& operator=(decltype(nullptr)) {
1015 assign_assuming_AddRef(nullptr);
1016 return *this;
1017 }
1018
1019 // Assign from |already_AddRefed|.
1020 nsCOMPtr<nsISupports>& operator=(already_AddRefed<nsISupports>& aRhs) {
1021 assign_assuming_AddRef(aRhs.take());
1022 return *this;
1023 }
1024
1025 // Assign from |otherComPtr.forget()|.
1026 nsCOMPtr<nsISupports>& operator=(already_AddRefed<nsISupports>&& aRhs) {
1027 assign_assuming_AddRef(aRhs.take());
1028 return *this;
1029 }
1030
1031 // Assign from |do_QueryInterface(expr)|.
1032 nsCOMPtr<nsISupports>& operator=(const nsQueryInterfaceISupports aRhs) {
1033 assign_from_qi(aRhs, NS_GET_IID(nsISupports));
1034 return *this;
1035 }
1036
1037 // Assign from |do_QueryInterface(expr, &rv)|.
1038 nsCOMPtr<nsISupports>& operator=(
1039 const nsQueryInterfaceISupportsWithError& aRhs) {
1040 assign_from_qi_with_error(aRhs, NS_GET_IID(nsISupports));
1041 return *this;
1042 }
1043
1044 // Assign from |do_GetService(cid_expr)|.
1045 nsCOMPtr<nsISupports>& operator=(const nsGetServiceByCID aRhs) {
1046 assign_from_gs_cid(aRhs, NS_GET_IID(nsISupports));
1047 return *this;
1048 }
1049
1050 // Assign from |do_GetService(cid_expr, &rv)|.
1051 nsCOMPtr<nsISupports>& operator=(const nsGetServiceByCIDWithError& aRhs) {
1052 assign_from_gs_cid_with_error(aRhs, NS_GET_IID(nsISupports));
1053 return *this;
1054 }
1055
1056 // Assign from |do_GetService(contractid_expr)|.
1057 nsCOMPtr<nsISupports>& operator=(const nsGetServiceByContractID aRhs) {
1058 assign_from_gs_contractid(aRhs, NS_GET_IID(nsISupports));
1059 return *this;
1060 }
1061
1062 // Assign from |do_GetService(contractid_expr, &rv)|.
1063 nsCOMPtr<nsISupports>& operator=(
1064 const nsGetServiceByContractIDWithError& aRhs) {
1065 assign_from_gs_contractid_with_error(aRhs, NS_GET_IID(nsISupports));
1066 return *this;
1067 }
1068
1069 // Assign from |do_QueryReferent(ptr)|.
1070 nsCOMPtr<nsISupports>& operator=(const nsQueryReferent& aRhs) {
1071 assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(nsISupports));
1072 return *this;
1073 }
1074
1075 // And finally, anything else we might need to assign from can exploit the
1076 // nsCOMPtr_helper facility
1077 nsCOMPtr<nsISupports>& operator=(const nsCOMPtr_helper& aRhs) {
1078 assign_from_helper(aRhs, NS_GET_IID(nsISupports));
1079 return *this;
1080 }
1081
1082 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
swap(nsCOMPtr<nsISupports> & aRhs)1083 void swap(nsCOMPtr<nsISupports>& aRhs) {
1084 nsISupports* temp = aRhs.mRawPtr;
1085 NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr);
1086 NSCAP_LOG_ASSIGNMENT(this, temp);
1087 NSCAP_LOG_RELEASE(this, mRawPtr);
1088 NSCAP_LOG_RELEASE(&aRhs, temp);
1089 aRhs.mRawPtr = mRawPtr;
1090 mRawPtr = temp;
1091 }
1092
1093 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
swap(nsISupports * & aRhs)1094 void swap(nsISupports*& aRhs) {
1095 nsISupports* temp = aRhs;
1096 NSCAP_LOG_ASSIGNMENT(this, temp);
1097 NSCAP_LOG_RELEASE(this, mRawPtr);
1098 aRhs = mRawPtr;
1099 mRawPtr = temp;
1100 }
1101
1102 // Return the value of mRawPtr and null out mRawPtr. Useful for
1103 // already_AddRefed return values.
forget()1104 already_AddRefed<nsISupports> forget() {
1105 nsISupports* temp = nullptr;
1106 swap(temp);
1107 return already_AddRefed<nsISupports>(temp);
1108 }
1109
1110 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
1111 // Useful to avoid unnecessary AddRef/Release pairs with "out"
1112 // parameters.
forget(nsISupports ** aRhs)1113 void forget(nsISupports** aRhs) {
1114 NS_ASSERTION(aRhs, "Null pointer passed to forget!");
1115 *aRhs = nullptr;
1116 swap(*aRhs);
1117 }
1118
1119 // Other pointer operators
1120
1121 // Prefer the implicit conversion provided automatically by
1122 // |operator nsISupports*() const|. Use |get()| to resolve ambiguity or to
1123 // get a castable pointer.
get()1124 nsISupports* get() const { return reinterpret_cast<nsISupports*>(mRawPtr); }
1125
1126 // Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
1127 // used in a context where a raw pointer is expected. It is this operator
1128 // that makes an nsCOMPtr substitutable for a raw pointer.
1129 //
1130 // Prefer the implicit use of this operator to calling |get()|, except where
1131 // necessary to resolve ambiguity/
1132 operator nsISupports*() const { return get(); }
1133
1134 nsISupports* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
1135 MOZ_ASSERT(mRawPtr != nullptr,
1136 "You can't dereference a NULL nsCOMPtr with operator->().");
1137 return get();
1138 }
1139
1140 // These are not intended to be used by clients. See |address_of| below.
get_address()1141 nsCOMPtr<nsISupports>* get_address() { return this; }
get_address()1142 const nsCOMPtr<nsISupports>* get_address() const { return this; }
1143
1144 public:
1145 nsISupports& operator*() const {
1146 MOZ_ASSERT(mRawPtr != nullptr,
1147 "You can't dereference a NULL nsCOMPtr with operator*().");
1148 return *get();
1149 }
1150
StartAssignment()1151 nsISupports** StartAssignment() {
1152 #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
1153 return reinterpret_cast<nsISupports**>(begin_assignment());
1154 #else
1155 assign_assuming_AddRef(nullptr);
1156 return reinterpret_cast<nsISupports**>(&mRawPtr);
1157 #endif
1158 }
1159 };
1160
1161 template <typename T>
ImplCycleCollectionUnlink(nsCOMPtr<T> & aField)1162 inline void ImplCycleCollectionUnlink(nsCOMPtr<T>& aField) {
1163 aField = nullptr;
1164 }
1165
1166 template <typename T>
1167 inline void ImplCycleCollectionTraverse(
1168 nsCycleCollectionTraversalCallback& aCallback, nsCOMPtr<T>& aField,
1169 const char* aName, uint32_t aFlags = 0) {
1170 CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
1171 }
1172
1173 #ifndef NSCAP_FEATURE_USE_BASE
1174 template <class T>
assign_with_AddRef(nsISupports * aRawPtr)1175 void nsCOMPtr<T>::assign_with_AddRef(nsISupports* aRawPtr) {
1176 if (aRawPtr) {
1177 NSCAP_ADDREF(this, aRawPtr);
1178 }
1179 assign_assuming_AddRef(reinterpret_cast<T*>(aRawPtr));
1180 }
1181
1182 template <class T>
1183 template <typename U>
assign_from_qi(const nsQueryInterface<U> aQI,const nsIID & aIID)1184 void nsCOMPtr<T>::assign_from_qi(const nsQueryInterface<U> aQI,
1185 const nsIID& aIID) {
1186 static_assert(
1187 !(std::is_same_v<T, U> || std::is_base_of<T, U>::value),
1188 "don't use do_QueryInterface for compile-time-determinable casts");
1189 void* newRawPtr;
1190 if (NS_FAILED(aQI(aIID, &newRawPtr))) {
1191 newRawPtr = nullptr;
1192 }
1193 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1194 }
1195
1196 template <class T>
1197 template <typename U>
assign_from_qi_with_error(const nsQueryInterfaceWithError<U> & aQI,const nsIID & aIID)1198 void nsCOMPtr<T>::assign_from_qi_with_error(
1199 const nsQueryInterfaceWithError<U>& aQI, const nsIID& aIID) {
1200 static_assert(
1201 !(std::is_same_v<T, U> || std::is_base_of<T, U>::value),
1202 "don't use do_QueryInterface for compile-time-determinable casts");
1203 void* newRawPtr;
1204 if (NS_FAILED(aQI(aIID, &newRawPtr))) {
1205 newRawPtr = nullptr;
1206 }
1207 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1208 }
1209
1210 template <class T>
assign_from_gs_cid(const nsGetServiceByCID aGS,const nsIID & aIID)1211 void nsCOMPtr<T>::assign_from_gs_cid(const nsGetServiceByCID aGS,
1212 const nsIID& aIID) {
1213 void* newRawPtr;
1214 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1215 newRawPtr = nullptr;
1216 }
1217 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1218 }
1219
1220 template <class T>
assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError & aGS,const nsIID & aIID)1221 void nsCOMPtr<T>::assign_from_gs_cid_with_error(
1222 const nsGetServiceByCIDWithError& aGS, const nsIID& aIID) {
1223 void* newRawPtr;
1224 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1225 newRawPtr = nullptr;
1226 }
1227 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1228 }
1229
1230 template <class T>
assign_from_gs_contractid(const nsGetServiceByContractID aGS,const nsIID & aIID)1231 void nsCOMPtr<T>::assign_from_gs_contractid(const nsGetServiceByContractID aGS,
1232 const nsIID& aIID) {
1233 void* newRawPtr;
1234 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1235 newRawPtr = nullptr;
1236 }
1237 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1238 }
1239
1240 template <class T>
assign_from_gs_contractid_with_error(const nsGetServiceByContractIDWithError & aGS,const nsIID & aIID)1241 void nsCOMPtr<T>::assign_from_gs_contractid_with_error(
1242 const nsGetServiceByContractIDWithError& aGS, const nsIID& aIID) {
1243 void* newRawPtr;
1244 if (NS_FAILED(aGS(aIID, &newRawPtr))) {
1245 newRawPtr = nullptr;
1246 }
1247 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1248 }
1249
1250 template <class T>
assign_from_query_referent(const nsQueryReferent & aQueryReferent,const nsIID & aIID)1251 void nsCOMPtr<T>::assign_from_query_referent(
1252 const nsQueryReferent& aQueryReferent, const nsIID& aIID) {
1253 void* newRawPtr;
1254 if (NS_FAILED(aQueryReferent(aIID, &newRawPtr))) {
1255 newRawPtr = nullptr;
1256 }
1257 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1258 }
1259
1260 template <class T>
assign_from_helper(const nsCOMPtr_helper & helper,const nsIID & aIID)1261 void nsCOMPtr<T>::assign_from_helper(const nsCOMPtr_helper& helper,
1262 const nsIID& aIID) {
1263 void* newRawPtr;
1264 if (NS_FAILED(helper(aIID, &newRawPtr))) {
1265 newRawPtr = nullptr;
1266 }
1267 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1268 }
1269
1270 template <class T>
begin_assignment()1271 void** nsCOMPtr<T>::begin_assignment() {
1272 assign_assuming_AddRef(nullptr);
1273 union {
1274 T** mT;
1275 void** mVoid;
1276 } result;
1277 result.mT = &mRawPtr;
1278 return result.mVoid;
1279 }
1280 #endif
1281
1282 template <class T>
address_of(nsCOMPtr<T> & aPtr)1283 inline nsCOMPtr<T>* address_of(nsCOMPtr<T>& aPtr) {
1284 return aPtr.get_address();
1285 }
1286
1287 template <class T>
address_of(const nsCOMPtr<T> & aPtr)1288 inline const nsCOMPtr<T>* address_of(const nsCOMPtr<T>& aPtr) {
1289 return aPtr.get_address();
1290 }
1291
1292 /**
1293 * This class is designed to be used for anonymous temporary objects in the
1294 * argument list of calls that return COM interface pointers, e.g.,
1295 *
1296 * nsCOMPtr<IFoo> fooP;
1297 * ...->QueryInterface(iid, getter_AddRefs(fooP))
1298 *
1299 * DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
1300 *
1301 * When initialized with a |nsCOMPtr|, as in the example above, it returns
1302 * a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call
1303 * (|QueryInterface| in this case) can fill in.
1304 *
1305 * This type should be a nested class inside |nsCOMPtr<T>|.
1306 */
1307 template <class T>
1308 class nsGetterAddRefs {
1309 public:
nsGetterAddRefs(nsCOMPtr<T> & aSmartPtr)1310 explicit nsGetterAddRefs(nsCOMPtr<T>& aSmartPtr)
1311 : mTargetSmartPtr(aSmartPtr) {}
1312
1313 #if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || \
1314 defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT)
~nsGetterAddRefs()1315 ~nsGetterAddRefs() {
1316 # ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
1317 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
1318 mTargetSmartPtr.get());
1319 # endif
1320
1321 # ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
1322 mTargetSmartPtr.Assert_NoQueryNeeded();
1323 # endif
1324 }
1325 #endif
1326
1327 operator void**() {
1328 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
1329 }
1330
1331 operator T**() { return mTargetSmartPtr.StartAssignment(); }
1332 T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
1333
1334 private:
1335 nsCOMPtr<T>& mTargetSmartPtr;
1336 };
1337
1338 template <>
1339 class nsGetterAddRefs<nsISupports> {
1340 public:
nsGetterAddRefs(nsCOMPtr<nsISupports> & aSmartPtr)1341 explicit nsGetterAddRefs(nsCOMPtr<nsISupports>& aSmartPtr)
1342 : mTargetSmartPtr(aSmartPtr) {}
1343
1344 #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
~nsGetterAddRefs()1345 ~nsGetterAddRefs() {
1346 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),
1347 mTargetSmartPtr.get());
1348 }
1349 #endif
1350
1351 operator void**() {
1352 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
1353 }
1354
1355 operator nsISupports**() { return mTargetSmartPtr.StartAssignment(); }
1356 nsISupports*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
1357
1358 private:
1359 nsCOMPtr<nsISupports>& mTargetSmartPtr;
1360 };
1361
1362 template <class T>
getter_AddRefs(nsCOMPtr<T> & aSmartPtr)1363 inline nsGetterAddRefs<T> getter_AddRefs(nsCOMPtr<T>& aSmartPtr) {
1364 return nsGetterAddRefs<T>(aSmartPtr);
1365 }
1366
1367 template <class T, class DestinationType>
CallQueryInterface(T * aSource,nsGetterAddRefs<DestinationType> aDestination)1368 inline nsresult CallQueryInterface(
1369 T* aSource, nsGetterAddRefs<DestinationType> aDestination) {
1370 return CallQueryInterface(aSource,
1371 static_cast<DestinationType**>(aDestination));
1372 }
1373
1374 // Comparing two |nsCOMPtr|s
1375
1376 template <class T, class U>
1377 inline bool operator==(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs) {
1378 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
1379 }
1380
1381 template <class T, class U>
1382 inline bool operator!=(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs) {
1383 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
1384 }
1385
1386 // Comparing an |nsCOMPtr| to a raw pointer
1387
1388 template <class T, class U>
1389 inline bool operator==(const nsCOMPtr<T>& aLhs, const U* aRhs) {
1390 return static_cast<const T*>(aLhs.get()) == aRhs;
1391 }
1392
1393 template <class T, class U>
1394 inline bool operator==(const U* aLhs, const nsCOMPtr<T>& aRhs) {
1395 return aLhs == static_cast<const T*>(aRhs.get());
1396 }
1397
1398 template <class T, class U>
1399 inline bool operator!=(const nsCOMPtr<T>& aLhs, const U* aRhs) {
1400 return static_cast<const T*>(aLhs.get()) != aRhs;
1401 }
1402
1403 template <class T, class U>
1404 inline bool operator!=(const U* aLhs, const nsCOMPtr<T>& aRhs) {
1405 return aLhs != static_cast<const T*>(aRhs.get());
1406 }
1407
1408 template <class T, class U>
1409 inline bool operator==(const nsCOMPtr<T>& aLhs, U* aRhs) {
1410 return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
1411 }
1412
1413 template <class T, class U>
1414 inline bool operator==(U* aLhs, const nsCOMPtr<T>& aRhs) {
1415 return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
1416 }
1417
1418 template <class T, class U>
1419 inline bool operator!=(const nsCOMPtr<T>& aLhs, U* aRhs) {
1420 return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
1421 }
1422
1423 template <class T, class U>
1424 inline bool operator!=(U* aLhs, const nsCOMPtr<T>& aRhs) {
1425 return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
1426 }
1427
1428 // Comparing an |nsCOMPtr| to |nullptr|
1429
1430 template <class T>
1431 inline bool operator==(const nsCOMPtr<T>& aLhs, decltype(nullptr)) {
1432 return aLhs.get() == nullptr;
1433 }
1434
1435 template <class T>
1436 inline bool operator==(decltype(nullptr), const nsCOMPtr<T>& aRhs) {
1437 return nullptr == aRhs.get();
1438 }
1439
1440 template <class T>
1441 inline bool operator!=(const nsCOMPtr<T>& aLhs, decltype(nullptr)) {
1442 return aLhs.get() != nullptr;
1443 }
1444
1445 template <class T>
1446 inline bool operator!=(decltype(nullptr), const nsCOMPtr<T>& aRhs) {
1447 return nullptr != aRhs.get();
1448 }
1449
1450 // Comparing any two [XP]COM objects for identity
1451
SameCOMIdentity(nsISupports * aLhs,nsISupports * aRhs)1452 inline bool SameCOMIdentity(nsISupports* aLhs, nsISupports* aRhs) {
1453 return nsCOMPtr<nsISupports>(do_QueryInterface(aLhs)) ==
1454 nsCOMPtr<nsISupports>(do_QueryInterface(aRhs));
1455 }
1456
1457 template <class SourceType, class DestinationType>
CallQueryInterface(nsCOMPtr<SourceType> & aSourcePtr,DestinationType ** aDestPtr)1458 inline nsresult CallQueryInterface(nsCOMPtr<SourceType>& aSourcePtr,
1459 DestinationType** aDestPtr) {
1460 return CallQueryInterface(aSourcePtr.get(), aDestPtr);
1461 }
1462
1463 template <class T>
RefPtr(const nsQueryReferent & aQueryReferent)1464 RefPtr<T>::RefPtr(const nsQueryReferent& aQueryReferent) {
1465 void* newRawPtr;
1466 if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1467 newRawPtr = nullptr;
1468 }
1469 mRawPtr = static_cast<T*>(newRawPtr);
1470 }
1471
1472 template <class T>
RefPtr(const nsCOMPtr_helper & aHelper)1473 RefPtr<T>::RefPtr(const nsCOMPtr_helper& aHelper) {
1474 void* newRawPtr;
1475 if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1476 newRawPtr = nullptr;
1477 }
1478 mRawPtr = static_cast<T*>(newRawPtr);
1479 }
1480
1481 template <class T>
1482 RefPtr<T>& RefPtr<T>::operator=(const nsQueryReferent& aQueryReferent) {
1483 void* newRawPtr;
1484 if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1485 newRawPtr = nullptr;
1486 }
1487 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1488 return *this;
1489 }
1490
1491 template <class T>
1492 RefPtr<T>& RefPtr<T>::operator=(const nsCOMPtr_helper& aHelper) {
1493 void* newRawPtr;
1494 if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))) {
1495 newRawPtr = nullptr;
1496 }
1497 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1498 return *this;
1499 }
1500
1501 template <class T>
do_AddRef(const nsCOMPtr<T> & aObj)1502 inline already_AddRefed<T> do_AddRef(const nsCOMPtr<T>& aObj) {
1503 nsCOMPtr<T> ref(aObj);
1504 return ref.forget();
1505 }
1506
1507 // MOZ_DBG support
1508
1509 template <class T>
1510 std::ostream& operator<<(std::ostream& aOut, const nsCOMPtr<T>& aObj) {
1511 return mozilla::DebugValue(aOut, aObj.get());
1512 }
1513
1514 // ToRefPtr allows to move an nsCOMPtr<T> into a RefPtr<T>. Be mindful when
1515 // using this, because usually RefPtr<T> should only be used with concrete T and
1516 // nsCOMPtr<T> should only be used with XPCOM interface T.
1517 template <class T>
ToRefPtr(nsCOMPtr<T> && aObj)1518 RefPtr<T> ToRefPtr(nsCOMPtr<T>&& aObj) {
1519 return aObj.forget();
1520 }
1521
1522 // Integration with ResultExtensions.h
1523 template <typename R>
ResultRefAsParam(nsCOMPtr<R> & aResult)1524 auto ResultRefAsParam(nsCOMPtr<R>& aResult) {
1525 return getter_AddRefs(aResult);
1526 }
1527
1528 namespace mozilla::detail {
1529 template <typename T>
1530 struct outparam_as_pointer;
1531
1532 template <typename T>
1533 struct outparam_as_pointer<nsGetterAddRefs<T>> {
1534 using type = T**;
1535 };
1536 } // namespace mozilla::detail
1537
1538 #endif // !defined(nsCOMPtr_h___)
1539