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.
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
 | 
			
		||||
static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM);
 | 
			
		||||
 | 
			
		||||
static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
 | 
			
		||||
                                          PathDiagnosticBuilder &PDB,
 | 
			
		||||
                                          const ExplodedNode<GRState> *N) {
 | 
			
		||||
| 
						 | 
				
			
			@ -740,6 +742,10 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
 | 
			
		|||
      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;  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#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,
 | 
			
		||||
                          PathDiagnosticBuilder &PDB,
 | 
			
		||||
                          PathDiagnosticLocation NewLoc,
 | 
			
		||||
| 
						 | 
				
			
			@ -930,6 +1188,7 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
// Methods for BugType and subclasses.
 | 
			
		||||
| 
						 | 
				
			
			@ -1337,10 +1596,6 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
 | 
			
		|||
      GenerateMinimalPathDiagnostic(PD, PDB, N);
 | 
			
		||||
      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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue