build/clang-plugin/NoDuplicateRefCntMemberChecker.cpp
author Dustin J. Mitchell <dustin@mozilla.com>
Mon, 02 Oct 2017 18:22:56 +0000
changeset 399728 0f0395687d36597098e4248457ed69f092c39f8f
parent 387474 88c9b8587db69f36601f45e6584ac2d1c5e459b5
child 444370 538a16d495142178a73e0bdc30f100b43d2fd62b
permissions -rw-r--r--
Bug 1403519 - only build docs when necessary r=gps This marks **/docs/** as exclusively docs, and code that is autodoc'd as inclusively docs. That means that a change that purely modifies documentation files will *only* run `docs` tasks, while a change that modifies autodoc'd source code will *additionaly* run `docs` tasks. The tasks do not run by default. MozReview-Commit-ID: G9tOK0AwtrI

/* This Source Code Form is subject to the terms of the Mozilla Public
 * 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 "NoDuplicateRefCntMemberChecker.h"
#include "CustomMatchers.h"

void NoDuplicateRefCntMemberChecker::registerMatchers(MatchFinder *AstMatcher) {
  AstMatcher->addMatcher(cxxRecordDecl().bind("decl"), this);
}

void NoDuplicateRefCntMemberChecker::check(
    const MatchFinder::MatchResult &Result) {
  const CXXRecordDecl *D = Result.Nodes.getNodeAs<CXXRecordDecl>("decl");
  const FieldDecl *RefCntMember = getClassRefCntMember(D);
  const FieldDecl *FoundRefCntBase = nullptr;

  if (!D->hasDefinition())
    return;
  D = D->getDefinition();

  // If we don't have an mRefCnt member, and we have less than 2 superclasses,
  // we don't have to run this loop, as neither case will ever apply.
  if (!RefCntMember && D->getNumBases() < 2) {
    return;
  }

  // Check every superclass for whether it has a base with a refcnt member, and
  // warn for those which do
  for (auto &Base : D->bases()) {
    // Determine if this base class has an mRefCnt member
    const FieldDecl *BaseRefCntMember = getBaseRefCntMember(Base.getType());

    if (BaseRefCntMember) {
      if (RefCntMember) {
        // We have an mRefCnt, and superclass has an mRefCnt
        const char *Error = "Refcounted record %0 has multiple mRefCnt members";
        const char *Note1 = "Superclass %0 also has an mRefCnt member";
        const char *Note2 =
            "Consider using the _INHERITED macros for AddRef and Release here";

        diag(D->getLocStart(), Error, DiagnosticIDs::Error) << D;
        diag(BaseRefCntMember->getLocStart(), Note1, DiagnosticIDs::Note)
            << BaseRefCntMember->getParent();
        diag(RefCntMember->getLocStart(), Note2, DiagnosticIDs::Note);
      }

      if (FoundRefCntBase) {
        const char *Error = "Refcounted record %0 has multiple superclasses "
                            "with mRefCnt members";
        const char *Note = "Superclass %0 has an mRefCnt member";

        // superclass has mRefCnt, and another superclass also has an mRefCnt
        diag(D->getLocStart(), Error, DiagnosticIDs::Error) << D;
        diag(BaseRefCntMember->getLocStart(), Note, DiagnosticIDs::Note)
            << BaseRefCntMember->getParent();
        diag(FoundRefCntBase->getLocStart(), Note, DiagnosticIDs::Note)
            << FoundRefCntBase->getParent();
      }

      // Record that we've found a base with a mRefCnt member
      FoundRefCntBase = BaseRefCntMember;
    }
  }
}