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