From: Ted Kremenek Date: Thu, 3 Apr 2008 17:57:38 +0000 (+0000) Subject: Hooked up GRSimpleAPICheck and the simple Objective-C Foundation checks to use X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f1ae705460552655fe7275327804444c62e86bae;p=clang Hooked up GRSimpleAPICheck and the simple Objective-C Foundation checks to use the new BugReporter interface. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49180 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h index 86bd43a6e1..a5af327195 100644 --- a/include/clang/Analysis/PathSensitive/BugReporter.h +++ b/include/clang/Analysis/PathSensitive/BugReporter.h @@ -41,6 +41,9 @@ public: virtual PathDiagnosticPiece* getEndPath(ASTContext& Ctx, ExplodedNode *N) const; + + virtual void getRanges(const SourceRange*& beg, + const SourceRange*& end) const; }; class BugReporter { diff --git a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h index 16db802290..16b23c558c 100644 --- a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h +++ b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h @@ -22,12 +22,20 @@ namespace clang { class ValueState; class Diagnostic; +class BugReporter; +class ASTContext; +class GRExprEngine; +class PathDiagnosticClient; +template class ExplodedGraph; + class GRSimpleAPICheck : public GRAuditor { public: GRSimpleAPICheck() {} virtual ~GRSimpleAPICheck() {} - virtual void ReportResults(Diagnostic& D) {} + virtual void ReportResults(Diagnostic& Diag, PathDiagnosticClient* PD, + ASTContext& Ctx, BugReporter& BR, + ExplodedGraph& G) = 0; }; } // end namespace clang diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index 82cabaf7a3..9169492f6d 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -16,9 +16,10 @@ #include "BasicObjCFoundationChecks.h" #include "clang/Analysis/PathSensitive/ExplodedGraph.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h" #include "clang/Analysis/PathSensitive/ValueState.h" -#include "clang/Analysis/PathSensitive/AnnotatedPath.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathDiagnostic.h" #include "clang/AST/Expr.h" #include "clang/AST/ASTContext.h" @@ -28,15 +29,73 @@ #include using namespace clang; + +static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) { + Expr* Receiver = ME->getReceiver(); + + if (!Receiver) + return NULL; + + assert (Receiver->getType()->isPointerType()); + + const PointerType* T = Receiver->getType()->getAsPointerType(); + return dyn_cast(T->getPointeeType().getTypePtr()); +} + +static const char* GetReceiverNameType(ObjCMessageExpr* ME) { + ObjCInterfaceType* ReceiverType = GetReceiverType(ME); + return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName() + : NULL; +} + namespace { +class VISIBILITY_HIDDEN NilArg : public BugDescription { + std::string Msg; + const char* s; + SourceRange R; +public: + NilArg(ObjCMessageExpr* ME, unsigned Arg); + virtual ~NilArg() {} + + virtual const char* getName() const { + return "nil argument"; + } + + virtual const char* getDescription() const { + return s; + } + + virtual void getRanges(const SourceRange*& beg, + const SourceRange*& end) const { + beg = &R; + end = beg+1; + } + +}; + +NilArg::NilArg(ObjCMessageExpr* ME, unsigned Arg) : s(NULL) { + + Expr* E = ME->getArg(Arg); + R = E->getSourceRange(); + + std::ostringstream os; + + os << "Argument to '" << GetReceiverNameType(ME) << "' method '" + << ME->getSelector().getName() << "' cannot be nil."; + + Msg = os.str(); + s = Msg.c_str(); +} + + class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck { ASTContext &Ctx; ValueStateManager* VMgr; - typedef std::list > ErrorsTy; + typedef std::vector > ErrorsTy; ErrorsTy Errors; RVal GetRVal(ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); } @@ -53,12 +112,26 @@ public: BasicObjCFoundationChecks(ASTContext& ctx, ValueStateManager* vmgr) : Ctx(ctx), VMgr(vmgr) {} - virtual ~BasicObjCFoundationChecks() {} + virtual ~BasicObjCFoundationChecks() { + for (ErrorsTy::iterator I = Errors.begin(), E = Errors.end(); I!=E; ++I) + delete I->second; + } virtual bool Audit(ExplodedNode* N); - virtual void ReportResults(Diagnostic& D); - + virtual void ReportResults(Diagnostic& Diag, PathDiagnosticClient* PD, + ASTContext& Ctx, BugReporter& BR, + ExplodedGraph& G); + +private: + + void AddError(NodeTy* N, BugDescription* D) { + Errors.push_back(std::make_pair(N, D)); + } + + void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) { + AddError(N, new NilArg(ME, Arg)); + } }; } // end anonymous namespace @@ -71,24 +144,7 @@ clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx, return new BasicObjCFoundationChecks(Ctx, VMgr); } -static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) { - Expr* Receiver = ME->getReceiver(); - - if (!Receiver) - return NULL; - - assert (Receiver->getType()->isPointerType()); - - const PointerType* T = Receiver->getType()->getAsPointerType(); - - return dyn_cast(T->getPointeeType().getTypePtr()); -} -static const char* GetReceiverNameType(ObjCMessageExpr* ME) { - ObjCInterfaceType* ReceiverType = GetReceiverType(ME); - return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName() - : NULL; -} bool BasicObjCFoundationChecks::Audit(ExplodedNode* N) { @@ -127,43 +183,13 @@ static inline bool isNil(RVal X) { //===----------------------------------------------------------------------===// -void BasicObjCFoundationChecks::Warn(NodeTy* N, Expr* E, const std::string& s) { - Errors.push_back(AnnotatedPath()); - Errors.back().push_back(N, s, E); -} - -void BasicObjCFoundationChecks::ReportResults(Diagnostic& D) { - - // FIXME: Expand errors into paths. For now, just issue warnings. - - for (ErrorsTy::iterator I=Errors.begin(), E=Errors.end(); I!=E; ++I) { - - AnnotatedNode& AN = I->back(); - - unsigned diag = D.getCustomDiagID(Diagnostic::Warning, - AN.getString().c_str()); - - Stmt* S = cast(AN.getNode()->getLocation()).getStmt(); - FullSourceLoc L(S->getLocStart(), Ctx.getSourceManager()); - - SourceRange R = AN.getExpr()->getSourceRange(); +void BasicObjCFoundationChecks::ReportResults(Diagnostic& Diag, + PathDiagnosticClient* PD, + ASTContext& Ctx, BugReporter& BR, + ExplodedGraph& G) { - D.Report(L, diag, &AN.getString(), 1, &R, 1); - } -} - -void BasicObjCFoundationChecks::WarnNilArg(NodeTy* N, Expr* E) { - - ObjCMessageExpr* ME = - cast(cast(N->getLocation()).getStmt()); - - std::ostringstream os; - - os << "Argument to '" << GetReceiverNameType(ME) << "' method '" - << ME->getSelector().getName() - << "' cannot be nil."; - - Warn(N, E, os.str()); + for (ErrorsTy::iterator I=Errors.begin(), E=Errors.end(); I!=E; ++I) + BR.EmitPathWarning(Diag, PD, Ctx, *I->second, G, I->first); } bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) { @@ -173,7 +199,7 @@ bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) { Expr * E = ME->getArg(Arg); if (isNil(GetRVal(N->getState(), E))) { - WarnNilArg(N, E); + WarnNilArg(N, ME, Arg); return true; } diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp index c5a59e20d8..9954298165 100644 --- a/lib/Analysis/BugReporter.cpp +++ b/lib/Analysis/BugReporter.cpp @@ -43,8 +43,7 @@ static inline Stmt* GetStmt(const ProgramPoint& P) { PathDiagnosticPiece* -BugDescription::getEndPath(ASTContext& Ctx, - ExplodedNode *N) const { +BugDescription::getEndPath(ASTContext& Ctx, ExplodedNode *N) const { Stmt* S = GetStmt(N->getLocation()); @@ -60,6 +59,12 @@ BugDescription::getEndPath(ASTContext& Ctx, return P; } +void BugDescription::getRanges(const SourceRange*& beg, + const SourceRange*& end) const { + beg = NULL; + end = NULL; +} + void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx, const BugDescription& B, ExplodedGraph& G, @@ -266,7 +271,7 @@ void BugReporter::EmitWarning(Diagnostic& Diag, ASTContext& Ctx, return; std::ostringstream os; - os << "[CHECKER] " << B.getName(); + os << "[CHECKER] " << B.getDescription(); unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, os.str().c_str()); diff --git a/lib/Analysis/GRSimpleVals.cpp b/lib/Analysis/GRSimpleVals.cpp index 36ffe33c6f..208e7cb7ae 100644 --- a/lib/Analysis/GRSimpleVals.cpp +++ b/lib/Analysis/GRSimpleVals.cpp @@ -164,8 +164,8 @@ static void EmitWarning(Diagnostic& Diag, PathDiagnosticClient* PD, namespace clang { unsigned RunGRSimpleVals(CFG& cfg, Decl& CD, ASTContext& Ctx, - Diagnostic& Diag, PathDiagnosticClient* PD, - bool Visualize, bool TrimGraph) { + Diagnostic& Diag, PathDiagnosticClient* PD, + bool Visualize, bool TrimGraph) { GRCoreEngine Eng(cfg, CD, Ctx); GRExprEngine* CS = &Eng.getCheckerState(); @@ -217,7 +217,8 @@ unsigned RunGRSimpleVals(CFG& cfg, Decl& CD, ASTContext& Ctx, EmitWarning(Diag, PD, Ctx, BR, RetStack(), G, CS->ret_stackaddr_begin(), CS->ret_stackaddr_end()); - FoundationCheck.get()->ReportResults(Diag); + + FoundationCheck.get()->ReportResults(Diag, PD, Ctx, BR, G); #ifndef NDEBUG if (Visualize) CS->ViewGraph(TrimGraph); #endif diff --git a/lib/Analysis/GRSimpleVals.h b/lib/Analysis/GRSimpleVals.h index 2b3d0fd00a..74f7fd81ea 100644 --- a/lib/Analysis/GRSimpleVals.h +++ b/lib/Analysis/GRSimpleVals.h @@ -21,6 +21,9 @@ namespace clang { +class PathDiagnostic; +class ASTContext; + class GRSimpleVals : public GRTransferFuncs { public: GRSimpleVals() {} @@ -58,6 +61,9 @@ public: CallExpr* CE, LVal L, ExplodedNode* Pred); + static void GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx, + ExplodedNode* N); + protected: // Equality operators for LVals.