diff options
author | Ted Kremenek <kremenek@apple.com> | 2011-08-06 06:54:45 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2011-08-06 06:54:45 +0000 |
commit | 993124ecdd44ec1430a3b7f01b22f65bbaadb586 (patch) | |
tree | 37cf3a5e149a09a6e262a8f5d3f2ff14a9724aa1 /lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | |
parent | 82cd2e5c15aa909ec9613c4228ab69e07f1c6f7a (diff) |
[analyzer] Start sketching out a new BugReporterVisitor that inspects branches and other expressions to generate interesting path events in diagnostics.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@137012 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/BugReporterVisitors.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 75e232f5bd..5f068dc9f0 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -468,3 +468,155 @@ void bugreporter::registerVarDeclsLastStore(BugReporterContext &BRC, WorkList.push_back(*I); } } + +//===----------------------------------------------------------------------===// +// Visitor that tries to report interesting diagnostics from conditions. +//===----------------------------------------------------------------------===// + +namespace { +class ConditionVisitor : public BugReporterVisitor { +public: + void Profile(llvm::FoldingSetNodeID &ID) const { + static int x = 0; + ID.AddPointer(&x); + } + + virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *Prev, + BugReporterContext &BRC); + + PathDiagnosticPiece *VisitTerminator(const Stmt *Term, + const GRState *CurrentState, + const GRState *PrevState, + const CFGBlock *srcBlk, + const CFGBlock *dstBlk, + BugReporterContext &BRC); + + PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, + bool tookTrue, + BugReporterContext &BRC); + + PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, + const DeclRefExpr *DR, + const bool tookTrue, + BugReporterContext &BRC); + +}; +} + +PathDiagnosticPiece *ConditionVisitor::VisitNode(const ExplodedNode *N, + const ExplodedNode *Prev, + BugReporterContext &BRC) { + + const ProgramPoint &progPoint = N->getLocation(); + + // If an assumption was made on a branch, it should be caught + // here by looking at the state transition. + if (const BlockEdge *BE = dyn_cast<BlockEdge>(&progPoint)) { + const CFGBlock *srcBlk = BE->getSrc(); + + if (const Stmt *term = srcBlk->getTerminator()) { + const GRState *CurrentState = N->getState(); + const GRState *PrevState = Prev->getState(); + if (CurrentState != PrevState) + return VisitTerminator(term, CurrentState, PrevState, + srcBlk, BE->getDst(), + BRC); + } + + return 0; + } + + return 0; +} + +PathDiagnosticPiece * +ConditionVisitor::VisitTerminator(const Stmt *Term, + const GRState *CurrentState, + const GRState *PrevState, + const CFGBlock *srcBlk, + const CFGBlock *dstBlk, + BugReporterContext &BRC) { + + assert(CurrentState != PrevState); + const Expr *Cond = 0; + + switch (Term->getStmtClass()) { + default: + return 0; + case Stmt::IfStmtClass: + Cond = cast<IfStmt>(Term)->getCond(); + break; + case Stmt::ConditionalOperatorClass: + Cond = cast<ConditionalOperator>(Term)->getCond(); + break; + } + + assert(Cond); + assert(srcBlk->succ_size() == 2); + const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk; + return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()), + tookTrue, BRC); +} + +PathDiagnosticPiece * +ConditionVisitor::VisitTrueTest(const Expr *Cond, + bool tookTrue, + BugReporterContext &BRC) { + + const Expr *Ex = Cond; + + while (true) + switch (Ex->getStmtClass()) { + default: + return 0; + case Stmt::DeclRefExprClass: + return VisitTrueTest(Cond, cast<DeclRefExpr>(Ex), tookTrue, BRC); + case Stmt::UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(Ex); + if (UO->getOpcode() == UO_LNot) { + tookTrue = !tookTrue; + Ex = UO->getSubExpr()->IgnoreParenNoopCasts(BRC.getASTContext()); + continue; + } + return 0; + } + } +} + +PathDiagnosticPiece * +ConditionVisitor::VisitTrueTest(const Expr *Cond, + const DeclRefExpr *DR, + const bool tookTrue, + BugReporterContext &BRC) { + + const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); + if (!VD) + return 0; + + llvm::SmallString<256> Buf; + llvm::raw_svector_ostream Out(Buf); + + Out << "Assuming '"; + VD->getDeclName().printName(Out); + Out << "' is "; + + QualType VDTy = VD->getType(); + + if (VDTy->isPointerType()) + Out << (tookTrue ? "non-null" : "null"); + else if (VDTy->isObjCObjectPointerType()) + Out << (tookTrue ? "non-nil" : "nil"); + else if (VDTy->isScalarType()) + Out << (tookTrue ? "not equal to 0" : "0"); + else + return 0; + + PathDiagnosticLocation Loc(Cond, BRC.getSourceManager()); + return new PathDiagnosticEventPiece(Loc, Out.str()); +} + +void bugreporter::registerConditionVisitor(BugReporterContext &BRC) { + BRC.addVisitor(new ConditionVisitor()); +} + |