Bug 1323455 - refactor the checker to handle new exprs in return stmts draft
authorTristan Bourvon <tbourvon@mozilla.com>
Tue, 25 Jul 2017 17:51:57 +0200
changeset 615180 adb0724ad5126a8593738f0c1bc88af237746c3d
parent 615178 0980b2da9773343aa82e9bb6b0b63c8ffd72e8f0
child 639098 c0eb336b7b0eb7a6cc9b13540f779484d12b19c0
push id70263
push userbmo:tbourvon@mozilla.com
push dateTue, 25 Jul 2017 15:52:23 +0000
bugs1323455
milestone56.0a1
Bug 1323455 - refactor the checker to handle new exprs in return stmts The matcher will now check that every new expression in a return statement is returned into an already_AddRefed<> object. If this is not the case, the checker will suggest fixit hints to change the return type of the function and add do_AddRef around the new expression. MozReview-Commit-ID: 4BQXLRN5utp
build/clang-plugin/CustomMatchers.h
build/clang-plugin/RefCountedToRawAssignmentChecker.cpp
build/clang-plugin/RefCountedToRawAssignmentChecker.h
build/clang-plugin/tests/TestRefCountedToRawAssignment.cpp
mfbt/AlreadyAddRefed.h
mfbt/Attributes.h
--- a/build/clang-plugin/CustomMatchers.h
+++ b/build/clang-plugin/CustomMatchers.h
@@ -189,16 +189,20 @@ AST_MATCHER(CXXConstructorDecl, isIntere
       !Declaration->isDeleted();
 }
 
 AST_POLYMORPHIC_MATCHER(isFirstParty, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt)) {
   return !inThirdPartyPath(&Node, &Finder->getASTContext()) &&
          !ASTIsInSystemHeader(Finder->getASTContext(), Node);
 }
 
+AST_MATCHER_P(Expr, ignoreTrivials, internal::Matcher<Expr>, InnerMatcher) {
+  return InnerMatcher.matches(*IgnoreTrivials(&Node), Finder, Builder);
+}
+
 // We can't call this "isImplicit" since it clashes with an existing matcher in
 // clang.
 AST_MATCHER(CXXConstructorDecl, isMarkedImplicit) {
   return hasCustomAnnotation(&Node, "moz_implicit");
 }
 
 AST_MATCHER(CXXRecordDecl, isConcreteClass) { return !Node.isAbstract(); }
 
@@ -265,16 +269,27 @@ AST_MATCHER(QualType, isSmartPtrToRefCou
   }
 
   D = D->getCanonicalDecl();
 
   return D && (hasCustomAnnotation(D, "moz_is_refptr") ||
                hasCustomAnnotation(D, "moz_is_smartptr_to_refcounted"));
 }
 
+AST_MATCHER(QualType, isAlreadyAddRefed) {
+  auto *D = getNonTemplateSpecializedCXXRecordDecl(Node);
+  if (!D) {
+    return false;
+  }
+
+  D = D->getCanonicalDecl();
+
+  return D && hasCustomAnnotation(D, "moz_is_already_addrefed");
+}
+
 AST_MATCHER(CXXRecordDecl, hasBaseClasses) {
   const CXXRecordDecl *Decl = Node.getCanonicalDecl();
 
   // Must have definition and should inherit other classes
   return Decl && Decl->hasDefinition() && Decl->getNumBases();
 }
 
 AST_MATCHER(CXXMethodDecl, isRequiredBaseMethod) {
--- a/build/clang-plugin/RefCountedToRawAssignmentChecker.cpp
+++ b/build/clang-plugin/RefCountedToRawAssignmentChecker.cpp
@@ -2,138 +2,282 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "RefCountedToRawAssignmentChecker.h"
 #include "CustomMatchers.h"
 
 void RefCountedToRawAssignmentChecker::registerMatchers(
     MatchFinder *AstMatcher) {
-  AstMatcher->addMatcher(
-      // This is a matcher on a new expression,
-      cxxNewExpr(
-          isFirstParty(),
 
-          // which points to a class or struct,
-          hasType(pointsTo(cxxRecordDecl(
-              // and which is refcounted.
-              isRefCounted()))),
-
-          // and which doesn't have an ancestor,
+  auto HasNoRefPtrAncestor =
+      allOf(
+          // Doesn't have an ancestor,
           unless(hasAncestor(
               // which is a (possibly implicit) constructor expression,
               cxxConstructExpr(
-                  // which is a ref counted pointer.
+                  // which has a ref counted pointer type.
+                  hasType(isSmartPtrToRefCounted())))),
+
+          // and doesn't have an ancestor,
+          unless(hasAncestor(
+              // which is a an overloaded = operator,
+              cxxOperatorCallExpr(
+                  hasOverloadedOperatorName("="),
+                  // which has a LHS of ref counted pointer type.
                   hasType(isSmartPtrToRefCounted())))),
 
           // and which doesn't have an ancestor,
           unless(hasAncestor(
               // which is a call expression,
               callExpr(
                   // which is allowed to take new raw refcounted pointers.
                   callee(functionDecl(canTakeNewRawRefCounted()))))),
 
+          // and doesn't have an ancestor,
           unless(hasAncestor(
-              cxxOperatorCallExpr(
-                  hasOverloadedOperatorName("="),
-                  hasType(isSmartPtrToRefCounted())))),
-
-          unless(hasAncestor(
+              // which is an = operator,
               binaryOperator(
                   hasOperatorName("="),
+
+                  // which has a LHS of ref counted pointer type.
                   hasLHS(
                       anyOf(declRefExpr(hasType(isSmartPtrToRefCounted())),
                             memberExpr(member(hasType(isSmartPtrToRefCounted()))))
                   )))),
 
+          // and doesn't have an ancestor,
+          unless(hasAncestor(
+              // which is a variable declaration,
+              varDecl(
+                  // which has a ref counted pointer type.
+                  hasType(isSmartPtrToRefCounted())))),
+
+          // and doesn't have an ancestor,
+          unless(hasAncestor(
+              // which is a return statement,
+              returnStmt(forFunction(
+                  // which returns an already_AddRefed.
+                  returns(isAlreadyAddRefed()))))));
+
+  auto OptionalCorrespondingDeclaration =
+      anyOf(
+          hasNonTrivialParent(varDecl().bind("decl")),
+          // Here using hasParent(cxxConstructorInit()) doesn't work, so
+          // we need to match the constructor declaration and then find
+          // the initializer in the check() method.
+          hasNonTrivialParent(cxxConstructorDecl().bind("ctorDecl")),
+          hasNonTrivialParent(callExpr().bind("callExpr")),
+          // Assignment
+          hasNonTrivialParent(binaryOperator(
+              hasOperatorName("="),
+              hasLHS(
+                  // This is a bit basic but probably sufficient until we
+                  // have more powerful helpers to be able to have a full
+                  // coverage of this kind of cases.
+                  anyOf(declRefExpr(to(decl().bind("decl"))),
+                        memberExpr(hasDeclaration(decl().bind("decl"))))))),
+          // Corresponding function declaration for a return statement.
+          hasNonTrivialParent(returnStmt(
+              forFunction(functionDecl().bind("funcDeclForReturn")))),
+          // We put anything as the last option in the anyOf to basically
+          // make the previous declarations optional (there are cases
+          // where the new expression is not within a declaration, or
+          // within one we can't handle).
+          anything());
+
+  AstMatcher->addMatcher(
+      // This is a matcher on a new expression,
+      cxxNewExpr(
+          isFirstParty(),
+
+          // which points to a class or struct,
+          hasType(pointsTo(cxxRecordDecl(
+              // which is refcounted.
+              isRefCounted()))),
+
+          // and which has no ancestor constructing a ref ptr from this new
+          // expression,
+          HasNoRefPtrAncestor,
+
           // and which optionally has a corresponding declaration.
-          anyOf(
-              hasNonTrivialParent(varDecl().bind("decl")),
-              // Here using hasParent(cxxConstructorInit()) doesn't work, so
-              // we need to match the constructor declaration and then find
-              // the initializer in the check() method.
-              hasNonTrivialParent(cxxConstructorDecl().bind("ctorDecl")),
-              hasNonTrivialParent(callExpr().bind("callExpr")),
-              // Assignment
-              hasNonTrivialParent(binaryOperator(
-                  hasOperatorName("="),
-                  hasLHS(
-                      // This is a bit basic but probably sufficient until we
-                      // have more powerful helpers to be able to have a full
-                      // coverage of this kind of cases.
-                      anyOf(declRefExpr(to(decl().bind("decl"))),
-                            memberExpr(hasDeclaration(decl().bind("decl"))))))),
-              // We put anything as the last option in the anyOf to basically
-              // make the previous declarations optional (there are cases
-              // where the new expression is not within a declaration, or
-              // within one we can't handle).
-              anything()),
+          OptionalCorrespondingDeclaration,
 
           expr().bind("newExpr")),
       this);
 }
 
 void RefCountedToRawAssignmentChecker::check(
     const MatchFinder::MatchResult &Result) {
-  const char *Error = "`new %0` must be immediately constructed into a smart "
-                      "pointer";
-  const char *Note = "consider making %0 a %1";
-
   const CXXNewExpr *NewExpression =
       Result.Nodes.getNodeAs<CXXNewExpr>("newExpr");
 
-  // Optional object bindings.
+  // This is used if we have a new expression inside a return statement.
+  const FunctionDecl *FuncDeclForReturn =
+      Result.Nodes.getNodeAs<FunctionDecl>("funcDeclForReturn");
+
+  // Optional object bindings for corresponding declarations.
   const DeclaratorDecl *Declaration =
       Result.Nodes.getNodeAs<DeclaratorDecl>("decl");
   const CallExpr *Call = Result.Nodes.getNodeAs<CallExpr>("callExpr");
   const CXXConstructorDecl *CtorDeclaration =
       Result.Nodes.getNodeAs<CXXConstructorDecl>("ctorDecl");
 
   // Just in case.
   if (!NewExpression) {
     return;
   }
 
+  // If FundDeclForReturn exists, we're in the case where the new expression
+  // is in a return statement and we emit the diagnostics accordingly.
+  // Otherwise, we emit the regular diagnostics.
+  if (FuncDeclForReturn) {
+    newInReturnStatementCase(NewExpression, FuncDeclForReturn);
+  } else if (Call) {
+    newInCallExpressionCase(NewExpression, Call);
+  } else {
+    generalCase(NewExpression, Declaration, CtorDeclaration);
+  }
+}
+
+void RefCountedToRawAssignmentChecker::newInReturnStatementCase(
+    const CXXNewExpr *NewExpression, const FunctionDecl *FuncDeclForReturn) {
+  const char *Error = "`new %0` must be returned as `already_AddRefed<%0>`";
+  const char *ReturnFixitNote = "consider changing the return type here";
+  const char *AddRefFixitNote = "and adding `do_AddRef` here";
+
+  // We need this to build a printing policy for C++ so that we have
+  // `<class name>` instead of `class <class name>`.
+  LangOptions LO;
+  PrintingPolicy PP(LO);
+  PP.adjustForCPlusPlus();
+
+  // We emit the error diagnostic indicating that we are assigning a
+  // refcounted object to a raw pointer.
+  diag(NewExpression->getStartLoc(), Error, DiagnosticIDs::Error)
+      << NewExpression->getAllocatedType().getAsString(PP);
+
+  auto ReturnTypeRange = FuncDeclForReturn->getReturnTypeSourceRange();
+
+  if (!FuncDeclForReturn->getReturnType()->isPointerType()) {
+    return;
+  }
+
+  // We emit the note indicating the possible fix, along with the replacement
+  // hint to make return type `already_AddRefed<...>`.
+  diag(ReturnTypeRange.getBegin(), ReturnFixitNote, DiagnosticIDs::Note)
+      << FixItHint::CreateReplacement(
+            ReturnTypeRange,
+            "already_AddRefed<" +
+                FuncDeclForReturn->getReturnType()->getPointeeType()
+                                                   .getAsString(PP) +
+                ">");
+
+  // We also emit a hint to add `do_AddRef()` around the new expression.
+  diag(NewExpression->getLocStart(), AddRefFixitNote, DiagnosticIDs::Note)
+      << FixItHint::CreateInsertion(
+            NewExpression->getLocStart(),
+            "do_AddRef(")
+      << FixItHint::CreateInsertion(
+            NewExpression->getLocEnd(),
+            ")");
+}
+
+void RefCountedToRawAssignmentChecker::newInCallExpressionCase(
+    const CXXNewExpr *NewExpression, const CallExpr *Call) {
+  const char *Error = "`new %0` must be passed to function "
+                      "as `already_AddRefed<%0>`";
+  const char *ParamFixitNote = "consider changing the parameter type here";
+  const char *AddRefFixitNote = "and adding `do_AddRef` here";
+
   // We need this to build a printing policy for C++ so that we have
   // `<class name>` instead of `class <class name>`.
   LangOptions LO;
   PrintingPolicy PP(LO);
   PP.adjustForCPlusPlus();
 
-  // We emit the error diagnostic indicating that we are assigning a refcounted
-  // object to a raw pointer.
+  // We emit the error diagnostic indicating that we are assigning a
+  // refcounted object to a raw pointer.
+  diag(NewExpression->getStartLoc(), Error, DiagnosticIDs::Error)
+      << NewExpression->getAllocatedType().getAsString(PP);
+
+  // We get the param declaration from the call expression.
+
+  auto FuncDecl = Call->getDirectCallee();
+  if (!FuncDecl) {
+    return;
+  }
+
+  const ParmVarDecl* ParamDecl = nullptr;
+  unsigned ArgNum = 0;
+  for (auto Arg : Call->arguments()) {
+    if (IgnoreTrivials(Arg) == NewExpression) {
+      if (ArgNum < FuncDecl->getNumParams()) {
+        ParamDecl = FuncDecl->getParamDecl(ArgNum);
+      }
+      // We break regardless of the previous condition, because if that
+      // expression is false, it will be false for all the next iterations
+      // as well.
+      break;
+    }
+
+    ++ArgNum;
+  }
+
+  // Somehow we didn't find the corresponding declaration.
+  if (!ParamDecl) {
+    return;
+  }
+
+  if (!ParamDecl->getType()->isPointerType()) {
+    return;
+  }
+
+  auto ParamTypeLoc = ParamDecl->getTypeSourceInfo()->getTypeLoc();
+  // We emit the note indicating the possible fix, along with the replacement
+  // hint to make parameter type `already_AddRefed<...>`.
+  diag(ParamTypeLoc.getBeginLoc(), ParamFixitNote, DiagnosticIDs::Note)
+      << FixItHint::CreateReplacement(
+            ParamTypeLoc.getSourceRange(),
+            "already_AddRefed<" +
+                ParamDecl->getType()->getPointeeType().getAsString(PP) +
+                ">");
+
+  // We also emit a hint to add `do_AddRef()` around the new expression.
+  diag(NewExpression->getLocStart(), AddRefFixitNote, DiagnosticIDs::Note)
+      << FixItHint::CreateInsertion(
+            NewExpression->getLocStart(),
+            "do_AddRef(")
+      << FixItHint::CreateInsertion(
+            NewExpression->getLocEnd(),
+            ")");
+}
+
+void RefCountedToRawAssignmentChecker::generalCase(
+    const CXXNewExpr *NewExpression, const DeclaratorDecl *Declaration,
+    const CXXConstructorDecl *CtorDeclaration) {
+  const char *Error = "`new %0` must be immediately constructed into a smart "
+                      "pointer";
+  const char *FixitNote = "consider making %0 a RefPtr";
+
+  // We need this to build a printing policy for C++ so that we have
+  // `<class name>` instead of `class <class name>`.
+  LangOptions LO;
+  PrintingPolicy PP(LO);
+  PP.adjustForCPlusPlus();
+
+  // We emit the error diagnostic indicating that we are assigning a
+  // refcounted object to a raw pointer.
   diag(NewExpression->getStartLoc(), Error, DiagnosticIDs::Error)
       << NewExpression->getAllocatedType().getAsString(PP);
 
   // In case we don't directly have a declaration object, we might have to get
   // it indirectly from the other objects we bound to the matches.
   if (!Declaration) {
-    if (Call) {
-      // If this is a call, we get the param declaration from the call
-      // expression.
-      auto FuncDecl = Call->getDirectCallee();
-      if (!FuncDecl) {
-        return;
-      }
-
-      unsigned ArgNum = 0;
-      for (auto Arg : Call->arguments()) {
-        if (IgnoreTrivials(Arg) == NewExpression) {
-          if (ArgNum < FuncDecl->getNumParams()) {
-            Declaration = FuncDecl->getParamDecl(ArgNum);
-          }
-          // We break regardless of the previous condition, because if that
-          // expression is false, it will be false for all the next iterations
-          // as well.
-          break;
-        }
-
-        ++ArgNum;
-      }
-    } else if (CtorDeclaration) {
+    if (CtorDeclaration) {
       // If this is a constructor declaration, we get the field declaration from
       // the constructor initializer.
       for (auto Init : CtorDeclaration->inits()) {
         if (IgnoreTrivials(Init->getInit()) == NewExpression) {
           Declaration = Init->getMember();
           break;
         }
       }
@@ -144,33 +288,22 @@ void RefCountedToRawAssignmentChecker::c
     }
 
     // Somehow we didn't find the corresponding declaration.
     if (!Declaration) {
       return;
     }
   }
 
-  StringRef FixitType;
-  if (Call) {
-    // If we are within a call we want to emit a note to change the type to
-    // already_AddRefed.
-    FixitType = "already_AddRefed";
-  } else {
-    // Otherwise we want to change the type to RefPtr.
-    FixitType = "RefPtr";
-  }
-
   if (!Declaration->getType()->isPointerType()) {
     return;
   }
 
   // We emit the note indicating the possible fix, along with the replacement
-  // hint to turn the raw pointer into the new type.
-  diag(Declaration->getLocation(), Note, DiagnosticIDs::Note)
+  // hint to turn the raw pointer into a RefPtr.
+  diag(Declaration->getLocation(), FixitNote, DiagnosticIDs::Note)
       << Declaration->getName()
-      << FixitType
       << FixItHint::CreateReplacement(
           Declaration->getTypeSourceInfo()->getTypeLoc().getSourceRange(),
-          FixitType.str() + "<" +
+          "RefPtr<" +
               Declaration->getType()->getPointeeType().getAsString(PP) +
               ">");
 }
--- a/build/clang-plugin/RefCountedToRawAssignmentChecker.h
+++ b/build/clang-plugin/RefCountedToRawAssignmentChecker.h
@@ -9,11 +9,19 @@
 
 class RefCountedToRawAssignmentChecker : public BaseCheck {
 public:
   RefCountedToRawAssignmentChecker(StringRef CheckName,
                                    ContextType *Context = nullptr)
       : BaseCheck(CheckName, Context) {}
   void registerMatchers(MatchFinder *AstMatcher) override;
   void check(const MatchFinder::MatchResult &Result) override;
+
+  void newInReturnStatementCase(const CXXNewExpr *NewExpression,
+                                const FunctionDecl *FuncDeclForReturn);
+  void newInCallExpressionCase(const CXXNewExpr *NewExpression,
+                               const CallExpr *Call);
+  void generalCase(const CXXNewExpr *NewExpression,
+                   const DeclaratorDecl *Declaration,
+                   const CXXConstructorDecl *CtorDeclaration);
 };
 
 #endif
--- a/build/clang-plugin/tests/TestRefCountedToRawAssignment.cpp
+++ b/build/clang-plugin/tests/TestRefCountedToRawAssignment.cpp
@@ -21,19 +21,24 @@ public:
 private:
   RC1 *ptr;  // expected-note {{consider making ptr a RefPtr}}
   RC1 *ptr2; // expected-note {{consider making ptr2 a RefPtr}}
 
   RefPtr<RC1> refptr;
   RefPtr<RC1> refptr2;
 };
 
+RC1* f_ret() { // expected-note {{consider changing the return type here}}
+  return new RC1; // expected-error {{`new RC1` must be returned as `already_AddRefed<RC1>`}} \
+                     expected-note {{and adding `do_AddRef` here}}
+}
+
 void unused(RefPtr<RC1> refptr) {}
 
-void Func1(RC1 *ptr) {} // expected-note {{consider making ptr a already_AddRefed}}
+void Func1(RC1 *ptr) {} // expected-note {{consider changing the parameter type here}}
 
 void TestFunc() {
   new RC1; // expected-error {{`new RC1` must be immediately constructed into a smart pointer}}
   RC1 *ptr = new RC1; // expected-error {{`new RC1` must be immediately constructed into a smart pointer}} \
                          expected-note {{consider making ptr a RefPtr}}
 
   RC1 *ptr2(new RC1); // expected-error {{`new RC1` must be immediately constructed into a smart pointer}} \
                          expected-note {{consider making ptr2 a RefPtr}}
@@ -44,12 +49,13 @@ void TestFunc() {
   RC1 *ptr4 = new RC2; // expected-error {{`new RC2` must be immediately constructed into a smart pointer}} \
                           expected-note {{consider making ptr4 a RefPtr}}
 
   RefPtr<RC1> refptr(static_cast<RC1 *>(new RC2));
   unused(refptr);
 
   RefPtr<RC1> refptr2(new RC1);
 
-  Func1(new RC1); // expected-error {{`new RC1` must be immediately constructed into a smart pointer}}
+  Func1(new RC1); // expected-error {{`new RC1` must be passed to function as `already_AddRefed<RC1>`}} \
+                  // expected-note {{and adding `do_AddRef` here}}
 
   already_AddRefed<RC1> AddRefed = do_AddRef(new RC1);
 }
--- a/mfbt/AlreadyAddRefed.h
+++ b/mfbt/AlreadyAddRefed.h
@@ -32,17 +32,17 @@ struct unused_t;
  * * Ensure a consumer takes ownership of a reference
  * * Pass ownership without calling AddRef/Release (sometimes required in
  *   off-main-thread code)
  * * The ref pointer type you're using doesn't support move construction
  *
  * Otherwise, use Move(RefPtr/nsCOMPtr/etc).
  */
 template<class T>
-struct MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed
+struct MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE MOZ_IS_ALREADY_ADDREFED already_AddRefed
 {
   /*
    * We want to allow returning nullptr from functions returning
    * already_AddRefed<T>, for simplicity.  But we also don't want to allow
    * returning raw T*, instead preferring creation of already_AddRefed<T> from
    * a reference counting smart pointer.
    *
    * We address the latter requirement by making the (T*) constructor explicit.
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -469,17 +469,19 @@
  * MOZ_HEAP_ALLOCATOR: Applies to any function. This indicates that the return
  *   value is allocated on the heap, and will as a result check such allocations
  *   during MOZ_STACK_CLASS and MOZ_NONHEAP_CLASS annotation checking.
  * MOZ_IMPLICIT: Applies to constructors. Implicit conversion constructors
  *   are disallowed by default unless they are marked as MOZ_IMPLICIT. This
  *   attribute must be used for constructors which intend to provide implicit
  *   conversions.
  * MOZ_CAN_TAKE_NEW_RAW_REFCOUNTED: Applies to function declarations which
-*   should be allowed to take new raw refcounted pointers.
+ *   should be allowed to take new raw refcounted pointers.
+ * MOZ_IS_ALREADY_ADDREFED: Applies to class declarations of already_AddRefed
+ *   types to mark them as such for use with static-analysis.
  * MOZ_IS_REFPTR: Applies to class declarations of ref pointer to mark them as
  *   such for use with static-analysis.
  * MOZ_IS_SMARTPTR_TO_REFCOUNTED: Applies to class declarations of smart
  *   pointers to ref counted classes to mark them as such for use with
  *   static-analysis.
  * MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT: Applies to functions. Makes it a compile
  *   time error to pass arithmetic expressions on variables to the function.
  * MOZ_OWNING_REF: Applies to declarations of pointers to reference counted
@@ -580,16 +582,17 @@
      /* in debug builds, these classes do have non-trivial constructors. */
 #    define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class")))
 #  else
 #    define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) \
             MOZ_TRIVIAL_CTOR_DTOR
 #  endif
 #  define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
 #  define MOZ_CAN_TAKE_NEW_RAW_REFCOUNTED __attribute__((annotate("moz_can_take_new_raw_refcounted")))
+#  define MOZ_IS_ALREADY_ADDREFED __attribute__((annotate("moz_is_already_addrefed")))
 #  define MOZ_IS_REFPTR __attribute__((annotate("moz_is_refptr")))
 #  define MOZ_IS_SMARTPTR_TO_REFCOUNTED __attribute__((annotate("moz_is_smartptr_to_refcounted")))
 #  define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg")))
 #  define MOZ_OWNING_REF __attribute__((annotate("moz_strong_ref")))
 #  define MOZ_NON_OWNING_REF __attribute__((annotate("moz_weak_ref")))
 #  define MOZ_UNSAFE_REF(reason) __attribute__((annotate("moz_weak_ref")))
 #  define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return")))
 #  define MOZ_MUST_USE_TYPE __attribute__((annotate("moz_must_use_type")))
@@ -627,16 +630,17 @@
 #  define MOZ_STACK_CLASS /* nothing */
 #  define MOZ_NONHEAP_CLASS /* nothing */
 #  define MOZ_HEAP_CLASS /* nothing */
 #  define MOZ_NON_TEMPORARY_CLASS /* nothing */
 #  define MOZ_TRIVIAL_CTOR_DTOR /* nothing */
 #  define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS /* nothing */
 #  define MOZ_IMPLICIT /* nothing */
 #  define MOZ_CAN_TAKE_NEW_RAW_REFCOUNTED /* nothing */
+#  define MOZ_IS_ALREADY_ADDREFED /* nothing */
 #  define MOZ_IS_SMARTPTR_TO_REFCOUNTED /* nothing */
 #  define MOZ_IS_REFPTR /* nothing */
 #  define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */
 #  define MOZ_HEAP_ALLOCATOR /* nothing */
 #  define MOZ_OWNING_REF /* nothing */
 #  define MOZ_NON_OWNING_REF /* nothing */
 #  define MOZ_UNSAFE_REF(reason) /* nothing */
 #  define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* nothing */