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

Code before:
    return true;

  return false;
}

bool isNoDeleteFunction(const FunctionDecl *F) {
  return typeAnnotationForReturnType(F) == WebKitAnnotation::NoDelete;
}

bool isTrivialBuiltinFunction(const FunctionDecl *F) {
  if (!F || !F->getDeclName().isIdentifier())
    return false;
  auto Name = F->getName();
  return Name.starts_with("__builtin") || Name == "__libcpp_verbose_abort" ||
         Name.starts_with("os_log") || Name.starts_with("_os_log");
}

bool isSingleton(const NamedDecl *F) {
  assert(F);
  // FIXME: check # of params == 1
  if (auto *MethodDecl = dyn_cast<CXXMethodDecl>(F)) {
    if (!MethodDecl->isStatic())
      return false;
  }
  const auto &NameStr = safeGetName(F);
  StringRef Name = NameStr; // FIXME: Make safeGetName return StringRef.
  return Name == "singleton" || Name.ends_with("Singleton");
}

// We only care about statements so let's use the simple
// (non-recursive) visitor.
class TrivialFunctionAnalysisVisitor
    : public ConstStmtVisitor<TrivialFunctionAnalysisVisitor, bool> {

  // Returns false if at least one child is non-trivial.
  bool VisitChildren(const Stmt *S) {
    for (const Stmt *Child : S->children()) {
      if (Child && !Visit(Child)) {
        if (OffendingStmt && !*OffendingStmt)
          *OffendingStmt = Child;
        return false;
      }
    }

    return true;
  }

  template <typename StmtOrDecl, typename CheckFunction>
  bool WithCachedResult(const StmtOrDecl *S, CheckFunction Function) {
    auto CacheIt = Cache.find(S);
    if (CacheIt != Cache.end() && !OffendingStmt)

Review comment (suggestion):
This code made me thinking if we detect an untruthful "nodelete" attribute in the following scenario?

```c++
struct Base {
  virtual void [[clang::annotate_type("webkit.nodelete")]] method(int *p) {}
};

struct Derived : Base {
  void method(int *p) override {
    delete p; // calls operator delete here, thus should be reported as violating the "nodelete" annotation of `Base::method`. right?
  }
};

Code after:
    return true;

  return false;
}

static bool isNoDeleteFunctionDecl(const FunctionDecl *F) {
  return typeAnnotationForReturnType(F) == WebKitAnnotation::NoDelete;
}

bool isNoDeleteFunction(const FunctionDecl *F) {
  if (llvm::any_of(F->redecls(), isNoDeleteFunctionDecl))
    return true;

  const auto *MD = dyn_cast<CXXMethodDecl>(F);
  if (!MD || !MD->isVirtual())
    return false;

  auto Overriders = llvm::to_vector(MD->overridden_methods());
  while (!Overriders.empty()) {
    const auto *Fn = Overriders.pop_back_val();
    llvm::append_range(Overriders, Fn->overridden_methods());
    if (isNoDeleteFunctionDecl(Fn))
      return true;
  }

  return false;
}

bool isTrivialBuiltinFunction(const FunctionDecl *F) {
  if (!F || !F->getDeclName().isIdentifier())
    return false;
  auto Name = F->getName();
  return Name.starts_with("__builtin") || Name == "__libcpp_verbose_abort" ||
         Name.starts_with("os_log") || Name.starts_with("_os_log");
}

bool isSingleton(const NamedDecl *F) {
  assert(F);
  // FIXME: check # of params == 1
  if (auto *MethodDecl = dyn_cast<CXXMethodDecl>(F)) {
    if (!MethodDecl->isStatic())
      return false;
  }
  const auto &NameStr = safeGetName(F);
  StringRef Name = NameStr; // FIXME: Make safeGetName return StringRef.
  return Name == "singleton" || Name.ends_with("Singleton");
}

// We only care about statements so let's use the simple
// (non-recursive) visitor.
class TrivialFunctionAnalysisVisitor