Repository: llvm/llvm-project
File: clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp (C++)

Code before:
      // C++ trivially destructible classes are fine.
      if (R->hasDefinition() && R->hasTrivialDestructor())
        return true;

      if (HasFieldWithNonTrivialDtor(R))
        return false;

      // For Webkit, side-effects are fine as long as we don't delete objects,
      // so check recursively.
      if (const auto *Dtor = R->getDestructor())
        return IsFunctionTrivial(Dtor);
    }

    // Structs in C are trivial.
    if (Ty->isRecordType())
      return true;

    // For arrays it depends on the element type.
    // FIXME: We should really use ASTContext::getAsArrayType instead.
    if (const auto *AT = Ty->getAsArrayTypeUnsafe())
      return CanTriviallyDestruct(AT->getElementType());

    return false; // Otherwise it's likely not trivial.
  }

  bool HasFieldWithNonTrivialDtor(const CXXRecordDecl *Cls) {

    auto HasNonTrivialField = [&](const CXXRecordDecl *R) {
      for (const FieldDecl *F : R->fields()) {
        if (!CanTriviallyDestruct(F->getType()))
          return true;
      }
      return false;
    };

    if (HasNonTrivialField(Cls))
      return true;

    if (!Cls->hasDefinition())
      return false;

    CXXBasePaths Paths;
    Paths.setOrigin(const_cast<CXXRecordDecl *>(Cls));
    return Cls->lookupInBases(
        [&](const CXXBaseSpecifier *B, CXXBasePath &) {
          auto *T = B->getType().getTypePtrOrNull();
          if (!T)
            return false;
          auto *R = T->getAsCXXRecordDecl();
          return R && HasNonTrivialField(R);
        },

Review comment (performance):
You should cache the "webkit triviality" information of CXXRecordDecls.
I recon, they can get pretty computationally expensive - especially by doing redundant work by traversing again and again the same class hierarchy.

Code after:
      // C++ trivially destructible classes are fine.
      if (R->hasDefinition() && R->hasTrivialDestructor())
        return true;

      if (HasFieldWithNonTrivialDtor(R))
        return false;

      // For Webkit, side-effects are fine as long as we don't delete objects,
      // so check recursively.
      if (const auto *Dtor = R->getDestructor())
        return IsFunctionTrivial(Dtor);
    }

    // Structs in C are trivial.
    if (Ty->isRecordType())
      return true;

    // For arrays it depends on the element type.
    // FIXME: We should really use ASTContext::getAsArrayType instead.
    if (const auto *AT = Ty->getAsArrayTypeUnsafe())
      return CanTriviallyDestruct(AT->getElementType());

    return false; // Otherwise it's likely not trivial.
  }

  bool HasFieldWithNonTrivialDtor(const CXXRecordDecl *Cls) {
    auto CacheIt = FieldDtorCache.find(Cls);
    if (CacheIt != FieldDtorCache.end())
      return CacheIt->second;

    bool Result = ([&] {
      auto HasNonTrivialField = [&](const CXXRecordDecl *R) {
        for (const FieldDecl *F : R->fields()) {
          if (!CanTriviallyDestruct(F->getType()))
            return true;
        }
        return false;
      };

      if (HasNonTrivialField(Cls))
        return true;

      if (!Cls->hasDefinition())
        return false;

      CXXBasePaths Paths;
      Paths.setOrigin(const_cast<CXXRecordDecl *>(Cls));
      return Cls->lookupInBases(
          [&](const CXXBaseSpecifier *B, CXXBasePath &) {
            auto *T = B->getType().getTypePtrOrNull();
            if (!T)