bool BlinkGCPluginConsumer::HasNonEmptyFinalizer(RecordInfo* info) {
  CXXDestructorDecl* dtor = info->record()->getDestructor();
  if (dtor && dtor->isUserProvided()) {
    if (!dtor->hasBody() || !EmptyStmtVisitor::isEmpty(dtor->getBody()))
      return true;
  }
  for (RecordInfo::Bases::iterator it = info->GetBases().begin();
       it != info->GetBases().end();
       ++it) {
    if (HasNonEmptyFinalizer(it->second.info()))
      return true;
  }
  for (RecordInfo::Fields::iterator it = info->GetFields().begin();
       it != info->GetFields().end();
       ++it) {
    if (it->second.edge()->NeedsFinalization())
      return true;
  }
  return false;
}
void VirtualCallsFromCTOR::VisitDecl(Decl *decl)
{
    CXXConstructorDecl *ctorDecl = dyn_cast<CXXConstructorDecl>(decl);
    CXXDestructorDecl *dtorDecl = dyn_cast<CXXDestructorDecl>(decl);
    if (ctorDecl == nullptr && dtorDecl == nullptr)
        return;

    Stmt *ctorOrDtorBody = ctorDecl ? ctorDecl->getBody() : dtorDecl->getBody();
    if (ctorOrDtorBody == nullptr)
        return;

    CXXRecordDecl *classDecl = ctorDecl ? ctorDecl->getParent() : dtorDecl->getParent();

    std::vector<Stmt*> processedStmts;
    SourceLocation loc = containsVirtualCall(classDecl, ctorOrDtorBody, processedStmts);
    if (loc.isValid()) {
        if (ctorDecl != nullptr) {
            emitWarning(decl->getLocStart(), "Calling pure virtual function in CTOR");
        } else {
            emitWarning(decl->getLocStart(), "Calling pure virtual function in DTOR");
        }
        emitWarning(loc, "Called here");
    }
}