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