25 #include "llvm/ADT/SmallSet.h" 26 #include "llvm/ADT/SmallString.h" 27 #include "llvm/Support/raw_ostream.h" 29 using namespace clang;
33 struct SelectorDescriptor {
34 const char *SelectorName;
35 unsigned ArgumentCount;
44 explicit FindSuperCallVisitor(
Selector S) : DoesCallSuper(
false), Sel(S) {}
52 return !DoesCallSuper;
65 class ObjCSuperCallChecker :
public Checker<
66 check::ASTDecl<ObjCImplementationDecl> > {
68 ObjCSuperCallChecker() : IsInitialized(
false) {}
71 BugReporter &BR)
const;
74 StringRef &SuperclassName)
const;
75 void initializeSelectors(
ASTContext &Ctx)
const;
77 StringRef ClassName)
const;
78 mutable llvm::StringMap<llvm::SmallSet<Selector, 16> > SelectorsForClass;
79 mutable bool IsInitialized;
90 StringRef &SuperclassName)
const {
95 if (SelectorsForClass.count(SuperclassName))
101 void ObjCSuperCallChecker::fillSelectors(
ASTContext &Ctx,
103 StringRef ClassName)
const {
104 llvm::SmallSet<Selector, 16> &ClassSelectors = 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);
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>();
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
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.