diff options
author | Ted Kremenek <kremenek@apple.com> | 2008-07-03 04:29:21 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2008-07-03 04:29:21 +0000 |
commit | 0e7d25233ecaa9ba618c2154474aaa53c3df616b (patch) | |
tree | 5a939c439ed517e5f1a866eff511c2e1aecafb04 /clang/lib/Analysis/CheckObjCDealloc.cpp | |
parent | 7a241baf2fad7719bc57acd2cf2fe400256b26f6 (diff) | |
download | bcm5719-llvm-0e7d25233ecaa9ba618c2154474aaa53c3df616b.tar.gz bcm5719-llvm-0e7d25233ecaa9ba618c2154474aaa53c3df616b.zip |
Added static analysis check to see if a subclass of NSObject implements -dealloc, and whether or not that implementation calls [super dealloc].
llvm-svn: 53075
Diffstat (limited to 'clang/lib/Analysis/CheckObjCDealloc.cpp')
-rw-r--r-- | clang/lib/Analysis/CheckObjCDealloc.cpp | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/clang/lib/Analysis/CheckObjCDealloc.cpp b/clang/lib/Analysis/CheckObjCDealloc.cpp new file mode 100644 index 00000000000..9a40fa97ec2 --- /dev/null +++ b/clang/lib/Analysis/CheckObjCDealloc.cpp @@ -0,0 +1,118 @@ +//==- CheckObjCDealloc.cpp - Check ObjC -dealloc implementation --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a DeadStores, a flow-sensitive checker that looks for +// stores to variables that are no longer live. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/LocalCheckers.h" +#include "clang/Analysis/PathDiagnostic.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/DeclObjC.h" +#include <sstream> + +using namespace clang; + +static bool scan_dealloc(Stmt* S, Selector Dealloc) { + + if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S)) + if (ME->getSelector() == Dealloc) + if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) + if (PreDefinedExpr* E = dyn_cast<PreDefinedExpr>(Receiver)) + if (E->getIdentType() == PreDefinedExpr::ObjCSuper) + return true; + + // Recurse to children. + + for (Stmt::child_iterator I = S->child_begin(), E= S->child_end(); I!=E; ++I) + if (*I && scan_dealloc(*I, Dealloc)) + return true; + + return false; +} + +void clang::CheckObjCDealloc(ObjCImplementationDecl* D, BugReporter& BR) { + + ASTContext& Ctx = BR.getContext(); + + // Determine if the class subclasses NSObject. + IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject"); + ObjCInterfaceDecl* ID = D->getClassInterface(); + + for ( ; ID ; ID = ID->getSuperClass()) + if (ID->getIdentifier() == NSObjectII) + break; + + if (!ID) + return; + + // Get the "dealloc" selector. + IdentifierInfo* II = &Ctx.Idents.get("dealloc"); + Selector S = Ctx.Selectors.getSelector(0, &II); + + ObjCMethodDecl* MD = 0; + + // Scan the instance methods for "dealloc". + for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(), + E = D->instmeth_end(); I!=E; ++I) { + + if ((*I)->getSelector() == S) { + MD = *I; + break; + } + } + + if (!MD) { // No dealloc found. + + // FIXME: This code should be reduced to three lines if possible (Refactor). + SimpleBugType BT("missing -dealloc"); + DiagCollector C(BT); + + std::ostringstream os; + os << "Objective-C class '" << D->getName() + << "' lacks a 'dealloc' instance method"; + + Diagnostic& Diag = BR.getDiagnostic(); + Diag.Report(&C, + Ctx.getFullLoc(D->getLocStart()), + Diag.getCustomDiagID(Diagnostic::Warning, os.str().c_str()), + NULL, 0, NULL, 0); + + for (DiagCollector::iterator I = C.begin(), E = C.end(); I != E; ++I) + BR.EmitWarning(*I); + + return; + } + + // dealloc found. Scan for missing [super dealloc]. + if (MD->getBody() && !scan_dealloc(MD->getBody(), S)) { + + // FIXME: This code should be reduced to three lines if possible (Refactor). + SimpleBugType BT("missing [super dealloc]"); + DiagCollector C(BT); + + std::ostringstream os; + os << "The 'dealloc' instance method in Objective-C class '" << D->getName() + << "' does not send a 'dealloc' message to it super class" + " (missing [super dealloc])"; + + Diagnostic& Diag = BR.getDiagnostic(); + Diag.Report(&C, + Ctx.getFullLoc(MD->getLocStart()), + Diag.getCustomDiagID(Diagnostic::Warning, os.str().c_str()), + NULL, 0, NULL, 0); + + for (DiagCollector::iterator I = C.begin(), E = C.end(); I != E; ++I) + BR.EmitWarning(*I); + } +} + |