summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2013-06-06 21:53:45 +0000
committerJordan Rose <jordan_rose@apple.com>2013-06-06 21:53:45 +0000
commitcf10ea8cb252fd7944edef909a064fa3d1b9965d (patch)
treee5c21cb16435c679ad4c5e1594b37b62c91a3c90 /clang/lib/StaticAnalyzer/Core/BugReporter.cpp
parent544053e353e38443c8cc992ff3a5f1fa8cb46234 (diff)
downloadbcm5719-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.cpp57
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?
OpenPOWER on IntegriCloud