Example #1
0
/// Warns on methods overridden in DerivedDecl with respect to BaseDecl.
/// FIXME: this warns on all overrides outside of the sliced path in case of
/// multiple inheritance.
void SlicingCheck::DiagnoseSlicedOverriddenMethods(
    const Expr &Call, const CXXRecordDecl &DerivedDecl,
    const CXXRecordDecl &BaseDecl) {
  if (DerivedDecl.getCanonicalDecl() == BaseDecl.getCanonicalDecl())
    return;
  for (const auto &Method : DerivedDecl.methods()) {
    // Virtual destructors are OK. We're ignoring constructors since they are
    // tagged as overrides.
    if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
      continue;
    if (Method->size_overridden_methods() > 0) {
      diag(Call.getExprLoc(),
           "slicing object from type %0 to %1 discards override %2")
          << &DerivedDecl << &BaseDecl << Method;
    }
  }
  // Recursively process bases.
  for (const auto &Base : DerivedDecl.bases()) {
    if (const auto *BaseRecordType = Base.getType()->getAs<RecordType>()) {
      if (const auto *BaseRecord = cast_or_null<CXXRecordDecl>(
              BaseRecordType->getDecl()->getDefinition()))
        DiagnoseSlicedOverriddenMethods(Call, *BaseRecord, BaseDecl);
    }
  }
}
void MustOverrideChecker::check(const MatchFinder::MatchResult &Result) {
  auto D = Result.Nodes.getNodeAs<CXXRecordDecl>("class");

  // Look through all of our immediate bases to find methods that need to be
  // overridden
  typedef std::vector<CXXMethodDecl *> OverridesVector;
  OverridesVector MustOverrides;
  for (const auto &Base : D->bases()) {
    // The base is either a class (CXXRecordDecl) or it's a templated class...
    CXXRecordDecl *Parent = Base.getType()
                                .getDesugaredType(D->getASTContext())
                                ->getAsCXXRecordDecl();
    // The parent might not be resolved to a type yet. In this case, we can't
    // do any checking here. For complete correctness, we should visit
    // template instantiations, but this case is likely to be rare, so we will
    // ignore it until it becomes important.
    if (!Parent) {
      continue;
    }
    Parent = Parent->getDefinition();
    for (const auto &M : Parent->methods()) {
      if (hasCustomAnnotation(M, "moz_must_override"))
        MustOverrides.push_back(M);
    }
  }

  for (auto &O : MustOverrides) {
    bool Overridden = false;
    for (const auto &M : D->methods()) {
      // The way that Clang checks if a method M overrides its parent method
      // is if the method has the same name but would not overload.
      if (getNameChecked(M) == getNameChecked(O) &&
          !CI->getSema().IsOverload(M, O, false)) {
        Overridden = true;
        break;
      }
    }
    if (!Overridden) {
      diag(D->getLocation(), "%0 must override %1", DiagnosticIDs::Error)
          << D->getDeclName() << O->getDeclName();
      diag(O->getLocation(), "function to override is here",
           DiagnosticIDs::Note);
    }
  }
}