]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
MFC r244628:
[FreeBSD/stable/9.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / ObjCMissingSuperCallChecker.cpp
1 //==- ObjCMissingSuperCallChecker.cpp - Check missing super-calls in ObjC --==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file defines a ObjCMissingSuperCallChecker, a checker that
11 //  analyzes a UIViewController implementation to determine if it
12 //  correctly calls super in the methods where this is mandatory.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "ClangSACheckers.h"
17 #include "clang/StaticAnalyzer/Core/Checker.h"
18 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
19 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
20 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
21 #include "clang/AST/ExprObjC.h"
22 #include "clang/AST/Expr.h"
23 #include "clang/AST/DeclObjC.h"
24 #include "clang/AST/RecursiveASTVisitor.h"
25 #include "llvm/ADT/SmallString.h"
26 #include "llvm/ADT/SmallSet.h"
27 #include "llvm/Support/raw_ostream.h"
28
29 using namespace clang;
30 using namespace ento;
31
32 static bool isUIViewControllerSubclass(ASTContext &Ctx, 
33                                        const ObjCImplementationDecl *D) {
34   IdentifierInfo *ViewControllerII = &Ctx.Idents.get("UIViewController");
35   const ObjCInterfaceDecl *ID = D->getClassInterface();
36
37   for ( ; ID; ID = ID->getSuperClass())
38     if (ID->getIdentifier() == ViewControllerII)
39       return true;
40   return false;  
41 }
42
43 //===----------------------------------------------------------------------===//
44 // FindSuperCallVisitor - Identify specific calls to the superclass.
45 //===----------------------------------------------------------------------===//
46
47 class FindSuperCallVisitor : public RecursiveASTVisitor<FindSuperCallVisitor> {
48 public:
49   explicit FindSuperCallVisitor(Selector S) : DoesCallSuper(false), Sel(S) {}
50
51   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
52     if (E->getSelector() == Sel)
53       if (E->getReceiverKind() == ObjCMessageExpr::SuperInstance)
54         DoesCallSuper = true;
55
56     // Recurse if we didn't find the super call yet.
57     return !DoesCallSuper; 
58   }
59
60   bool DoesCallSuper;
61
62 private:
63   Selector Sel;
64 };
65
66 //===----------------------------------------------------------------------===//
67 // ObjCSuperCallChecker 
68 //===----------------------------------------------------------------------===//
69
70 namespace {
71 class ObjCSuperCallChecker : public Checker<
72                                       check::ASTDecl<ObjCImplementationDecl> > {
73 public:
74   void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager &Mgr,
75                     BugReporter &BR) const;
76 };
77 }
78
79 void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
80                                         AnalysisManager &Mgr,
81                                         BugReporter &BR) const {
82   ASTContext &Ctx = BR.getContext();
83
84   if (!isUIViewControllerSubclass(Ctx, D))
85     return;
86
87   const char *SelectorNames[] = 
88     {"addChildViewController", "viewDidAppear", "viewDidDisappear", 
89      "viewWillAppear", "viewWillDisappear", "removeFromParentViewController",
90      "didReceiveMemoryWarning", "viewDidUnload", "viewWillUnload",
91      "viewDidLoad"};
92   const unsigned SelectorArgumentCounts[] =
93    {1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
94   const size_t SelectorCount = llvm::array_lengthof(SelectorNames);
95   assert(llvm::array_lengthof(SelectorArgumentCounts) == SelectorCount);
96
97   // Fill the Selectors SmallSet with all selectors we want to check.
98   llvm::SmallSet<Selector, 16> Selectors;
99   for (size_t i = 0; i < SelectorCount; i++) { 
100     unsigned ArgumentCount = SelectorArgumentCounts[i];
101     const char *SelectorCString = SelectorNames[i];
102
103     // Get the selector.
104     IdentifierInfo *II = &Ctx.Idents.get(SelectorCString);
105     Selectors.insert(Ctx.Selectors.getSelector(ArgumentCount, &II));
106   }
107
108   // Iterate over all instance methods.
109   for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
110                                                  E = D->instmeth_end();
111        I != E; ++I) {
112     Selector S = (*I)->getSelector();
113     // Find out whether this is a selector that we want to check.
114     if (!Selectors.count(S))
115       continue;
116
117     ObjCMethodDecl *MD = *I;
118
119     // Check if the method calls its superclass implementation.
120     if (MD->getBody())
121     {
122       FindSuperCallVisitor Visitor(S);
123       Visitor.TraverseDecl(MD);
124
125       // It doesn't call super, emit a diagnostic.
126       if (!Visitor.DoesCallSuper) {
127         PathDiagnosticLocation DLoc =
128           PathDiagnosticLocation::createEnd(MD->getBody(),
129                                             BR.getSourceManager(),
130                                             Mgr.getAnalysisDeclContext(D));
131
132         const char *Name = "Missing call to superclass";
133         SmallString<256> Buf;
134         llvm::raw_svector_ostream os(Buf);
135
136         os << "The '" << S.getAsString() 
137            << "' instance method in UIViewController subclass '" << *D
138            << "' is missing a [super " << S.getAsString() << "] call";
139
140         BR.EmitBasicReport(MD, Name, categories::CoreFoundationObjectiveC,
141                            os.str(), DLoc);
142       }
143     }
144   }
145 }
146
147
148 //===----------------------------------------------------------------------===//
149 // Check registration.
150 //===----------------------------------------------------------------------===//
151
152 void ento::registerObjCSuperCallChecker(CheckerManager &Mgr) {
153   Mgr.registerChecker<ObjCSuperCallChecker>();
154 }
155
156
157 /*
158  ToDo list for expanding this check in the future, the list is not exhaustive.
159  There are also cases where calling super is suggested but not "mandatory".
160  In addition to be able to check the classes and methods below, architectural
161  improvements like being able to allow for the super-call to be done in a called
162  method would be good too.
163
164 *** trivial cases:
165 UIResponder subclasses
166 - resignFirstResponder
167
168 NSResponder subclasses
169 - cursorUpdate
170
171 *** more difficult cases:
172
173 UIDocument subclasses
174 - finishedHandlingError:recovered: (is multi-arg)
175 - finishedHandlingError:recovered: (is multi-arg)
176
177 UIViewController subclasses
178 - loadView (should *never* call super)
179 - transitionFromViewController:toViewController:
180          duration:options:animations:completion: (is multi-arg)
181
182 UICollectionViewController subclasses
183 - loadView (take care because UIViewController subclasses should NOT call super
184             in loadView, but UICollectionViewController subclasses should)
185
186 NSObject subclasses
187 - doesNotRecognizeSelector (it only has to call super if it doesn't throw)
188
189 UIPopoverBackgroundView subclasses (some of those are class methods)
190 - arrowDirection (should *never* call super)
191 - arrowOffset (should *never* call super)
192 - arrowBase (should *never* call super)
193 - arrowHeight (should *never* call super)
194 - contentViewInsets (should *never* call super)
195
196 UITextSelectionRect subclasses (some of those are properties)
197 - rect (should *never* call super)
198 - range (should *never* call super)
199 - writingDirection (should *never* call super)
200 - isVertical (should *never* call super)
201 - containsStart (should *never* call super)
202 - containsEnd (should *never* call super)
203 */