[cfe-commits] r53075 - in /cfe/trunk: Driver/AnalysisConsumer.cpp include/clang/Analysis/LocalCheckers.h include/clang/Analysis/PathSensitive/BugReporter.h lib/Analysis/CheckObjCDealloc.cpp lib/Analysis/DeadStores.cpp test/Analysis/NSPanel.m test/Analysis/NSString.m
Ted Kremenek
kremenek at apple.com
Wed Jul 2 21:29:21 PDT 2008
Author: kremenek
Date: Wed Jul 2 23:29:21 2008
New Revision: 53075
URL: http://llvm.org/viewvc/llvm-project?rev=53075&view=rev
Log:
Added static analysis check to see if a subclass of NSObject implements -dealloc, and whether or not that implementation calls [super dealloc].
Added:
cfe/trunk/lib/Analysis/CheckObjCDealloc.cpp
Modified:
cfe/trunk/Driver/AnalysisConsumer.cpp
cfe/trunk/include/clang/Analysis/LocalCheckers.h
cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h
cfe/trunk/lib/Analysis/DeadStores.cpp
cfe/trunk/test/Analysis/NSPanel.m
cfe/trunk/test/Analysis/NSString.m
Modified: cfe/trunk/Driver/AnalysisConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/AnalysisConsumer.cpp?rev=53075&r1=53074&r2=53075&view=diff
==============================================================================
--- cfe/trunk/Driver/AnalysisConsumer.cpp (original)
+++ cfe/trunk/Driver/AnalysisConsumer.cpp Wed Jul 2 23:29:21 2008
@@ -17,7 +17,6 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/Support/Compiler.h"
-#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/OwningPtr.h"
#include "clang/AST/CFG.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
@@ -25,6 +24,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/TranslationUnit.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/LocalCheckers.h"
@@ -32,6 +32,8 @@
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "llvm/Support/Streams.h"
+#include <vector>
+
using namespace clang;
@@ -53,11 +55,10 @@
namespace {
class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
- typedef llvm::ImmutableList<CodeAction> Actions;
+ typedef std::vector<CodeAction> Actions;
Actions FunctionActions;
Actions ObjCMethodActions;
-
- Actions::Factory F;
+ Actions ObjCImplementationActions;
public:
const bool Visualize;
@@ -78,16 +79,19 @@
const std::string& fname,
const std::string& htmldir,
bool visualize, bool trim, bool analyzeAll)
- : FunctionActions(F.GetEmptyList()), ObjCMethodActions(F.GetEmptyList()),
- Visualize(visualize), TrimGraph(trim), LOpts(lopts), Diags(diags),
+ : Visualize(visualize), TrimGraph(trim), LOpts(lopts), Diags(diags),
Ctx(0), PP(pp), PPF(ppf),
HTMLDir(htmldir),
FName(fname),
AnalyzeAll(analyzeAll) {}
void addCodeAction(CodeAction action) {
- FunctionActions = F.Concat(action, FunctionActions);
- ObjCMethodActions = F.Concat(action, ObjCMethodActions);
+ FunctionActions.push_back(action);
+ ObjCMethodActions.push_back(action);
+ }
+
+ void addObjCImplementationAction(CodeAction action) {
+ ObjCImplementationActions.push_back(action);
}
virtual void Initialize(ASTContext &Context) {
@@ -95,6 +99,8 @@
}
virtual void HandleTopLevelDecl(Decl *D);
+ virtual void HandleTranslationUnit(TranslationUnit &TU);
+
void HandleCode(Decl* D, Stmt* Body, Actions actions);
};
@@ -235,6 +241,18 @@
}
}
+void AnalysisConsumer::HandleTranslationUnit(TranslationUnit& TU) {
+
+ if (ObjCImplementationActions.empty())
+ return;
+
+ for (TranslationUnit::iterator I = TU.begin(), E = TU.end(); I!=E; ++I) {
+
+ if (ObjCImplementationDecl* ID = dyn_cast<ObjCImplementationDecl>(*I))
+ HandleCode(ID, 0, ObjCImplementationActions);
+ }
+}
+
void AnalysisConsumer::HandleCode(Decl* D, Stmt* Body, Actions actions) {
// Don't run the actions if an error has occured with parsing the file.
@@ -259,7 +277,7 @@
// Dispatch on the actions.
for (Actions::iterator I = actions.begin(),
E = actions.end(); I != E; ++I)
- ((*I).getHead())(mgr);
+ (*I)(mgr);
}
//===----------------------------------------------------------------------===//
@@ -351,6 +369,11 @@
mgr.getCFG().viewCFG();
}
+static void ActionCheckObjCDealloc(AnalysisManager& mgr) {
+ BugReporter BR(mgr);
+ CheckObjCDealloc(cast<ObjCImplementationDecl>(mgr.getCodeDecl()), BR);
+}
+
//===----------------------------------------------------------------------===//
// AnalysisConsumer creation.
//===----------------------------------------------------------------------===//
@@ -401,6 +424,9 @@
default: break;
}
+ // Checks we always perform:
+ C->addObjCImplementationAction(&ActionCheckObjCDealloc);
+
return C.take();
}
Modified: cfe/trunk/include/clang/Analysis/LocalCheckers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/LocalCheckers.h?rev=53075&r1=53074&r2=53075&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/LocalCheckers.h (original)
+++ cfe/trunk/include/clang/Analysis/LocalCheckers.h Wed Jul 2 23:29:21 2008
@@ -28,6 +28,7 @@
class ParentMap;
class LiveVariables;
class BugReporter;
+class ObjCImplementationDecl;
void CheckDeadStores(LiveVariables& L, BugReporter& BR);
@@ -39,6 +40,9 @@
bool StandardWarnings,
const LangOptions& lopts);
+void CheckObjCDealloc(ObjCImplementationDecl* D, BugReporter& BR);
+
+
} // end namespace clang
#endif
Modified: cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h?rev=53075&r1=53074&r2=53075&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/BugReporter.h Wed Jul 2 23:29:21 2008
@@ -24,7 +24,6 @@
#include <vector>
#include <list>
-
namespace clang {
class PathDiagnostic;
@@ -286,6 +285,15 @@
iterator end() { return Reports.end(); }
};
+class SimpleBugType : public BugTypeCacheLocation {
+ const char* name;
+public:
+ SimpleBugType(const char* n) : name(n) {}
+
+ virtual const char* getName() const { return name; }
+ virtual const char* getDescription() const { return name; }
+};
+
} // end clang namespace
#endif
Added: cfe/trunk/lib/Analysis/CheckObjCDealloc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CheckObjCDealloc.cpp?rev=53075&view=auto
==============================================================================
--- cfe/trunk/lib/Analysis/CheckObjCDealloc.cpp (added)
+++ cfe/trunk/lib/Analysis/CheckObjCDealloc.cpp Wed Jul 2 23:29:21 2008
@@ -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);
+ }
+}
+
Modified: cfe/trunk/lib/Analysis/DeadStores.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/DeadStores.cpp?rev=53075&r1=53074&r2=53075&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/DeadStores.cpp (original)
+++ cfe/trunk/lib/Analysis/DeadStores.cpp Wed Jul 2 23:29:21 2008
@@ -144,23 +144,6 @@
} // end anonymous namespace
//===----------------------------------------------------------------------===//
-// BugReporter-based invocation of the Dead-Stores checker.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class SimpleBugType : public BugTypeCacheLocation {
- const char* name;
-public:
- SimpleBugType(const char* n) : name(n) {}
-
- virtual const char* getName() const {
- return name;
- }
-};
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
// Driver function to invoke the Dead-Stores checker on a CFG.
//===----------------------------------------------------------------------===//
Modified: cfe/trunk/test/Analysis/NSPanel.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/NSPanel.m?rev=53075&r1=53074&r2=53075&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/NSPanel.m (original)
+++ cfe/trunk/test/Analysis/NSPanel.m Wed Jul 2 23:29:21 2008
@@ -67,7 +67,8 @@
- (void)myMethod;
- (void)myMethod2;
@end
- at implementation MyClass
+
+ at implementation MyClass // no-warning
- (void)myMethod
{
NSPanel *panel = [[NSPanel alloc] initWithContentRect:NSMakeRect(0, 0, 200, 200) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:(BOOL)1];
Modified: cfe/trunk/test/Analysis/NSString.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/NSString.m?rev=53075&r1=53074&r2=53075&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/NSString.m (original)
+++ cfe/trunk/test/Analysis/NSString.m Wed Jul 2 23:29:21 2008
@@ -143,7 +143,7 @@
- (NSString*) getShared;
+ (C1*) sharedInstance;
@end
- at implementation C1 : NSObject {}
+ at implementation C1 : NSObject {} // expected-warning{{Objective-C class 'C1' lacks a 'dealloc' instance method}}
- (NSString*) getShared {
static NSString* s = 0;
if (!s) s = [[NSString alloc] init];
@@ -161,7 +161,7 @@
@interface SharedClass : NSObject
+ (id)sharedInstance;
@end
- at implementation SharedClass
+ at implementation SharedClass // expected-warning {{Objective-C class 'SharedClass' lacks a 'dealloc' instance method}}
- (id)_init {
if ((self = [super init])) {
More information about the cfe-commits
mailing list