24 #include "llvm/ADT/SmallPtrSet.h"
25 #include "llvm/ADT/SmallString.h"
26 #include "llvm/Support/raw_ostream.h"
28 using namespace clang;
32 struct SelectorDescriptor {
33 const char *SelectorName;
34 unsigned ArgumentCount;
43 explicit FindSuperCallVisitor(
Selector S) : DoesCallSuper(
false), Sel(S) {}
51 return !DoesCallSuper;
64 class ObjCSuperCallChecker :
public Checker<
65 check::ASTDecl<ObjCImplementationDecl> > {
67 ObjCSuperCallChecker() : IsInitialized(
false) {}
70 BugReporter &BR)
const;
73 StringRef &SuperclassName)
const;
74 void initializeSelectors(
ASTContext &Ctx)
const;
76 StringRef ClassName)
const;
77 mutable llvm::StringMap<llvm::SmallPtrSet<Selector, 16>> SelectorsForClass;
78 mutable bool IsInitialized;
89 StringRef &SuperclassName)
const {
91 for ( ;
ID ;
ID =
ID->getSuperClass())
93 SuperclassName =
ID->getIdentifier()->getName();
94 if (SelectorsForClass.count(SuperclassName))
100 void ObjCSuperCallChecker::fillSelectors(
ASTContext &Ctx,
102 StringRef ClassName)
const {
104 SelectorsForClass[ClassName];
108 SelectorDescriptor Descriptor = *I;
109 assert(Descriptor.ArgumentCount <= 1);
115 ClassSelectors.insert(Sel);
119 void ObjCSuperCallChecker::initializeSelectors(
ASTContext &Ctx)
const {
122 const SelectorDescriptor Selectors[] = {
123 {
"addChildViewController", 1 },
124 {
"viewDidAppear", 1 },
125 {
"viewDidDisappear", 1 },
126 {
"viewWillAppear", 1 },
127 {
"viewWillDisappear", 1 },
128 {
"removeFromParentViewController", 0 },
129 {
"didReceiveMemoryWarning", 0 },
130 {
"viewDidUnload", 0 },
131 {
"viewDidLoad", 0 },
132 {
"viewWillUnload", 0 },
133 {
"updateViewConstraints", 0 },
134 {
"encodeRestorableStateWithCoder", 1 },
135 {
"restoreStateWithCoder", 1 }};
137 fillSelectors(Ctx, Selectors,
"UIViewController");
141 const SelectorDescriptor Selectors[] = {
142 {
"resignFirstResponder", 0 }};
144 fillSelectors(Ctx, Selectors,
"UIResponder");
148 const SelectorDescriptor Selectors[] = {
149 {
"encodeRestorableStateWithCoder", 1 },
150 {
"restoreStateWithCoder", 1 }};
152 fillSelectors(Ctx, Selectors,
"NSResponder");
156 const SelectorDescriptor Selectors[] = {
157 {
"encodeRestorableStateWithCoder", 1 },
158 {
"restoreStateWithCoder", 1 }};
160 fillSelectors(Ctx, Selectors,
"NSDocument");
163 IsInitialized =
true;
167 AnalysisManager &Mgr,
168 BugReporter &BR)
const {
173 initializeSelectors(Ctx);
176 StringRef SuperclassName;
177 if (!isCheckableClass(D, SuperclassName))
185 if (!SelectorsForClass[SuperclassName].count(S))
191 FindSuperCallVisitor Visitor(S);
192 Visitor.TraverseDecl(MD);
195 if (!Visitor.DoesCallSuper) {
196 PathDiagnosticLocation DLoc =
198 BR.getSourceManager(),
199 Mgr.getAnalysisDeclContext(D));
201 const char *Name =
"Missing call to superclass";
203 llvm::raw_svector_ostream os(Buf);
205 os <<
"The '" << S.getAsString()
206 <<
"' instance method in " << SuperclassName.str() <<
" subclass '"
207 << *D <<
"' is missing a [super " << S.getAsString() <<
"] call";
221 void ento::registerObjCSuperCallChecker(CheckerManager &Mgr) {
222 Mgr.registerChecker<ObjCSuperCallChecker>();
225 bool ento::shouldRegisterObjCSuperCallChecker(
const CheckerManager &mgr) {