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 file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 /**
8  * A struct that encapsulates a JSContex and information about
9  * which binding method was called.  The idea is to automatically annotate
10  * exceptions thrown via the BindingCallContext with the method name.
11  */
12 
13 #ifndef mozilla_dom_BindingCallContext_h
14 #define mozilla_dom_BindingCallContext_h
15 
16 #include <utility>
17 
18 #include "js/TypeDecls.h"
19 #include "mozilla/Assertions.h"
20 #include "mozilla/Attributes.h"
21 #include "mozilla/ErrorResult.h"
22 
23 namespace mozilla {
24 namespace dom {
25 
26 class MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS BindingCallContext {
27  public:
28   // aCx is allowed to be null.  If it is, the BindingCallContext should
29   // generally act like a null JSContext*: test false when tested as a boolean
30   // and produce nullptr when used as a JSContext*.
31   //
32   // aMethodDescription should be something with longer lifetime than this
33   // BindingCallContext.  Most simply, a string literal.  nullptr or "" is
34   // allowed if we want to not have any particular message description.  This
35   // argument corresponds to the "context" string used for DOM error codes that
36   // support one.  See Errors.msg and the documentation for
37   // ErrorResult::MaybeSetPendingException for details on he context arg.
BindingCallContext(JSContext * aCx,const char * aMethodDescription)38   BindingCallContext(JSContext* aCx, const char* aMethodDescription)
39       : mCx(aCx), mDescription(aMethodDescription) {}
40 
41   ~BindingCallContext() = default;
42 
43   // Allow passing a BindingCallContext as a JSContext*, as needed.
44   operator JSContext*() const { return mCx; }
45 
46   // Allow testing a BindingCallContext for falsiness, just like a
47   // JSContext* could be tested.
48   explicit operator bool() const { return !!mCx; }
49 
50   // Allow throwing an error message, if it has a context.
51   template <dom::ErrNum errorNumber, typename... Ts>
ThrowErrorMessage(Ts &&...aMessageArgs)52   bool ThrowErrorMessage(Ts&&... aMessageArgs) const {
53     static_assert(ErrorFormatHasContext[errorNumber],
54                   "We plan to add a context; it better be expected!");
55     MOZ_ASSERT(mCx);
56     return dom::ThrowErrorMessage<errorNumber>(
57         mCx, mDescription, std::forward<Ts>(aMessageArgs)...);
58   }
59 
60  private:
61   JSContext* const mCx;
62   const char* const mDescription;
63 };
64 
65 }  // namespace dom
66 }  // namespace mozilla
67 
68 #endif  // mozilla_dom_BindingCallContext_h
69