85 lines · cpp
1//==- ObjCPropertyChecker.cpp - Check ObjC properties ------------*- C++ -*-==//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This checker finds issues with Objective-C properties.10// Currently finds only one kind of issue:11// - Find synthesized properties with copy attribute of mutable NS collection12// types. Calling -copy on such collections produces an immutable copy,13// which contradicts the type of the property.14//15//===----------------------------------------------------------------------===//16 17#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"18#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"19#include "clang/StaticAnalyzer/Core/Checker.h"20 21using namespace clang;22using namespace ento;23 24namespace {25class ObjCPropertyChecker26 : public Checker<check::ASTDecl<ObjCPropertyDecl>> {27 void checkCopyMutable(const ObjCPropertyDecl *D, BugReporter &BR) const;28 29public:30 void checkASTDecl(const ObjCPropertyDecl *D, AnalysisManager &Mgr,31 BugReporter &BR) const;32};33} // end anonymous namespace.34 35void ObjCPropertyChecker::checkASTDecl(const ObjCPropertyDecl *D,36 AnalysisManager &Mgr,37 BugReporter &BR) const {38 checkCopyMutable(D, BR);39}40 41void ObjCPropertyChecker::checkCopyMutable(const ObjCPropertyDecl *D,42 BugReporter &BR) const {43 if (D->isReadOnly() || D->getSetterKind() != ObjCPropertyDecl::Copy)44 return;45 46 QualType T = D->getType();47 if (!T->isObjCObjectPointerType())48 return;49 50 const std::string &PropTypeName(T->getPointeeType().getCanonicalType()51 .getUnqualifiedType()52 .getAsString());53 if (!StringRef(PropTypeName).starts_with("NSMutable"))54 return;55 56 const ObjCImplDecl *ImplD = nullptr;57 if (const ObjCInterfaceDecl *IntD =58 dyn_cast<ObjCInterfaceDecl>(D->getDeclContext())) {59 ImplD = IntD->getImplementation();60 } else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) {61 ImplD = CatD->getClassInterface()->getImplementation();62 }63 64 if (!ImplD || ImplD->HasUserDeclaredSetterMethod(D))65 return;66 67 SmallString<128> Str;68 llvm::raw_svector_ostream OS(Str);69 OS << "Property of mutable type '" << PropTypeName70 << "' has 'copy' attribute; an immutable object will be stored instead";71 72 BR.EmitBasicReport(73 D, this, "Objective-C property misuse", "Logic error", OS.str(),74 PathDiagnosticLocation::createBegin(D, BR.getSourceManager()),75 D->getSourceRange());76}77 78void ento::registerObjCPropertyChecker(CheckerManager &Mgr) {79 Mgr.registerChecker<ObjCPropertyChecker>();80}81 82bool ento::shouldRegisterObjCPropertyChecker(const CheckerManager &mgr) {83 return true;84}85