24 #include "llvm/ADT/SmallSet.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::SmallSet<Selector, 16> > SelectorsForClass;
78 mutable bool IsInitialized;
89 StringRef &SuperclassName)
const {
94 if (SelectorsForClass.count(SuperclassName))
100 void ObjCSuperCallChecker::fillSelectors(
ASTContext &Ctx,
102 StringRef ClassName)
const {
103 llvm::SmallSet<Selector, 16> &ClassSelectors = SelectorsForClass[ClassName];
107 SelectorDescriptor Descriptor = *I;
108 assert(Descriptor.ArgumentCount <= 1);
114 ClassSelectors.insert(Sel);
118 void ObjCSuperCallChecker::initializeSelectors(
ASTContext &Ctx)
const {
121 const SelectorDescriptor Selectors[] = {
122 {
"addChildViewController", 1 },
123 {
"viewDidAppear", 1 },
124 {
"viewDidDisappear", 1 },
125 {
"viewWillAppear", 1 },
126 {
"viewWillDisappear", 1 },
127 {
"removeFromParentViewController", 0 },
128 {
"didReceiveMemoryWarning", 0 },
129 {
"viewDidUnload", 0 },
130 {
"viewDidLoad", 0 },
131 {
"viewWillUnload", 0 },
132 {
"updateViewConstraints", 0 },
133 {
"encodeRestorableStateWithCoder", 1 },
134 {
"restoreStateWithCoder", 1 }};
136 fillSelectors(Ctx, Selectors,
"UIViewController");
140 const SelectorDescriptor Selectors[] = {
141 {
"resignFirstResponder", 0 }};
143 fillSelectors(Ctx, Selectors,
"UIResponder");
147 const SelectorDescriptor Selectors[] = {
148 {
"encodeRestorableStateWithCoder", 1 },
149 {
"restoreStateWithCoder", 1 }};
151 fillSelectors(Ctx, Selectors,
"NSResponder");
155 const SelectorDescriptor Selectors[] = {
156 {
"encodeRestorableStateWithCoder", 1 },
157 {
"restoreStateWithCoder", 1 }};
159 fillSelectors(Ctx, Selectors,
"NSDocument");
162 IsInitialized =
true;
166 AnalysisManager &Mgr,
167 BugReporter &BR)
const {
172 initializeSelectors(Ctx);
175 StringRef SuperclassName;
176 if (!isCheckableClass(D, SuperclassName))
184 if (!SelectorsForClass[SuperclassName].count(S))
190 FindSuperCallVisitor Visitor(S);
191 Visitor.TraverseDecl(MD);
194 if (!Visitor.DoesCallSuper) {
195 PathDiagnosticLocation DLoc =
197 BR.getSourceManager(),
198 Mgr.getAnalysisDeclContext(D));
200 const char *Name =
"Missing call to superclass";
202 llvm::raw_svector_ostream os(Buf);
205 <<
"' instance method in " << SuperclassName.str() <<
" subclass '" 206 << *D <<
"' is missing a [super " << S.
getAsString() <<
"] call";
220 void ento::registerObjCSuperCallChecker(CheckerManager &Mgr) {
221 Mgr.registerChecker<ObjCSuperCallChecker>();
224 bool ento::shouldRegisterObjCSuperCallChecker(
const LangOptions &LO) {
The receiver is the instance of the superclass object.
const char *const CoreFoundationObjectiveC
Smart pointer class that efficiently represents Objective-C method names.
Selector getSelector() const
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
One of these records is kept for each identifier that is lexed.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
instmeth_range instance_methods() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Represents an ObjC class declaration.
ObjCInterfaceDecl * getSuperClass() const
An expression that sends a message to the given Objective-C object or class.
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
std::string getAsString() const
Derive the full selector name (e.g.
SelectorTable & Selectors
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
static PathDiagnosticLocation createEnd(const Stmt *S, const SourceManager &SM, const LocationOrAnalysisDeclContext LAC)
Create a location for the end of the statement.
StringRef getName() const
Return the actual identifier string.
const ObjCInterfaceDecl * getClassInterface() const
Dataflow Directional Tag Classes.
ObjCImplementationDecl - Represents a class definition - this is where method definitions are specifi...
Selector getSelector(unsigned NumArgs, IdentifierInfo **IIV)
Can create any sort of selector.