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
--- 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 */