Rewrite control-flow diagnostic generation "extensive" algorithm using "edge
contexts". This allows us to use a stack of contexts to keep track of what control-flow pieces to include when exiting blocks like 'if', 'for', etc. llvm-svn: 68473
This commit is contained in:
		
							parent
							
								
									2ed6a20934
								
							
						
					
					
						commit
						c4c9ed0f9b
					
				| 
						 | 
					@ -456,6 +456,8 @@ public:
 | 
				
			||||||
// "Minimal" path diagnostic generation algorithm.
 | 
					// "Minimal" path diagnostic generation algorithm.
 | 
				
			||||||
//===----------------------------------------------------------------------===//
 | 
					//===----------------------------------------------------------------------===//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
 | 
					static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
 | 
				
			||||||
                                          PathDiagnosticBuilder &PDB,
 | 
					                                          PathDiagnosticBuilder &PDB,
 | 
				
			||||||
                                          const ExplodedNode<GRState> *N) {
 | 
					                                          const ExplodedNode<GRState> *N) {
 | 
				
			||||||
| 
						 | 
					@ -740,6 +742,10 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
 | 
				
			||||||
      PDB.getStateManager().iterBindings(N->getState(), SNS);
 | 
					      PDB.getStateManager().iterBindings(N->getState(), SNS);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  // After constructing the full PathDiagnostic, do a pass over it to compact
 | 
				
			||||||
 | 
					  // PathDiagnosticPieces that occur within a macro.
 | 
				
			||||||
 | 
					  CompactPathDiagnostic(PD, PDB.getSourceManager());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//===----------------------------------------------------------------------===//
 | 
					//===----------------------------------------------------------------------===//
 | 
				
			||||||
| 
						 | 
					@ -764,6 +770,258 @@ static bool IsControlFlowExpr(const Stmt *S) {
 | 
				
			||||||
  return false;  
 | 
					  return false;  
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace {
 | 
				
			||||||
 | 
					class VISIBILITY_HIDDEN EdgeBuilder {
 | 
				
			||||||
 | 
					  std::vector<PathDiagnosticLocation> CLocs;
 | 
				
			||||||
 | 
					  typedef std::vector<PathDiagnosticLocation>::iterator iterator;
 | 
				
			||||||
 | 
					  PathDiagnostic &PD;
 | 
				
			||||||
 | 
					  PathDiagnosticBuilder &PDB;
 | 
				
			||||||
 | 
					  PathDiagnosticLocation PrevLoc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool containsLocation(const PathDiagnosticLocation &Container,
 | 
				
			||||||
 | 
					                        const PathDiagnosticLocation &Containee);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  PathDiagnosticLocation getContextLocation(const PathDiagnosticLocation &L);
 | 
				
			||||||
 | 
					  void rawAddEdge(PathDiagnosticLocation NewLoc);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  void popLocation() {
 | 
				
			||||||
 | 
					    rawAddEdge(CLocs.back());
 | 
				
			||||||
 | 
					    CLocs.pop_back();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  PathDiagnosticLocation IgnoreParens(const PathDiagnosticLocation &L);  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  EdgeBuilder(PathDiagnostic &pd, PathDiagnosticBuilder &pdb)
 | 
				
			||||||
 | 
					    : PD(pd), PDB(pdb) {
 | 
				
			||||||
 | 
					      CLocs.push_back(PathDiagnosticLocation(&PDB.getCodeDecl(),
 | 
				
			||||||
 | 
					                                             PDB.getSourceManager()));
 | 
				
			||||||
 | 
					      if (!PD.empty()) {
 | 
				
			||||||
 | 
					        PrevLoc = PD.begin()->getLocation();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (const Stmt *S = PrevLoc.asStmt())
 | 
				
			||||||
 | 
					          addContext(PDB.getEnclosingStmtLocation(S).asStmt());
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ~EdgeBuilder() {
 | 
				
			||||||
 | 
					    while (!CLocs.empty()) popLocation();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  void addEdge(const Stmt *S, bool alwaysAdd = false) {
 | 
				
			||||||
 | 
					    addEdge(PathDiagnosticLocation(S, PDB.getSourceManager()), alwaysAdd);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  void addContext(const Stmt *S);
 | 
				
			||||||
 | 
					};  
 | 
				
			||||||
 | 
					} // end anonymous namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PathDiagnosticLocation
 | 
				
			||||||
 | 
					EdgeBuilder::getContextLocation(const PathDiagnosticLocation &L) {
 | 
				
			||||||
 | 
					  if (const Stmt *S = L.asStmt()) {
 | 
				
			||||||
 | 
					    if (IsControlFlowExpr(S))
 | 
				
			||||||
 | 
					      return L;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return PDB.getEnclosingStmtLocation(S);    
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  return L;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container,
 | 
				
			||||||
 | 
					                                   const PathDiagnosticLocation &Containee) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (Container == Containee)
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					  if (Container.asDecl())
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  if (const Stmt *S = Containee.asStmt())
 | 
				
			||||||
 | 
					    if (const Stmt *ContainerS = Container.asStmt()) {
 | 
				
			||||||
 | 
					      while (S) {
 | 
				
			||||||
 | 
					        if (S == ContainerS)
 | 
				
			||||||
 | 
					          return true;
 | 
				
			||||||
 | 
					        S = PDB.getParent(S);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Less accurate: compare using source ranges.
 | 
				
			||||||
 | 
					  SourceRange ContainerR = Container.asRange();
 | 
				
			||||||
 | 
					  SourceRange ContaineeR = Containee.asRange();
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  SourceManager &SM = PDB.getSourceManager();
 | 
				
			||||||
 | 
					  SourceLocation ContainerRBeg = SM.getInstantiationLoc(ContainerR.getBegin());
 | 
				
			||||||
 | 
					  SourceLocation ContainerREnd = SM.getInstantiationLoc(ContainerR.getEnd());
 | 
				
			||||||
 | 
					  SourceLocation ContaineeRBeg = SM.getInstantiationLoc(ContaineeR.getBegin());
 | 
				
			||||||
 | 
					  SourceLocation ContaineeREnd = SM.getInstantiationLoc(ContaineeR.getEnd());
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  unsigned ContainerBegLine = SM.getInstantiationLineNumber(ContainerRBeg);
 | 
				
			||||||
 | 
					  unsigned ContainerEndLine = SM.getInstantiationLineNumber(ContainerREnd);
 | 
				
			||||||
 | 
					  unsigned ContaineeBegLine = SM.getInstantiationLineNumber(ContaineeRBeg);
 | 
				
			||||||
 | 
					  unsigned ContaineeEndLine = SM.getInstantiationLineNumber(ContaineeREnd);
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  assert(ContainerBegLine <= ContainerEndLine);
 | 
				
			||||||
 | 
					  assert(ContaineeBegLine <= ContaineeEndLine);  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  return (ContainerBegLine <= ContaineeBegLine &&
 | 
				
			||||||
 | 
					          ContainerEndLine >= ContaineeEndLine &&
 | 
				
			||||||
 | 
					          (ContainerBegLine != ContaineeBegLine ||
 | 
				
			||||||
 | 
					           SM.getInstantiationColumnNumber(ContainerRBeg) <= 
 | 
				
			||||||
 | 
					           SM.getInstantiationColumnNumber(ContaineeRBeg)) &&
 | 
				
			||||||
 | 
					          (ContainerEndLine != ContaineeEndLine ||
 | 
				
			||||||
 | 
					           SM.getInstantiationColumnNumber(ContainerREnd) >=
 | 
				
			||||||
 | 
					           SM.getInstantiationColumnNumber(ContainerREnd)));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PathDiagnosticLocation
 | 
				
			||||||
 | 
					EdgeBuilder::IgnoreParens(const PathDiagnosticLocation &L) {
 | 
				
			||||||
 | 
					  if (const Expr* E = dyn_cast_or_null<Expr>(L.asStmt()))
 | 
				
			||||||
 | 
					      return PathDiagnosticLocation(E->IgnoreParenCasts(),
 | 
				
			||||||
 | 
					                                    PDB.getSourceManager());
 | 
				
			||||||
 | 
					  return L;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
 | 
				
			||||||
 | 
					  if (!PrevLoc.isValid()) {
 | 
				
			||||||
 | 
					    PrevLoc = NewLoc;
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  if (NewLoc.asLocation() == PrevLoc.asLocation())
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					  // FIXME: Ignore intra-macro edges for now.
 | 
				
			||||||
 | 
					  if (NewLoc.asLocation().getInstantiationLoc() ==
 | 
				
			||||||
 | 
					      PrevLoc.asLocation().getInstantiationLoc())
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PD.push_front(new PathDiagnosticControlFlowPiece(NewLoc, PrevLoc));
 | 
				
			||||||
 | 
					  PrevLoc = NewLoc;  
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) {
 | 
				
			||||||
 | 
					  const PathDiagnosticLocation &CLoc = getContextLocation(NewLoc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (!CLocs.empty()) {
 | 
				
			||||||
 | 
					    const PathDiagnosticLocation &TopContextLoc = CLocs.back();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Is the top location context the same as the one for the new location?
 | 
				
			||||||
 | 
					    if (TopContextLoc == CLoc) {
 | 
				
			||||||
 | 
					      if (alwaysAdd && NewLoc.asLocation() != CLoc.asLocation())
 | 
				
			||||||
 | 
					        rawAddEdge(NewLoc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (containsLocation(TopContextLoc, CLoc)) {
 | 
				
			||||||
 | 
					      if (alwaysAdd)
 | 
				
			||||||
 | 
					        rawAddEdge(NewLoc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      CLocs.push_back(CLoc);
 | 
				
			||||||
 | 
					      return;      
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Context does not contain the location.  Flush it.
 | 
				
			||||||
 | 
					    popLocation();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  assert(0 && "addEdge should never pop the top context");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EdgeBuilder::addContext(const Stmt *S) {
 | 
				
			||||||
 | 
					  if (!S)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PathDiagnosticLocation L(S, PDB.getSourceManager());
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  while (!CLocs.empty()) {
 | 
				
			||||||
 | 
					    const PathDiagnosticLocation &TopContextLoc = CLocs.back();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Is the top location context the same as the one for the new location?
 | 
				
			||||||
 | 
					    if (TopContextLoc == L)
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (containsLocation(TopContextLoc, L)) {
 | 
				
			||||||
 | 
					    //   if (const Stmt *S = L.asStmt())
 | 
				
			||||||
 | 
					    //     if (isa<Expr>(S))
 | 
				
			||||||
 | 
					    //       if (const Stmt *P = PDB.getParent(S))
 | 
				
			||||||
 | 
					    //         addContext(PDB.getEnclosingStmtLocation(P).asStmt());
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      CLocs.push_back(L);
 | 
				
			||||||
 | 
					      return;      
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Context does not contain the location.  Flush it.
 | 
				
			||||||
 | 
					    popLocation();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CLocs.push_back(L);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
 | 
				
			||||||
 | 
					                                            PathDiagnosticBuilder &PDB,
 | 
				
			||||||
 | 
					                                            const ExplodedNode<GRState> *N) {
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  EdgeBuilder EB(PD, PDB);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const ExplodedNode<GRState>* NextNode = N->pred_empty() 
 | 
				
			||||||
 | 
					                                        ? NULL : *(N->pred_begin());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (NextNode) {
 | 
				
			||||||
 | 
					    N = NextNode;
 | 
				
			||||||
 | 
					    NextNode = GetPredecessorNode(N);
 | 
				
			||||||
 | 
					    ProgramPoint P = N->getLocation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Block edges.
 | 
				
			||||||
 | 
					    if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
 | 
				
			||||||
 | 
					      const CFGBlock &Blk = *BE->getSrc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (const Stmt *Term = Blk.getTerminator())
 | 
				
			||||||
 | 
					        EB.addContext(Term);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Only handle blocks with more than 1 statement here, as the blocks
 | 
				
			||||||
 | 
					      // with one statement are handled at BlockEntrances.
 | 
				
			||||||
 | 
					      if (Blk.size() > 1) {
 | 
				
			||||||
 | 
					        const Stmt *S = *Blk.rbegin();
 | 
				
			||||||
 | 
					        EB.addEdge(S);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      continue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
 | 
				
			||||||
 | 
					      if (const Stmt* S = BE->getFirstStmt()) {
 | 
				
			||||||
 | 
					       if (IsControlFlowExpr(S))
 | 
				
			||||||
 | 
					         EB.addContext(S);
 | 
				
			||||||
 | 
					       else
 | 
				
			||||||
 | 
					        EB.addEdge(S);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      continue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    PathDiagnosticPiece* p =
 | 
				
			||||||
 | 
					    PDB.getReport().VisitNode(N, NextNode, PDB.getGraph(),
 | 
				
			||||||
 | 
					                              PDB.getBugReporter(), PDB.getNodeMapClosure());
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (p) {
 | 
				
			||||||
 | 
					      EB.addEdge(p->getLocation(), true);
 | 
				
			||||||
 | 
					      PD.push_front(p);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void GenExtAddEdge(PathDiagnostic& PD,
 | 
					static void GenExtAddEdge(PathDiagnostic& PD,
 | 
				
			||||||
                          PathDiagnosticBuilder &PDB,
 | 
					                          PathDiagnosticBuilder &PDB,
 | 
				
			||||||
                          PathDiagnosticLocation NewLoc,
 | 
					                          PathDiagnosticLocation NewLoc,
 | 
				
			||||||
| 
						 | 
					@ -930,6 +1188,7 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//===----------------------------------------------------------------------===//
 | 
					//===----------------------------------------------------------------------===//
 | 
				
			||||||
// Methods for BugType and subclasses.
 | 
					// Methods for BugType and subclasses.
 | 
				
			||||||
| 
						 | 
					@ -1337,10 +1596,6 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
 | 
				
			||||||
      GenerateMinimalPathDiagnostic(PD, PDB, N);
 | 
					      GenerateMinimalPathDiagnostic(PD, PDB, N);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  // After constructing the full PathDiagnostic, do a pass over it to compact
 | 
					 | 
				
			||||||
  // PathDiagnosticPieces that occur within a macro.
 | 
					 | 
				
			||||||
  CompactPathDiagnostic(PD, PDB.getSourceManager());  
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void BugReporter::Register(BugType *BT) {
 | 
					void BugReporter::Register(BugType *BT) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue