/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
Line | Count | Source (jump to first uncovered line) |
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-exception |
6 | | // |
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 collection |
12 | | // 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 | | |
21 | | using namespace clang; |
22 | | using namespace ento; |
23 | | |
24 | | namespace { |
25 | | class ObjCPropertyChecker |
26 | | : public Checker<check::ASTDecl<ObjCPropertyDecl>> { |
27 | | void checkCopyMutable(const ObjCPropertyDecl *D, BugReporter &BR) const; |
28 | | |
29 | | public: |
30 | | void checkASTDecl(const ObjCPropertyDecl *D, AnalysisManager &Mgr, |
31 | | BugReporter &BR) const; |
32 | | }; |
33 | | } // end anonymous namespace. |
34 | | |
35 | | void ObjCPropertyChecker::checkASTDecl(const ObjCPropertyDecl *D, |
36 | | AnalysisManager &Mgr, |
37 | 19 | BugReporter &BR) const { |
38 | 19 | checkCopyMutable(D, BR); |
39 | 19 | } |
40 | | |
41 | | void ObjCPropertyChecker::checkCopyMutable(const ObjCPropertyDecl *D, |
42 | 19 | BugReporter &BR) const { |
43 | 19 | if (D->isReadOnly() || D->getSetterKind() != ObjCPropertyDecl::Copy14 ) |
44 | 8 | return; |
45 | | |
46 | 11 | QualType T = D->getType(); |
47 | 11 | if (!T->isObjCObjectPointerType()) |
48 | 0 | return; |
49 | | |
50 | 11 | const std::string &PropTypeName(T->getPointeeType().getCanonicalType() |
51 | 11 | .getUnqualifiedType() |
52 | 11 | .getAsString()); |
53 | 11 | if (!StringRef(PropTypeName).startswith("NSMutable")) |
54 | 1 | return; |
55 | | |
56 | 10 | const ObjCImplDecl *ImplD = nullptr; |
57 | 10 | if (const ObjCInterfaceDecl *IntD = |
58 | 10 | dyn_cast<ObjCInterfaceDecl>(D->getDeclContext())) { |
59 | 7 | ImplD = IntD->getImplementation(); |
60 | 7 | } else if (auto *3 CatD3 = dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) { |
61 | 2 | ImplD = CatD->getClassInterface()->getImplementation(); |
62 | 2 | } |
63 | | |
64 | 10 | if (!ImplD || ImplD->HasUserDeclaredSetterMethod(D)8 ) |
65 | 5 | return; |
66 | | |
67 | 5 | SmallString<128> Str; |
68 | 5 | llvm::raw_svector_ostream OS(Str); |
69 | 5 | OS << "Property of mutable type '" << PropTypeName |
70 | 5 | << "' has 'copy' attribute; an immutable object will be stored instead"; |
71 | | |
72 | 5 | BR.EmitBasicReport( |
73 | 5 | D, this, "Objective-C property misuse", "Logic error", OS.str(), |
74 | 5 | PathDiagnosticLocation::createBegin(D, BR.getSourceManager()), |
75 | 5 | D->getSourceRange()); |
76 | 5 | } |
77 | | |
78 | 47 | void ento::registerObjCPropertyChecker(CheckerManager &Mgr) { |
79 | 47 | Mgr.registerChecker<ObjCPropertyChecker>(); |
80 | 47 | } |
81 | | |
82 | 94 | bool ento::shouldRegisterObjCPropertyChecker(const CheckerManager &mgr) { |
83 | 94 | return true; |
84 | 94 | } |