Files
clang-p2996/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
Kristof Umann 058a7a450a [analyzer] Supply all checkers with a shouldRegister function
Introduce the boolean ento::shouldRegister##CHECKERNAME(const LangOptions &LO)
function very similarly to ento::register##CHECKERNAME. This will force every
checker to implement this function, but maybe it isn't that bad: I saw a lot of
ObjC or C++ specific checkers that should probably not register themselves based
on some LangOptions (mine too), but they do anyways.

A big benefit of this is that all registry functions now register their checker,
once it is called, registration is guaranteed.

This patch is a part of a greater effort to reinvent checker registration, more
info here: D54438#1315953

Differential Revision: https://reviews.llvm.org/D55424

llvm-svn: 352277
2019-01-26 14:23:08 +00:00

85 lines
3.0 KiB
C++

//==- ObjCPropertyChecker.cpp - Check ObjC properties ------------*- 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 checker finds issues with Objective-C properties.
// Currently finds only one kind of issue:
// - Find synthesized properties with copy attribute of mutable NS collection
// types. Calling -copy on such collections produces an immutable copy,
// which contradicts the type of the property.
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
using namespace clang;
using namespace ento;
namespace {
class ObjCPropertyChecker
: public Checker<check::ASTDecl<ObjCPropertyDecl>> {
void checkCopyMutable(const ObjCPropertyDecl *D, BugReporter &BR) const;
public:
void checkASTDecl(const ObjCPropertyDecl *D, AnalysisManager &Mgr,
BugReporter &BR) const;
};
} // end anonymous namespace.
void ObjCPropertyChecker::checkASTDecl(const ObjCPropertyDecl *D,
AnalysisManager &Mgr,
BugReporter &BR) const {
checkCopyMutable(D, BR);
}
void ObjCPropertyChecker::checkCopyMutable(const ObjCPropertyDecl *D,
BugReporter &BR) const {
if (D->isReadOnly() || D->getSetterKind() != ObjCPropertyDecl::Copy)
return;
QualType T = D->getType();
if (!T->isObjCObjectPointerType())
return;
const std::string &PropTypeName(T->getPointeeType().getCanonicalType()
.getUnqualifiedType()
.getAsString());
if (!StringRef(PropTypeName).startswith("NSMutable"))
return;
const ObjCImplDecl *ImplD = nullptr;
if (const ObjCInterfaceDecl *IntD =
dyn_cast<ObjCInterfaceDecl>(D->getDeclContext())) {
ImplD = IntD->getImplementation();
} else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) {
ImplD = CatD->getClassInterface()->getImplementation();
}
if (!ImplD || ImplD->HasUserDeclaredSetterMethod(D))
return;
SmallString<128> Str;
llvm::raw_svector_ostream OS(Str);
OS << "Property of mutable type '" << PropTypeName
<< "' has 'copy' attribute; an immutable object will be stored instead";
BR.EmitBasicReport(
D, this, "Objective-C property misuse", "Logic error", OS.str(),
PathDiagnosticLocation::createBegin(D, BR.getSourceManager()),
D->getSourceRange());
}
void ento::registerObjCPropertyChecker(CheckerManager &Mgr) {
Mgr.registerChecker<ObjCPropertyChecker>();
}
bool ento::shouldRegisterObjCPropertyChecker(const LangOptions &LO) {
return true;
}