llvm/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp

//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//  This file defines BasicObjCFoundationChecks, a class that encapsulates
//  a set of simple checks to run on Objective-C code using Apple's Foundation
//  classes.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Analysis/SelectorExtras.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>

usingnamespaceclang;
usingnamespaceento;
usingnamespacellvm;

namespace {
class APIMisuse : public BugType {};
} // end anonymous namespace

//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//

static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {}

enum FoundationClass {};

static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
                                      bool IncludeSuperclasses = true) {}

//===----------------------------------------------------------------------===//
// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
//===----------------------------------------------------------------------===//

namespace {
class NilArgChecker : public Checker<check::PreObjCMessage,
                                     check::PostStmt<ObjCDictionaryLiteral>,
                                     check::PostStmt<ObjCArrayLiteral>,
                                     EventDispatcher<ImplicitNullDerefEvent>> {};
} // end anonymous namespace

void NilArgChecker::warnIfNilExpr(const Expr *E,
                                  const char *Msg,
                                  CheckerContext &C) const {}

void NilArgChecker::warnIfNilArg(CheckerContext &C,
                                 const ObjCMethodCall &msg,
                                 unsigned int Arg,
                                 FoundationClass Class,
                                 bool CanBeSubscript) const {}

void NilArgChecker::generateBugReport(ExplodedNode *N,
                                      StringRef Msg,
                                      SourceRange Range,
                                      const Expr *E,
                                      CheckerContext &C) const {}

void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
                                        CheckerContext &C) const {}

void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
                                  CheckerContext &C) const {}

void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
                                  CheckerContext &C) const {}

//===----------------------------------------------------------------------===//
// Checking for mismatched types passed to CFNumberCreate/CFNumberGetValue.
//===----------------------------------------------------------------------===//

namespace {
class CFNumberChecker : public Checker< check::PreStmt<CallExpr> > {};
} // end anonymous namespace

enum CFNumberType {};

static std::optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {}

#if 0
static const char* GetCFNumberTypeStr(uint64_t i) {
  static const char* Names[] = {
    "kCFNumberSInt8Type",
    "kCFNumberSInt16Type",
    "kCFNumberSInt32Type",
    "kCFNumberSInt64Type",
    "kCFNumberFloat32Type",
    "kCFNumberFloat64Type",
    "kCFNumberCharType",
    "kCFNumberShortType",
    "kCFNumberIntType",
    "kCFNumberLongType",
    "kCFNumberLongLongType",
    "kCFNumberFloatType",
    "kCFNumberDoubleType",
    "kCFNumberCFIndexType",
    "kCFNumberNSIntegerType",
    "kCFNumberCGFloatType"
  };

  return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
}
#endif

void CFNumberChecker::checkPreStmt(const CallExpr *CE,
                                         CheckerContext &C) const {}

//===----------------------------------------------------------------------===//
// CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
//===----------------------------------------------------------------------===//

namespace {
class CFRetainReleaseChecker : public Checker<check::PreCall> {};
} // end anonymous namespace

void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
                                          CheckerContext &C) const {}

//===----------------------------------------------------------------------===//
// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
//===----------------------------------------------------------------------===//

namespace {
class ClassReleaseChecker : public Checker<check::PreObjCMessage> {};
} // end anonymous namespace

void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
                                              CheckerContext &C) const {}

//===----------------------------------------------------------------------===//
// Check for passing non-Objective-C types to variadic methods that expect
// only Objective-C types.
//===----------------------------------------------------------------------===//

namespace {
class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {};
} // end anonymous namespace

/// isVariadicMessage - Returns whether the given message is a variadic message,
/// where all arguments must be Objective-C types.
bool
VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {}

void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
                                                    CheckerContext &C) const {}

//===----------------------------------------------------------------------===//
// Improves the modeling of loops over Cocoa collections.
//===----------------------------------------------------------------------===//

// The map from container symbol to the container count symbol.
// We currently will remember the last container count symbol encountered.
REGISTER_MAP_WITH_PROGRAMSTATE()
REGISTER_MAP_WITH_PROGRAMSTATE()

namespace {
class ObjCLoopChecker
  : public Checker<check::PostStmt<ObjCForCollectionStmt>,
                   check::PostObjCMessage,
                   check::DeadSymbols,
                   check::PointerEscape > {};
} // end anonymous namespace

static bool isKnownNonNilCollectionType(QualType T) {}

/// Assumes that the collection is non-nil.
///
/// If the collection is known to be nil, returns NULL to indicate an infeasible
/// path.
static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
                                             ProgramStateRef State,
                                             const ObjCForCollectionStmt *FCS) {}

/// Assumes that the collection elements are non-nil.
///
/// This only applies if the collection is one of those known not to contain
/// nil values.
static ProgramStateRef checkElementNonNil(CheckerContext &C,
                                          ProgramStateRef State,
                                          const ObjCForCollectionStmt *FCS) {}

/// Returns NULL state if the collection is known to contain elements
/// (or is known not to contain elements if the Assumption parameter is false.)
static ProgramStateRef
assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
                         SymbolRef CollectionS, bool Assumption) {}

static ProgramStateRef
assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
                         const ObjCForCollectionStmt *FCS,
                         bool Assumption) {}

/// If the fist block edge is a back edge, we are reentering the loop.
static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
                                             const ObjCForCollectionStmt *FCS) {}

void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
                                    CheckerContext &C) const {}

bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
                                              CheckerContext &C) const {}

void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
                                           CheckerContext &C) const {}

static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {}

ProgramStateRef
ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
                                    const InvalidatedSymbols &Escaped,
                                    const CallEvent *Call,
                                    PointerEscapeKind Kind) const {}

void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
                                       CheckerContext &C) const {}

namespace {
/// \class ObjCNonNilReturnValueChecker
/// The checker restricts the return values of APIs known to
/// never (or almost never) return 'nil'.
class ObjCNonNilReturnValueChecker
  : public Checker<check::PostObjCMessage,
                   check::PostStmt<ObjCArrayLiteral>,
                   check::PostStmt<ObjCDictionaryLiteral>,
                   check::PostStmt<ObjCBoxedExpr> > {};
} // end anonymous namespace

ProgramStateRef
ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
                                                  ProgramStateRef State,
                                                  CheckerContext &C) const {}

void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
                                                        CheckerContext &C)
                                                        const {}

//===----------------------------------------------------------------------===//
// Check registration.
//===----------------------------------------------------------------------===//

void ento::registerNilArgChecker(CheckerManager &mgr) {}

bool ento::shouldRegisterNilArgChecker(const CheckerManager &mgr) {}

void ento::registerCFNumberChecker(CheckerManager &mgr) {}

bool ento::shouldRegisterCFNumberChecker(const CheckerManager &mgr) {}

void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {}

bool ento::shouldRegisterCFRetainReleaseChecker(const CheckerManager &mgr) {}

void ento::registerClassReleaseChecker(CheckerManager &mgr) {}

bool ento::shouldRegisterClassReleaseChecker(const CheckerManager &mgr) {}

void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {}

bool ento::shouldRegisterVariadicMethodTypeChecker(const CheckerManager &mgr) {}

void ento::registerObjCLoopChecker(CheckerManager &mgr) {}

bool ento::shouldRegisterObjCLoopChecker(const CheckerManager &mgr) {}

void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {}

bool ento::shouldRegisterObjCNonNilReturnValueChecker(const CheckerManager &mgr) {}