diff options
author | Jordan Rose <jordan_rose@apple.com> | 2013-06-06 21:53:45 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2013-06-06 21:53:45 +0000 |
commit | cf10ea8cb252fd7944edef909a064fa3d1b9965d (patch) | |
tree | e5c21cb16435c679ad4c5e1594b37b62c91a3c90 /clang/lib/StaticAnalyzer/Core/BugReporter.cpp | |
parent | 544053e353e38443c8cc992ff3a5f1fa8cb46234 (diff) | |
download | bcm5719-llvm-cf10ea8cb252fd7944edef909a064fa3d1b9965d.tar.gz bcm5719-llvm-cf10ea8cb252fd7944edef909a064fa3d1b9965d.zip |
[analyzer; new edges] Simplify edges in a C++11 for-range loop.
Previously our edges were completely broken here; now, the final result
is a very simple set of edges in most cases: one up to the "for" keyword
for context, and one into the body of the loop. This matches the behavior
for ObjC for-in loops.
In the AST, however, CXXForRangeStmts are handled very differently from
ObjCForCollectionStmts. Since they are specified in terms of equivalent
statements in the C++ standard, we actually have implicit AST nodes for
all of the semantic statements. This makes evaluation very easy, but
diagnostic locations a bit trickier. Fortunately, the problem can be
generally defined away by marking all of the implicit statements as
part of the top-level for-range statement.
One of the implicit statements in a for-range statement is the declaration
of implicit iterators __begin and __end. The CFG synthesizes two
separate DeclStmts to match each of these decls, but until now these
synthetic DeclStmts weren't in the function's ParentMap. Now, the CFG
keeps track of its synthetic statements, and the AnalysisDeclContext will
make sure to add them to the ParentMap.
<rdar://problem/14038483>
llvm-svn: 183449
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/BugReporter.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/BugReporter.cpp | 57 |
1 files changed, 41 insertions, 16 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index 829e7482ebe..96aa4886186 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -363,6 +363,7 @@ static const Stmt *getEnclosingParent(const Stmt *S, const ParentMap &PM) { case Stmt::DoStmtClass: case Stmt::WhileStmtClass: case Stmt::ObjCForCollectionStmtClass: + case Stmt::CXXForRangeStmtClass: return Parent; default: break; @@ -404,6 +405,10 @@ getEnclosingStmtLocation(const Stmt *S, SourceManager &SMgr, const ParentMap &P, return PathDiagnosticLocation(Parent, SMgr, LC); else return PathDiagnosticLocation(S, SMgr, LC); + case Stmt::CXXForRangeStmtClass: + if (cast<CXXForRangeStmt>(Parent)->getBody() == S) + return PathDiagnosticLocation(S, SMgr, LC); + break; case Stmt::DoStmtClass: return PathDiagnosticLocation(S, SMgr, LC); case Stmt::ForStmtClass: @@ -1253,6 +1258,7 @@ static bool isLoop(const Stmt *Term) { case Stmt::ForStmtClass: case Stmt::WhileStmtClass: case Stmt::ObjCForCollectionStmtClass: + case Stmt::CXXForRangeStmtClass: return true; default: // Note that we intentionally do not include do..while here. @@ -1302,6 +1308,15 @@ static const Stmt *getStmtBeforeCond(ParentMap &PM, const Stmt *Term, static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) { const Stmt *LoopBody = 0; switch (Term->getStmtClass()) { + case Stmt::CXXForRangeStmtClass: { + const CXXForRangeStmt *FR = cast<CXXForRangeStmt>(Term); + if (isContainedByStmt(PM, FR->getInc(), S)) + return true; + if (isContainedByStmt(PM, FR->getLoopVarStmt(), S)) + return true; + LoopBody = FR->getBody(); + break; + } case Stmt::ForStmtClass: { const ForStmt *FS = cast<ForStmt>(Term); if (isContainedByStmt(PM, FS->getInc(), S)) @@ -1718,16 +1733,20 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, // Are we jumping to the head of a loop? Add a special diagnostic. if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) { PathDiagnosticLocation L(Loop, SM, PDB.LC); - const CompoundStmt *CS = NULL; + const Stmt *Body = NULL; if (const ForStmt *FS = dyn_cast<ForStmt>(Loop)) - CS = dyn_cast<CompoundStmt>(FS->getBody()); + Body = FS->getBody(); else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop)) - CS = dyn_cast<CompoundStmt>(WS->getBody()); + Body = WS->getBody(); else if (const ObjCForCollectionStmt *OFS = - dyn_cast<ObjCForCollectionStmt>(Loop)) { - CS = dyn_cast<CompoundStmt>(OFS->getBody()); + dyn_cast<ObjCForCollectionStmt>(Loop)) { + Body = OFS->getBody(); + } else if (const CXXForRangeStmt *FRS = + dyn_cast<CXXForRangeStmt>(Loop)) { + Body = FRS->getBody(); } + // do-while statements are explicitly excluded here PathDiagnosticEventPiece *p = new PathDiagnosticEventPiece(L, "Looping back to the head " @@ -1737,7 +1756,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), PDB.LC); PD.getActivePath().push_front(p); - if (CS) { + if (const CompoundStmt *CS = dyn_cast_or_null<CompoundStmt>(Body)) { addEdgeToPath(PD.getActivePath(), PrevLoc, PathDiagnosticLocation::createEndBrace(CS, SM), PDB.LC); @@ -1871,16 +1890,22 @@ static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond) { } case Stmt::ObjCForCollectionStmtClass: return cast<ObjCForCollectionStmt>(S)->getElement() == Cond; + case Stmt::CXXForRangeStmtClass: { + const CXXForRangeStmt *FRS = cast<CXXForRangeStmt>(S); + return FRS->getCond() == Cond || FRS->getRangeInit() == Cond; + } default: return false; } } static bool isIncrementOrInitInForLoop(const Stmt *S, const Stmt *FL) { - const ForStmt *FS = dyn_cast<ForStmt>(FL); - if (!FS) - return false; - return FS->getInc() == S || FS->getInit() == S; + if (const ForStmt *FS = dyn_cast<ForStmt>(FL)) + return FS->getInc() == S || FS->getInit() == S; + if (const CXXForRangeStmt *FRS = dyn_cast<CXXForRangeStmt>(FL)) + return FRS->getInc() == S || FRS->getRangeStmt() == S || + FRS->getLoopVarStmt() || FRS->getRangeInit() == S; + return false; } typedef llvm::DenseSet<const PathDiagnosticCallPiece *> @@ -1903,16 +1928,15 @@ static void addContextEdges(PathPieces &pieces, SourceManager &SM, continue; PathDiagnosticLocation SrcLoc = Piece->getStartLocation(); - const Stmt *Src = getLocStmt(SrcLoc); SmallVector<PathDiagnosticLocation, 4> SrcContexts; - PathDiagnosticLocation NextSrcContext = - getEnclosingStmtLocation(Src, SM, PM, LCtx, /*allowNested=*/true); - const Stmt *InnerStmt = Src; + PathDiagnosticLocation NextSrcContext = SrcLoc; + const Stmt *InnerStmt = 0; while (NextSrcContext.isValid() && NextSrcContext.asStmt() != InnerStmt) { SrcContexts.push_back(NextSrcContext); InnerStmt = NextSrcContext.asStmt(); - NextSrcContext = getEnclosingStmtLocation(InnerStmt, SM, PM, LCtx, true); + NextSrcContext = getEnclosingStmtLocation(InnerStmt, SM, PM, LCtx, + /*allowNested=*/true); } // Repeatedly split the edge as necessary. @@ -2024,7 +2048,8 @@ static void simplifySimpleBranches(PathPieces &pieces) { // We only perform this transformation for specific branch kinds. // We don't want to do this for do..while, for example. if (!(isa<ForStmt>(s1Start) || isa<WhileStmt>(s1Start) || - isa<IfStmt>(s1Start) || isa<ObjCForCollectionStmt>(s1Start))) + isa<IfStmt>(s1Start) || isa<ObjCForCollectionStmt>(s1Start) || + isa<CXXForRangeStmt>(s1Start))) continue; // Is s1End the branch condition? |